Exercise 4.4.28* (Algorithm to compute $V_n$)

Show that V 2 n + 1 = V n V n + 1 a ( b ) n . Explain how this formula and the duplication formula (4.13) can be used to compute the triple ( V 2 n , V 2 n + 1 , ( b ) 2 n ) , if the triple ( V n , V n + 1 , ( b ) n ) is known. Similarly, explain how the triple ( V 2 n + 1 , V 2 n + 2 , ( b ) 2 n + 1 ) can be computed in terms of the triple ( V n , V n + 1 , ( b ) n ) . Explain how this triple can be determined for general n 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 b = 1 . 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 U n = λ n μ n λ μ , V n = λ n + μ n , (1)

where λ , μ are the roots of x 2 ax b , so that

λ + μ = a , λμ = b . (2)

Then

V 2 n + 1 = λ 2 n + 1 + μ 2 n + 1 = ( λ n + μ n ) ( λ n + 1 + μ n + 1 ) ( λμ ) n ( λ + μ ) = V n V n + 1 a ( b ) n ( by (1) ) .

In conclusion,

V 2 n + 1 = V n V n + 1 a ( b ) n . (3)

(Lucas defined λ , μ as roots of x 2 Px + Q , which gives the more aesthetically pleasing formula V 2 n + 1 = V n V n + 1 P Q n .)

(b)
We recall the duplication formulas (4.13): U 2 n = U n V n , V 2 n = V n 2 2 ( b ) n .

Suppose that we know the triple ( V n , V n + 1 , ( b ) n ) . Then

V 2 n = V n 2 2 ( b ) n , (4) V 2 n + 1 = V n V n + 1 a ( b ) n , (5) ( b ) 2 n = [ ( b ) n ] 2 . (6)

This gives the triple ( V 2 n , V 2 n + 1 , ( b ) 2 n ) with a fixed number of multiplications and additions.

Similarly

V 2 n + 1 = V n V n + 1 a ( b ) n , (7) V 2 n + 2 = V n + 1 2 + 2 b ( b ) n , (8) ( b ) 2 n + 1 = b [ ( b ) n ] 2 . (9)
(c)
We compute the triple ( V k ( a , b ) , V k + 1 ( a , b ) , ( b ) n ) recursively,. We use (4),(5),(6) with n = k 2 if n is even, and (7),(8),(9) with n = ( k 1 ) 2 is n is odd (see algorithm in the note 1), until we reach n = 0 , for which ( V 0 ( a , b ) , V 1 ( a , b ) , ( b ) 0 ) = ( 2 , a , 1 ) . If we compute V k ( mod p ) ) by reducing modulo p at each step, the time is T = O ( log ( k ) ) .

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 V p ( 1 , 1 ) a = 1 ( mod p ) for some prime p .

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 V n (or V n mod p ) is to write the relation between the V n in matrix form. Since V 0 = 2 , V 1 = a and V n + 2 = a V n + 1 + b V n , then

( V n + 1 V n + 2 ) = ( 0 1 b a ) ( V n V n + 1 ) ,

so

( V n V n + 1 ) = ( 0 1 b a ) n ( 2 a ) .

By using fast exponentiation for matrices, we obtain the result V n mod p in a time T = O ( log ( n ) ) .

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 p u p is 271 , 441 = 52 1 2 .

User profile picture
2025-03-12 09:15
Comments