Binary Recurrence Sequences¶
This class implements several methods relating to general linear binary recurrence sequences, including a sieve to find perfect powers in integral linear binary recurrence sequences.
EXAMPLES:
sage: R = BinaryRecurrenceSequence(1,1) #the Fibonacci sequence
sage: R(137) #the 137th term of the Fibonacci sequence
19134702400093278081449423917
sage: R(137) == fibonacci(137)
True
sage: [R(i) % 4 for i in range(12)]
[0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1]
sage: R.period(4) #the period of the fibonacci sequence modulo 4
6
sage: R.pthpowers(2, 10**10) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06]
[0, 1, 2, 12]
sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence
sage: S.period(73)
148
sage: S(5) % 73 == S(5 +148) %73
True
sage: S.pthpowers(3, 10**10) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^10
[0, 1, 2]
sage: T = BinaryRecurrenceSequence(2,0,1,2)
sage: [T(i) for i in range(10)]
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
sage: T.is_degenerate()
True
sage: T.is_geometric()
True
sage: T.pthpowers(7, 10**30) # needs sage.symbolic
Traceback (most recent call last):
...
ValueError: the degenerate binary recurrence sequence is geometric or quasigeometric
and has many pth powers
>>> from sage.all import *
>>> R = BinaryRecurrenceSequence(Integer(1),Integer(1)) #the Fibonacci sequence
>>> R(Integer(137)) #the 137th term of the Fibonacci sequence
19134702400093278081449423917
>>> R(Integer(137)) == fibonacci(Integer(137))
True
>>> [R(i) % Integer(4) for i in range(Integer(12))]
[0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1]
>>> R.period(Integer(4)) #the period of the fibonacci sequence modulo 4
6
>>> R.pthpowers(Integer(2), Integer(10)**Integer(10)) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06]
[0, 1, 2, 12]
>>> S = BinaryRecurrenceSequence(Integer(8),Integer(1)) #a Lucas sequence
>>> S.period(Integer(73))
148
>>> S(Integer(5)) % Integer(73) == S(Integer(5) +Integer(148)) %Integer(73)
True
>>> S.pthpowers(Integer(3), Integer(10)**Integer(10)) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^10
[0, 1, 2]
>>> T = BinaryRecurrenceSequence(Integer(2),Integer(0),Integer(1),Integer(2))
>>> [T(i) for i in range(Integer(10))]
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
>>> T.is_degenerate()
True
>>> T.is_geometric()
True
>>> T.pthpowers(Integer(7), Integer(10)**Integer(30)) # needs sage.symbolic
Traceback (most recent call last):
...
ValueError: the degenerate binary recurrence sequence is geometric or quasigeometric
and has many pth powers
AUTHORS:
Isabel Vogt (2013): initial version
See [SV2013], [BMS2006], and [SS1983].
- class sage.combinat.binary_recurrence_sequences.BinaryRecurrenceSequence(b, c, u0=0, u1=1)[source]¶
Bases:
SageObject
Create a linear binary recurrence sequence defined by initial conditions \(u_0\) and \(u_1\) and recurrence relation \(u_{n+2} = b*u_{n+1}+c*u_n\).
INPUT:
b
– integer; (partially determining the recurrence relation)c
– integer; (partially determining the recurrence relation)u0
– integer; (the \(0\)-th term of the binary recurrence sequence)u1
– integer; (the \(1\)-st term of the binary recurrence sequence)
OUTPUT: an integral linear binary recurrence sequence defined by \(u_0\), \(u_1\), and \(u_{n+2} = b u_{n+1}+c u_n\)
See also
EXAMPLES:
sage: R = BinaryRecurrenceSequence(3,3,2,1) sage: R Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2}; With initial conditions: u_0 = 2, and u_1 = 1
>>> from sage.all import * >>> R = BinaryRecurrenceSequence(Integer(3),Integer(3),Integer(2),Integer(1)) >>> R Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2}; With initial conditions: u_0 = 2, and u_1 = 1
- is_arithmetic()[source]¶
Decide whether the sequence is degenerate and an arithmetic sequence.
The sequence is arithmetic if and only if \(u_1 - u_0 = u_2 - u_1 = u_3 - u_2\).
This corresponds to the matrix \(F = [[0,1],[c,b]]\) being nondiagonalizable and \(\alpha/\beta = 1\).
EXAMPLES:
sage: S = BinaryRecurrenceSequence(2,-1) sage: [S(i) for i in range(10)] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] sage: S.is_arithmetic() True
>>> from sage.all import * >>> S = BinaryRecurrenceSequence(Integer(2),-Integer(1)) >>> [S(i) for i in range(Integer(10))] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> S.is_arithmetic() True
- is_degenerate()[source]¶
Decide whether the binary recurrence sequence is degenerate.
Let \(\alpha\) and \(\beta\) denote the roots of the characteristic polynomial \(p(x) = x^2-bx -c\). Let \(a = u_1-u_0\beta/(\beta - \alpha)\) and \(b = u_1-u_0\alpha/(\beta - \alpha)\). The sequence is, thus, given by \(u_n = a \alpha^n - b\beta^n\). Then we say that the sequence is nondegenerate if and only if \(a*b*\alpha*\beta \neq 0\) and \(\alpha/\beta\) is not a root of unity.
More concretely, there are 4 classes of degeneracy, that can all be formulated in terms of the matrix \(F = [[0,1], [c, b]]\).
\(F\) is singular – this corresponds to
c
= 0, and thus \(\alpha*\beta = 0\). This sequence is geometric after termu0
and so we call itquasigeometric
\(v = [[u_0], [u_1]]\) is an eigenvector of \(F\) – this corresponds to a
geometric
sequence with \(a*b = 0\)\(F\) is nondiagonalizable – this corresponds to \(\alpha = \beta\). This sequence will be the point-wise product of an arithmetic and geometric sequence.
\(F^k\) is scalar, 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
.
EXAMPLES:
sage: S = BinaryRecurrenceSequence(0,1) sage: S.is_degenerate() True sage: S.is_geometric() False sage: S.is_quasigeometric() True sage: R = BinaryRecurrenceSequence(3,-2) sage: R.is_degenerate() False sage: T = BinaryRecurrenceSequence(2,-1) sage: T.is_degenerate() True sage: T.is_arithmetic() True
>>> from sage.all import * >>> S = BinaryRecurrenceSequence(Integer(0),Integer(1)) >>> S.is_degenerate() True >>> S.is_geometric() False >>> S.is_quasigeometric() True >>> R = BinaryRecurrenceSequence(Integer(3),-Integer(2)) >>> R.is_degenerate() False >>> T = BinaryRecurrenceSequence(Integer(2),-Integer(1)) >>> T.is_degenerate() True >>> T.is_arithmetic() True
- is_geometric()[source]¶
Decide whether the binary recurrence sequence is geometric - ie a geometric sequence.
This is a subcase of a degenerate binary recurrence sequence, for which \(ab=0\), i.e. \(u_{n}/u_{n-1}=r\) for some value of \(r\).
See
is_degenerate()
for a description of degeneracy and definitions of \(a\) and \(b\).EXAMPLES:
sage: S = BinaryRecurrenceSequence(2,0,1,2) sage: [S(i) for i in range(10)] [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] sage: S.is_geometric() True
>>> from sage.all import * >>> S = BinaryRecurrenceSequence(Integer(2),Integer(0),Integer(1),Integer(2)) >>> [S(i) for i in range(Integer(10))] [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] >>> S.is_geometric() True
- is_quasigeometric()[source]¶
Decide whether the binary recurrence sequence is degenerate and similar to a geometric sequence, i.e. the union of multiple geometric sequences, or geometric after term
u0
.If \(\alpha/\beta\) is a \(k\) th root of unity, where \(k>1\), then necessarily \(k = 2, 3, 4, 6\). Then \(F = [[0,1],[c,b]\) is diagonalizable, and \(F^k = [[\alpha^k, 0], [0,\beta^k]]\) is a diagonal matrix. Thus for all values of \(j\) mod \(k\), the \(j\) mod \(k\) terms of \(u_n\) form a geometric series.
If \(\alpha\) or \(\beta\) is zero, this implies that \(c=0\). This is the case when \(F\) is singular. In this case, \(u_1, u_2, u_3, ...\) is geometric.
EXAMPLES:
sage: S = BinaryRecurrenceSequence(0,1) sage: [S(i) for i in range(10)] [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] sage: S.is_quasigeometric() True sage: R = BinaryRecurrenceSequence(3,0) sage: [R(i) for i in range(10)] [0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561] sage: R.is_quasigeometric() True
>>> from sage.all import * >>> S = BinaryRecurrenceSequence(Integer(0),Integer(1)) >>> [S(i) for i in range(Integer(10))] [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] >>> S.is_quasigeometric() True >>> R = BinaryRecurrenceSequence(Integer(3),Integer(0)) >>> [R(i) for i in range(Integer(10))] [0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561] >>> R.is_quasigeometric() True
- period(m)[source]¶
Return the period of the binary recurrence sequence modulo an integer
m
.If \(n_1\) is congruent to \(n_2\) modulo
period(m)
, then \(u_{n_1}\) is is congruent to \(u_{n_2}\) modulom
.INPUT:
m
– integer; modulo which the period of the recurrence relation is calculated
OUTPUT: integer (the period of the sequence modulo m)
EXAMPLES:
If \(p = \pm 1 \mod 5\), then the period of the Fibonacci sequence mod \(p\) is \(p-1\) (c.f. Lemma 3.3 of [BMS2006]).
sage: R = BinaryRecurrenceSequence(1,1) sage: R.period(31) 30 sage: [R(i) % 4 for i in range(12)] [0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1] sage: R.period(4) 6
>>> from sage.all import * >>> R = BinaryRecurrenceSequence(Integer(1),Integer(1)) >>> R.period(Integer(31)) 30 >>> [R(i) % Integer(4) for i in range(Integer(12))] [0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1] >>> R.period(Integer(4)) 6
This function works for degenerate sequences as well.
sage: S = BinaryRecurrenceSequence(2,0,1,2) sage: S.is_degenerate() True sage: S.is_geometric() True sage: [S(i) % 17 for i in range(16)] [1, 2, 4, 8, 16, 15, 13, 9, 1, 2, 4, 8, 16, 15, 13, 9] sage: S.period(17) 8
>>> from sage.all import * >>> S = BinaryRecurrenceSequence(Integer(2),Integer(0),Integer(1),Integer(2)) >>> S.is_degenerate() True >>> S.is_geometric() True >>> [S(i) % Integer(17) for i in range(Integer(16))] [1, 2, 4, 8, 16, 15, 13, 9, 1, 2, 4, 8, 16, 15, 13, 9] >>> S.period(Integer(17)) 8
Note
The answer is cached.
- pthpowers(p, Bound)[source]¶
Find the indices of proveably all \(p\)-th powers in the recurrence sequence bounded by Bound.
Let \(u_n\) be a binary recurrence sequence. A
p
th power in \(u_n\) is a solution to \(u_n = y^p\) for some integer \(y\). There are only finitely manyp
th powers in any recurrence sequence [SS1983].INPUT:
p
– a rational prime integer (the fixed p in \(u_n = y^p\))Bound
– a natural number (the maximum index \(n\) in \(u_n = y^p\) that is checked)
OUTPUT:
A list of the indices of all
p
th powers less bounded byBound
. If the sequence is degenerate and there are manyp
th powers, raisesValueError
.EXAMPLES:
sage: R = BinaryRecurrenceSequence(1,1) #the Fibonacci sequence sage: R.pthpowers(2, 10**10) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS2006]_ [0, 1, 2, 12] sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence sage: S.pthpowers(3,10**10) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^10 [0, 1, 2] sage: Q = BinaryRecurrenceSequence(3,3,2,1) sage: Q.pthpowers(11,10**10) # long time (7.5 seconds) [1]
>>> from sage.all import * >>> R = BinaryRecurrenceSequence(Integer(1),Integer(1)) #the Fibonacci sequence >>> R.pthpowers(Integer(2), Integer(10)**Integer(10)) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS2006]_ [0, 1, 2, 12] >>> S = BinaryRecurrenceSequence(Integer(8),Integer(1)) #a Lucas sequence >>> S.pthpowers(Integer(3),Integer(10)**Integer(10)) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^10 [0, 1, 2] >>> Q = BinaryRecurrenceSequence(Integer(3),Integer(3),Integer(2),Integer(1)) >>> Q.pthpowers(Integer(11),Integer(10)**Integer(10)) # long time (7.5 seconds) [1]
If the sequence is degenerate, and there are no
p
th powers, returns \([]\). Otherwise, if there are manyp
th powers, raisesValueError
.sage: T = BinaryRecurrenceSequence(2,0,1,2) sage: T.is_degenerate() True sage: T.is_geometric() True sage: T.pthpowers(7, 10**30) # needs sage.symbolic Traceback (most recent call last): ... ValueError: the degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers sage: L = BinaryRecurrenceSequence(4,0,2,2) sage: [L(i).factor() for i in range(10)] [2, 2, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15, 2^17] sage: L.is_quasigeometric() True sage: L.pthpowers(2, 10**30) # needs sage.symbolic []
>>> from sage.all import * >>> T = BinaryRecurrenceSequence(Integer(2),Integer(0),Integer(1),Integer(2)) >>> T.is_degenerate() True >>> T.is_geometric() True >>> T.pthpowers(Integer(7), Integer(10)**Integer(30)) # needs sage.symbolic Traceback (most recent call last): ... ValueError: the degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers >>> L = BinaryRecurrenceSequence(Integer(4),Integer(0),Integer(2),Integer(2)) >>> [L(i).factor() for i in range(Integer(10))] [2, 2, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15, 2^17] >>> L.is_quasigeometric() True >>> L.pthpowers(Integer(2), Integer(10)**Integer(30)) # needs sage.symbolic []
Note
This function is primarily optimized in the range where
Bound
is much larger thanp
.