From f54083389bb7ff0789e90289d9ce288ffae74d78 Mon Sep 17 00:00:00 2001 From: Daniele Fucini Date: Wed, 7 Jun 2023 20:27:05 +0200 Subject: [PATCH] Use timing decorator for problems 61-70 --- Python/p061.py | 67 +++++++++++++++++++++----------------------------- Python/p062.py | 25 ++++++++----------- Python/p063.py | 17 +++++-------- Python/p064.py | 22 ++++++----------- Python/p065.py | 29 +++++++++------------- Python/p066.py | 16 ++++-------- Python/p067.py | 16 ++++-------- Python/p068.py | 47 +++++++++++++++-------------------- Python/p069.py | 29 +++++++++------------- Python/p070.py | 24 ++++++------------ 10 files changed, 112 insertions(+), 180 deletions(-) diff --git a/Python/p061.py b/Python/p061.py index 117553b..b5e2a3f 100644 --- a/Python/p061.py +++ b/Python/p061.py @@ -19,10 +19,10 @@ # Find the sum of the only ordered set of six cyclic 4-digit numbers for which each polygonal type: triangle, square, pentagonal, # hexagonal, heptagonal, and octagonal, is represented by a different number in the set. -from timeit import default_timer - from numpy import zeros +from projecteuler import timing + polygonal = zeros((6, 10000), int) chain = [0] * 6 @@ -30,47 +30,40 @@ flags = [0] * 6 sum_ = 0 -# Recursive function to find the required set. It finds a polygonal number, -# check if it can be part of the chain, then use recursion to find the next -# number. If a solution can't be found with the current numbers, it uses -# backtracking and tries the next polygonal number. +# Recursive function to find the required set. It finds a polygonal number, check if it can be part of the chain, then use recursion to find the next +# number. If a solution can't be found with the current numbers, it uses backtracking and tries the next polygonal number. def find_set(step): global sum_ -# Use one polygonal number per type, starting from triangular. + # Use one polygonal number per type, starting from triangular. for i in range(6): -# If the current type has not been used yet, try it. + # If the current type has not been used yet, try it. if flags[i] == 0: -# Set a flag to record that the current polygonal type has been used. + # Set a flag to record that the current polygonal type has been used. flags[i] = 1 -# Start from 1010 because numbers finishing with 00, 01, ..., 09 can't -# be part of the chain. + # Start from 1010 because numbers finishing with 00, 01, ..., 09 can't be part of the chain. for j in range(1010, 10000): -# If the number doesn't finish with 00, 01, ..., 09 and is poligonal, -# try adding it to the chain and add its value to the total sum. + # If the number doesn't finish with 00, 01, ..., 09 and is poligonal, + # try adding it to the chain and add its value to the total sum. if j % 100 > 9 and polygonal[i, j] == 1: -# If it's the first number, just add it as first step in the chain. + # If it's the first number, just add it as first step in the chain. if step == 0: chain[step] = j sum_ += j -# Recursively try to add other numbers to the chain. If a solution -# is found, return 1. + # Recursively try to add other numbers to the chain. If a solution is found, return 1. if find_set(step+1): return 1 -# If a solution was not found, backtrack, subtracting the value of -# the number from the total. + # If a solution was not found, backtrack, subtracting the value of the number from the total. sum_ -= j -# If this is the last step and the current number can be added to the chain, -# add it, update the sum and return 1. A solution has been found. + # If this is the last step and the current number can be added to the chain, add it, update the sum and return 1. A solution has been found. elif step == 5 and j % 100 == chain[0] // 100 and j // 100 == chain[step-1] % 100: chain[step] = j sum_ += j return 1 -# For every other step, add the number to the chain if possible, then recursively -# try to add other numbers. + # For every other step, add the number to the chain if possible, then recursively try to add other numbers. elif step < 5 and j // 100 == chain[step-1] % 100: chain[step] = j sum_ += + j @@ -78,22 +71,21 @@ def find_set(step): if find_set(step+1): return 1 -# If a solution was not found, backtrack. + # If a solution was not found, backtrack. sum_ -= j -# Remove the flag for the current polygonal type. + # Remove the flag for the current polygonal type. flags[i] = 0 return 0 -def main(): - start = default_timer() - +@timing +def p061(): i = 1 n = 1 -# Generate all triangle numbers smaller than 10000 + # Generate all triangle numbers smaller than 10000 while True: polygonal[0, n] = 1 i = i + 1 @@ -105,7 +97,7 @@ def main(): i = 1 n = 1 -# Generate all square numbers smaller than 10000 + # Generate all square numbers smaller than 10000 while True: polygonal[1, n] = 1 i = i + 1 @@ -117,7 +109,7 @@ def main(): i = 1 n = 1 -# Generate all pentagonal numbers smaller than 10000 + # Generate all pentagonal numbers smaller than 10000 while True: polygonal[2, n] = 1 i = i + 1 @@ -129,7 +121,7 @@ def main(): i = 1 n = 1 -# Generate all hexagonal numbers smaller than 10000 + # Generate all hexagonal numbers smaller than 10000 while True: polygonal[3, n] = 1 i = i + 1 @@ -141,7 +133,7 @@ def main(): i = 1 n = 1 -# Generate all heptagonal numbers smaller than 10000 + # Generate all heptagonal numbers smaller than 10000 while True: polygonal[4, n] = 1 i = i + 1 @@ -152,7 +144,8 @@ def main(): i = 1 n = 1 -# Generate all octagonal numbers smaller than 10000 + + # Generate all octagonal numbers smaller than 10000 while True: polygonal[5, n] = 1 i = i + 1 @@ -161,17 +154,13 @@ def main(): if n >= 10000: break -# Find the requested set of numbers + # Find the requested set of numbers if find_set(0) == 0: print('Set not found') - end = default_timer() - print('Project Euler, Problem 61') print(f'Answer: {sum_}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p061() diff --git a/Python/p062.py b/Python/p062.py index f3e089f..b62d6f0 100644 --- a/Python/p062.py +++ b/Python/p062.py @@ -5,30 +5,29 @@ # # Find the smallest cube for which exactly five permutations of its digits are cube. -from timeit import default_timer - from numpy import zeros +from projecteuler import timing -def main(): - start = default_timer() +@timing +def p062(): N = 10000 cubes = zeros(N, int) -# Calculate i^3 for all i smaller than 10000 + # Calculate i^3 for all i smaller than 10000 for i in range(N): cubes[i] = i * i * i -# For each cube, check if there are four other cubes which are also -# a permutation of the first cube. + # For each cube, check if there are four other cubes which are also + # a permutation of the first cube. for i in range(N-5): count = 1 -# Stop when the limit has been reached, when 5 values have been found or -# when j^3 has more digits than i^3 (if they don't have the same digits, -# they can't be permutations). + # Stop when the limit has been reached, when 5 values have been found or + # when j^3 has more digits than i^3 (if they don't have the same digits, + # they can't be permutations). j = i + 1 while j < N and len(str(cubes[j])) == len(str(cubes[i])): @@ -43,13 +42,9 @@ def main(): if count == 5: break - end = default_timer() - print('Project Euler, Problem 62') print(f'Answer: {cubes[i]}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p062() diff --git a/Python/p063.py b/Python/p063.py index 37cb589..fe149f9 100644 --- a/Python/p063.py +++ b/Python/p063.py @@ -4,37 +4,32 @@ # # How many n-digit positive integers exist which are also an nth power? -from timeit import default_timer +from projecteuler import timing -def main(): - start = default_timer() - +@timing +def p063(): i = 1 count = 0 finished = 0 while not finished: -# When j=10, j^i will have i+1 digits (e.g. if i=3, 10^3=1000). + # When j=10, j^i will have i+1 digits (e.g. if i=3, 10^3=1000). for j in range(1, 10): p = j ** i if len(str(p)) == i: count = count + 1 -# When 9^i has less than i digits, all the numbers have been found. + # When 9^i has less than i digits, all the numbers have been found. if len(str(p)) < i: finished = 1 i = i + 1 - end = default_timer() - print('Project Euler, Problem 63') print(f'Answer: {count}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p063() diff --git a/Python/p064.py b/Python/p064.py index 831d6f3..69a7919 100644 --- a/Python/p064.py +++ b/Python/p064.py @@ -43,9 +43,8 @@ # How many continued fractions for N≤10000 have an odd period? from math import sqrt -from timeit import default_timer -from projecteuler import build_sqrt_cont_fraction +from projecteuler import build_sqrt_cont_fraction, timing def is_square(n): @@ -55,28 +54,23 @@ def is_square(n): return bool(p == m) -def main(): - start = default_timer() - +@timing +def p064(): count = 0 for i in range(2, 10000): -# Perfect squares are obviously not represented as continued fractions. -# For all other numbers, calculate their period and check if it's odd. + # Perfect squares are obviously not represented as continued fractions. + # For all other numbers, calculate their period and check if it's odd. if not is_square(i): -# period_cf(i) % 2 != 0: - fraction, period = build_sqrt_cont_fraction(i, 300) + # period_cf(i) % 2 != 0: + _, period = build_sqrt_cont_fraction(i, 300) if period % 2 != 0: count = count + 1 - end = default_timer() - print('Project Euler, Problem 64') print(f'Answer: {count}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p064() diff --git a/Python/p065.py b/Python/p065.py index e52d802..188f232 100644 --- a/Python/p065.py +++ b/Python/p065.py @@ -29,12 +29,11 @@ # # Find the sum of digits in the numerator of the 100th convergent of the continued fraction for e. -from timeit import default_timer +from projecteuler import timing -def main(): - start = default_timer() - +@timing +def p065(): ai = [1, 2, 1] count = 4 @@ -42,14 +41,14 @@ def main(): n1 = 8 n2 = 11 -# For a continued fractions [a_0; a_1, a_2, ...], the numerator of the -# next convergent N_n=a_n*N_(n-1)+N_(n-2). The first three values for e are -# 3, 8 and 11, the next ones are easily calculated, considering that a_n -# follows a simple pattern: -# a_1=1, a_2=2, a_3=1 -# a_4=1, a_5=4, a_6=1 -# a_7=1, a_8=6, a_9=1 -# and so on. + # For a continued fractions [a_0; a_1, a_2, ...], the numerator of the + # next convergent N_n=a_n*N_(n-1)+N_(n-2). The first three values for e are + # 3, 8 and 11, the next ones are easily calculated, considering that a_n + # follows a simple pattern: + # a_1=1, a_2=2, a_3=1 + # a_4=1, a_5=4, a_6=1 + # a_7=1, a_8=6, a_9=1 + # and so on. while count < 100: ai[1] = ai[1] + 2 @@ -68,13 +67,9 @@ def main(): sum_ = sum_ + n2 % 10 n2 = n2 // 10 - end = default_timer() - print('Project Euler, Problem 65') print(f'Answer: {sum_}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p065() diff --git a/Python/p066.py b/Python/p066.py index 9adb00f..1a238aa 100644 --- a/Python/p066.py +++ b/Python/p066.py @@ -21,9 +21,8 @@ # Find the value of D ≤ 1000 in minimal solutions of x for which the largest value of x is obtained. from math import sqrt -from timeit import default_timer -from projecteuler import pell_eq +from projecteuler import pell_eq, timing def is_square(n): @@ -33,28 +32,23 @@ def is_square(n): return bool(p == m) -def main(): - start = default_timer() - +@timing +def p066(): max_ = 0 max_d = -1 for i in range(2, 1001): if not is_square(i): -# Solve the Diophantine equation x^2-D*y^2=1 (Pell equation) + # Solve the Diophantine equation x^2-D*y^2=1 (Pell equation) x = pell_eq(i) if x > max_: max_ = x max_d = i - end = default_timer() - print('Project Euler, Problem 66') print(f'Answer: {max_d}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p066() diff --git a/Python/p067.py b/Python/p067.py index 8c3201a..e656db1 100644 --- a/Python/p067.py +++ b/Python/p067.py @@ -16,14 +16,12 @@ # There is an efficient algorithm to solve it. ;o) import sys -from timeit import default_timer -from projecteuler import find_max_path +from projecteuler import find_max_path, timing -def main(): - start = default_timer() - +@timing +def p067(): triang = [] try: @@ -39,16 +37,12 @@ def main(): for i in range(l): triang[i] = list(map(int, triang[i])) -# Use the function implemented in projecteuler.c to find the maximum path. + # Use the function implemented in projecteuler.c to find the maximum path. max_ = find_max_path(triang, 100) - end = default_timer() - print('Project Euler, Problem 67') print(f'Answer: {max_}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p067() diff --git a/Python/p068.py b/Python/p068.py index ca85ac7..635e493 100644 --- a/Python/p068.py +++ b/Python/p068.py @@ -46,7 +46,8 @@ # from itertools import permutations -from timeit import default_timer + +from projecteuler import timing # Function to evaluate the ring. The ring is represented as a vector of 2*n elements, @@ -54,38 +55,36 @@ from timeit import default_timer # represent the internal ring. def eval_ring(ring, n): for i in range(1, n): -# We need to start from the lowest external node, so if -# the first element in the vector is not the lowest of -# the first n elements (the external elements), the configuration -# is not a valid one. + # We need to start from the lowest external node, so if + # the first element in the vector is not the lowest of + # the first n elements (the external elements), the configuration + # is not a valid one. if ring[i] < ring[0]: return None res = [0] * 3 * n -# Each group of three must have the same value. + # Each group of three must have the same value. magic_val = ring[0] + ring[n] + ring[n+1] j = 0 for i in range(n): -# We need to find the maximum 16-digit string, this is -# possible only if the element "10" is used only once, -# i.e. if it's one of the external nodes. - if ring[n+i] == 10 or ring[n+(i+1)%n] == 10: + # We need to find the maximum 16-digit string, this is possible only if the element "10" is used only once, + # i.e. if it's one of the external nodes. + if ring[n+i] == 10 or ring[n+(i+1) % n] == 10: return None -# Check that the value of the current three-element group -# is the "magic" value. - val = ring[i] + ring[n+i] + ring[n+(i+1)%n] + # Check that the value of the current three-element group is the "magic" value. + val = ring[i] + ring[n+i] + ring[n+(i+1) % n] - if val != magic_val : + if val != magic_val: return None -# Save the current element group in the result string. + # Save the current element group in the result string. res[j] = ring[i] res[j+1] = ring[n+i] - res[j+2] = ring[n+(i+1)%n] + res[j+2] = ring[n+(i+1) % n] j = j + 3 @@ -110,11 +109,9 @@ def list_to_int(l): return res -def main(): - start = default_timer() - -# Generate all possible permutations, for each one check if -# it's a possible solution for the ring and save the maximum +@timing +def p068(): + # Generate all possible permutations, for each one check if it's a possible solution for the ring and save the maximum rings = list(permutations(list(range(1, 11)))) max_ = 0 n = None @@ -122,19 +119,15 @@ def main(): for ring in rings: eval_ = eval_ring(ring, 5) -# Convert the list into an integer number. + # Convert the list into an integer number. n = list_to_int(eval_) if n > max_: max_ = n - end = default_timer() - print('Project Euler, Problem 68') print(f'Answer: {max_}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p068() diff --git a/Python/p069.py b/Python/p069.py index a119836..f540a09 100644 --- a/Python/p069.py +++ b/Python/p069.py @@ -18,41 +18,34 @@ # # Find the value of n ≤ 1,000,000 for which n/φ(n) is a maximum. -from timeit import default_timer - -from projecteuler import is_prime +from projecteuler import is_prime, timing -def main(): - start = default_timer() - +@timing +def p069(): N = 1000000 i = 1 res = 1 -# Using Euler's formula, phi(n)=n*prod(1-1/p), where p are the distinct -# primes that divide n. So n/phi(n)=1/prod(1-1/p). To find the maximum -# value of this function, the denominator must be minimized. This happens -# when n has the most distinct small prime factor, i.e. to find the solution -# we need to multiply the smallest consecutive primes until the result is -# larger than 1000000. + # Using Euler's formula, phi(n)=n*prod(1-1/p), where p are the distinct + # primes that divide n. So n/phi(n)=1/prod(1-1/p). To find the maximum + # value of this function, the denominator must be minimized. This happens + # when n has the most distinct small prime factor, i.e. to find the solution + # we need to multiply the smallest consecutive primes until the result is + # larger than 1000000. while res < N: i = i + 1 if is_prime(i): res = res * i -# We need the previous value, because we want i<1000000 + # We need the previous value, because we want i<1000000 res = res // i - end = default_timer() - print('Project Euler, Problem 69') print(f'Answer: {res}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p069() diff --git a/Python/p070.py b/Python/p070.py index 92eadab..30394f8 100644 --- a/Python/p070.py +++ b/Python/p070.py @@ -9,14 +9,11 @@ # # Find the value of n, 1 < n < 10^7, for which φ(n) is a permutation of n and the ratio n/φ(n) produces a minimum. -from timeit import default_timer - -from projecteuler import sieve, is_semiprime, phi_semiprime +from projecteuler import sieve, is_semiprime, phi_semiprime, timing -def main(): - start = default_timer() - +@timing +def p070(): N = 10000000 n = -1 min_ = float('inf') @@ -25,12 +22,9 @@ def main(): primes = sieve(N) for i in range(2, N): -# When n is prime, phi(n)=(n-1), so to minimize n/phi(n) we should -# use n prime. But n-1 can't be a permutation of n. The second best -# bet is to use semiprimes. For a semiprime n=p*q, phi(n)=(p-1)(q-1). -# So we check if a number is semiprime, if yes calculate phi, finally -# check if phi(n) is a permutation of n and update the minimum if it's -# smaller. + # When n is prime, phi(n)=(n-1), so to minimize n/phi(n) we should use n prime. But n-1 can't be a permutation of n. The second best + # bet is to use semiprimes. For a semiprime n=p*q, phi(n)=(p-1)(q-1). So we check if a number is semiprime, if yes calculate phi, finally + # check if phi(n) is a permutation of n and update the minimum if it's smaller. semi_p, a, b = is_semiprime(i, primes) if semi_p is True: @@ -40,13 +34,9 @@ def main(): n = i min_ = i / p - end = default_timer() - print('Project Euler, Problem 70') print(f'Answer: {n}') - print(f'Elapsed time: {end - start:.9f} seconds') - if __name__ == '__main__': - main() + p070()