(module number-theory mzscheme
  (provide (all-defined))
  
  (require (lib "include.ss"))
  (require (lib "27.ss" "srfi"))
  (require (only (lib "etc.ss") compose rec)
           (only (lib "list.ss") filter mergesort) )
  (define first car)
  (define second cadr)
  (define rest cdr)
  (define empty '())
  
  (define ^ expt)
  
      (define (interval m n)
    (if (> m n)
        '()
        (cons m (interval (+ m 1) n))))
  
    (define (square z)
    (* z z))
  
                                  
  (define (product xs)
    (apply * xs))
  
  (define (sum xs)
    (apply + xs))
  
  
  (define (boolify x)
    (if x #t #f))
  
                        
  (define big-random random-integer)
  
  (define (random-integer-in-interval from to)
            (+ from (random-integer (- to from))))
  
  
    
            
        
          
    (define (divides? a b)
    (= (remainder b a) 0))
  
                
        
      
      (define (gcd-euclid a b)
    (define (loop a b)        (let ([r (remainder a b)])
        (if (= r 0)
            b
            (loop b r))))
    (loop (max (abs a) (abs b))
          (min (abs a) (abs b))))
  
  
            
    (define (bezout-binary a b)
    (define (loop a b ua va ub vb)              (let ([r (remainder a b)]
            [q (quotient a b)])
        (if (= r 0)
            (list ub vb)
            (loop b r ub vb (- ua (* q ub)) (- va (* q vb))))))
    (if (> a b)
        (loop a b 1 0 0 1)
        (loop b a 0 1 1 0)))
  
                      
    (define (bezout a . bs)
    (if (null? bs)
        (list 1)
        (let ([uvs (apply bezout bs)]
              [st  (bezout-binary (apply gcd bs) a)])
          (let ([s (first st)]
                [t (second st)])
            (cons t (map (lambda (u) (* s u))
                         uvs))))))
  
        
  (define (coprime? a . bs)
    (= 1 (apply gcd (cons a bs))))
  
  (define (pairwise-coprime? a . bs)
    (cond
      [(null? bs) #t]
      [else       (and (andmap (lambda (b)
                                 (coprime? a b))
                               bs)
                       (apply pairwise-coprime? bs))]))
  
  (define relatively-prime? coprime?)
  (define pairwise-relatively-prime? pairwise-coprime?)
  
      
        
  (define (odd-prime? n)
    (and (odd? n) (prime? n)))
  
    
        
    
  (define (positive-divisors n)
    (positive-divisors-of-n-below n n))
  
  (define (positive-divisors-of-n-below n m)
    (cond 
      [(<= m 0)        empty]
      [(divides? m n) (cons m (positive-divisors-of-n-below n (- m 1)))]
      [else           (positive-divisors-of-n-below n (- m 1))]))
  
          
      
  (define (cyclotomic p x)
    (if (= p 1)
        1
        (+ 1 (* x (cyclotomic (- p 1) x))))) 
  
    
  
          
  
    
      
            
      (define (max-dividing-power p n)
    (define (loop p-to-e e)
      (if (divides? p-to-e n)
          (loop (* p p-to-e) (+ e 1))
          (- e 1)))
    (loop 1 0))
  
  (define (max-dividing-power p n)
      (define (loop n-divided-by-p-to-e e)
        (if (divides? p n-divided-by-p-to-e)
            (loop (quotient n-divided-by-p-to-e p) (+ e 1))
            e))
      (if (= p 1)
          n
          (loop n 0)))
  
  (define (max-dividing-power2 p n)
    (define (find-start p-to-e e)
                  (let ([p-to-e2 (square p-to-e)])
        (cond [(= p-to-e2 n) (* 2 e)]
              [(> p-to-e2 n) (find-power p-to-e e)]
              [(divides? p-to-e2 n) (if (divides? p (quotient n p-to-e2))
                                        (find-start p-to-e2 (* 2 e))
                                        (* 2 e))]
              [else (find-power p-to-e e)])))
    (define (find-power p-to-e e)
                  (+ e (max-dividing-power p (quotient n p-to-e))))
    (cond [(= p 1)              1]
          [(not (divides? p n)) 0]
          [else                 (find-start p 1)]))
  
  
            
    
        (define (prime-power n)
    (let ([factorization (prime-divisors/exponents n)])
      (if (= (length factorization) 1)
          (first (prime-divisors/exponents n))
          #f)))
  
  (define (prime-power? n)
    (boolify (prime-power n)))
  
  (define (odd-prime-power? n)
    (let ([p/e (prime-power n)])
      (and p/e
           (odd? (first p/e)))))
  
  
    (define (nth-prime n)
    (define (next c) (+ c 2))
    (define (loop candidate m)
      (if (prime? candidate)
          (if (= m n)
              candidate
              (loop (next candidate) (+ m 1)))
          (loop (next candidate) m)))
    (if (= n 1)
        2
        (loop 3 2)))
  
            (define (fermat n)
    (+ 1 (expt 2 (expt 2 n))))
  
      
  (define (mersenne p)
    (- (expt 2 p) 1))
  
    
          
    (define (inverse a n)
    (if (coprime? a n)
        (modulo (first (bezout a n)) n)
        #f))
  
          
    
  (define-syntax (with-modulus stx)
    (syntax-case stx ()
      [(with-modulus e form ...)
       (with-syntax ([+   (datum->syntax-object (syntax with-modulus) '+)]
                     [-   (datum->syntax-object (syntax with-modulus) '-)]
                     [*   (datum->syntax-object (syntax with-modulus) '*)]
                     [^   (datum->syntax-object (syntax with-modulus) '^)]
                     [mod (datum->syntax-object (syntax with-modulus) 'mod)]
                     [inv (datum->syntax-object (syntax with-modulus) 'inv)])
         (syntax (let* ([n e]
                        [mod    (lambda (x)   (modulo x n))]
                        [inv    (lambda (x)   (inverse x n))]
                        [+      (compose mod +)]
                        [-      (compose mod -)]
                        [*      (compose mod *)]
                        [square (lambda (x) (* x x))]
                        [^      (rec ^ (lambda (a b)
                                         (cond
                                           [(= b 0)   1]
                                           [(even? b) (square (^ a (/ b 2)))]
                                           [else      (* a (^ a (sub1 b)))])))])
                   form ...)))]))
  
            
    
  (define (solve-chinese as ns)
        (let* ([n  (product ns)]
           [cs (map (lambda (ni) (/ n ni)) ns)]
           [ds (map inverse cs ns)])
      (modulo (sum (map * as cs ds)) n)))
  
      
      
      
  (define (prime-wilson? n)
    (with-modulus n
                  (define (fac x)
                    (if (= 0 x)
                        1
                        (* x (fac (sub1 x)))))
                  
                  (= (mod (fac (- n 1)))
                     (mod -1))))
  
    
      
        
                  
  (define (phi2 n)
    (* n (product
          (map (lambda (p) (- 1 (/ 1 p)))
               (prime-divisors n)))))
  
  (define (phi n)
    (let ((divisors (prime-divisors n)))
      (* (quotient n (product divisors))
         (product (map (lambda (p) (- p 1)) divisors)))))
  
    (define totient phi)
  
    
          
        
  (define (unit-group n)
    (filter (lambda (m)
              (coprime? m n))
            (interval 1 (- n 1))))
  
  (define (order g n)
    (if (not (coprime? g n))
        (error "In (order g n) the g and n must me coprime")
        (with-modulus n
                      (let loop ([k 1]
                                 [a g])
                        (if (= a 1)
                            k
                            (loop (+ k 1) (* a g)))))))
  
  (define (orders n)
    (map (lambda (m) (order m n))
         (unit-group n)))
  
        
  
  (define (primitive-root? g n)
    (if (not (coprime? g n))
        (error "In (primitive-root? g n) the g and n must me coprime")
        (= (order g n) (phi n))))
  
        
  (define (exists-primitive-root? n)
    (cond 
      [(member n '(1 2 4)) #t]
      [(odd? n)            (odd-prime-power? n)]
      [else                (odd-prime-power? (quotient n 2))]))
  
  
          
  (define (primitive-root? g n)
    (if (not (coprime? g n))
        (error "In (primitive-root? g n) the g and n must me coprime")
        (let ([phi-n (phi n)])
          (with-modulus n
                        (andmap (lambda (x) x)
                                (map (lambda (q)
                                       (not (= (^ g (/ phi-n q)) 1)))
                                     (prime-divisors phi-n)))))))
  
        
  (define (primitive-root n)
    (and (exists-primitive-root? n)
         (let* ([phi-n (phi n)]
                [qs    (prime-divisors phi-n)])
           (define (primitive-root? g)
             (with-modulus n
                           (andmap (lambda (x) x)
                                   (map (lambda (q)
                                          (not (= (^ g (/ phi-n q)) 1)))
                                        qs))))
           (let loop ([g 1])
             (cond
               [(= g n)                #f]
               [(not (coprime? g n))   (loop (+ g 1))]
               [(primitive-root? g)    g]
               [else                   (loop (+ g 1))])))))
  
      
      (define (primitive-roots n)
    (if  (not (exists-primitive-root? n))
         empty
         (let* ([phi-n (phi n)]
                [qs    (prime-divisors phi-n)])
           (define (primitive-root? g)
             (with-modulus n
                           (andmap (lambda (x) x)
                                   (map (lambda (q)
                                          (not (= (^ g (/ phi-n q)) 1)))
                                        qs))))
           (let loop ([g     1] 
                      [roots empty])
             (cond
               [(= g n)                (reverse roots)]
               [(not (coprime? g n))   (loop (+ g 1)  roots)]
               [(primitive-root? g)    (loop (+ g 1) (cons g roots))]
               [else                   (loop (+ g 1)  roots)])))))
  
  (define (primitive-root n)
    (and (exists-primitive-root? n)
         (cond
                      [(and (odd-prime-power? n)
                 (not (prime? n)))              (let* ([p (first (prime-power n))]
                                                       [g (primitive-root p)])
                                                  (if (= (order g (* p p)) (phi (* p p)))
                                                      g
                                                      (modulo (+ g p) n)))]
                      [(and (even? n)
                 (odd-prime? (quotient n 2)))   (let ([g (primitive-root (quotient n 2))])
                                                  (if (odd? g)
                                                      g
                                                      (modulo (+ g (quotient n 2)) n)))]
           
                      [else                                (let* ([phi-n (phi n)]
                                                       [qs    (prime-divisors phi-n)])
                                                  (define (primitive-root? g)
                                                    (with-modulus n
                                                                  (andmap (lambda (x) x)
                                                                          (map (lambda (q)
                                                                                 (not (= (^ g (/ phi-n q)) 1)))
                                                                               qs))))
                                                  (let loop ([g 1])
                                                    (cond
                                                      [(= g n)                #f]
                                                      [(not (coprime? g n))   (loop (+ g 1))]
                                                      [(primitive-root? g)    g]
                                                      [else                   (loop (+ g 1))])))])))
  
    
          
    (define (legendre a p)
    (let ([l (with-modulus p
                           (^ a (/ (- p 1) 2)))])
      (if (<= 0 l 1)
          l
          -1)))
  
  (define (quadratic-residue? a n)
    (let* ([ps     (prime-divisors n)]
           [odd-ps (if (= (first ps) 2)
                       (rest ps)
                       ps)])
      (and (andmap (lambda (p)
                     (= (legendre a p) 1))
                   odd-ps)
           (cond 
             [(divides? 8 n)  (= (modulo a 8) 1)]
             [(divides? 4 n)  (= (modulo a 4) 1)]
             [else            #t]))))
  
  
    
            
    (define (prime-fermat? n)
    (cond
      [(= n 2) #t]
      [else    (let* ([a (random-integer-in-interval 2 (- n 1))]
                      [b (with-modulus n
                                       (^ a (- n 1)))])
                 (if (= b 1)
                     'possibly-prime
                     #f))]))
  
      
  
              
    (define (prime-strong-pseudo-single? n)
        (cond
      [(= n 2) #t]
      [(= n 3) #t]
      [(< n 2) #f]
      [else    (let* ([a (random-integer-in-interval 2 (- n 1))]
                      [g (gcd a n)])
                 (if (> g 1)
                     g
                                          (let loop ([ny 0]
                                [m  (- n 1)])
                       (if (even? m)
                           (loop (add1 ny) (/ m 2))
                                                      (let ([b (with-modulus n (^ a m))])
                             (if (= b 1)
                                 'probably-prime
                                 (let loop ([i 0]
                                            [b b]
                                            [b-old b])
                                   
                                   (if (< i ny)
                                       (loop (add1 i)
                                             (with-modulus n (* b b))
                                             b)
                                       (if (= b 1)
                                           (let ([g (gcd (+ b-old 1) n)])
                                             (if (or (= g 1) (= g n))
                                                 'probably-prime
                                                 g))
                                           'composite)))))))))]))
  
  (define integer-log2 
    (let ([log2 (log 2)])
      (lambda (n)
        (/ (log n) log2))))
  
  (define (big-log2 n)
    (define (loop n l)
      (if (<= n 1)
          l
          (loop (quotient n 2) (add1 l))))
    (loop n 0))
  
  (define prime-strong-pseudo-certainty 1/10000000)
  (define prime-strong-pseudo-trials (integer-length (/ 1 prime-strong-pseudo-certainty)))
  
    (define (prime-strong-pseudo/explanation n)
    (if #f         (error "prime-strong-pseudo: n must be 'large'" n)
        (let loop ([trials prime-strong-pseudo-trials]
                   [result (prime-strong-pseudo-single? n)])
          (if (= trials 0)
              'very-probably-prime
              (cond
                [(equal? result 'probably-prime)  (loop (sub1 trials) (prime-strong-pseudo-single? n))]
                [else                             result])))))
  
  
  (define (prime-strong-pseudo? n)
    (let ([explanation (prime-strong-pseudo/explanation n)])
      (if (or (equal? explanation 'very-probably-prime)
              (equal? explanation #t))
          #t
          #f)))
  
  (require (lib "42.ss" "srfi"))
  
  (define *SMALL-PRIME-LIMIT* 1000000)
  
  (define prime?
        (let ()
      (define N *SMALL-PRIME-LIMIT*)        (define ps (make-vector (+ N 1) #t))
      (define ! vector-set!)
      (! ps 0 #f)
      (! ps 1 #f)
      (do-ec (: n 2 (+ N 1))
             (if (vector-ref ps n))
             (: m (+ n n) (+ N 1) n)
             (! ps m #f))
      (lambda (n)
        (if (< n N)
            (vector-ref ps n)
            (prime-strong-pseudo? n)))))
  
  
  (define (next-prime n)
    (cond
      [(< n 2)   2]
      [(= n 2)   3]
      [(even? n) (let ([n+1 (add1 n)])
                   (if (prime? n+1)
                       n+1
                       (next-prime n+1)))]
      [else      (let ([n+2 (+ n 2)])
                   (if (prime? n+2)
                       n+2
                       (next-prime n+2)))]))
  
  (define (prev-prime n)
    (cond
      [(= n 3)   2]
      [(< n 3)   #f]
      [(even? n) (let ([n-1 (sub1 n)])
                   (if (prime? n-1)
                       n-1
                       (prev-prime n-1)))]
      [else      (let ([n-2 (- n 2)])
                   (if (prime? n-2)
                       n-2
                       (prev-prime n-2)))]))
  
  (define (next-primes n primes-wanted)
    (if (= primes-wanted 0)
        '()
        (let ([next (next-prime n)])
          (if next
              (cons next (next-primes next (sub1 primes-wanted)))
              '()))))
  
  
  (define (prev-primes n primes-wanted)
    (if (= primes-wanted 0)
        '()
        (let ([prev (prev-prime n)])
          (if prev
              (cons prev (prev-primes prev (sub1 primes-wanted)))
              '()))))
  
      
        (define (floyd-detect-cycle f x0)
    (do ([xi x0 (f xi)]
         [yi x0 (f (f yi))]
         [i  0  (add1 i)])
      [(= xi yi) i]))
  
    
      
  (define (pollard n)
        (let ([x0 (big-random n)])
            (do ([xi x0 (remainder (+ (* xi xi) 1) n)]
           [yi x0 (remainder (+ (square (+ (* yi yi) 1)) 1) n)]
           [i  0  (add1 i)]
           [g  1  (gcd (- xi yi) n)])
        [(or (< 1 g n)
             (> i (sqrt n))
             )   (if (< 1 g n)
                     g
                     #f)]
                )))
  
  (define (pollard-factorize n)
        (if (< n 10000)          (factorize-small n)
        (cond
          [(= n 1)                     '()]
          [(prime? n)                  `((, n 1))]
          [(even? n)                   `((2 1) ,@(pollard-factorize (quotient n 2)))]
          [(divides? 3 n)              `((3 1) ,@(pollard-factorize (quotient n 3)))]
          [(simple-perfect-power n) => (lambda (base-and-exp) 
                                         (cond
                                           [(prime? (car base-and-exp)) (list base-and-exp)]
                                           [else (map (lambda (b-and-e)
                                                        (list (car b-and-e) (* (cadr base-and-exp)
                                                                               (cadr b-and-e))))
                                                      (pollard-factorize (car base-and-exp)))]))]
          [else                 (let loop ([divisor (pollard n)])
                                  (if divisor
                                      (append (pollard-factorize divisor)
                                              (pollard-factorize (quotient n divisor)))
                                      (loop (pollard n))))])))
  
                                        
  (define (base-and-exponenent<? x y)
    (let ([id-or-first 
           (lambda (x)
             (if (number? x)
                 x
                 (first x)))])
      (<= (id-or-first x) (id-or-first y))))
  
  (define (factorize n)
    (if (< n *SMALL-PRIME-LIMIT*)           (factorize-small n)
        (factorize-large n)))
  
  (require (only (lib "1.ss" "srfi") find-tail))
  
  (define (small-prime-factors-over n p)
        (cond
      [(< n p)         '()]
      [(= n p)         (list (list p 1))]
      [(prime? n)      (list (list n 1))]
      [(divides? p n)  (let ([m (max-dividing-power p n)])
                         (cons (list p m)
                               (small-prime-factors-over 
                                (quotient n (expt p m))
                                (next-prime p))))]
      [else            (small-prime-factors-over n (next-prime p))]))
  
  (define (factorize-small n)
            (small-prime-factors-over n 2))
  
  
  (define (combine-same-base list-of-base-and-exponents)
        (let ([l list-of-base-and-exponents])
      (cond
        [(null? l)        '()]
        [(null? (cdr l))  l]
        [else             (let ([b1 (first  (first l))]
                                [e1 (second (first l))]
                                [b2 (first  (second l))]
                                [e2 (second (second l))]
                                [more (cddr l)])
                            (if (= b1 b2)
                                (combine-same-base (cons (list b1 (+ e1 e2))
                                                         (cdr (cdr list-of-base-and-exponents))))
                                (cons (car list-of-base-and-exponents)
                                      (combine-same-base (cdr list-of-base-and-exponents)))))])))
  
  (define (factorize-large n)
    (combine-same-base
     (mergesort 
      (pollard-factorize n)
      base-and-exponenent<?)))
  
  
  (define prime-divisors/exponents factorize)
  
  (define (prime-divisors n)
    (map car (prime-divisors/exponents n)))
  
  (define (prime-exponents n)
    (map cadr (factorize n)))
  
  
                
  (define (p-adic-newton-iteration phi Dphi p l g0 s0)
    (let ([r (integer-length l)])
      (let loop ([i 1]
                 [gi g0]
                 [si s0])
        (cond
          [(< i r) (let ([g_i+1 (modulo (- gi (* (phi gi) si)) (expt p (expt 2 i)))])
                     (loop (+ i 1)
                           g_i+1
                           (modulo (- (* 2 si) (* (Dphi g_i+1) si si)) (expt p (expt 2 i)))))]
          [else    (modulo (- gi (* (phi gi) si)) (expt p l))]))))
  
                
  
    (define (is-nth-root a n candidate)
    (if (= (expt candidate n) a)
        candidate
        #f))
  
  (define (integer-root/odd-odd a n)
            (unless (and (odd? a) (odd? n))
      (error "integer-root/odd-odd: Both a and n must be odd; given " a n))
        (let ([candidate 
                      (let* ([k (do ([k 1 (add1 k)])
                       [(> (expt 2 (* n k)) a) k])]
                  [r (integer-length k)])
             (let loop ([i  1]
                        [gi 1]
                        [si 1]
                        [ti 1])
                              (cond
                 [(< i r) (let* ([g_i+1 (modulo (- gi (* (- (* gi ti) a) si)) 
                                                (expt 2 (expt 2 i)))]
                                 [t_i+1 (modulo (expt g_i+1 (- n 1))
                                                (expt 2 (expt 2 (+ i 1))))])
                            (loop (+ i 1)
                                  g_i+1
                                  (modulo (- (* 2 si) (* n t_i+1 si si))
                                          (expt 2 (expt 2 i)))
                                  t_i+1))]
                 [else    (modulo (- gi (* (- (* gi ti) a) si))
                                  (expt 2 (expt 2 i)))])))])
      (is-nth-root a n candidate)))
  
  (define (integer-root/power-of-two  a n)
                              (let ([phi  (lambda (y) (- (expt y n) a))]
            [Dphi (lambda (y) (* n (expt y (- n 1))))])
        (let ([candidate1 (p-adic-newton-iteration phi Dphi 3 11 1 (inverse (Dphi 1) 3))])
          (if (= (expt candidate1 n) a)
              candidate1
              (let ([candidate2 (p-adic-newton-iteration phi Dphi 3 11 2 (inverse (Dphi 2) 3))])
                (is-nth-root a n candidate2))))))
  
  (define (integer-root/power-of-two a n)
            (let loop ([d (- (integer-length n) 1)]
               [b a])
      (if (= d 0)
          b
          (let-values ([(s r) (integer-sqrt/remainder b)])
            (if (not (zero? r))
                #f
                (loop (- d 1) s))))))
  
  
  (define (integer-root-factor a n)
        (let* ([d      (max-dividing-power 2 a)]
           [e      (max-dividing-power 3 a)]
           [b-to-r (quotient a (* (expt 2 d) (expt 3 e)))]
                      [f         (max-dividing-power 2 n)]
           [two-to-f  (expt 2 f)]
           [c         (quotient n two-to-f)]
                      [b (integer-root/power-of-two 
               (integer-root/odd-odd b-to-r c) 
               two-to-f)]
           [r (max-dividing-power b b-to-r)])
      (list d e b r)))
  
  
  (define (integer-root a n)
            (cond
        [(= n 1) a]
        [(= n 2) (let-values ([(s r) (integer-sqrt/remainder a)])
                   (if (zero? r)
                       s
                       #f))]
        [else
         (let ([d (max-dividing-power 2 a)])
           (if (not (divides? n d))
               #f
               (let ([e (max-dividing-power 3 a)])
                 (if (not (divides? n e))
                     #f
                     (let* ([b-to-r (quotient a (* (expt 2 d) (expt 3 e)))]
                                                        [f         (max-dividing-power 2 n)]
                            [two-to-f  (expt 2 f)]
                            [c         (quotient n two-to-f)])
                                              (cond
                         [(integer-root/odd-odd b-to-r c) 
                          => (lambda (cth-root--of--b-to-r)
                               (cond
                                 [(integer-root/power-of-two cth-root--of--b-to-r two-to-f)
                                  => (lambda (nth-root--of--b-to-r)
                                       (* (expt 2 (quotient d n))
                                          (expt 3 (quotient e n))
                                          nth-root--of--b-to-r))]
                                 [else #f]))]
                         [else #f]))))))]))
  
  (define (integer-root/remainder a n)
    (let ([i (integer-root a n)])
      (values i (- a (expt i n)))))
  
  (define (integer-root x y)
        (cond 
      ((eq? x 0)
       0)
      ((eq? x 1)
       1)
      ((eq? y 1)
       x)
      ((eq? y 2)
       (integer-sqrt x))
      ((not (integer? y))
       1)
      (else
       (let ((length (integer-length x)))
                  (cond ((<= length y)
                1)
                              ((<= length (* 2 y))
                                (if (< x (expt 3 y))
                    2
                    3))
               ((even? y)
                (integer-root (integer-sqrt x)
                              (quotient y 2)))
               (else
                (let* ((length/y/2                         (quotient (quotient (- length 1) y) 2)))
                  (let ((init-g
                         (let* ((top-bits
                                 (arithmetic-shift
                                  x
                                  (- (* length/y/2 y))))
                                (nth-root-top-bits
                                 (integer-root top-bits y)))
                           (arithmetic-shift
                            (+ nth-root-top-bits 1)
                            length/y/2))))
                    (let loop ((g init-g))
                      (let* ((a (expt g (- y 1)))
                             (b (* a y))
                             (c (* a (- y 1)))
                             (d (quotient (+ x (* g c)) b)))
                        (let ((diff (- d g)))
                          (cond ((not (negative? diff))
                                 g)
                                ((< diff -1)
                                 (loop d))
                                (else
                                                                                                   (let loop ((g d))
                                   (if (not (< x (expt g y)))
                                       g
                                       (loop (- g 1)))))))))))))))))
  
      (define (simple-as-power a)
        (let loop ([n (integer-length a)])
      (let-values ([(root rem) (integer-root/remainder a (add1 n))])
        (if (zero? rem)
            (values root (add1 n))
            (loop (sub1 n))))))
  
  (define (as-power a)
    (let ([r (apply gcd (map second (factorize a)))])
      (values (integer-root a r) r)))
  
  (define (prime-power? n)
      (let-values ([(b r) (as-power n)])
        (prime? b)))
  
  (define (perfect-power? a)
    (let-values ([(base n) (as-power a)])
      (and (> n 1) (> a 1))))
  
  (define (simple-perfect-power a)
        (let-values ([(base n) (simple-as-power a)])
      (if (and (> n 1) (> a 1))
          (list base n)
          #f)))
  
  (define (perfect-power a)
    (let-values ([(base n) (as-power a)])
      (if (and (> n 1) (> a 1))
          (list base n)
          #f)))
  
      (define (powers-of a n)
    (let loop ([i    0]
               [a^i  1])
      (if (<= i n)
          (cons a^i (loop (+ i 1) (* a^i a)))
          '())))
  
  (define (factorization->divisors f)
    (cond
      [(null? f) '(1)]
      [else      (let ([p (first (first f))]
                       [n (second (first f))]
                       [g (rest f)])
                                      (let ([divisors-of-g (factorization->divisors g)])
                     (apply append
                            (map (lambda (p^i)
                                   (map (lambda (d) (* p^i d))
                                        divisors-of-g))
                                 (powers-of p n)))))]))
  
  (define (divisors n)
    (factorization->divisors (factorize n)))
  
    
  (require (only (lib "1.ss" "srfi") every))
  
  (define (one? n)
    (= n 1))
  
  (define euler-phi phi)
  
          (define (moebius-mu n)
    (let* ([f          (factorize n)]
           [primes     (map first f)]
           [exponents  (map second f)])
      (if (every one? exponents)
          (if (even? (length primes))
              1
              -1)
          0)))
  
      (define divisor-sum 
      (case-lambda
        [(n)   (divisor-sum n 1)]
        [(n k) (let loop ([sum 0] [ds (divisors n)])
                 (if (null? ds)
                     sum
                     (loop (+ sum (expt (car ds) k))
                           (cdr ds))))]))
  
  (define divisor-sum 
    (let ()
      (case-lambda 
        [(n)   (divisor-sum n 1)]
        [(n k) (let* ([f  (factorize n)]
                     [ps (map first f)]
                     [es (map second f)])
                 (define (divisor-sum0 p e)
                   (+ e 1))
                 (define (divisor-sum1 p e)
                   (let loop ([sum 1]
                              [n 0]
                              [p-to-n 1])
                     (cond [(= n e) sum]
                           [else (let ([t (* p p-to-n)])
                                   (loop (+ t sum) (+ n 1) t))])))
                 (define (divisor-sumk p e)
                   (let ([p-to-k (expt p k)])
                     (let loop ([sum 1]
                                [n 0]
                                [p-to-kn 1])
                       (cond [(= n e) sum]
                             [else (let ([t (* p-to-k p-to-kn)])
                                     (loop (+ t sum) (+ n 1) t))]))))
                 (product
                  (map (cond [(= k 0) divisor-sum0]
                             [(= k 1) divisor-sum1]
                             [else    divisor-sumk])
                       ps es)))])))
  
  (require (lib "42.ss" "srfi"))
  
  
  
  
    
          (define (bernoulli n)
                                    (let ([b (make-vector (max (+ n 1) 2) #f)])
      (vector-set! b 0 1)
      (vector-set! b 1 -1/2)
      (let ()
        (define (next-binom old x k)
                    (* old
             (/ (* k (- k 1) (- k 2) (- k 3) (- k 4) (- k 5) )
                (* (- x (- k 1)) (- x (- k 2)) (- x (- k 3)) (- x (- k 4)) (- x (- k 5)) (- x (- k 6))))))
        (define (A m M)
          (if (< M 1)
              0
              (sum-ec (:parallel
                       (: j 1 (+ M 1))
                       (:do ([bin (binomial (+ m 3) (- m 6))]) #t ((next-binom bin (+ m 3) (- m (* 6 j))))))
                      (* bin
                         (bern (- m (* 6 j)))))))
        (define (bern n)
          (let ([bn (vector-ref b n)])
            (if bn
                bn
                (let ([bn 
                       (cond
                         [(odd? n)               0]
                         [(= (remainder n 6) 0)  (/   (-  (/ (+ n 3)  3)  (A n (/ n       6)))   (binomial (+ n 3) n))]
                         [(= (remainder n 6) 2)  (/   (-  (/ (+ n 3)  3)  (A n (/ (- n 2) 6)))   (binomial (+ n 3) n))]
                         [(= (remainder n 6) 4)  (/   (-  (/ (+ n 3) -6)  (A n (/ (- n 4) 6)))   (binomial (+ n 3) n))])])
                  (vector-set! b n bn)
                  bn))))
        (bern n))))
  
        (define (tangent-number n)
            (let ([T (make-vector (+ n 2) 0)])
            (vector-set! T 1 1)
      (do-ec (: k (+ n 1))
             (begin
                              (do-ec (: i (+ k 1))
                      (vector-set! T i 
                                   (* (+ i 1) (vector-ref T (+ i 1)))))
                              (do-ec (: i (+ k 1) 1 -1)
                      (vector-set! T i 
                                   (+ (vector-ref T i)
                                      (vector-ref T (- i 2)))))))
      (vector-ref T 0)))
  
      (define (bernoulli/tangent n)
                                (cond
      [(= n 0)   1]
      [(= n 1)  -1/2]
      [(= n 2)   1/6]
      [(odd? n)  0]
      [else      (let ([m (/ n 2)])
                   (* (tangent-number (- n 1))
                      (/ n
                         (let ([4^m (expt 4 m)])
                           (* 4^m (- 4^m 1))))
                      (if (even? m)
                          -1
                          1)))]))
  
      (define (binomial n k)
            (cond
      [(= k 0)            1]
      [(= k 1)            n]
      [(= k 2)            (/ (* n (- n 1)) 2)]
      [(> k (/ n 2))      (binomial n (- n k))]
      [else               (* (+ n (- k) 1)
                             (product-ec (:range i 2 (+ k 1))
                                         (/ (+ n (- k) i)
                                            i)))]))
  
  
  
      (define (factorial n)
    (define (fact-small n)
      (if (= n 1)
          1
          (* n (factorial (- n 1)))))
    (define (fact-big n)
                              (let ([n/2 (quotient n 2)])
        (product (append
                  (list-ec (:range i 1 n/2) i)
                  (reverse (list-ec (:range i n/2 (+ n 1)) i))))))
    (cond
      [(= n 0)   1]
      [(< n 400) (fact-small n)]
      [else      (fact-big n)]))
  
      (define (euler-number n k)
                (if (= k 0)
        1
        (let ([E (make-vector (max (+ k 1) (+ n 1)) 0)])
          (vector-set! E 0 1)           (do-ec (:range i 1 (+ n 1))
                 (do-ec (:range j (- i 1) 0 -1)
                        (vector-set! E j
                                     (+ (* (+ j 1) (vector-ref E j))
                                        (* (- i j) (vector-ref E (- j 1)))))))
          (vector-ref E k))))
  
  (list-ec (: n 10) (list-ec (: k 10) (euler-number n k)))
  
  (define (perfect-square n)
    (let ([sqrt-n (integer-sqrt n)])
      (if (= (* sqrt-n sqrt-n) n)
          sqrt-n
          #f)))
  
  
  (define (second-degree-solutions a b c)
        (let ([d (- (* b b) (* 4 a c))])
      (cond
        [(< d 0) 
         '()]
        [(= d 0)
         (list (/ b (* -2 a)))]
        [else
         (let ([sqrt-d (sqrt d)])
           (list (/ (- (- b) sqrt-d) (* 2 a))
                 (/ (+ (- b) sqrt-d) (* 2 a))))])))
  
  
  (define (second-degree-integer-solutions a b c)
        (filter integer? (second-degree-solutions a b c)))
  
  (define (natural? n)
    (and (integer? n)
         (positive? n)))
  
  (define (second-degree-natural-solutions a b c)
        (filter natural? (second-degree-solutions a b c)))
  
  (define (triangle n)
    (quotient (* n (+ n 1)) 2))
  
  (define (triangle? n)
    (not (null? (second-degree-natural-solutions 1/2 1/2 (- n)))))
  
  (define (square? n)
    (perfect-square n))
  
  (define (pentagonal n)
    (quotient (* n (- (* 3 n) 1)) 2))
  
  (define (pentagonal? n)
    (not (null? (second-degree-natural-solutions 3/2 -1/2 (- n)))))
  
  (define (hexagonal n)
    (* n (- (* 2 n) 1)))
  
  (define (hexagonal? n)
    (not (null? (second-degree-natural-solutions 2 -1 (- n)))))
  
  (define (heptagonal n)
    (quotient (* n (- (* 5 n) 3)) 2))
  
  (define (heptagonal? n)
    (not (null? (second-degree-natural-solutions 5/2 -3/2 (- n)))))
  
  (define (octagonal n)
    (* n (- (* 3 n) 2)))
  
  (define (octagonal? n)
    (not (null? (second-degree-natural-solutions 3 -2 (- n)))))
  
  (require (planet "memoize.ss" ("dherman" "memoize.plt" 2 1)))
  
  (define (partitions n)
    (define p
      (memo-lambda* (n)
                    (cond
                      [(< n 0) 0]
                      [(= n 0) 1]
                      [else   (sum-ec (:range k 1 (add1 (inexact->exact (floor (/ (+ 1.0 (sqrt (+ 1.0 (* 24.0 n)))) 6.0)))))
                                      (* (if (odd? k) 1 -1)
                                         (+ (p (- n (quotient (* k (- (* 3 k) 1)) 2)))
                                            (p (- n (quotient (* k (+ (* 3 k) 1)) 2))))))])))
    (p n))
  
  
  (define (digits n)
    (define (d x)
      (if (< x 10)
          (list x)
          (cons (remainder x 10)
                (d (quotient x 10)))))
    (unless (integer? n)
      (error 'digits "expected an integer, got: n"))
    (reverse (d (if (negative? n) (- n) n))))
  
  (define (digits->number ds)
    (define (rev-digits->number ds)
      (if (null? ds)
          0
          (+ (car ds)
             (* 10 (rev-digits->number (cdr ds))))))
    (rev-digits->number (reverse ds)))
  
  (define (number-append x y)
    (unless (and (natural? x) (natural? y))
      (error 'number-append "expected two natural numbers, got: " x y))
    (string->number
     (string-append
      (number->string x)
      (number->string y))))
  
  (define (number-reverse n)
    (digits->number
     (reverse
      (digits n))))
  
  (define (palindromic? n)
    (let ([ds (digits n)])
      (equal? ds (reverse ds))))
  
  (define (number-length n)
    (unless (and (integer? n) (not (negative? n)))
      (error 'number-lengh "expected non-negative integer, got: " n))
    (let ([len (inexact->exact (floor (/ (log n) (log 10))))])
      (let loop ([len len])
        (if (< (- (expt 10 len) 1) n (expt 10 (+ len 1)))
            (+ len 1)
            (loop (+ len 1))))))
  
    
  (define (generator a b p q count)
    (cond ((= count 0) b)
          ((even? count)
           (generator a
                      b
                      (+ (* p p) (* q q))
                      (+ (* 2 p q) (* q q))
                      (quotient count 2)))
          (else (generator (+ (* b q) (* a q) (* a p))
                           (+ (* b p) (* a q))
                           p
                           q
                           (- count 1)))))
  
  (define (fibonacci n)
    (generator 1 0 0 1 n))
  
  (define (lucas n)
    (generator 1 3 0 1 n))
  
  (define (fibonacci-mod n mod)
    (define (generator a b p q count)
      (cond ((= count 0) b)
            ((even? count)
             (generator a
                        b
                        (remainder (+ (* p p) (* q q)) mod)
                        (remainder (+ (* 2 p q) (* q q)) mod)
                        (quotient count 2)))
            (else (generator (remainder (+ (* b q) (* a q) (* a p)) mod)
                             (remainder (+ (* b p) (* a q)) mod)
                             p
                             q
                             (- count 1)))))
    (generator 1 0 0 1 n))
  
  
  
  
    
  (define (mediant x y)
    (/ (+ (numerator x) (numerator y))
       (+ (denominator x) (denominator y))))
  
  (require (only (lib "list.ss") sort))
  (define farey
    (memo-lambda* (d)
                  (define (delete-last xs)
                    (reverse (cdr (reverse xs))))
                  (define (successive? x y)
                    (= (- (* (denominator x) (numerator y))
                          (* (denominator y) (numerator x)))
                       1))
                  (cond
                    [(= d 1) (list 0 1)]
                    [else    (let ([fs (farey (- d 1))])
                               (sort (append fs
                                             (filter {lambda (x) (<= (denominator x) d)}
                                                     (map mediant
                                                          (delete-last fs) (rest fs))))
                                     <))])))
  
  
      
  )