summaryrefslogtreecommitdiff
path: root/sieve/atkin.scm
blob: 842954172fd8a046ebd70dcf8340886a543733ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106



(add-to-load-path (dirname (current-filename)))

(import
    (srfi srfi-41)
    (extra-functional)
    (my-streams))



; this implementation could use some optimisation



(define base (stream-from 7))



; tests potential solutions to 4x^2 + y^2 = n
(define (f1 x y n)
    (eq? (+ (* 4 (expt x 2)) (expt y 2)) n))



; tests potential solutions to 3x^2 + y^2 = n
(define (f2 x y n)
    (eq? (+ (* 3 (expt x 2)) (expt y 2)) n))



; tests potential solutions to 3x^2 - y^2 = n with x > y
(define (f3 x y n)
    (and (> x y) (eq? (- (* 3 (expt x 2)) (expt y 2)) n)))



; counts the number of positive integer solutions to one of the above equations for a given n
(define (num-solutions func n)
    (letrec ((sol (lambda (r x y)
                        (cond ((func x y n) (sol (+ r 1) x (+ y 1)))
                              ((> y (sqrt n)) (sol r (+ x 1) 1))
                              ((> x (sqrt n)) r)
                              (else (sol r x (+ y 1)))))))
        (sol 0 1 1)))



(define (test item)
    (let ((r (modulo (car item) 60)))

        (cond ((or (eq? r 1)
                   (eq? r 13)
                   (eq? r 17)
                   (eq? r 29)
                   (eq? r 37)
                   (eq? r 41)
                   (eq? r 49)
                   (eq? r 53)) (if (odd? (num-solutions f1 (car item)))
                                   (cons (car item) (not (cdr item)))
                                   item))

              ((or (eq? r 7)
                   (eq? r 19)
                   (eq? r 31)
                   (eq? r 43)) (if (odd? (num-solutions f2 (car item)))
                                   (cons (car item) (not (cdr item)))
                                   item))

              ((or (eq? r 11)
                   (eq? r 23)
                   (eq? r 47)
                   (eq? r 59)) (if (odd? (num-solutions f3 (car item)))
                                   (cons (car item) (not (cdr item)))
                                   item))

              (else item))))



(define (square n) (* n n))



(define (mark n item)
    (if (eq? (remainder (car item) n) 0)
        (cons (car item) #f)
        item))



(define-stream (sieve input)
    (stream-let loop ((strm (stream-map (compose test (part (flip cons) #f)) input)))
        (stream-match strm ((item . rest)
            (if (cdr item)
                (stream-cons
                    (car item)
                    (loop (stream-map (part mark (square (car item))) rest)))
                (loop rest))))))



(define atkin (stream-append (list->stream '(2 3 5)) (sieve base)))