Path: blob/master/src/sage/combinat/binary_recurrence_sequences.py
8815 views
"""1Binary Recurrence Sequences.234This class implements several methods relating to5general linear binary recurrence sequences, including a sieve6to find perfect powers in integral linear binary recurrence sequences.78EXAMPLES::910sage: R = BinaryRecurrenceSequence(1,1) #the Fibonacci sequence11sage: R(137) #the 137th term of the Fibonacci sequence121913470240009327808144942391713sage: R(137) == fibonacci(137)14True15sage: [R(i) % 4 for i in xrange(12)]16[0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1]17sage: R.period(4) #the period of the fibonacci sequence modulo 418619sage: R.pthpowers(2, 10**30) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06]20[0, 1, 2, 12]2122sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence23sage: S.period(73)2414825sage: S(5) % 73 == S(5 +148) %7326True27sage: S.pthpowers(3,10**30) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^3028[0, 1, 2]2930sage: T = BinaryRecurrenceSequence(2,0,1,2)31sage: [T(i) for i in xrange(10)]32[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]33sage: T.is_degenerate()34True35sage: T.is_geometric()36True37sage: T.pthpowers(7,10**30)38Traceback (most recent call last):39...40ValueError: The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers.414243AUTHORS:4445-Isabel Vogt (2013): initial version4647REFERENCES:4849.. [SV13] Silliman and Vogt. "Powers in Lucas Sequences via Galois Representations." Proceedings of the American Mathematical Society, 2013. :arxiv:`1307.5078v2`5051.. [BMS06] Bugeaud, Mignotte, and Siksek. "Classical and modular approaches to exponential Diophantine equations: I. Fibonacci and Lucas perfect powers." Annals of Math, 2006.5253.. [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.54"""5556#****************************************************************************#57# Copyright (C) 2013 Isabel Vogt <[email protected]> #58# #59# Distributed under the terms of the GNU General Public License (GPL) #60# as published by the Free Software Foundation; either version 2 of #61# the License, or (at your option) any later version. #62# http://www.gnu.org/licenses/ #63#****************************************************************************#6465from sage.structure.sage_object import SageObject66from sage.matrix.constructor import matrix, vector67from sage.rings.number_field.number_field import QuadraticField68from sage.rings.finite_rings.integer_mod_ring import Integers69from sage.rings.finite_rings.constructor import GF70from sage.rings.integer import Integer71from sage.rings.arith import gcd, lcm, next_prime, is_prime, next_prime_power, legendre_symbol72from sage.functions.log import log73from sage.functions.other import sqrt7475class BinaryRecurrenceSequence(SageObject):7677"""78Create a linear binary recurrence sequence defined by initial conditions79`u_0` and `u_1` and recurrence relation `u_{n+2} = b*u_{n+1}+c*u_n`.8081INPUT:8283- ``b`` -- an integer (partially determining the recurrence relation)8485- ``c`` -- an integer (partially determining the recurrence relation)8687- ``u0`` -- an integer (the 0th term of the binary recurrence sequence)8889- ``u1`` -- an integer (the 1st term of the binary recurrence sequence)909192OUTPUT:9394- An integral linear binary recurrence sequence defined by ``u0``, ``u1``, and `u_{n+2} = b*u_{n+1}+c*u_n`9596.. SEEALSO::9798:func:`fibonacci`, :func:`lucas_number1`, :func:`lucas_number2`99100EXAMPLES::101102sage: R = BinaryRecurrenceSequence(3,3,2,1)103sage: R104Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2};105With initial conditions: u_0 = 2, and u_1 = 1106107"""108109def __init__(self, b, c, u0=0, u1=1):110111"""112See ``BinaryRecurrenceSequence`` for full documentation.113114EXAMPLES::115116sage: R = BinaryRecurrenceSequence(3,3,2,1)117sage: R118Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2};119With initial conditions: u_0 = 2, and u_1 = 1120121sage: R = BinaryRecurrenceSequence(1,1)122sage: loads(R.dumps()) == R123True124125"""126self.b = b127self.c = c128self.u0 = u0129self.u1 = u1130self._period_dict = {} #dictionary to cache the period of a sequence for future lookup131self._PGoodness = {} #dictionary to cache primes that are "good" by some prime power132self._ell = 1 #variable that keeps track of the last prime power to be used as a goodness133134135def __repr__(self):136"""137Give string representation of the class.138139EXAMPLES::140141sage: R = BinaryRecurrenceSequence(3,3,2,1)142sage: R143Binary recurrence sequence defined by: u_n = 3 * u_{n-1} + 3 * u_{n-2};144With initial conditions: u_0 = 2, and u_1 = 1145146"""147return '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)148149def __eq__(self, other):150"""151Compare two binary recurrence sequences.152153EXAMPLES::154155sage: R = BinaryRecurrenceSequence(3,3,2,1)156sage: S = BinaryRecurrenceSequence(3,3,2,1)157sage: R == S158True159160sage: T = BinaryRecurrenceSequence(3,3,2,2)161sage: R == T162False163164"""165166return (self.u0 == other.u0) and (self.u1 == other.u1) and (self.b == other.b) and (self.c == other.c)167168def __call__(self, n, modulus=0):169170"""171Give the nth term of a binary recurrence sequence, possibly mod some modulus.172173INPUT:174175- ``n`` -- an integer (the index of the term in the binary recurrence sequence)176177- ``modulus`` -- a natural number (optional -- default value is 0)178179OUTPUT:180181- An integer (the nth term of the binary recurrence sequence modulo ``modulus``)182183EXAMPLES::184185sage: R = BinaryRecurrenceSequence(3,3,2,1)186sage: R(2)1879188sage: R(101)18916158686318788579168659644539538474790082623100896663971001190sage: R(101,12)1919192sage: R(101)%121939194195"""196R = Integers(modulus)197F = 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).198v = matrix(R, [[self.u0],[self.u1]])199return list(F**n*v)[0][0]200201def is_degenerate(self):202"""203Decide whether the binary recurrence sequence is degenerate.204205Let `\\alpha` and `\\beta` denote the roots of the characteristic polynomial206`p(x) = x^2-bx -c`. Let `a = u_1-u_0\\beta/(\\beta - \\alpha)` and207`b = u_1-u_0\\alpha/(\\beta - \\alpha)`. The sequence is, thus, given by208`u_n = a \\alpha^n - b\\beta^n`. Then we say that the sequence is nondegenerate209if and only if `a*b*\\alpha*\\beta \\neq 0` and `\\alpha/\\beta` is not a210root of unity.211212More concretely, there are 4 classes of degeneracy, that can all be formulated213in terms of the matrix `F = [[0,1], [c, b]]`.214215- `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``.216217- `v = [[u_0], [u_1]]` is an eigenvector of `F` -- this corresponds to a ``geometric`` sequence with `a*b = 0`.218219- `F` is nondiagonalizable -- this corresponds to `\\alpha = \\beta`. This sequence will be the point-wise product of an arithmetic and geometric sequence.220221- `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``.222223EXAMPLES::224225sage: S = BinaryRecurrenceSequence(0,1)226sage: S.is_degenerate()227True228sage: S.is_geometric()229False230sage: S.is_quasigeometric()231True232233sage: R = BinaryRecurrenceSequence(3,-2)234sage: R.is_degenerate()235False236237sage: T = BinaryRecurrenceSequence(2,-1)238sage: T.is_degenerate()239True240sage: T.is_arithmetic()241True242243"""244245if (self.b**2+4*self.c) != 0:246247if (self.b**2+4*self.c).is_square():248A = sqrt((self.b**2+4*self.c))249250else:251K = QuadraticField((self.b**2+4*self.c), 'x')252A = K.gen()253254aa = (self.u1 - self.u0*(self.b + A)/2)/(A) #called `a` in Docstring255bb = (self.u1 - self.u0*(self.b - A)/2)/(A) #called `b` in Docstring256257#(b+A)/2 is called alpha in Docstring, (b-A)/2 is called beta in Docstring258259if (self.b - A) != 0:260if ((self.b+A)/(self.b-A))**(6) == 1:261return True262else:263return True264265if aa*bb*(self.b + A)*(self.b - A) == 0:266return True267return False268return True269270271def is_geometric(self):272"""273Decide whether the binary recurrence sequence is geometric - ie a geometric sequence.274275This is a subcase of a degenerate binary recurrence sequence, for which `ab=0`, i.e.276`u_{n}/u_{n-1}=r` for some value of `r`. See ``is_degenerate`` for a description of277degeneracy and definitions of `a` and `b`.278279EXAMPLES::280281sage: S = BinaryRecurrenceSequence(2,0,1,2)282sage: [S(i) for i in xrange(10)]283[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]284sage: S.is_geometric()285True286287"""288289#If [u_0, u_1]^T is an eigenvector for the incrementation matrix F = [[0,1],[c,b]], then the sequence290#is geometric, ie we can write u_n = a*r^n for some a and r.291292#We decide if u0, u1, u2 = b*u1+c*u0 are in geometric progression by whether u1^2 = (b*u1+c*u0)*u0293294return bool((self.u1)**2 == (self.b*self.u1 + self.c*self.u0)*self.u0)295296def is_quasigeometric(self):297"""298Decide whether the binary recurrence sequence is degenerate and similar to a geometric sequence,299i.e. the union of multiple geometric sequences, or geometric after term ``u0``.300301If `\\alpha/\\beta` is a `k` th root of unity, where `k>1`, then necessarily `k = 2, 3, 4, 6`.302Then `F = [[0,1],[c,b]` is diagonalizable, and `F^k = [[\\alpha^k, 0], [0,\\beta^k]]` is scaler303matrix. Thus for all values of `j` mod `k`, the `j` mod `k` terms of `u_n` form a geometric304series.305306If `\\alpha` or `\\beta` is zero, this implies that `c=0`. This is the case when `F` is307singular. In this case, `u_1, u_2, u_3, ...` is geometric.308309EXAMPLES::310311sage: S = BinaryRecurrenceSequence(0,1)312sage: [S(i) for i in xrange(10)]313[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]314sage: S.is_quasigeometric()315True316317sage: R = BinaryRecurrenceSequence(3,0)318sage: [R(i) for i in xrange(10)]319[0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561]320sage: R.is_quasigeometric()321True322"""323324#First test if F is singular... i.e. beta = 0325if self.c == 0:326return True327328#Otherwise test if alpha/beta is a root of unity that is not 1329else:330if (self.b**2+4*self.c) != 0: #thus alpha/beta != 1331332if (self.b**2+4*self.c).is_square():333A = sqrt((self.b**2+4*self.c))334335else:336K = QuadraticField((self.b**2+4*self.c), 'x')337A = K.gen()338339if ((self.b+A)/(self.b-A))**(6) == 1:340return True341342return False343344def is_arithmetic(self):345"""346Decide whether the sequence is degenerate and an arithmetic sequence.347348The sequence is arithmetic if and only if `u_1 - u_0 = u_2 - u_1 = u_3 - u_2`.349350This corresponds to the matrix `F = [[0,1],[c,b]]` being nondiagonalizable351and `\\alpha/\\beta = 1`.352353EXAMPLES::354355sage: S = BinaryRecurrenceSequence(2,-1)356sage: [S(i) for i in xrange(10)]357[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]358sage: S.is_arithmetic()359True360"""361362#Test if u_1-u_0 = u_2-u_1 = u_3-u_2363364return bool(self(1) - self(0) == self(2) - self(1) == self(3) - self(2))365366367def period(self, m):368"""369Return the period of the binary recurrence sequence modulo370an integer ``m``.371372If `n_1` is congruent to `n_2` modulu ``period(m)``, then `u_{n_1}` is373is congruent to `u_{n_2}` modulo ``m``.374375INPUT:376377- ``m`` -- an integer (modulo which the period of the recurrence relation is calculated).378379OUTPUT:380381- The integer (the period of the sequence modulo m)382383EXAMPLES:384385If `p = \\pm 1 \\mod 5`, then the period of the Fibonacci sequence386mod `p` is `p-1` (c.f. Lemma 3.3 of [BMS06]).387388::389390sage: R = BinaryRecurrenceSequence(1,1)391sage: R.period(31)39230393394sage: [R(i) % 4 for i in xrange(12)]395[0, 1, 1, 2, 3, 1, 0, 1, 1, 2, 3, 1]396sage: R.period(4)3976398399This function works for degenerate sequences as well.400401::402403sage: S = BinaryRecurrenceSequence(2,0,1,2)404sage: S.is_degenerate()405True406sage: S.is_geometric()407True408sage: [S(i) % 17 for i in xrange(16)]409[1, 2, 4, 8, 16, 15, 13, 9, 1, 2, 4, 8, 16, 15, 13, 9]410sage: S.period(17)4118412413Note: the answer is cached.414"""415416#If we have already computed the period mod m, then we return the stored value.417418if m in self._period_dict:419return self._period_dict[m]420421else:422R = Integers(m)423A = matrix(R, [[0,1],[self.c,self.b]])424w = matrix(R, [[self.u0],[self.u1]])425Fac = list(m.factor())426Periods = {}427428#To compute the period mod m, we compute the least integer n such that A^n*w == w. This necessarily429#divides the order of A as a matrix in GL_2(Z/mZ).430431#We compute the period modulo all distinct prime powers dividing m, and combine via the lcm.432#To compute the period mod p^e, we first compute the order mod p. Then the period mod p^e433#must divide p^{4e-4}*period(p), as the subgroup of matrices mod p^e, which reduce to434#the identity mod p is of order (p^{e-1})^4. So we compute the period mod p^e by successively435#multiplying the period mod p by powers of p.436437for i in Fac:438p = i[0]; e = i[1]439#first compute the period mod p440if p in self._period_dict:441perp = self._period_dict[p]442else:443F = A.change_ring(GF(p))444v = w.change_ring(GF(p))445FF = F**(p-1)446p1fac = list((p-1).factor())447448#The order of any matrix in GL_2(F_p) either divides p(p-1) or (p-1)(p+1).449#The order divides p-1 if it is diagaonalizable. In any case, det(F^(p-1))=1,450#so if tr(F^(p-1)) = 2, then it must be triangular of the form [[1,a],[0,1]].451#The order of the subgroup of matrices of this form is p, so the order must divide452#p(p-1) -- in fact it must be a multiple of p. If this is not the case, then the453#order divides (p-1)(p+1). As the period divides the order of the matrix in GL_2(F_p),454#these conditions hold for the period as well.455456#check if the order divides (p-1)457if FF*v == v:458M = p-1459Mfac = p1fac460461#check if the trace is 2, then the order is a multiple of p dividing p*(p-1)462elif (FF).trace() == 2:463M = p-1464Mfac = p1fac465F = F**p #replace F by F^p as now we only need to determine the factor dividing (p-1)466467#otherwise it will divide (p+1)(p-1)468else :469M = (p+1)*(p-1)470p2fac = list((p+1).factor()) #factor the (p+1) and (p-1) terms seperately and then combine for speed471Mfac_dic = {}472for i in list(p1fac + p2fac):473if i[0] not in Mfac_dic:474Mfac_dic[i[0]] = i[1]475else :476Mfac_dic[i[0]] = Mfac_dic[i[0]] + i[1]477Mfac = [(i,Mfac_dic[i]) for i in Mfac_dic]478479#Now use a fast order algorithm to compute the period. We know that the period divides480#M = i_1*i_2*...*i_l where the i_j denote not necessarily distinct prime factors. As481#F^M*v == v, for each i_j, if F^(M/i_j)*v == v, then the period divides (M/i_j). After482#all factors have been iterated over, the result is the period mod p.483484Mfac = list(Mfac)485C=[]486487#expand the list of prime factors so every factor is with multiplicity 1488489for i in xrange(len(Mfac)):490for j in xrange(Mfac[i][1]):491C.append(Mfac[i][0])492493Mfac = C494n = M495for i in Mfac:496b = Integer(n/i)497if F**b*v == v:498n = b499perp = n500501#Now compute the period mod p^e by steping up by multiples of p502F = A.change_ring(Integers(p**e))503v = w.change_ring(Integers(p**e))504FF = F**perp505if FF*v == v:506perpe = perp507else :508tries = 0509while True:510tries += 1511FF = FF**p512if FF*v == v:513perpe = perp*p**tries514break515Periods[p] = perpe516517#take the lcm of the periods mod all distinct primes dividing m518period = 1519for p in Periods:520period = lcm(Periods[p],period)521522self._period_dict[m] = period #cache the period mod m523return period524525526def pthpowers(self, p, Bound):527"""528Find the indices of proveably all pth powers in the recurrence sequence bounded by Bound.529530Let `u_n` be a binary recurrence sequence. A ``p`` th power in `u_n` is a solution531to `u_n = y^p` for some integer `y`. There are only finitely many ``p`` th powers in532any recurrence sequence [SS].533534INPUT:535536- ``p`` - a rational prime integer (the fixed p in `u_n = y^p`)537538- ``Bound`` - a natural number (the maximum index `n` in `u_n = y^p` that is checked).539540OUTPUT:541542- 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``.543544EXAMPLES::545546sage: R = BinaryRecurrenceSequence(1,1) #the Fibonacci sequence547sage: R.pthpowers(2, 10**30) # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06]548[0, 1, 2, 12]549550sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence551sage: S.pthpowers(3,10**30) # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^30552[0, 1, 2]553554sage: Q = BinaryRecurrenceSequence(3,3,2,1)555sage: Q.pthpowers(11,10**30) # long time (7.5 seconds)556[1]557558If the sequence is degenerate, and there are are no ``p`` th powers, returns `[]`. Otherwise, if559there are many ``p`` th powers, raises ``ValueError``.560561::562563sage: T = BinaryRecurrenceSequence(2,0,1,2)564sage: T.is_degenerate()565True566sage: T.is_geometric()567True568sage: T.pthpowers(7,10**30)569Traceback (most recent call last):570...571ValueError: The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers.572573sage: L = BinaryRecurrenceSequence(4,0,2,2)574sage: [L(i).factor() for i in xrange(10)]575[2, 2, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15, 2^17]576sage: L.is_quasigeometric()577True578sage: L.pthpowers(2,10**30)579[]580581NOTE: This function is primarily optimized in the range where ``Bound`` is much larger than ``p``.582583"""584585#Thanks to Jesse Silliman for helpful conversations!586587#Reset the dictionary of good primes, as this depends on p588self._PGoodness = {}589#Starting lower bound on good primes590self._ell = 1591592#If the sequence is geometric, then the `n`th term is `a*r^n`. Thus the593#property of being a ``p`` th power is periodic mod ``p``. So there are either594#no ``p`` th powers if there are none in the first ``p`` terms, or many if there595#is at least one in the first ``p`` terms.596597if self.is_geometric() or self.is_quasigeometric():598no_powers = True599for i in xrange(1,6*p+1):600if _is_p_power(self(i), p) :601no_powers = False602break603if no_powers:604if _is_p_power(self.u0,p):605return [0]606return []607else :608raise ValueError, "The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers."609610#If the sequence is degenerate without being geometric or quasigeometric, there611#may be many ``p`` th powers or no ``p`` th powers.612613elif (self.b**2+4*self.c) == 0 :614615#This is the case if the matrix F is not diagonalizable, ie b^2 +4c = 0, and alpha/beta = 1.616617alpha = self.b/2618619#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)),620#that is, it is a geometric term (alpha^(n-1)) times an arithmetic term (u_0 + n*(u_1-u_0*alpha)).621622#Look at classes n = k mod p, for k = 1,...,p.623624for k in xrange(1,p+1):625626#The linear equation alpha^(k-1)*u_0 + (k+pm)*(alpha^(k-1)*u1 - u0*alpha^k)627#must thus be a pth power. This is a linear equation in m, namely, A + B*m, where628629A = (alpha**(k-1)*self.u0 + k*(alpha**(k-1)*self.u1 - self.u0*alpha**k))630B = p*(alpha**(k-1)*self.u1 - self.u0*alpha**k)631632#This linear equation represents a pth power iff A is a pth power mod B.633634if _is_p_power_mod(A, p, B):635raise ValueError, "The degenerate binary recurrence sequence has many pth powers."636return []637638#We find ``p`` th powers using an elementary sieve. Term `u_n` is a ``p`` th639#power if and only if it is a ``p`` th power modulo every prime `\\ell`. This condition640#gives nontrivial information if ``p`` divides the order of the multiplicative group of641#`\\Bold(F)_{\\ell}`, i.e. if `\\ell` is ` 1 \mod{p}`, as then only `1/p` terms are ``p`` th642#powers modulo `\\ell``.643644#Thus, given such an `\\ell`, we get a set of necessary congruences for the index modulo the645#the period of the sequence mod `\\ell`. Then we intersect these congruences for many primes646#to get a tight list modulo a growing modulus. In order to keep this step manageable, we647#only use primes `\\ell` that are have particularly smooth periods.648649#Some congruences in the list will remain as the modulus grows. If a congruence remains through650#7 rounds of increasing the modulus, then we check if this corresponds to a perfect power (if651#it does, we add it to our list of indices corresponding to ``p`` th powers). The rest of the congruences652#are transient and grow with the modulus. Once the smallest of these is greater than the bound,653#the list of known indices corresponding to ``p`` th powers is complete.654655else:656657if Bound < 3 * p :658659powers = []660ell = p + 1661662while not is_prime(ell):663ell = ell + p664665F = GF(ell)666a0 = F(self.u0); a1 = F(self.u1) #a0 and a1 are variables for terms in sequence667bf, cf = F(self.b), F(self.c)668669for n in xrange(Bound): # n is the index of the a0670671#Check whether a0 is a perfect power mod ell672if _is_p_power_mod(a0, p, ell) :673#if a0 is a perfect power mod ell, check if nth term is ppower674if _is_p_power(self(n), p):675powers.append(n)676677a0, a1 = a1, bf*a1 + cf*a0 #step up the variables678679else :680681powers = [] #documents the indices of the sequence that provably correspond to pth powers682cong = [0] #list of necessary congruences on the index for it to correspond to pth powers683Possible_count = {} #keeps track of the number of rounds a congruence lasts in cong684685#These parameters are involved in how we choose primes to increase the modulus686qqold = 1 #we believe that we know complete information coming from primes good by qqold687M1 = 1 #we have congruences modulo M1, this may not be the tightest list688M2 = p #we want to move to have congruences mod M2689qq = 1 #the largest prime power divisor of M1 is qq690691#This loop ups the modulus.692while True:693694#Try to get good data mod M2695696#patience of how long we should search for a "good prime"697patience = 0.01 * _estimated_time(lcm(M2,p*next_prime_power(qq)), M1, len(cong), p)698tries = 0699700#This loop uses primes to get a small set of congruences mod M2.701while True:702703#only proceed if took less than patience time to find the next good prime704ell = _next_good_prime(p, self, qq, patience, qqold)705if ell:706707#gather congruence data for the sequence mod ell, which will be mod period(ell) = modu708cong1, modu = _find_cong1(p, self, ell)709710CongNew = [] #makes a new list from cong that is now mod M = lcm(M1, modu) instead of M1711M = lcm(M1, modu)712for k in xrange(M/M1):713for i in cong:714CongNew.append(k*M1+i)715cong = set(CongNew)716717M1 = M718719killed_something = False #keeps track of when cong1 can rule out a congruence in cong720721#CRT by hand to gain speed722for i in list(cong):723if not (i % modu in cong1): #congruence in cong is inconsistent with any in cong1724cong.remove(i) #remove that congruence725killed_something = True726727if M1 == M2:728if not killed_something:729tries += 1730if tries == 2: #try twice to rule out congruences731cong = list(cong)732qqold = qq733qq = next_prime_power(qq)734M2 = lcm(M2,p*qq)735break736737else :738qq = next_prime_power(qq)739M2 = lcm(M2,p*qq)740cong = list(cong)741break742743#Document how long each element of cong has been there744for i in cong:745if i in Possible_count:746Possible_count[i] = Possible_count[i] + 1747else :748Possible_count[i] = 1749750#Check how long each element has persisted, if it is for at least 7 cycles,751#then we check to see if it is actually a perfect power752for i in Possible_count:753if Possible_count[i] == 7:754n = Integer(i)755if n < Bound:756if _is_p_power(self(n),p):757powers.append(n)758759#check for a contradiction760if len(cong) > len(powers):761if cong[len(powers)] > Bound:762break763elif M1 > Bound:764break765766return powers767768769def _prime_powers(N):770771"""772Find the prime powers dividing ``N``.773774In other words, if `N = q_1^(e_1)q_2^(e_2)...q_n^(e_n)`, it returns775`[q_1^(e_1),q_2^(e_2),...,q_n^(e_n)]`.776777INPUT:778779- ``N`` -- an integer780781OUTPUT:782783- A list of the prime powers dividing N.784785EXAMPLES::786787sage: sage.combinat.binary_recurrence_sequences._prime_powers(124656)788[3, 16, 49, 53]789790sage: sage.combinat.binary_recurrence_sequences._prime_powers(65537)791[65537]792793"""794795output = [i**j for i,j in N.factor()]796output.sort()797return output798799#This function finds the largest prime power divisor of an integer N800def _largest_ppower_divisor(N):801802"""803Find the largest prime power divisor of N.804805INPUT:806807- ``N`` -- an integer (of which the largest prime power divisor will be found)808809OUTPUT:810811- The largest prime power dividing ``N``.812813EXAMPLES::814815sage: sage.combinat.binary_recurrence_sequences._largest_ppower_divisor(124656)81653817sage: sage.combinat.binary_recurrence_sequences._largest_ppower_divisor(65537)81865537819820"""821822output = _prime_powers(N)[-1]823824return output825826827def _goodness(n, R, p):828829"""830Return the goodness of ``n`` for the sequence ``R`` and the prime ``p`` -- that is the largest831non-``p`` prime power dividing ``period(n)``.832833INPUT:834835- ``n`` -- an integer836837- ``R`` -- an object in the class ``BinaryRecurrenceSequence``838839- ``p`` -- a rational prime840841OUTPUT:842843- An integer which is the "goodness" of ``n``, i.e. the largest non-``p`` prime power dividing ``period(n)``.844845EXAMPLES::846847sage: R = BinaryRecurrenceSequence(11,2)848sage: sage.combinat.binary_recurrence_sequences._goodness(89,R,7)84911850851sage: R = BinaryRecurrenceSequence(1,1)852sage: sage.combinat.binary_recurrence_sequences._goodness(13,R,7)8534854sage: R.period(13) #the period of R mod 13 is divisible by 785528856857"""858859#The period of R mod ell860K = R.period(n)861862return _largest_ppower_divisor(K/gcd(K,p))863864865def _next_good_prime(p, R, qq, patience, qqold):866867"""868Find the next prime `\\ell` which is good by ``qq`` but not by ``qqold``, 1 mod ``p``, and for which869``b^2+4*c`` is a square mod `\\ell`, for the sequence ``R`` if it is possible in runtime patience.870871INPUT:872873- ``p`` -- a prime874875- ``R`` -- an object in the class ``BinaryRecurrenceSequence``876877- ``qq`` -- a perfect power878879- ``patience`` -- a real number880881- ``qqold`` -- a perfect power less than or equal to ``qq``882883OUTPUT:884885- 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``.886887888EXAMPLES::889890sage: R = BinaryRecurrenceSequence(1,1)891sage: sage.combinat.binary_recurrence_sequences._next_good_prime(7,R,1,100,1) #ran out of patience to search for good primes892False893sage: sage.combinat.binary_recurrence_sequences._next_good_prime(7,R,2,100,1)89429895sage: sage.combinat.binary_recurrence_sequences._next_good_prime(7,R,2,100,2) #ran out of patience, as qqold == qq, so no primes work896False897898"""899900#We are looking for pth powers in R.901#Our primes must be good by qq, but not qqold.902#We only allow patience number of iterations to find a good prime.903904#The variable _ell for R keeps track of the last "good" prime returned905#that was not found from the dictionary _PGoodness906907#First, we check to see if we have already computed the goodness of a prime that fits908#our requirement of being good by qq but not by qqold. This is stored in the _PGoodness909#dictionary.910911#Then if we have, we return the smallest such prime and delete it from the list. If not, we912#search through patience number of primes R._ell to find one good by qq but not qqold. If it is913#not good by either qqold or qq, then we add this prime to R._PGoodness under its goodness.914915#Possible_Primes keeps track of possible primes satisfying our goodness requirements we might return916Possible_Primes = []917918919#check to see if anything in R._PGoodness fits our goodness requirements920for j in R._PGoodness:921if (qqold < j <= qq) and len(R._PGoodness[j]):922Possible_Primes.append(R._PGoodness[j][0])923924#If we found good primes, we take the smallest925if Possible_Primes != []:926q = min(Possible_Primes)927n = _goodness(q, R, p)928del R._PGoodness[n][0] #if we are going to use it, then we delete it from R._PGoodness929return q930931#If nothing is already stored in R._PGoodness, we start (from where we left off at R._ell) checking932#for good primes. We only tolerate patience number of tries before giving up.933else:934i = 0935while i < patience:936i += 1937R._ell = next_prime(R._ell)938939#we require that R._ell is 1 mod p, so that p divides the order of the multiplicative940#group mod R._ell, so that not all elements of GF(R._ell) are pth powers.941if R._ell % p == 1:942943#requiring that b^2 + 4c is a square in GF(R._ell) ensures that the period mod R._ell944#divides R._ell - 1945if legendre_symbol(R.b**2+4*R.c, R._ell) == 1:946947N = _goodness(R._ell, R, p)948949#proceed only if R._ell statisfies the goodness requirements950if qqold < N <= qq:951return R._ell952953#if we do not use the prime, we store it in R._PGoodness954else:955if N in R._PGoodness:956R._PGoodness[N].append(R._ell)957else :958R._PGoodness[N] = [R._ell]959960return False961962963def _is_p_power_mod(a,p,N):964965"""966Determine if ``a`` is a ``p`` th power modulo ``N``.967968By the CRT, this is equivalent to the condition that ``a`` be a ``p`` th power mod all969distinct prime powers dividing ``N``. For each of these, we use the strong statement of970Hensel's lemma to lift ``p`` th powers mod `q` or `q^2` or `q^3` to ``p`` th powers mod `q^e`.971972INPUT:973974- ``a`` -- an integer975976- ``p`` -- a rational prime number977978- ``N`` -- a positive integer979980OUTPUT:981982- True if ``a`` is a ``p`` th power modulo ``N``; False otherwise.983984EXAMPLES::985986sage: sage.combinat.binary_recurrence_sequences._is_p_power_mod(2**3,7,29)987False988sage: sage.combinat.binary_recurrence_sequences._is_p_power_mod(2**3,3,29)989True990991"""992993#By the chinese remainder theorem, we can answer this question by examining whether994#a is a pth power mod q^e, for all distinct prime powers q^e dividing N.995996for q, e in N.factor():997998#If a = q^v*x, with9991000v = a.valuation(q)10011002#then if v>=e, a is congruent to 0 mod q^e and is thus a pth power trivially.10031004if v >= e:1005continue10061007#otherwise, it can only be a pth power if v is a multiple of p.10081009if v % p != 0:1010return False10111012#in this cse it is a pth power if x is a pth power mod q^(e-v), so let x = aa,1013#and (e-v) = ee:10141015aa = a/q**v1016ee = e - v10171018#The above steps are equivalent to the statement that we may assume a and qq are1019#relatively prime, if we replace a with aa and e with ee. Now we must determine when1020#aa is a pth power mod q^ee for (aa,q)=1.10211022#If q != p, then by Hensel's lemma, we may lift a pth power mod q, to a pth power1023#mod q^2, etc.10241025if q != p:10261027#aa is necessarily a pth power mod q if p does not divide the order of the multiplicative1028#group mod q, ie if q is not 1 mod p.10291030if q % p == 1:10311032#otherwise aa if a pth power mod q iff aa^(q-1)/p == 110331034if GF(q)(aa)**((q-1)/p) != 1:1035return False10361037#If q = p and ee = 1, then everything is a pth power p by Fermat's little theorem.10381039elif ee > 1:10401041#We use the strong statement of Hensel's lemma, which implies that if p is odd1042#and aa is a pth power mod p^2, then aa is a pth power mod any higher power of p10431044if p % 2 == 1:10451046#ZZ/(p^2)ZZ^\times is abstractly isomorphic to ZZ/(p)ZZ cross ZZ/(p-1)ZZ. then1047#aa is a pth power mod p^2 if (aa)^(p*(p-1)/p) == 1, ie if aa^(p-1) == 1.10481049if Integers(p**2)(aa)**(p-1) != 1:1050return False10511052#Otherwise, p=2. By the strong statement of Hensel's lemma, if aa is a pth power1053#mod p^3, then it is a pth power mod higher powers of p. So we need only check if it1054#is a pth power mod p^2 and p^3.10551056elif ee == 2:10571058#all odd squares a 1 mod 410591060if aa % 4 != 1:1061return False10621063#all odd squares are 1 mod 810641065elif aa % 8 != 1:1066return False10671068return True106910701071def _estimated_time(M2, M1, length, p):10721073"""1074Find the estimated time to extend congruences mod M1 to consistent congruences mod M2.10751076INPUT:10771078- ``M2`` -- an integer (the new modulus)10791080- ``M1`` -- an integer (the old modulus)10811082- ``length`` -- a list (the current length of the list of congruences mod ``M1``)10831084- ``p`` -- a prime10851086OUTPUT:10871088- The estimated run time of the "CRT" step to combine consistent congruences.10891090EXAMPLES::10911092sage: 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)1093106.21115930942110941095"""10961097#The heuristic run time of the CRT step to go from modulus M1 to M210981099#length is the current length of cong11001101Q = p * log(M2) #Size of our primes.1102NPrimes = log(M2/M1) / log(Q) #The number of primes11031104return (length * (Q/p)**NPrimes).n()11051106#Find the list of necessary congruences for the index n of binary recurrence1107#sequence R using the fact that the reduction mod ell must be a pth power1108def _find_cong1(p, R, ell):11091110"""1111Find the list of permissible indices `n` for which `u_n = y^p` mod ``ell``.11121113INPUT:11141115- ``p`` -- a prime number11161117- ``R`` -- an object in class BinaryRecurrenceSequence11181119- ``ell`` -- a prime number11201121OUTPUT:11221123- A list of permissible values of `n` modulo ``period(ell)`` and the integer ``period(ell)``.11241125EXAMPLES::11261127sage: R = BinaryRecurrenceSequence(1,1)1128sage: sage.combinat.binary_recurrence_sequences._find_cong1(7, R, 29)1129([0, 1, 2, 12, 13], 14)11301131"""11321133F = GF(ell)1134u0 = F(R.u0); u1 = F(R.u1)1135bf, cf = F(R.b), F(R.c)1136a0 = u0; a1 = u1 #a0 and a1 are variables for terms in sequence11371138#The set of pth powers mod ell1139PPowers = set([])1140for i in F:1141PPowers.add(i**p)11421143#The period of R mod ell1144modu = R.period(ell)11451146#cong1 keeps track of congruences mod modu for the sequence mod ell1147cong1 = []11481149for n in xrange(modu): # n is the index of the a011501151#Check whether a0 is a perfect power mod ell1152if a0 in PPowers:1153#if a0 is a perfect power mod ell, add the index1154#to the list of necessary congruences1155cong1.append(n)11561157a0, a1 = a1, bf*a1 + cf*a0 #step up the variables11581159cong1.sort()11601161return cong1, modu116211631164#check for when a is a perfect pth power1165def _is_p_power(a, p):11661167"""1168Determine whether ``a`` is a ``p`` th power.11691170INPUT:11711172- ``a`` -- an integer11731174- ``p`` -- a prime number11751176OUTPUT:11771178- True if ``a`` is a ``p`` th power; else False.117911801181EXAMPLES::11821183sage: sage.combinat.binary_recurrence_sequences._is_p_power(2**7,7)1184True1185sage: sage.combinat.binary_recurrence_sequences._is_p_power(2**7*3**2,7)1186False11871188"""11891190return (int(a**(1/p))**p == a)119111921193119411951196