Why does this Miller-Rabin Procedure in Scheme works when the code seems to be wrong? - scheme

I am working through SICP. In exercise 1.28 about the Miller-Rabin test. I had this code, that I know is wrong because it does not follow the instrcuccions of the exercise.
(define (fast-prime? n times)
(define (even? x)
(= (remainder x 2) 0))
(define (miller-rabin-test n)
(try-it (+ 1 (random (- n 1)))))
(define (try-it a)
(= (expmod a (- n 1) n) 1))
(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp)
(if (and (not (= exp (- m 1))) (= (remainder (square exp) m) 1))
0
(remainder (square (expmod base (/ exp 2) m)) m)))
(else
(remainder (* base (expmod base (- exp 1) m)) m))))
(cond ((= times 0) true)
((miller-rabin-test n) (fast-prime? n (- times 1)))
(else false)))
In it I test if the square of the exponent is congruent to 1 mod n. Which according
to what I have read, and other correct implementations I have seen is wrong. I should test
the entire number as in:
...
(square
(trivial-test (expmod base (/ exp 2) m) m))
...
The thing is that I have tested this, with many prime numbers and large Carmicheal numbers,
and it seems to give the correct answer, though a bit slower. I don't understand why this
seems to work.

Your version of the function "works" only because you are lucky. Try this experiment: evaluate (fast-prime? 561 3) a hundred times. Depending on the random witnesses that your function chooses, sometimes it will return true and sometimes it will return false. When I did that I got 12 true and 88 false, but you may get different results, depending on your random number generator.
> (let loop ((k 0) (t 0) (f 0))
(if (= k 100) (values t f)
(if (fast-prime? 561 3)
(loop (+ k 1) (+ t 1) f)
(loop (+ k 1) t (+ f 1)))))
12
88
I don't have SICP in front of me -- my copy is at home -- but I can tell you the right way to perform a Miller-Rabin primality test.
Your expmod function is incorrect; there is no reason to square the exponent. Here is a proper function to perform modular exponentiation:
(define (expm b e m) ; modular exponentiation
(let loop ((b b) (e e) (x 1))
(if (zero? e) x
(loop (modulo (* b b) m) (quotient e 2)
(if (odd? e) (modulo (* b x) m) x)))))
Then Gary Miller's strong pseudoprime test, which is a strong version of your try-it test for which there is a witness a that proves the compositeness of every composite n, looks like this:
(define (strong-pseudoprime? n a) ; strong pseudoprime base a
(let loop ((r 0) (s (- n 1)))
(if (even? s) (loop (+ r 1) (/ s 2))
(if (= (expm a s n) 1) #t
(let loop ((r r) (s s))
(cond ((zero? r) #f)
((= (expm a s n) (- n 1)) #t)
(else (loop (- r 1) (* s 2)))))))))
Assuming the Extended Riemann Hypothesis, testing every a from 2 to n-1 will prove (an actual, deterministic proof, not just a probabilistic estimate of primality) the primality of a prime n, or identify at least one a that is a witness to the compositeness of a composite n. Michael Rabin proved that if n is composite, at least three-quarters of the a from 2 to n-1 are witnesses to that compositeness, so testing k random bases demonstrates, but does not prove, the primality of a prime n to a probability of 4−k. Thus, this implementation of the Miller-Rabin primality test:
(define (prime? n k)
(let loop ((k k))
(cond ((zero? k) #t)
((not (strong-pseudoprime? n (random (+ 2 (- n 3))))) #f)
(else (loop (- k 1))))))
That always works properly:
> (let loop ((k 0) (t 0) (f 0))
(if (= k 100) (values t f)
(if (prime? 561 3)
(loop (+ k 1) (+ t 1) f)
(loop (+ k 1) t (+ f 1)))))
0
100
I know your purpose is to study SICP rather than to program primality tests, but if you're interested in programming with prime numbers, I modestly recommend this essay at my blog, which discusses the Miller-Rabin test, among other topics. You should also know there are better (faster, less likely to report erroneous result) primality tests available than randomized Miller-Rabin.

It seems to me, you still got correct answer, because in each iteration of expmod you check conditions for previous iteration. You could try to debug exp value using display function inside expmod. Really, your code is not very different from this one.

Related

Miller-Rabin test (SICP 1.28)

One variant of the Fermat test that cannot be fooled is called the Miller-Rabin test (Miller 1976; Rabin 1980). This starts from an alternate form of Fermat's Little Theorem, which states that if n is a prime number and a is any positive integer less than n, then a raised to the (n - 1)st power is congruent to 1 modulo n.
To test the primality of a number n by the Miller-Rabin test, we pick a random number a less than n and raise a to the (n - 1)st power modulo n using the expmod procedure. However, whenever we perform the squaring step in expmod, we check to see if we have discovered a “nontrivial square root of 1 modulo n,” that is, a number not equal to 1 or n - 1 whose square is equal to 1 modulo n.
It is possible to prove that if such a nontrivial square root of 1 exists, then n is not prime. It is also possible to prove that if n is an odd number that is not prime, then, for at least half the numbers a < n, computing an-1 in this way will reveal a nontrivial square root of 1 modulo n. (This is why the Miller-Rabin test cannot be fooled.)
Modify the expmod procedure to signal if it discovers a nontrivial square root of 1, and use this to implement the Miller-Rabin test with a procedure analogous to fermat-test. Check your procedure by testing various known primes and non-primes. Hint: One convenient way to make expmod signal is to have it return 0.
This is what I have so far.
(define (square x) (* x x))
(define (even? n) (= (remainder n 2)))
(define (expmod-signal b n m)
(define (check a)
(and (not (= a 1))
(not (= a (- n 1)))
(= (square a) (remainder 1 n))))
(cond ((= n 0) 1)
((check b) 0)
((even? n) (remainder (square (expmod-signal b (/ n 2) m)) m))
(else (remainder (* b (expmod-signal b (- n 1) m)) m))))
(define (miller-rabin n)
(define (fail? n a)
(or (= n 0) (not (= n a))))
(define (try a)
(cond ((= a 1) #t)
((fail? (expmod-signal a (- n 1) n) a) #f)
(else (try (- a 1)))))
(try (- n 1)))
I think I implemented miller-rabin correctly but I don't understand how the modified expmod is supposed to work. Do you check the number before the square or after the square? I don't know from reading the question.
I solved this by using the original definition of expmod inside of expmod-signal. Somewhere in my tests, expmod-signal was naturally returning zero and messing with the tests. I misunderstood the check function, "whose square is equal to 1 modulo n" means check if a^2 % m = 1. The way this check function works is to return 0 if the argument is a non-trivial square root of 1 mod n, and return the argument otherwise. If it returns zero, the zero propagates through the remainder of expmod-signal and is returned.
(define (square x) (* x x))
(define (even? n) (= (remainder n 2)))
(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp) (remainder (square (expmod base (/ exp 2) m)) m))
(else (remainder (* base (expmod base (- exp 1) m)) m))))
(define (expmod-signal b n m)
(define (check a)
(if (and (not (= a 1))
(not (= a (- n 1)))
(= (remainder (square a) n) 1))
0
a))
(cond ((= n 0) 1)
((even? n) (remainder (square (check (expmod b (/ n 2) m))) m))
(else (remainder (* b (expmod b (- n 1) m)) m))))
(define (miller-rabin n)
(define (fail? a)
(or (= a 0) (not (= a 1))))
(define (try a)
(cond ((= a 1) #t)
((fail? (expmod-signal a (- n 1) n)) #f)
(else (try (- a 1)))))
(try (- n 1)))

Leibniz Formula in Scheme

I've spent some time looking at the questions about this on here and throughout the internet but I can't really find anything that makes sense to me.
Basically I need help on realizing a function in scheme that evaluates Leibniz's formula when you give it a value k. The value you input lets the function know how many values in the series it should compute. This is what I have so far, I'm not sure what way I need to write this program to make it work. Thanks!
(define (fin-alt-series k)
(cond ((= k 1)4)
((> k 1)(+ (/ (expt -1 k) (+(* 2.0 k) 1.0)) (fin-alt-series (- k 1.0))))))
The base case is incorrect. And we can clean-up the code a bit:
(define (fin-alt-series k)
(cond ((= k 0) 1)
(else
(+ (/ (expt -1.0 k)
(+ (* 2 k) 1))
(fin-alt-series (- k 1))))))
Even better, we can rewrite the procedure to use tail recursion, it'll be faster this way:
(define (fin-alt-series k)
(let loop ((k k) (sum 0))
(if (< k 0)
sum
(loop (- k 1)
(+ sum (/ (expt -1.0 k) (+ (* 2 k) 1)))))))
For example:
(fin-alt-series 1000000)
=> 0.7853984133971936
(/ pi 4)
=> 0.7853981633974483

Language Scheme: find the sum of proper divisors

I am wondering how to write a function calculating the sum of proper divisors of a integer greater than 1.
(define (sum-of-proper-divisors n)
(cond
[(= n 1) 1]
[(= 0 (remainder n (sub1 n)))
(+ (remainder n (sub1 n)) (sum-of-proper-divisors (sub1 (sub1 n))))]
[else (sum-of-proper-divisors (sub1 n))]))
This is the code that I wrote, however, it does not work. It will never stop evaluating because it will always do n-1. And I don't know how to fix this. Also, there might be other problems. How to put the restriction that makes the function stop evaluating when the divisor becomes 1?
You're confusing the number n whose divisors you want to find, with said divisors. Notice that n never changes, what must be modified at each step is the current integer being tested (a possible divisor). For that you'll need to pass around two parameters:
(define (sum-of-proper-divisors n i)
(cond
[(= i 1) 1]
[(= (remainder n i) 0)
(+ i (sum-of-proper-divisors n (sub1 i)))]
[else (sum-of-proper-divisors n (sub1 i))]))
Call it like this, at the beginning i must be one unit less than n:
(sum-of-proper-divisors 10 9)
=> 8
If having two parameters bothers you there are several ways to pass a single parameter, for instance using a named let:
(define (sum-of-proper-divisors n)
(let loop ((i (sub1 n)))
(cond
[(= i 1) 1]
[(= (remainder n i) 0)
(+ i (loop (sub1 i)))]
[else (loop (sub1 i))])))

Collatz function in scheme

So i'm trying to solve the collatz function iteratively in scheme but my test cases keep showing up as
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
1
(if (even? n) (collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1))
)
)
)
)
However, my test cases keep resulting in "#[constant 13 #x2]". What did I write wrong, if anything?
You forgot to call collatz-iter. Also, it's not clear what do you intend to do with counter, you just increment it, but never actually use its value - your procedure will always return 1 (assuming that the Collatz conjecture is true, which seems quite possible).
I'm guessing you intended to return the counter, so here's how to fix your procedure:
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
counter ; return the counter
(if (even? n)
(collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1)))))
(collatz-iter n 1)) ; call collatz-iter
And this is how it works for the examples in wikipedia:
(collatz 6)
=> 9
(collatz 11)
=> 15
(collatz 27)
=> 112
So basically we're counting the length of the Collatz sequence for a given number.
You should indent your code properly. With proper formatting, it's
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
1
(if (even? n)
(collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1))))))
which clearly has no body forms to execute, just an internal definition. You need to add a call to collatz-iter, like this:
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
1
(if (even? n)
(collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1)))))
(collatz-iter n 1))
(I'm not sure what your initial counter value should be. I'm assuming 1 is reasonable, but perhaps it should be zero?) Better yet, since the body it just a call to collatz-iter, you can make this a named let, which is more like your original code:
(define (collatz n)
(let iter ((n n) (counter 1))
(if (<= n 1)
1
(if (even? n)
(iter (/ n 2) (+ counter 1))
(iter (+ (* n 3) 1) (+ counter 1))))))
It's sort of like combining the internal definition with the single call to the local function. Once you've done this, though, you'll see that it always returns 1, when it eventually gets to the base case (assuming the Collatz conjecture is true, of course). Fixing this, you'll end up with:
(define (collatz n)
(let iter ((n n) (counter 1))
(if (<= n 1)
counter
(if (even? n)
(iter (/ n 2) (+ counter 1))
(iter (+ (* n 3) 1) (+ counter 1))))))
When I try to run your code in Racket I get the error:
no expression after a sequence of internal definitions
This is telling us that the collatz function conatains the collatz-iter definition, but no expression to call it (other than the recursive calls in collatz-iter). That can be fixed by adding a call to (collatz-iter n 0) as the last line in collatz.
However, when you run the program it always returns 1. Not very interesting. If instead you change it to return the value of counter you can see how many steps it took for the sequence to reach 1.
(define (collatz n)
(define (collatz-iter n counter)
(if (<= n 1)
counter
(if (even? n) (collatz-iter (/ n 2) (+ counter 1))
(collatz-iter (+ (* n 3) 1) (+ counter 1))
)
)
)
(collatz-iter n 0)
)
We can check it against a few examples given on the Wikipedia Collatz conjecture article.
> (collatz 6)
8
> (collatz 11)
14
> (collatz 27)
111
>

Scheme Monte-Carlo-Sampling

I am trying to determine the number of marbles that fall within a given circle (radius 1) given that they have random x and y coordinates.
My overall goal is to find an approximate value for pi by using monte carlo sampling by multiplying by 4 the (number of marbles within the circle)/(total number of marbles).
I intended for my function to count the number of marbles within the circle, but I am having trouble following why it does not work. Any help on following the function here would be appreciated.
Please comment if my above request for help is unclear.
(define(monte-carlo-sampling n)
(let ((x (- (* 2 (random)) 1))
(y (- (* 2 (random)) 1)))
(cond((= 0 n)
* 4 (/ monte-carlo-sampling(+ n 1) n)
((> 1 n)
(cond((< 1 (sqrt(+ (square x) (square y))) (+ 1 (monte-carlo-sampling(- n 1)))))
((> 1 (sqrt(+ (square x) (square y))) (monte-carlo-sampling(- n 1))))
)))))
Your parentheses are all messed up, and your argument order for < is wrong. Here's how the code should look like after it's corrected:
(define (monte-carlo-sampling n)
(let ((x (- (* 2 (random)) 1))
(y (- (* 2 (random)) 1)))
(cond ((= n 0)
0)
(else
(cond ((< (sqrt (+ (square x) (square y))) 1)
(+ 1 (monte-carlo-sampling (- n 1))))
(else
(monte-carlo-sampling (- n 1))))))))
This returns the number of hits. You'd have to convert the number of hits into a pi estimate using an outer function, such as:
(define (estimate-pi n)
(* 4 (/ (monte-carlo-sampling n) n)))
Here's how I'd write the whole thing, if it were up to me:
(define (estimate-pi n)
(let loop ((i 0)
(hits 0))
(cond ((>= i n)
(* 4 (/ hits n)))
((<= (hypot (sub1 (* 2 (random)))
(sub1 (* 2 (random)))) 1)
(loop (add1 i) (add1 hits)))
(else
(loop (add1 i) hits)))))
(Tested on Racket, using the definition of hypot I gave in my last answer. If you're not using Racket, you have to change add1 and sub1 to something appropriate.)
I wrote a solution to this problem at my blog; the inner function is called sand because I was throwing grains of sand instead of marbles:
(define (pi n)
(define (sand?) (< (+ (square (rand)) (square (rand))) 1))
(do ((i 0 (+ i 1)) (p 0 (+ p (if (sand?) 1 0))))
((= i n) (exact->inexact (* 4 p (/ n))))))
This converges very slowly; after a hundred thousand iterations I had 3.14188. The blog entry also discusses a method for estimating pi developed by Archimedes over two hundred years before Christ that converges very quickly, with 27 iterations taking us to the bound of double-precision arithmetic.
Here's a general method of doing monte-carlo it accepts as arguments the number of iterations, and a thunk (procedure with no arguments) that should return #t or #f which is the experiment to be run each iteration
(define (monte-carlo trials experiment)
(define (iter trials-remaining trials-passed)
(cond ((= trials-remaining 0)
(/ trials-passed trials))
((experiment)
(iter (- trials-remaining 1) (+ trials-passed 1)))
(else
(iter (- trials-remaining 1) trials-passed))))
(iter trials 0))
Now it's just a mater of writing the specific experiment
You could write in your experiment where experiment is invoked in monte-carlo, but abstracting here gives you a much more flexible and comprehensible function. If you make a function do too many things at once it becomes hard to reason about and debug.
(define (marble-experiment)
(let ((x ...) ;;assuming you can come up with
(y ...)) ;;a way to get a random x between 0 and 1
;;with sufficient granularity for your estimate)
(< (sqrt (+ (* x x) (* y y))) 1)))
(define pi-estimate
(* 4 (monte-carlo 1000 marble-experiment)))

Resources