Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/binary_recurrence_sequences.py
8815 views
1
"""
2
Binary Recurrence Sequences.
3
4
5
This class implements several methods relating to
6
general linear binary recurrence sequences, including a sieve
7
to find perfect powers in integral linear binary recurrence sequences.
8
9
EXAMPLES::
10
11
sage: R = BinaryRecurrenceSequence(1,1) #the Fibonacci sequence
12
sage: R(137) #the 137th term of the Fibonacci sequence
13
19134702400093278081449423917
14
sage: R(137) == fibonacci(137)
15
True
16
sage: [R(i) % 4 for i in xrange(12)]
17
[0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1]
18
sage: R.period(4) #the period of the fibonacci sequence modulo 4
19
6
20
sage: R.pthpowers(2, 10**30) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06]
21
[0, 1, 2, 12]
22
23
sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence
24
sage: S.period(73)
25
148
26
sage: S(5) % 73 == S(5 +148) %73
27
True
28
sage: S.pthpowers(3,10**30) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^30
29
[0, 1, 2]
30
31
sage: T = BinaryRecurrenceSequence(2,0,1,2)
32
sage: [T(i) for i in xrange(10)]
33
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
34
sage: T.is_degenerate()
35
True
36
sage: T.is_geometric()
37
True
38
sage: T.pthpowers(7,10**30)
39
Traceback (most recent call last):
40
...
41
ValueError: The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers.
42
43
44
AUTHORS:
45
46
-Isabel Vogt (2013): initial version
47
48
REFERENCES:
49
50
.. [SV13] Silliman and Vogt. "Powers in Lucas Sequences via Galois Representations." Proceedings of the American Mathematical Society, 2013. :arxiv:`1307.5078v2`
51
52
.. [BMS06] Bugeaud, Mignotte, and Siksek. "Classical and modular approaches to exponential Diophantine equations: I. Fibonacci and Lucas perfect powers." Annals of Math, 2006.
53
54
.. [SS] Shorey and Stewart. "On the Diophantine equation a x^{2t} + b x^t y + c y^2 = d and pure powers in recurrence sequences." Mathematica Scandinavica, 1983.
55
"""
56
57
#****************************************************************************#
58
# Copyright (C) 2013 Isabel Vogt <[email protected]> #
59
# #
60
# Distributed under the terms of the GNU General Public License (GPL) #
61
# as published by the Free Software Foundation; either version 2 of #
62
# the License, or (at your option) any later version. #
63
# http://www.gnu.org/licenses/ #
64
#****************************************************************************#
65
66
from sage.structure.sage_object import SageObject
67
from sage.matrix.constructor import matrix, vector
68
from sage.rings.number_field.number_field import QuadraticField
69
from sage.rings.finite_rings.integer_mod_ring import Integers
70
from sage.rings.finite_rings.constructor import GF
71
from sage.rings.integer import Integer
72
from sage.rings.arith import gcd, lcm, next_prime, is_prime, next_prime_power, legendre_symbol
73
from sage.functions.log import log
74
from sage.functions.other import sqrt
75
76
class BinaryRecurrenceSequence(SageObject):
77
78
"""
79
Create a linear binary recurrence sequence defined by initial conditions
80
`u_0` and `u_1` and recurrence relation `u_{n+2} = b*u_{n+1}+c*u_n`.
81
82
INPUT:
83
84
- ``b`` -- an integer (partially determining the recurrence relation)
85
86
- ``c`` -- an integer (partially determining the recurrence relation)
87
88
- ``u0`` -- an integer (the 0th term of the binary recurrence sequence)
89
90
- ``u1`` -- an integer (the 1st term of the binary recurrence sequence)
91
92
93
OUTPUT:
94
95
- An integral linear binary recurrence sequence defined by ``u0``, ``u1``, and `u_{n+2} = b*u_{n+1}+c*u_n`
96
97
.. SEEALSO::
98
99
:func:`fibonacci`, :func:`lucas_number1`, :func:`lucas_number2`
100
101
EXAMPLES::
102
103
sage: R = BinaryRecurrenceSequence(3,3,2,1)
104
sage: R
105
Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2};
106
With initial conditions: u_0 = 2, and u_1 = 1
107
108
"""
109
110
def __init__(self, b, c, u0=0, u1=1):
111
112
"""
113
See ``BinaryRecurrenceSequence`` for full documentation.
114
115
EXAMPLES::
116
117
sage: R = BinaryRecurrenceSequence(3,3,2,1)
118
sage: R
119
Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2};
120
With initial conditions: u_0 = 2, and u_1 = 1
121
122
sage: R = BinaryRecurrenceSequence(1,1)
123
sage: loads(R.dumps()) == R
124
True
125
126
"""
127
self.b = b
128
self.c = c
129
self.u0 = u0
130
self.u1 = u1
131
self._period_dict = {} #dictionary to cache the period of a sequence for future lookup
132
self._PGoodness = {} #dictionary to cache primes that are "good" by some prime power
133
self._ell = 1 #variable that keeps track of the last prime power to be used as a goodness
134
135
136
def __repr__(self):
137
"""
138
Give string representation of the class.
139
140
EXAMPLES::
141
142
sage: R = BinaryRecurrenceSequence(3,3,2,1)
143
sage: R
144
Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2};
145
With initial conditions: u_0 = 2, and u_1 = 1
146
147
"""
148
return 'Binary recurrence sequence defined by: u_n = ' + str(self.b) + ' * u_{n-1} + ' + str(self.c) + ' * u_{n-2};\nWith initial conditions: u_0 = ' + str(self.u0) + ', and u_1 = ' + str(self.u1)
149
150
def __eq__(self, other):
151
"""
152
Compare two binary recurrence sequences.
153
154
EXAMPLES::
155
156
sage: R = BinaryRecurrenceSequence(3,3,2,1)
157
sage: S = BinaryRecurrenceSequence(3,3,2,1)
158
sage: R == S
159
True
160
161
sage: T = BinaryRecurrenceSequence(3,3,2,2)
162
sage: R == T
163
False
164
165
"""
166
167
return (self.u0 == other.u0) and (self.u1 == other.u1) and (self.b == other.b) and (self.c == other.c)
168
169
def __call__(self, n, modulus=0):
170
171
"""
172
Give the nth term of a binary recurrence sequence, possibly mod some modulus.
173
174
INPUT:
175
176
- ``n`` -- an integer (the index of the term in the binary recurrence sequence)
177
178
- ``modulus`` -- a natural number (optional -- default value is 0)
179
180
OUTPUT:
181
182
- An integer (the nth term of the binary recurrence sequence modulo ``modulus``)
183
184
EXAMPLES::
185
186
sage: R = BinaryRecurrenceSequence(3,3,2,1)
187
sage: R(2)
188
9
189
sage: R(101)
190
16158686318788579168659644539538474790082623100896663971001
191
sage: R(101,12)
192
9
193
sage: R(101)%12
194
9
195
196
"""
197
R = Integers(modulus)
198
F = matrix(R, [[0,1],[self.c,self.b]]) # F*[u_{n}, u_{n+1}]^T = [u_{n+1}, u_{n+2}]^T (T indicates transpose).
199
v = matrix(R, [[self.u0],[self.u1]])
200
return list(F**n*v)[0][0]
201
202
def is_degenerate(self):
203
"""
204
Decide whether the binary recurrence sequence is degenerate.
205
206
Let `\\alpha` and `\\beta` denote the roots of the characteristic polynomial
207
`p(x) = x^2-bx -c`. Let `a = u_1-u_0\\beta/(\\beta - \\alpha)` and
208
`b = u_1-u_0\\alpha/(\\beta - \\alpha)`. The sequence is, thus, given by
209
`u_n = a \\alpha^n - b\\beta^n`. Then we say that the sequence is nondegenerate
210
if and only if `a*b*\\alpha*\\beta \\neq 0` and `\\alpha/\\beta` is not a
211
root of unity.
212
213
More concretely, there are 4 classes of degeneracy, that can all be formulated
214
in terms of the matrix `F = [[0,1], [c, b]]`.
215
216
- `F` is singular -- this corresponds to ``c`` = 0, and thus `\\alpha*\\beta = 0`. This sequence is geometric after term ``u0`` and so we call it ``quasigeometric``.
217
218
- `v = [[u_0], [u_1]]` is an eigenvector of `F` -- this corresponds to a ``geometric`` sequence with `a*b = 0`.
219
220
- `F` is nondiagonalizable -- this corresponds to `\\alpha = \\beta`. This sequence will be the point-wise product of an arithmetic and geometric sequence.
221
222
- `F^k` is scaler, for some `k>1` -- this corresponds to `\\alpha/\\beta` a `k` th root of unity. This sequence is a union of several geometric sequences, and so we again call it ``quasigeometric``.
223
224
EXAMPLES::
225
226
sage: S = BinaryRecurrenceSequence(0,1)
227
sage: S.is_degenerate()
228
True
229
sage: S.is_geometric()
230
False
231
sage: S.is_quasigeometric()
232
True
233
234
sage: R = BinaryRecurrenceSequence(3,-2)
235
sage: R.is_degenerate()
236
False
237
238
sage: T = BinaryRecurrenceSequence(2,-1)
239
sage: T.is_degenerate()
240
True
241
sage: T.is_arithmetic()
242
True
243
244
"""
245
246
if (self.b**2+4*self.c) != 0:
247
248
if (self.b**2+4*self.c).is_square():
249
A = sqrt((self.b**2+4*self.c))
250
251
else:
252
K = QuadraticField((self.b**2+4*self.c), 'x')
253
A = K.gen()
254
255
aa = (self.u1 - self.u0*(self.b + A)/2)/(A) #called `a` in Docstring
256
bb = (self.u1 - self.u0*(self.b - A)/2)/(A) #called `b` in Docstring
257
258
#(b+A)/2 is called alpha in Docstring, (b-A)/2 is called beta in Docstring
259
260
if (self.b - A) != 0:
261
if ((self.b+A)/(self.b-A))**(6) == 1:
262
return True
263
else:
264
return True
265
266
if aa*bb*(self.b + A)*(self.b - A) == 0:
267
return True
268
return False
269
return True
270
271
272
def is_geometric(self):
273
"""
274
Decide whether the binary recurrence sequence is geometric - ie a geometric sequence.
275
276
This is a subcase of a degenerate binary recurrence sequence, for which `ab=0`, i.e.
277
`u_{n}/u_{n-1}=r` for some value of `r`. See ``is_degenerate`` for a description of
278
degeneracy and definitions of `a` and `b`.
279
280
EXAMPLES::
281
282
sage: S = BinaryRecurrenceSequence(2,0,1,2)
283
sage: [S(i) for i in xrange(10)]
284
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
285
sage: S.is_geometric()
286
True
287
288
"""
289
290
#If [u_0, u_1]^T is an eigenvector for the incrementation matrix F = [[0,1],[c,b]], then the sequence
291
#is geometric, ie we can write u_n = a*r^n for some a and r.
292
293
#We decide if u0, u1, u2 = b*u1+c*u0 are in geometric progression by whether u1^2 = (b*u1+c*u0)*u0
294
295
return bool((self.u1)**2 == (self.b*self.u1 + self.c*self.u0)*self.u0)
296
297
def is_quasigeometric(self):
298
"""
299
Decide whether the binary recurrence sequence is degenerate and similar to a geometric sequence,
300
i.e. the union of multiple geometric sequences, or geometric after term ``u0``.
301
302
If `\\alpha/\\beta` is a `k` th root of unity, where `k>1`, then necessarily `k = 2, 3, 4, 6`.
303
Then `F = [[0,1],[c,b]` is diagonalizable, and `F^k = [[\\alpha^k, 0], [0,\\beta^k]]` is scaler
304
matrix. Thus for all values of `j` mod `k`, the `j` mod `k` terms of `u_n` form a geometric
305
series.
306
307
If `\\alpha` or `\\beta` is zero, this implies that `c=0`. This is the case when `F` is
308
singular. In this case, `u_1, u_2, u_3, ...` is geometric.
309
310
EXAMPLES::
311
312
sage: S = BinaryRecurrenceSequence(0,1)
313
sage: [S(i) for i in xrange(10)]
314
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
315
sage: S.is_quasigeometric()
316
True
317
318
sage: R = BinaryRecurrenceSequence(3,0)
319
sage: [R(i) for i in xrange(10)]
320
[0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561]
321
sage: R.is_quasigeometric()
322
True
323
"""
324
325
#First test if F is singular... i.e. beta = 0
326
if self.c == 0:
327
return True
328
329
#Otherwise test if alpha/beta is a root of unity that is not 1
330
else:
331
if (self.b**2+4*self.c) != 0: #thus alpha/beta != 1
332
333
if (self.b**2+4*self.c).is_square():
334
A = sqrt((self.b**2+4*self.c))
335
336
else:
337
K = QuadraticField((self.b**2+4*self.c), 'x')
338
A = K.gen()
339
340
if ((self.b+A)/(self.b-A))**(6) == 1:
341
return True
342
343
return False
344
345
def is_arithmetic(self):
346
"""
347
Decide whether the sequence is degenerate and an arithmetic sequence.
348
349
The sequence is arithmetic if and only if `u_1 - u_0 = u_2 - u_1 = u_3 - u_2`.
350
351
This corresponds to the matrix `F = [[0,1],[c,b]]` being nondiagonalizable
352
and `\\alpha/\\beta = 1`.
353
354
EXAMPLES::
355
356
sage: S = BinaryRecurrenceSequence(2,-1)
357
sage: [S(i) for i in xrange(10)]
358
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
359
sage: S.is_arithmetic()
360
True
361
"""
362
363
#Test if u_1-u_0 = u_2-u_1 = u_3-u_2
364
365
return bool(self(1) - self(0) == self(2) - self(1) == self(3) - self(2))
366
367
368
def period(self, m):
369
"""
370
Return the period of the binary recurrence sequence modulo
371
an integer ``m``.
372
373
If `n_1` is congruent to `n_2` modulu ``period(m)``, then `u_{n_1}` is
374
is congruent to `u_{n_2}` modulo ``m``.
375
376
INPUT:
377
378
- ``m`` -- an integer (modulo which the period of the recurrence relation is calculated).
379
380
OUTPUT:
381
382
- The integer (the period of the sequence modulo m)
383
384
EXAMPLES:
385
386
If `p = \\pm 1 \\mod 5`, then the period of the Fibonacci sequence
387
mod `p` is `p-1` (c.f. Lemma 3.3 of [BMS06]).
388
389
::
390
391
sage: R = BinaryRecurrenceSequence(1,1)
392
sage: R.period(31)
393
30
394
395
sage: [R(i) % 4 for i in xrange(12)]
396
[0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1]
397
sage: R.period(4)
398
6
399
400
This function works for degenerate sequences as well.
401
402
::
403
404
sage: S = BinaryRecurrenceSequence(2,0,1,2)
405
sage: S.is_degenerate()
406
True
407
sage: S.is_geometric()
408
True
409
sage: [S(i) % 17 for i in xrange(16)]
410
[1, 2, 4, 8, 16, 15, 13, 9, 1, 2, 4, 8, 16, 15, 13, 9]
411
sage: S.period(17)
412
8
413
414
Note: the answer is cached.
415
"""
416
417
#If we have already computed the period mod m, then we return the stored value.
418
419
if m in self._period_dict:
420
return self._period_dict[m]
421
422
else:
423
R = Integers(m)
424
A = matrix(R, [[0,1],[self.c,self.b]])
425
w = matrix(R, [[self.u0],[self.u1]])
426
Fac = list(m.factor())
427
Periods = {}
428
429
#To compute the period mod m, we compute the least integer n such that A^n*w == w. This necessarily
430
#divides the order of A as a matrix in GL_2(Z/mZ).
431
432
#We compute the period modulo all distinct prime powers dividing m, and combine via the lcm.
433
#To compute the period mod p^e, we first compute the order mod p. Then the period mod p^e
434
#must divide p^{4e-4}*period(p), as the subgroup of matrices mod p^e, which reduce to
435
#the identity mod p is of order (p^{e-1})^4. So we compute the period mod p^e by successively
436
#multiplying the period mod p by powers of p.
437
438
for i in Fac:
439
p = i[0]; e = i[1]
440
#first compute the period mod p
441
if p in self._period_dict:
442
perp = self._period_dict[p]
443
else:
444
F = A.change_ring(GF(p))
445
v = w.change_ring(GF(p))
446
FF = F**(p-1)
447
p1fac = list((p-1).factor())
448
449
#The order of any matrix in GL_2(F_p) either divides p(p-1) or (p-1)(p+1).
450
#The order divides p-1 if it is diagaonalizable. In any case, det(F^(p-1))=1,
451
#so if tr(F^(p-1)) = 2, then it must be triangular of the form [[1,a],[0,1]].
452
#The order of the subgroup of matrices of this form is p, so the order must divide
453
#p(p-1) -- in fact it must be a multiple of p. If this is not the case, then the
454
#order divides (p-1)(p+1). As the period divides the order of the matrix in GL_2(F_p),
455
#these conditions hold for the period as well.
456
457
#check if the order divides (p-1)
458
if FF*v == v:
459
M = p-1
460
Mfac = p1fac
461
462
#check if the trace is 2, then the order is a multiple of p dividing p*(p-1)
463
elif (FF).trace() == 2:
464
M = p-1
465
Mfac = p1fac
466
F = F**p #replace F by F^p as now we only need to determine the factor dividing (p-1)
467
468
#otherwise it will divide (p+1)(p-1)
469
else :
470
M = (p+1)*(p-1)
471
p2fac = list((p+1).factor()) #factor the (p+1) and (p-1) terms seperately and then combine for speed
472
Mfac_dic = {}
473
for i in list(p1fac + p2fac):
474
if i[0] not in Mfac_dic:
475
Mfac_dic[i[0]] = i[1]
476
else :
477
Mfac_dic[i[0]] = Mfac_dic[i[0]] + i[1]
478
Mfac = [(i,Mfac_dic[i]) for i in Mfac_dic]
479
480
#Now use a fast order algorithm to compute the period. We know that the period divides
481
#M = i_1*i_2*...*i_l where the i_j denote not necessarily distinct prime factors. As
482
#F^M*v == v, for each i_j, if F^(M/i_j)*v == v, then the period divides (M/i_j). After
483
#all factors have been iterated over, the result is the period mod p.
484
485
Mfac = list(Mfac)
486
C=[]
487
488
#expand the list of prime factors so every factor is with multiplicity 1
489
490
for i in xrange(len(Mfac)):
491
for j in xrange(Mfac[i][1]):
492
C.append(Mfac[i][0])
493
494
Mfac = C
495
n = M
496
for i in Mfac:
497
b = Integer(n/i)
498
if F**b*v == v:
499
n = b
500
perp = n
501
502
#Now compute the period mod p^e by steping up by multiples of p
503
F = A.change_ring(Integers(p**e))
504
v = w.change_ring(Integers(p**e))
505
FF = F**perp
506
if FF*v == v:
507
perpe = perp
508
else :
509
tries = 0
510
while True:
511
tries += 1
512
FF = FF**p
513
if FF*v == v:
514
perpe = perp*p**tries
515
break
516
Periods[p] = perpe
517
518
#take the lcm of the periods mod all distinct primes dividing m
519
period = 1
520
for p in Periods:
521
period = lcm(Periods[p],period)
522
523
self._period_dict[m] = period #cache the period mod m
524
return period
525
526
527
def pthpowers(self, p, Bound):
528
"""
529
Find the indices of proveably all pth powers in the recurrence sequence bounded by Bound.
530
531
Let `u_n` be a binary recurrence sequence. A ``p`` th power in `u_n` is a solution
532
to `u_n = y^p` for some integer `y`. There are only finitely many ``p`` th powers in
533
any recurrence sequence [SS].
534
535
INPUT:
536
537
- ``p`` - a rational prime integer (the fixed p in `u_n = y^p`)
538
539
- ``Bound`` - a natural number (the maximum index `n` in `u_n = y^p` that is checked).
540
541
OUTPUT:
542
543
- A list of the indices of all ``p`` th powers less bounded by ``Bound``. If the sequence is degenerate and there are many ``p`` th powers, raises ``ValueError``.
544
545
EXAMPLES::
546
547
sage: R = BinaryRecurrenceSequence(1,1) #the Fibonacci sequence
548
sage: R.pthpowers(2, 10**30) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06]
549
[0, 1, 2, 12]
550
551
sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence
552
sage: S.pthpowers(3,10**30) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^30
553
[0, 1, 2]
554
555
sage: Q = BinaryRecurrenceSequence(3,3,2,1)
556
sage: Q.pthpowers(11,10**30) # long time (7.5 seconds)
557
[1]
558
559
If the sequence is degenerate, and there are are no ``p`` th powers, returns `[]`. Otherwise, if
560
there are many ``p`` th powers, raises ``ValueError``.
561
562
::
563
564
sage: T = BinaryRecurrenceSequence(2,0,1,2)
565
sage: T.is_degenerate()
566
True
567
sage: T.is_geometric()
568
True
569
sage: T.pthpowers(7,10**30)
570
Traceback (most recent call last):
571
...
572
ValueError: The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers.
573
574
sage: L = BinaryRecurrenceSequence(4,0,2,2)
575
sage: [L(i).factor() for i in xrange(10)]
576
[2, 2, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15, 2^17]
577
sage: L.is_quasigeometric()
578
True
579
sage: L.pthpowers(2,10**30)
580
[]
581
582
NOTE: This function is primarily optimized in the range where ``Bound`` is much larger than ``p``.
583
584
"""
585
586
#Thanks to Jesse Silliman for helpful conversations!
587
588
#Reset the dictionary of good primes, as this depends on p
589
self._PGoodness = {}
590
#Starting lower bound on good primes
591
self._ell = 1
592
593
#If the sequence is geometric, then the `n`th term is `a*r^n`. Thus the
594
#property of being a ``p`` th power is periodic mod ``p``. So there are either
595
#no ``p`` th powers if there are none in the first ``p`` terms, or many if there
596
#is at least one in the first ``p`` terms.
597
598
if self.is_geometric() or self.is_quasigeometric():
599
no_powers = True
600
for i in xrange(1,6*p+1):
601
if _is_p_power(self(i), p) :
602
no_powers = False
603
break
604
if no_powers:
605
if _is_p_power(self.u0,p):
606
return [0]
607
return []
608
else :
609
raise ValueError, "The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers."
610
611
#If the sequence is degenerate without being geometric or quasigeometric, there
612
#may be many ``p`` th powers or no ``p`` th powers.
613
614
elif (self.b**2+4*self.c) == 0 :
615
616
#This is the case if the matrix F is not diagonalizable, ie b^2 +4c = 0, and alpha/beta = 1.
617
618
alpha = self.b/2
619
620
#In this case, u_n = u_0*alpha^n + (u_1 - u_0*alpha)*n*alpha^(n-1) = alpha^(n-1)*(u_0 +n*(u_1 - u_0*alpha)),
621
#that is, it is a geometric term (alpha^(n-1)) times an arithmetic term (u_0 + n*(u_1-u_0*alpha)).
622
623
#Look at classes n = k mod p, for k = 1,...,p.
624
625
for k in xrange(1,p+1):
626
627
#The linear equation alpha^(k-1)*u_0 + (k+pm)*(alpha^(k-1)*u1 - u0*alpha^k)
628
#must thus be a pth power. This is a linear equation in m, namely, A + B*m, where
629
630
A = (alpha**(k-1)*self.u0 + k*(alpha**(k-1)*self.u1 - self.u0*alpha**k))
631
B = p*(alpha**(k-1)*self.u1 - self.u0*alpha**k)
632
633
#This linear equation represents a pth power iff A is a pth power mod B.
634
635
if _is_p_power_mod(A, p, B):
636
raise ValueError, "The degenerate binary recurrence sequence has many pth powers."
637
return []
638
639
#We find ``p`` th powers using an elementary sieve. Term `u_n` is a ``p`` th
640
#power if and only if it is a ``p`` th power modulo every prime `\\ell`. This condition
641
#gives nontrivial information if ``p`` divides the order of the multiplicative group of
642
#`\\Bold(F)_{\\ell}`, i.e. if `\\ell` is ` 1 \mod{p}`, as then only `1/p` terms are ``p`` th
643
#powers modulo `\\ell``.
644
645
#Thus, given such an `\\ell`, we get a set of necessary congruences for the index modulo the
646
#the period of the sequence mod `\\ell`. Then we intersect these congruences for many primes
647
#to get a tight list modulo a growing modulus. In order to keep this step manageable, we
648
#only use primes `\\ell` that are have particularly smooth periods.
649
650
#Some congruences in the list will remain as the modulus grows. If a congruence remains through
651
#7 rounds of increasing the modulus, then we check if this corresponds to a perfect power (if
652
#it does, we add it to our list of indices corresponding to ``p`` th powers). The rest of the congruences
653
#are transient and grow with the modulus. Once the smallest of these is greater than the bound,
654
#the list of known indices corresponding to ``p`` th powers is complete.
655
656
else:
657
658
if Bound < 3 * p :
659
660
powers = []
661
ell = p + 1
662
663
while not is_prime(ell):
664
ell = ell + p
665
666
F = GF(ell)
667
a0 = F(self.u0); a1 = F(self.u1) #a0 and a1 are variables for terms in sequence
668
bf, cf = F(self.b), F(self.c)
669
670
for n in xrange(Bound): # n is the index of the a0
671
672
#Check whether a0 is a perfect power mod ell
673
if _is_p_power_mod(a0, p, ell) :
674
#if a0 is a perfect power mod ell, check if nth term is ppower
675
if _is_p_power(self(n), p):
676
powers.append(n)
677
678
a0, a1 = a1, bf*a1 + cf*a0 #step up the variables
679
680
else :
681
682
powers = [] #documents the indices of the sequence that provably correspond to pth powers
683
cong = [0] #list of necessary congruences on the index for it to correspond to pth powers
684
Possible_count = {} #keeps track of the number of rounds a congruence lasts in cong
685
686
#These parameters are involved in how we choose primes to increase the modulus
687
qqold = 1 #we believe that we know complete information coming from primes good by qqold
688
M1 = 1 #we have congruences modulo M1, this may not be the tightest list
689
M2 = p #we want to move to have congruences mod M2
690
qq = 1 #the largest prime power divisor of M1 is qq
691
692
#This loop ups the modulus.
693
while True:
694
695
#Try to get good data mod M2
696
697
#patience of how long we should search for a "good prime"
698
patience = 0.01 * _estimated_time(lcm(M2,p*next_prime_power(qq)), M1, len(cong), p)
699
tries = 0
700
701
#This loop uses primes to get a small set of congruences mod M2.
702
while True:
703
704
#only proceed if took less than patience time to find the next good prime
705
ell = _next_good_prime(p, self, qq, patience, qqold)
706
if ell:
707
708
#gather congruence data for the sequence mod ell, which will be mod period(ell) = modu
709
cong1, modu = _find_cong1(p, self, ell)
710
711
CongNew = [] #makes a new list from cong that is now mod M = lcm(M1, modu) instead of M1
712
M = lcm(M1, modu)
713
for k in xrange(M/M1):
714
for i in cong:
715
CongNew.append(k*M1+i)
716
cong = set(CongNew)
717
718
M1 = M
719
720
killed_something = False #keeps track of when cong1 can rule out a congruence in cong
721
722
#CRT by hand to gain speed
723
for i in list(cong):
724
if not (i % modu in cong1): #congruence in cong is inconsistent with any in cong1
725
cong.remove(i) #remove that congruence
726
killed_something = True
727
728
if M1 == M2:
729
if not killed_something:
730
tries += 1
731
if tries == 2: #try twice to rule out congruences
732
cong = list(cong)
733
qqold = qq
734
qq = next_prime_power(qq)
735
M2 = lcm(M2,p*qq)
736
break
737
738
else :
739
qq = next_prime_power(qq)
740
M2 = lcm(M2,p*qq)
741
cong = list(cong)
742
break
743
744
#Document how long each element of cong has been there
745
for i in cong:
746
if i in Possible_count:
747
Possible_count[i] = Possible_count[i] + 1
748
else :
749
Possible_count[i] = 1
750
751
#Check how long each element has persisted, if it is for at least 7 cycles,
752
#then we check to see if it is actually a perfect power
753
for i in Possible_count:
754
if Possible_count[i] == 7:
755
n = Integer(i)
756
if n < Bound:
757
if _is_p_power(self(n),p):
758
powers.append(n)
759
760
#check for a contradiction
761
if len(cong) > len(powers):
762
if cong[len(powers)] > Bound:
763
break
764
elif M1 > Bound:
765
break
766
767
return powers
768
769
770
def _prime_powers(N):
771
772
"""
773
Find the prime powers dividing ``N``.
774
775
In other words, if `N = q_1^(e_1)q_2^(e_2)...q_n^(e_n)`, it returns
776
`[q_1^(e_1),q_2^(e_2),...,q_n^(e_n)]`.
777
778
INPUT:
779
780
- ``N`` -- an integer
781
782
OUTPUT:
783
784
- A list of the prime powers dividing N.
785
786
EXAMPLES::
787
788
sage: sage.combinat.binary_recurrence_sequences._prime_powers(124656)
789
[3, 16, 49, 53]
790
791
sage: sage.combinat.binary_recurrence_sequences._prime_powers(65537)
792
[65537]
793
794
"""
795
796
output = [i**j for i,j in N.factor()]
797
output.sort()
798
return output
799
800
#This function finds the largest prime power divisor of an integer N
801
def _largest_ppower_divisor(N):
802
803
"""
804
Find the largest prime power divisor of N.
805
806
INPUT:
807
808
- ``N`` -- an integer (of which the largest prime power divisor will be found)
809
810
OUTPUT:
811
812
- The largest prime power dividing ``N``.
813
814
EXAMPLES::
815
816
sage: sage.combinat.binary_recurrence_sequences._largest_ppower_divisor(124656)
817
53
818
sage: sage.combinat.binary_recurrence_sequences._largest_ppower_divisor(65537)
819
65537
820
821
"""
822
823
output = _prime_powers(N)[-1]
824
825
return output
826
827
828
def _goodness(n, R, p):
829
830
"""
831
Return the goodness of ``n`` for the sequence ``R`` and the prime ``p`` -- that is the largest
832
non-``p`` prime power dividing ``period(n)``.
833
834
INPUT:
835
836
- ``n`` -- an integer
837
838
- ``R`` -- an object in the class ``BinaryRecurrenceSequence``
839
840
- ``p`` -- a rational prime
841
842
OUTPUT:
843
844
- An integer which is the "goodness" of ``n``, i.e. the largest non-``p`` prime power dividing ``period(n)``.
845
846
EXAMPLES::
847
848
sage: R = BinaryRecurrenceSequence(11,2)
849
sage: sage.combinat.binary_recurrence_sequences._goodness(89,R,7)
850
11
851
852
sage: R = BinaryRecurrenceSequence(1,1)
853
sage: sage.combinat.binary_recurrence_sequences._goodness(13,R,7)
854
4
855
sage: R.period(13) #the period of R mod 13 is divisible by 7
856
28
857
858
"""
859
860
#The period of R mod ell
861
K = R.period(n)
862
863
return _largest_ppower_divisor(K/gcd(K,p))
864
865
866
def _next_good_prime(p, R, qq, patience, qqold):
867
868
"""
869
Find the next prime `\\ell` which is good by ``qq`` but not by ``qqold``, 1 mod ``p``, and for which
870
``b^2+4*c`` is a square mod `\\ell`, for the sequence ``R`` if it is possible in runtime patience.
871
872
INPUT:
873
874
- ``p`` -- a prime
875
876
- ``R`` -- an object in the class ``BinaryRecurrenceSequence``
877
878
- ``qq`` -- a perfect power
879
880
- ``patience`` -- a real number
881
882
- ``qqold`` -- a perfect power less than or equal to ``qq``
883
884
OUTPUT:
885
886
- A prime `\\ell` such that `\\ell` is 1 mod ``p``, ``b^2+4*c`` is a square mod `\\ell` and the period of `\\ell` has ``goodness`` by ``qq`` but not ``qqold``, if patience has not be surpased. Otherwise ``False``.
887
888
889
EXAMPLES::
890
891
sage: R = BinaryRecurrenceSequence(1,1)
892
sage: sage.combinat.binary_recurrence_sequences._next_good_prime(7,R,1,100,1) #ran out of patience to search for good primes
893
False
894
sage: sage.combinat.binary_recurrence_sequences._next_good_prime(7,R,2,100,1)
895
29
896
sage: sage.combinat.binary_recurrence_sequences._next_good_prime(7,R,2,100,2) #ran out of patience, as qqold == qq, so no primes work
897
False
898
899
"""
900
901
#We are looking for pth powers in R.
902
#Our primes must be good by qq, but not qqold.
903
#We only allow patience number of iterations to find a good prime.
904
905
#The variable _ell for R keeps track of the last "good" prime returned
906
#that was not found from the dictionary _PGoodness
907
908
#First, we check to see if we have already computed the goodness of a prime that fits
909
#our requirement of being good by qq but not by qqold. This is stored in the _PGoodness
910
#dictionary.
911
912
#Then if we have, we return the smallest such prime and delete it from the list. If not, we
913
#search through patience number of primes R._ell to find one good by qq but not qqold. If it is
914
#not good by either qqold or qq, then we add this prime to R._PGoodness under its goodness.
915
916
#Possible_Primes keeps track of possible primes satisfying our goodness requirements we might return
917
Possible_Primes = []
918
919
920
#check to see if anything in R._PGoodness fits our goodness requirements
921
for j in R._PGoodness:
922
if (qqold < j <= qq) and len(R._PGoodness[j]):
923
Possible_Primes.append(R._PGoodness[j][0])
924
925
#If we found good primes, we take the smallest
926
if Possible_Primes != []:
927
q = min(Possible_Primes)
928
n = _goodness(q, R, p)
929
del R._PGoodness[n][0] #if we are going to use it, then we delete it from R._PGoodness
930
return q
931
932
#If nothing is already stored in R._PGoodness, we start (from where we left off at R._ell) checking
933
#for good primes. We only tolerate patience number of tries before giving up.
934
else:
935
i = 0
936
while i < patience:
937
i += 1
938
R._ell = next_prime(R._ell)
939
940
#we require that R._ell is 1 mod p, so that p divides the order of the multiplicative
941
#group mod R._ell, so that not all elements of GF(R._ell) are pth powers.
942
if R._ell % p == 1:
943
944
#requiring that b^2 + 4c is a square in GF(R._ell) ensures that the period mod R._ell
945
#divides R._ell - 1
946
if legendre_symbol(R.b**2+4*R.c, R._ell) == 1:
947
948
N = _goodness(R._ell, R, p)
949
950
#proceed only if R._ell statisfies the goodness requirements
951
if qqold < N <= qq:
952
return R._ell
953
954
#if we do not use the prime, we store it in R._PGoodness
955
else:
956
if N in R._PGoodness:
957
R._PGoodness[N].append(R._ell)
958
else :
959
R._PGoodness[N] = [R._ell]
960
961
return False
962
963
964
def _is_p_power_mod(a,p,N):
965
966
"""
967
Determine if ``a`` is a ``p`` th power modulo ``N``.
968
969
By the CRT, this is equivalent to the condition that ``a`` be a ``p`` th power mod all
970
distinct prime powers dividing ``N``. For each of these, we use the strong statement of
971
Hensel's lemma to lift ``p`` th powers mod `q` or `q^2` or `q^3` to ``p`` th powers mod `q^e`.
972
973
INPUT:
974
975
- ``a`` -- an integer
976
977
- ``p`` -- a rational prime number
978
979
- ``N`` -- a positive integer
980
981
OUTPUT:
982
983
- True if ``a`` is a ``p`` th power modulo ``N``; False otherwise.
984
985
EXAMPLES::
986
987
sage: sage.combinat.binary_recurrence_sequences._is_p_power_mod(2**3,7,29)
988
False
989
sage: sage.combinat.binary_recurrence_sequences._is_p_power_mod(2**3,3,29)
990
True
991
992
"""
993
994
#By the chinese remainder theorem, we can answer this question by examining whether
995
#a is a pth power mod q^e, for all distinct prime powers q^e dividing N.
996
997
for q, e in N.factor():
998
999
#If a = q^v*x, with
1000
1001
v = a.valuation(q)
1002
1003
#then if v>=e, a is congruent to 0 mod q^e and is thus a pth power trivially.
1004
1005
if v >= e:
1006
continue
1007
1008
#otherwise, it can only be a pth power if v is a multiple of p.
1009
1010
if v % p != 0:
1011
return False
1012
1013
#in this cse it is a pth power if x is a pth power mod q^(e-v), so let x = aa,
1014
#and (e-v) = ee:
1015
1016
aa = a/q**v
1017
ee = e - v
1018
1019
#The above steps are equivalent to the statement that we may assume a and qq are
1020
#relatively prime, if we replace a with aa and e with ee. Now we must determine when
1021
#aa is a pth power mod q^ee for (aa,q)=1.
1022
1023
#If q != p, then by Hensel's lemma, we may lift a pth power mod q, to a pth power
1024
#mod q^2, etc.
1025
1026
if q != p:
1027
1028
#aa is necessarily a pth power mod q if p does not divide the order of the multiplicative
1029
#group mod q, ie if q is not 1 mod p.
1030
1031
if q % p == 1:
1032
1033
#otherwise aa if a pth power mod q iff aa^(q-1)/p == 1
1034
1035
if GF(q)(aa)**((q-1)/p) != 1:
1036
return False
1037
1038
#If q = p and ee = 1, then everything is a pth power p by Fermat's little theorem.
1039
1040
elif ee > 1:
1041
1042
#We use the strong statement of Hensel's lemma, which implies that if p is odd
1043
#and aa is a pth power mod p^2, then aa is a pth power mod any higher power of p
1044
1045
if p % 2 == 1:
1046
1047
#ZZ/(p^2)ZZ^\times is abstractly isomorphic to ZZ/(p)ZZ cross ZZ/(p-1)ZZ. then
1048
#aa is a pth power mod p^2 if (aa)^(p*(p-1)/p) == 1, ie if aa^(p-1) == 1.
1049
1050
if Integers(p**2)(aa)**(p-1) != 1:
1051
return False
1052
1053
#Otherwise, p=2. By the strong statement of Hensel's lemma, if aa is a pth power
1054
#mod p^3, then it is a pth power mod higher powers of p. So we need only check if it
1055
#is a pth power mod p^2 and p^3.
1056
1057
elif ee == 2:
1058
1059
#all odd squares a 1 mod 4
1060
1061
if aa % 4 != 1:
1062
return False
1063
1064
#all odd squares are 1 mod 8
1065
1066
elif aa % 8 != 1:
1067
return False
1068
1069
return True
1070
1071
1072
def _estimated_time(M2, M1, length, p):
1073
1074
"""
1075
Find the estimated time to extend congruences mod M1 to consistent congruences mod M2.
1076
1077
INPUT:
1078
1079
- ``M2`` -- an integer (the new modulus)
1080
1081
- ``M1`` -- an integer (the old modulus)
1082
1083
- ``length`` -- a list (the current length of the list of congruences mod ``M1``)
1084
1085
- ``p`` -- a prime
1086
1087
OUTPUT:
1088
1089
- The estimated run time of the "CRT" step to combine consistent congruences.
1090
1091
EXAMPLES::
1092
1093
sage: sage.combinat.binary_recurrence_sequences._estimated_time(2**4*3**2*5*7*11*13*17, 2**4*3**2*5*7*11*13, 20, 7)
1094
106.211159309421
1095
1096
"""
1097
1098
#The heuristic run time of the CRT step to go from modulus M1 to M2
1099
1100
#length is the current length of cong
1101
1102
Q = p * log(M2) #Size of our primes.
1103
NPrimes = log(M2/M1) / log(Q) #The number of primes
1104
1105
return (length * (Q/p)**NPrimes).n()
1106
1107
#Find the list of necessary congruences for the index n of binary recurrence
1108
#sequence R using the fact that the reduction mod ell must be a pth power
1109
def _find_cong1(p, R, ell):
1110
1111
"""
1112
Find the list of permissible indices `n` for which `u_n = y^p` mod ``ell``.
1113
1114
INPUT:
1115
1116
- ``p`` -- a prime number
1117
1118
- ``R`` -- an object in class BinaryRecurrenceSequence
1119
1120
- ``ell`` -- a prime number
1121
1122
OUTPUT:
1123
1124
- A list of permissible values of `n` modulo ``period(ell)`` and the integer ``period(ell)``.
1125
1126
EXAMPLES::
1127
1128
sage: R = BinaryRecurrenceSequence(1,1)
1129
sage: sage.combinat.binary_recurrence_sequences._find_cong1(7, R, 29)
1130
([0, 1, 2, 12, 13], 14)
1131
1132
"""
1133
1134
F = GF(ell)
1135
u0 = F(R.u0); u1 = F(R.u1)
1136
bf, cf = F(R.b), F(R.c)
1137
a0 = u0; a1 = u1 #a0 and a1 are variables for terms in sequence
1138
1139
#The set of pth powers mod ell
1140
PPowers = set([])
1141
for i in F:
1142
PPowers.add(i**p)
1143
1144
#The period of R mod ell
1145
modu = R.period(ell)
1146
1147
#cong1 keeps track of congruences mod modu for the sequence mod ell
1148
cong1 = []
1149
1150
for n in xrange(modu): # n is the index of the a0
1151
1152
#Check whether a0 is a perfect power mod ell
1153
if a0 in PPowers:
1154
#if a0 is a perfect power mod ell, add the index
1155
#to the list of necessary congruences
1156
cong1.append(n)
1157
1158
a0, a1 = a1, bf*a1 + cf*a0 #step up the variables
1159
1160
cong1.sort()
1161
1162
return cong1, modu
1163
1164
1165
#check for when a is a perfect pth power
1166
def _is_p_power(a, p):
1167
1168
"""
1169
Determine whether ``a`` is a ``p`` th power.
1170
1171
INPUT:
1172
1173
- ``a`` -- an integer
1174
1175
- ``p`` -- a prime number
1176
1177
OUTPUT:
1178
1179
- True if ``a`` is a ``p`` th power; else False.
1180
1181
1182
EXAMPLES::
1183
1184
sage: sage.combinat.binary_recurrence_sequences._is_p_power(2**7,7)
1185
True
1186
sage: sage.combinat.binary_recurrence_sequences._is_p_power(2**7*3**2,7)
1187
False
1188
1189
"""
1190
1191
return (int(a**(1/p))**p == a)
1192
1193
1194
1195
1196