]> gitweb.factorcode.org Git - factor.git/blob - extra/project-euler/070/070.factor
project-euler: Rewrap, update links, add copyrights, tests
[factor.git] / extra / project-euler / 070 / 070.factor
1 ! Copyright (c) 2010 Aaron Schaefer.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: arrays combinators.short-circuit kernel math
4 math.combinatorics math.functions math.primes
5 project-euler.common sequences sequences.extras ;
6 FROM: project-euler.common => permutations? ;
7 IN: project-euler.070
8
9 ! https://projecteuler.net/problem=70
10
11 ! DESCRIPTION
12 ! -----------
13
14 ! Euler's Totient function, φ(n) [sometimes called the phi
15 ! function], is used to determine the number of positive numbers
16 ! less than or equal to n which are relatively prime to n. For
17 ! example, as 1, 2, 4, 5, 7, and 8, are all less than nine and
18 ! relatively prime to nine, φ(9)=6. The number 1 is considered
19 ! to be relatively prime to every positive number, so φ(1)=1.
20
21 ! Interestingly, φ(87109)=79180, and it can be seen that 87109
22 ! is a permutation of 79180.
23
24 ! Find the value of n, 1 < n < 10^(7), for which φ(n) is a
25 ! permutation of n and the ratio n/φ(n) produces a minimum.
26
27
28 ! SOLUTION
29 ! --------
30
31 ! For n/φ(n) to be minimised, φ(n) must be as close to n as
32 ! possible; that is, we want to maximize φ(n). The minimal
33 ! solution for n/φ(n) would be if n was prime giving n/(n-1) but
34 ! since n-1 never is a permutation of n it cannot be prime.
35
36 ! The next best thing would be if n only consisted of 2 prime
37 ! factors close to (in this case) sqrt(10000000). Hence n =
38 ! p1*p2 and we only need to search through a list of known prime
39 ! pairs. In addition:
40
41 !     φ(p1*p2) = p1*p2*(1-1/p1)(1-1/p2) = (p1-1)(p2-1)
42
43 ! ...so we can compute φ(n) more efficiently.
44
45 <PRIVATE
46
47 ! NOTE: ±1000 is an arbitrary range
48 : likely-prime-factors ( -- seq )
49     7 10^ sqrt >integer 1000 [ - ] [ + ] 2bi primes-between ; inline
50
51 : n-and-phi ( seq -- seq' )
52     ! ( seq  = { p1, p2 } -- seq' = { n, φ(n) } )
53     [ product ] [ [ 1 - ] map product ] bi 2array ;
54
55 : fit-requirements? ( seq -- ? )
56     first2 { [ drop 7 10^ < ] [ permutations? ] } 2&& ;
57
58 : minimum-ratio ( seq -- n )
59     [ [ first2 / ] map arg-min ] keep nth first ;
60
61 PRIVATE>
62
63 : euler070 ( -- answer )
64     likely-prime-factors 2 all-combinations [ n-and-phi ] map
65     [ fit-requirements? ] filter minimum-ratio ;
66
67 ! [ euler070 ] 100 ave-time
68 ! 379 ms ave run time - 1.15 SD (100 trials)
69
70 SOLUTION: euler070