###################################################################### ## PerrinVV.txt Save this file as PerrinVV. to use it, # # stay in the # ## same directory, get into Maple (by typing: maple ) # ## and then type: read PerrinVV.txt # ## Then follow the instructions given there # ## # ## Written by Robert Dougherty-Bliss and # #and Doron Zeilberger, Rutgers University , # ## DoronZeil at gmail dot com # ###################################################################### #with(LinearAlgebra): print(`First Written: Feb. 2023: tested for Maple 2020 `): print(): print(`This is PerrinVV.txt, one of the Maple packages`): print(`accompanying Robert Dougherty-Bliss and Doron Zeilberger's article: `): print(` Lots and Lots of Perrin-Type Primality Tests and Their Pseudo-Primes `): print(``): print(`----------------------------`): print(`It finds Perrin-style primality tests inspired by Vince Vatter's beautiful combinatorial proof`): print(`of the original Perrin test, and the Edlin-Zeilberger version of the Goulden-Jackons algorithm`): print(`----------------------------`): print(): print(`The most current version is available on WWW at:`): print(` http://sites.math.rutgers.edu/~zeilberg/tokhniot/Perrin.txt .`): print(`Please report all bugs to: DoronZeil at gmail dot com .`): print(): print(`For general help, and a list of the MAIN functions,`): print(` type "ezra();". For specific help type "ezra(procedure_name);" `): print(`------------------------------------`): print(`For a list of the supporting functions type: ezra1();`): print(): print(`For help with a specific procedure, type:`): print(`"ezra(procedure_name);"`): print(`------------------------------------`): print(`For a list of the Generalized functions type: ezraG();`): print(): print(`For help with a specific procedure, type:`): print(`"ezra(procedure_name);"`): print(`------------------------------------`): print(`For a list of the Story functions type: ezraS();`): print(): print(`For help with a specific procedure, type:`): print(`"ezra(procedure_name);"`): print(`------------------------------------`): print(): print(`For help with procedures taken from CGJ `): print(` type "ezraCGJ();". For specific help type "ezra(procedure_name);" `): print(`For a list of the supporting functions type: ezraCGJ(procedure_name);`): print(): with(linalg): with(numtheory): ezraG:=proc() if args=NULL then print(`The General procedures are`): print(` FindPP1G, GenPerrin3, GenPerrin, PPg, PtestG,`): print(` GenPerrinPatternSearch, PatternDB`): else ezra(args): fi: end: ezra1:=proc() if args=NULL then print(`The SUPPORTING procedures are`): print(` CheckSeq, FindPP1, FindPP2, FindPP2gen, FindPP3, GenLucas, IncVecs, MatC, Pow1, PPlucas, RecPat, SeqLucas, ValC, ValCp, ValPatP `): else ezra(args): fi: end: ezraS:=proc() if args=NULL then print(`The STORY procedures are`): print(` Info1, Paper1, Paper2, Paper3 `): else ezra(args): fi: end: ezra:=proc() if args=NULL then print(` PrimTest.txt: A Maple package for generating Perrin-like Primality Tests and for detecting pseudo-primes `): print(`The MAIN procedures are`): print(` FindPP, PP, Ptest, SeqPat, ValPat `): elif nargs=1 and args[1]=CheckSeq then print(`CheckSeq(L): Given a sequece of integers L,checks that the quantity`): print(`Sum(L[n/d]*mobius(d), d in Divisors(n)). if true for n from 1 to nops(L). Try:`): print(` CheckSeq(SeqPat({0,1},{[1,1]},100));`): elif nargs=1 and args[1]=FindPP then print(`FindPP(Alph,Pats,A,K): Inputs an alphabet Alph and a set of patterns Pats, and a template A=[a1,a2,...,ak] of positive integers , outputs`): print(`of pseudo-primes for the primality tests induced by [Alph,Pats] of the form p1^a1*...*pk^ak with p1<..L then print(`The first two arguments must be lists of the same size`): RETURN(FAIL): fi: if not type(N,integer) then print(`The third argument must be an integer`, L): RETURN(FAIL): fi: if Nv then ERROR(v,`is a subword of`,u,`illegal input`): fi: if j=nops(u)+1 and (i>1 or j>2) then gug:=1: gug:=gug*s^(nops(v)-(j-i)): lu:=lu+gug: fi: od: lu: end: #WrapAround(MISTAKES,s): The contibution from Case I clusters #in the Edlin-Zeilberger cyclic words analog of Goulden-Jackosn #index by the LIST of MISTAKES, and whose entries give all possible #overlaps, phrased in terms of the variable s WrapAround:=proc(MISTAKES,s) local n,A,B,C,i,j,D1,lu,gu,gu1,r: with(linalg): n:=nops(MISTAKES): A:=matrix(n,n): B:=matrix(n,n): C:=matrix(n,n): n:=nops(MISTAKES): for i from 1 to n do for j from 1 to n do A[i,j]:=-overlapz(MISTAKES[i],MISTAKES[j],s): B[i,j]:=s*diff(A[i,j],s): if i=j then C[i,j]:=1-A[i,j]: else C[i,j]:=-A[i,j]: fi: od: od: D1:=multiply(multiply(A,inverse(C)),B): gu:=0: for i from 1 to n do gu1:=D1[i,i]: lu:=taylor(gu1,s=0,nops(MISTAKES[i])+1): for r from 0 to nops(MISTAKES[i])-1 do gu1:=gu1-coeff(lu,s,r)*s^r: od: gu:=normal(gu+gu1): od: gu: end: hakten:=proc(B) local w,i: for i from 1 to nops(B) do w:=op(i,B): if superflous(B,w)=1 then RETURN(B minus {w}): fi: od: B: end: #Hakten(B) removes all superflous words Hakten:=proc(B) local B1,B2: B1:=B: B2:=hakten(B1): while B1<>B2 do B1:=B2: B2:=hakten(B2): od: B2: end: #BW(k,w,x): The Burstein-Wilf generating function BW:=proc(k,w,x) normal(1+ (1-x^w)/(1-x)* (k*x+(k-1)*x*( (w+1-w*k*x)/(1-k*x+(k-1)*x^(w+1))- (w+1)/(1-x^(w+1)) ) )): end: #BWb(k,w): Checking the Edlin-Zeilberger Analog of Goulden-Jackson #for cyclic words against the Burstein-Wilf generating function BWb:=proc(k,w) local al,MI,i,j,x,gu: al:={seq(i,i=1..k)}: MI:={seq([seq(j,i=1..w+1)],j=1..k)}: gu:=CGJs(al,MI,x): gu:=gu-BW(k,w,x): normal(gu): end: #bdokC(alphabet,MISTAKES,L): checks the validity of #of the Edlin-Zeilberger method bdokC:=proc(alphabet,MISTAKES,L) local lu,gu,s,i: lu:=EmpiricalGJseriesC(alphabet,MISTAKES,L): gu:=taylor(CGJs(alphabet,MISTAKES,s),s=0,L+1): gu:=[seq(coeff(gu,s,i),i=0..L)]: evalb(lu=gu): end: #EmpiricalGJSeriesC(alphabet,MISTAKES1,L): Does what #GJseriesC(nops(alphabet),MISTAKES,L) does, but #empirically. Don't make L too large, unless there #are lots of mistakes. It is meant to be a check #on the validity of the (usually) much much faster #and should not be used except for curiosity EmpiricalGJseriesC:=proc(alphabet,MISTAKES,L) local n,gu: gu:=[]: for n from 0 to L do gu:=[op(gu),nops(SetOfCorrectWordsC(alphabet,MISTAKES,n))]: od: gu: end: #SetOfCorrectWords(Alphabet,MISTAKES,n): given an alphabet, Alphabet #and a set of mistakes, MISTAKES, finds, empirically, the #set of words that that do not have factors that belong to MISTAKES SetOfCorrectWords:=proc(Alphabet,MISTAKES,n) local MISTAKES1,gu,mu,i,j,cand: option remember: MISTAKES1:=Hakten(MISTAKES): if n=0 then RETURN({[]}): fi: mu:=SetOfCorrectWords(Alphabet,MISTAKES,n-1): gu:={}: for i from 1 to nops(mu) do for j from 1 to nops(Alphabet) do cand:=[op(op(i,mu)),op(j,Alphabet)]: if not isbad(cand,MISTAKES1) then gu:=gu union {cand}: fi: od: od: gu: end: #SetOfCorrectWordsC(Alphabet,MISTAKES,n): given an alphabet, Alphabet #and a set of mistakes, MISTAKES, finds, empirically, the #set of CYCLIC words (with a marked beginning) #that that do not have factors that belong to MISTAKES SetOfCorrectWordsC:=proc(Alphabet,MISTAKES,n) local gu,mila,mu,i: mu:=SetOfCorrectWords(Alphabet,MISTAKES,n): gu:={}: for i from 1 to nops(mu) do mila:=op(i,mu): if not isbadC(mila,MISTAKES) then gu:=gu union {mila}: fi: od: gu: end: #isbadC(mila,MISTAKES): returns true if one of the suffices of #one of the CYCLIC shifts of mila belongs to the set of MISTAKES isbadC:=proc(mila,MISTAKES) local i,mila1,n: n:=nops(mila): for i from 1 to n do mila1:=[op(i..n,mila),op(1..i-1,mila)]: if isbad(mila1,MISTAKES) then RETURN(true): fi: od: false: end: #isbad(mila,MISTAKES): returns true if one of the suffices of #mila belongs to the set of MISTAKES isbad:=proc(mila,MISTAKES) local i,shegi: for i from 1 to nops(MISTAKES) do shegi:=op(i,MISTAKES): if nops(mila)>=nops(shegi) and [op(nops(mila)-nops(shegi)+1..nops(mila),mila)]=shegi then RETURN(true): fi: od: false: end: SBW:=proc(k,w,s) local i,L,gu,mu,A,matkhil: A:=-sum(s^i,i=1..w): L:=-k*s^(w+1)/(1-A): matkhil:=sum((i-1)*s^i,i=1..w): gu:=k*normal(s*diff(A,s)*A/(1-A))-k*matkhil: mu:=normal(1/(1-k*s-L)): normal((s*diff(L,s)-L+1)*mu+gu): end: #ProveBW(): proves the Burstein-Wilf formula ProveBW:=proc() local i,L,gu,mu,A,matkhil,k,w,s: A:=-sum(s^i,i=1..w): L:=-k*s^(w+1)/(1-A): matkhil:=sum((i-1)*s^i,i=1..w): gu:=k*normal(s*diff(A,s)*A/(1-A))-k*matkhil: mu:=normal(1/(1-k*s-L)): evalb(simplify(normal((s*diff(L,s)-L+1)*mu+gu-BW(k,w,s)))=0): end: findeqzG:=proc(v,MISTAKES,C,s,t) local eq,i,u: eq:=-1: for i from 1 to nops(v) do eq:=eq*s: od: for i from 1 to nops(MISTAKES) do u:=op(i,MISTAKES): eq:=eq+(t-1)*overlapz(u,v,s)*C[op(u)]: od: C[op(v)]-eq=0: end: CGJsG:=proc(alphabet,MISTAKES1,s,t) local v,eq, var,i,lu,C,MISTAKES,mu: MISTAKES:=Hakten(MISTAKES1): eq:={}: var:={}: for i from 1 to nops(MISTAKES) do v:=op(i,MISTAKES): eq:= eq union {findeqzG(v,MISTAKES,C,s,t)}: var:=var union {C[op(v)]}: od: var:=solve(eq,var): lu:=1: mu:=0: for i from 1 to nops(alphabet) do lu:=lu-s: od: for i from 1 to nops(MISTAKES) do v:=op(i,MISTAKES): lu:=lu-subs(var,C[op(v)]): mu:=mu+subs(var,C[op(v)]): od: normal((1/lu)*(1+s*diff(mu,s)-mu)+WrapAround(convert(MISTAKES,list),s)): end: ###END FROM CGJ #SeqPatOri(Alph,Pats,L): Given an alphabet Alph, a finite set of patterns Pats, and a positive integer L, outputs the first L terms of #the number of circular words (with a clasp) in the alphabet Alph avoding the set of Patterns Pats. For the first 100 terms of the Perrin sequence (except the begining) try: #SeqPatOri({0,1},{[1,1],[0,0,0]},100); SeqPatOri:=proc(Alph,Pats,L) local f,s,f1,i: f:=CGJs(Alph,Pats,s): f1:=taylor(f,s=0,L+5): [seq(coeff(f1,s,i),i=1..L)]: end: #SeqPat(Alph,Pats,L): Given an alphabet Alph, a finite set of patterns Pats, and a positive integer L, outputs the first L terms of #the number of circular words (with a clasp) in the alphabet Alph avoding the set of Patterns Pats. For the first 100 terms of the Perrin sequence (except the begining) try: #SeqPat({0,1},{[1,1],[0,0,0]},100); SeqPat:=proc(Alph,Pats,L) local f,s,f1,i,D1: f:=CGJs(Alph,Pats,s): D1:=denom(f): f1:=rem(numer(f),D1,s): f1:=f1/D1: f1:=taylor(f1,s=0,L+5): [seq(coeff(f1,s,i),i=1..L)]: end: #SeqPatSlow(Alph,Pats,L): Given an alphabet Alph, a finite set of patterns Pats, and a positive integer L, outputs the first L terms of #the number of circular words (with a clasp) in the alphabet Alph avoding the set of Patterns Pats. For the first 100 terms of the Perrin sequence (except the begining) try: #SeqPatSlow({0,1},{[1,1],[0,0,0]},100); SeqPatSlow:=proc(Alph,Pats,L) local f,s,C: f:=CGJs(Alph,Pats,s): C:=RtoC(f,s): SeqFromRec(C,L): end: #PP(Alph,Pats,L): All the pseudo-primes <=L in the primality set induced by the alphabet Alph and the set of patterns Pats. Try: #PP({0,1},{[1,1],[0,0,0]},1000); PP:=proc(Alph,Pats,L) local gu,i,mu,lu: if L<=100 then print(` Make `, L, `bigger `): RETURN(FAIL): fi: gu:=SeqPat(Alph,Pats,L): lu:={seq(gu[ithprime(i)] mod ithprime(i),i=4..10)}: if nops(lu)<>1 then RETURN(FAIL): fi: lu:=lu[1]: mu:=[]: for i from 4 to L do if not isprime(i) and gu[i] mod i=lu then mu:=[op(mu),i]: fi: od: mu: end: #Pow1(M,k,p): M^k mod p Pow1:=proc(M,k,p) local d,M1,i,j: option remember: d:=nops(M): if k=0 then RETURN([seq([0$(i-1),1,0$(d-i)],i=1..d)]): fi: if k mod 2=1 then M1:=convert(multiply(Pow1(M,k-1,p),M),list): RETURN([seq([seq(M1[i][j] mod p,j=1..d)],i=1..d)]): else M1:=Pow1(M,k/2,p): M1:=convert(multiply(M1,M1),list): RETURN([seq([seq(M1[i][j] mod p,j=1..d)],i=1..d)]): fi: end: #MatC(C): The matrix corresponding to the recurrence C=[INI,Rec]. Try #MatC([[1,1],[1,1]]); MatC:=proc(C) local INI1,k,i,M: INI1:=C[1]: INI1:=[seq(INI1[nops(INI1)+1-i],i=1..nops(INI1))]: k:=nops(C[2]): M:=[C[2],seq([0$(i-1),1,0$(k-i)],i=1..k-1)]: M,INI1: end: #ValC(C,n): The n-th term of the C-finite sequence given by the recurrence C=[INI,REC], using Matrix multiplication. Should be the same as #SeqFromRec(C,n)[n], but hopefully faster. Try: #ValC([[1,1],[1,1]],30); ValC:=proc(C,n) local gu,M,k,i1,Ini: gu:=MatC(C): M:=gu[1]: k:=nops(M): Ini:=gu[2]: Ini:=[seq([Ini[i1]],i1=1..k)]: multiply(M&^(n-k),Ini)[1,1]: end: #ValCp(C,n,p): The n-th term of the C-finite sequence mod p, given by the recurrence C=[INI,REC]. Should be the same (but faster) than #ValCp(C,n) mod p. #ValCp([[1,1],[1,1]],30,101); ValCp:=proc(C,n,p) local gu,M,k,i1,Ini: gu:=MatC(C): M:=gu[1]: k:=nops(M): Ini:=gu[2]: Ini:=[seq([Ini[i1]],i1=1..k)]: multiply(Pow1(M,n-k,p),Ini)[1,1] mod p: end: #RecPat(Alph,Pats): The C-finite recurrence satisfied by the set of circular words in the alphabet Alph avoiding the set of patterns Pats. For the Perrim sequence, type: #RecPat({0,1},{[1,1],[0,0,0]}); RecPat:=proc(Alph,Pats) local gu,s: option remember: gu:=CGJs(Alph,Pats,s): RtoC(gu,s): end: #ValPat(Alph,Pats,n): The number of circular words of length n in the alphabet Alph avoiding as consecutive subwords the patterns in the set Pats #Same, but faster as SeqPat(Alph,Pats,n)[n]. Try: #ValPat({0,1},{[1,1],[0,0,0]},1000); ValPat:=proc(Alph,Pats,n) ValC(RecPat(Alph,Pats),n):end: #ValPatP(Alph,Pats,n,p): The number of circular words of length n in the alphabet Alph avoiding as consecutive subwords the patterns in the set Pats mod p #Same, but faster as ValPat(Alph,Pats,n) mod p. Try: #ValPatP({0,1},{[1,1],[0,0,0]},1000,101); ValPatP:=proc(Alph,Pats,n,p) ValCp(RecPat(Alph,Pats),n,p):end: #Ptest(Alph,Pats,n,p0): Testing pos. integer n according to the primality test where the p-th term mod p should be p0, #inspired by the set of patterns Pats in the alphabet Alph. For the Perrin test try: #Ptest({0,1},{[1,1],[0,0,0]},1001,0); For the Lucas test try: #Ptest({0,1},{[1,1]},1001,1); Ptest:=proc(Alph,Pats,n,p0) evalb(ValPatP(Alph,Pats,n,n)=p0): end: #FindPP1slow(Alph,Pats,k,K): All the pseudo-primes for the test inspired by Alph and Pats, of the form p^k, where p is a one of the first K primes. #Try: #FindPP1slow({0,1},{[1,1],[0,0,0]},2,1000); FindPP1slow:=proc(Alph,Pats,k,K) local i,p,gu: gu:=[]: for i from 1 to K do p:=ithprime(i): if ValPat(Alph,Pats,p^(k-1)) mod p^k=0 then gu:=[op(gu),p^k]: fi: od: gu: end: #FindPP1(Alph,Pats,k,K): All the pseudo-primes for the test inspired by Alph and Pats, that happens to be L[n],of the form p^k, where p is a one of the first K primes. #Try: #FindPP1({0,1},{[1,1],[0,0,0]},2,1000); FindPP1:=proc(Alph,Pats,k,K) local i,p,gu,mu,mu1,p0: mu:=SeqPat(Alph,Pats,ithprime(K)^(k-1)+10): mu1:={seq(mu[ithprime(i)] mod ithprime(i),i=10..20)}: if nops(mu1)<>1 then print(`Not a primality test`): RETURN(FAIL): fi: p0:=mu1[1]: gu:=[]: for i from 1 to K do p:=ithprime(i): if mu[p^(k-1)] mod p^k=p0 then gu:=[op(gu),p^k]: fi: od: gu: end: #FindPP2(Alph,Pats,K): All the pseudo-primes for the test inspired by Alph and Pats, of the form p*q, where p,q<=ithprime(K) are #FindPP2({0,1},{[1,1],[0,0,0]},1000); FindPP2:=proc(Alph,Pats,K) local i,j,p,q,gu,mu,p0,mu1: mu:=SeqPat(Alph,Pats,ithprime(K+10)+1): mu1:={seq(mu[ithprime(i)] mod ithprime(i),i=10..K+10)}: if nops(mu1)<>1 then print(`Not a primality test`): RETURN(FAIL): fi: p0:=mu1[1]: gu:=[]: for i from 2 to K do p:=ithprime(i): for j from i+1 to K do q:=ithprime(j): if mu[p]+mu[q] mod p*q=2*p0 then if not (p*q<=nops(mu) and mu[p*q] mod p*q<>p0) then gu:=[op(gu),p*q]: fi: fi: od: od: sort(gu): end: #FindPP3(Alph,Pats,K): All the pseudo-primes for the test inspired by Alph and Pats, of the form p*q*r, where p,q,r<=ithprime(K) #FindPP3({0,1},{[1,1],[0,0,0]},1000); FindPP3:=proc(Alph,Pats,K) local i,j,p,q,gu,mu,k,r: mu:=SeqPat(Alph,Pats,ithprime(K)^2+1): gu:=[]: for i from 1 to K do p:=ithprime(i): for j from i+1 to K do q:=ithprime(j): for k from j+1 to K do r:=ithprime(k): if mu[p*q]+mu[q*r]+mu[p*r]-mu[p]-mu[q]-mu[r] mod p*q*r=0 then gu:=[op(gu),p*q*r]: fi: od: od: od: sort(gu): end: #CheckSeq(L,n): Given a sequence of integers L, and a positive integer n, checks that the #Sum(L[n/d]*mobius(d), d in Divisors(n)) is always 0. Try: #L:=SeqPat({0,1},{[1,1]},1000): CheckSeq(L); CheckSeq:=proc(L) local D1,d1,i,n: if not (type(L,list) and {seq(type(L[i],integer),i=1..nops(L))}={true}) then print(`bad input`): RETURN(FAIL): fi: for n from 1 to nops(L) do D1:=divisors(n): if add(L[n/d1]*mobius(d1), d1 in D1) mod n<>0 then print(`does not work for n=`, n): RETURN(false): fi: od: true: end: #IncVecs(k,K): The set of all increasing vectors of length k with entries<=K, Try #IncVecs(4,5); IncVecs:=proc(k,K) local gu,mu,i,mu1: option remember: if k=1 then RETURN({seq([i],i=1..K)}): fi: gu:={}: for i from 1 to K do mu:=IncVecs(k-1,i-1): gu:=gu union {seq([op(mu1),i],mu1 in mu)}: od: gu: end: #FindPP(Alph,Pats,A,K): Inputs an alphabet Alph and a set of patterns Pats, and a template A=[a1,a2,...,ak] of positive integers , outputs #of pseudo-primes for the primality tests induced by [Alph,Pats] of the form p1^a1*...*pk^ak with p1<..1 then RETURN(FAIL): fi: lu:=lu[1]: mu:=[]: for i from y0 to L do if not isprime(i) and gu[i] mod i=lu then mu:=[op(mu),i]: fi: od: mu: end: ###start general #PtestG(f,x,n,p0): Testing pos. integer n according to the primality test where the p-th term mod p should be p0, #inspired by the rational generating function f of x #PtestG(CGJs({0,1},{[1,1],[0,0,0]},s),s,1001,0); PtestG:=proc(f,x,n,p0) local C: C:=RtoC(f,x): evalb(ValCp(C,n,n)=p0): end: #PPg(f,s,L): All the pseudo-primes <=L in the primality set induced by the rational function f of s #PPg((1+s^2)/(1-s-s^2),x,1000); PPg:=proc(f,s,L) local gu,i,mu,lu,D1,f1: if L<=100 then print(` Make `, L, `bigger `): RETURN(FAIL): fi: D1:=denom(f): f1:=rem(numer(f),D1,s): f1:=f1/D1: f1:=taylor(f1,s=0,L+5): gu:=[seq(coeff(f1,s,i),i=1..L)]: lu:={seq(gu[ithprime(i)] mod ithprime(i),i=4..10)}: if nops(lu)<>1 then RETURN(FAIL): fi: lu:=lu[1]: mu:=[]: for i from 4 to L do if not isprime(i) and gu[i] mod i=lu then mu:=[op(mu),i]: fi: od: mu: end: #FindPP1G(f,s,k,K): All the pseudo-primes for the test inspired by the rational function f of s that happens to be L[n],of the form p^k, where p is a one of the first K primes. #Try: #FindPP1G(CGJsG({0,1},{[1,1],[0,0,0]},s,0),s,2,1000); FindPP1G:=proc(f,s,k,K) local f1,i,p,gu,mu,mu1,p0: f1:=taylor(f,s=0,ithprime(K)^(k-1)+10): mu:=[seq(coeff(f1,s,i),i=1..ithprime(K)^(k-1)+9)]: mu1:={seq(mu[ithprime(i)] mod ithprime(i),i=10..20)}: if nops(mu1)<>1 then print(`Not a primality test`): RETURN(FAIL): fi: p0:=mu1[1]: gu:=[]: for i from 1 to K do p:=ithprime(i): if mu[p^(k-1)] mod p^k=p0 then gu:=[op(gu),p^k]: fi: od: gu: end: #GenPerrin3 (a1, a2, a3, x): The general Perrin-style rational function with cubic denominator. #To get the original Perrin generating function.Try: #GenPerrin3(0,-1,1,x); GenPerrin3:=proc (a1, a2, a3, x): (3-2*a1*x+a2*x^2)/(1-a1*x+a2*x^2-a3*x^3): end: # Evaluate the nth term of the generalized lucas sequence with respect to p(x) # in terms of the coefficients of p(x). # See: https://en.wikipedia.org/wiki/Newton%27s_identities newton := proc(p, x, n) option remember: local d, k: d := degree(p, x): if n = 0 then return d: fi: -n * coeff(p, x, d - n) - expand(add(coeff(p, x, d - n + k) * newton(p, x, k), k=1..n-1)): end: CtoR:=proc(S,t) local D1,i,N1,L1,f,f1,L: if not (type(S,list) and nops(S)=2 and type(S[1],list) and type(S[2],list) and nops(S[1])=nops(S[2]) and type(t, symbol) ) then print(`Bad input`): RETURN(FAIL): fi: D1:=1-add(S[2][i]*t^i,i=1..nops(S[2])): N1:=add(S[1][i]*t^(i-1),i=1..nops(S[1])): L1:=expand(D1*N1): L1:=add(coeff(L1,t,i)*t^i,i=0..nops(S[1])-1): f:=L1/D1: L:=degree(D1,t)+10: f1:=taylor(f,t=0,L+1): if expand([seq(coeff(f1,t,i),i=0..L)])<>expand(SeqFromRec(S,L+1)) then print([seq(coeff(f1,t,i),i=0..L)],SeqFromRec(S,L+1)): RETURN(FAIL): else RETURN(f): fi: end: #SeqFromRec(S,N): Inputs S=[INI,ope] #where INI is the list of initial conditions, a ope a list of #size L, say, and a recurrence operator ope, codes a list of #size L, finds the first N0 terms of the sequence satisfying #the recurrence f(n)=ope[1]*f(n-1)+...ope[L]*f(n-L). #For example, for the first 20 Fibonacci numbers, #try: SeqFromRec([[1,1],[1,1]],20); SeqFromRec:=proc(S,N) local gu,L,n,i,INI,ope: INI:=S[1]:ope:=S[2]: if not type(INI,list) or not type(ope,list) then print(`The first two arguments must be lists `): RETURN(FAIL): fi: L:=nops(INI): if nops(ope)<>L then print(`The first two arguments must be lists of the same size`): RETURN(FAIL): fi: if not type(N,integer) then print(`The third argument must be an integer`, L): RETURN(FAIL): fi: if N member(p^k, pseudos), [seq(2..8)]) then res := [op(res), [p, cs]]: fi: od: finish := time(): time_sum := time_sum + finish - start: if time_sum > next_time then next_time := 5 * (floor(round(time_sum) / 5) + 1): printf("Iteration %d/%d\n", k, count): printf("Est. %ds remaining\n", round((count - k) * (time_sum / k))): fi: k := k + 1: od: od: res: end: PatternDB := proc() [[2, [2, 1]], [2, [1, 2]], [3, [2, 2]], [2, [0, -2, -2]], [2, [0, 2, -2]], [2, [0, 2, -1]], [2, [0, -2, -1]], [3, [1, 2, 1]], [2, [0, 2, 1]], [3, [1, -1, 1]], [5, [1, -1, 1]], [5, [2, -2, 1]], [2, [0, -2, 1]], [2, [0, -2, 2]], [2, [1, -2, 2]], [3, [1, -2, 2]], [5, [1, -2, 2]], [2, [2, -1, 2]], [2, [1, 0, 2]], [2, [2, 1, 2]], [3, [1, 1, 2]], [2, [0, 2, 2]], [2, [1, 2, 2]]]: end: ####