Solovay-Strassen Primality Testing
April 29, 2014
Both tests are easy to write, but both rely on infrastructure that we have built in previous exercises. Here is the probabilistic test:
(define (ss-prime? n) (if (not (integer? n)) (error 'ss-prime? "must be integer") (if (< n 2) #f (if (zero? (modulo n 2)) (= n 2) ; n is even (let loop ((k 40) (a (randint 1 n))) (if (zero? k) #t ; probably prime (let ((j (jacobi a n)) (x (expm a (/ (- n 1) 2) n))) (if (or (zero? j) (not (= (modulo j n) x))) #f ; composite (loop (- k 1) (randint 1 n))))))))))
We choose k = 40, which is a reasonable value; you could choose something different or make it a parameter if you wish. Note that there is no need to explicitly compute gcd(a, n), as the Jacobi symbol will be zero in that case. The version on the ERH is similar, except that we loop over primes instead of counting down k:
(define (ss-proof? n) (if (not (integer? n)) (error 'ss-proof? "must be integer") (if (exact (floor (* 2 (square (log n))))))))) (if (null? as) #t ; prime on the erh (let ((j (jacobi (car as) n)) (x (expm (car as) (/ (- n 1) 2) n))) (if (or (zero? j) (not (= (modulo j n) x))) #f ; composite (loop (cdr as))))))))))
It is easy to test the two functions by comparing their output to the primes computed by the Sieve of Eratosthenes:
(let ((ps (primes 1000000))) (do ((n 2 (+ n 1))) ((= n 1000000)) (assert (if (member n ps) #t #f) (ss-prime? n)) (assert (if (member n ps) #t #f) (ss-proof? n))))
You can see the entire code at http://programmingpraxis.codepad.org/1nFhkEil.