Homepage › Solution manuals › Ivan Niven › An Introduction to the Theory of Numbers › Exercise 4.4.28* (Algorithm to compute $V_n$)
Exercise 4.4.28* (Algorithm to compute $V_n$)
Show that . Explain how this formula and the duplication formula (4.13) can be used to compute the triple , if the triple is known. Similarly, explain how the triple can be computed in terms of the triple . Explain how this triple can be determined for general by using these two operations. (This method is not very much more efficient than the method described in the text, but it involves less work in the special case . By constructing congruential analogues of the identities in Problem 18 one may see that for purpose of constructing Lucas pseudoprime tests this does not involve any loss of generality.)
Answers
Proof.
- (a)
-
By definition
where are the roots of , so that
Then
In conclusion,
(Lucas defined as roots of , which gives the more aesthetically pleasing formula .)
- (b)
-
We recall the duplication formulas (4.13):
Suppose that we know the triple . Then
This gives the triple with a fixed number of multiplications and additions.
Similarly
- (c)
- We compute the triple recursively,. We use (4),(5),(6) with if is even, and (7),(8),(9) with is is odd (see algorithm in the note 1), until we reach , for which . If we compute by reducing modulo at each step, the time is .
Note 1: This algorithm gives in Python the following procedure
def triple(k, a, b): """return the tuple (V_k(a,b), V_(k+1)(a,b), (-b)^n)""" if k == 0: return (2, a, 1) if k % 2 == 0: n = k // 2 (V, W, P) = triple(n, a, b) return (V * V - 2 * P, V * W - a * P, P * P) else: n = (k - 1) // 2 (V, W, P) = triple(n, a, b) return (V * W - a * P, W * W + 2 * b * P, -b * P * P) def V(k, a, b): """return (V_k(a,b)""" v , _ , _ = triple(k, a, b) return v
To test this program, we verify that for some prime .
p = 11213 V(p, 1, 1) 239006726.....34499771 (2344 digits) V(p, 1, 1) % p 1
We give the modular version:
def triple_mod(k, a, b , p): """return the tuple (V_k(a,b), V_(k+1)(a,b), (-b)^n) mod p""" a, b = a % p, b % p if k == 0: return (2, a, 1) if k % 2 == 0: n = k // 2 (V, W, P) = triple_mod(n, a, b, p) return ((V * V - 2 * P) % p, (V * W - a * P) % p, (P * P) % p) else: n = (k - 1) // 2 (V, W, P) = triple_mod(n, a, b, p) return ((V * W - a * P) % p, (W * W + 2 * b * P) % p, (-b * P * P) % p) def V_mod(k, a, b, p): """return (V_k(a,b) mod p""" v , _ , _ = triple_mod(k, a, b, p) return v p = 1234567891234567891234567891 # p is prime! V_mod(p, 1, 1, p) 1
Note 2: A more natural and generalizable method to compute (or ) is to write the relation between the in matrix form. Since and , then
so
By using fast exponentiation for matrices, we obtain the result in a time .
With Sagemath:
def V(n, a, b, p): """return (V_n(a,b) mod p""" a , b = Mod(a, p), Mod(b, p) A = matrix([[0, 1], [b, a]]) B = A^n * matrix([[2], [a]]) return B[0][0] p = 1234567891234567891234567891 V(p, 1, 1, p) 1 %timeit V(p, 1, 1, p) 1000 loops, best of 3: 981 micro-s per loop %timeit V_mod(p, 1, 1, p) The slowest run took 60.92 times longer than the fastest. This could mean that an intermediate result is being cached. 1000 loops, best of 3: 244 micro-s per loop
We see in this example that the execution speeds are comparable, nevertheless with an advantage for the first function V_mod.
Note 3: For Problem 27, the second method becomes indispensable. This gives
sage: def u(n, p): ....: """return u_n mod p, see Problem 4.4.27* from Niven""" ....: R = Integers(p) ....: A = matrix(R, [[0, 1, 0], [0, 0 , 1], [1, 1, 0]]) ....: B = A^n * matrix(R, [[3], [0], [2]]) ....: return B[0][0] ....:
To verify the affirmation in the statement of Problem 27:
sage: for n in range(2, 1000000): ....: if u(n,n) == 0 and not is_pseudoprime(n): ....: print(n) ....: 271441 904631
So the least composite number with the property is .