###################################################################### ## EMILIE: Save this file as EMILIE to use it, # # stay in the # ## same directory, get into Maple (by typing: maple ) # ## and then type: read EMILIE: # ## Then follow the instructions given there # ## # ## Written by Doron Zeilberger, Rutgers University , # ## zeilberg at math dot rutgers dot edu. # ###################################################################### print(` Started : March 28, 2006: tested for Maple 10 `): print(`Version of Sept. 19, 2006: `): print(): print(`This is EMILIE, A Maple package that completes the proof`): print(`of the main theorem in the beautiful on-line paper`): print(`"New Family of Somos-like Recurrences" by Paul Heideman and Emilie `): print(` Hogan`): print(`www.math.wisc.edu/~propp/SSL/heiho.pdf `): print(`It also conjectures [ EmilieS(K,x,Z);] a general generating function`): print(): print(`The most current version is available on WWW at:`): print(` http://www.math.rutgers.edu/~zeilberg/tokhniot/EMILIE .`): print(`Please report all bugs to: zeilberg at math dot rutgers dot edu .`): print(): print(`For general help, and a list of the functions,`): print(` type "ezra();". For specific help type "ezra(procedure_name);" `): print(): ezra1:=proc() if args=NULL then print(` The supporting and less important procedures are `): print(`CheckEmilie, Emilie, EmilieS , GrabPolHead `): print(` findCrec, GuessPol, GuessPWP, GuessR, GuessR1, Paul`): else ezra(args): fi: end: ezra:=proc() if args=NULL then print(` EMILIE: A Maple package for `): print(`The MAIN procedures are: `): print(` anK, EmiliePaul, EmilieRec, EmilieRecG, GlobalPaul`): elif nargs=1 and args[1]=anK then print(` anK(n,K) : The sequence a_n of the Heideman-Hogan paper`): print(`where k=2*K+1` ): print(`For example, try: anK(4,3); `): elif nargs=1 and args[1]=CheckEmilie then print(` CheckEmilie(K,L) : Checks that the coefficients of the conjectured generating function`): print(`for Emilie(K,x) satisfy the quadratic recurrence (1) of the paper up to n=L`): print(`For example, try: CheckEmilie(5,1000);`); elif nargs=1 and args[1]=Emilie then print(`Emilie(K,x): Conjectures a generating function, in x, for the Somos-Like sequence`): print(`satisfying the recurrence`): print(` a(n)a(n-2*K-1)=a(n-1)*(a(n-2*K)+a(n-K)+a(n-K-1)`): print(`subject to the inital conditions a(m)=1 for m=0...2*K`): print(`Note that in the Heideman-Hogan paper, k=2*K+1`): print(`For example, try: Emilie(5,x);`): elif nargs=1 and args[1]=EmiliePaul then print(`EmiliePaul(K,n): completes the proof of Paul Heideman and`): print(`Emilie Hogan's beautiful conjecture`): elif nargs=1 and args[1]=EmilieRec then print(`EmilieRec(K,N) : guesses a linear recurrence equation with`): print(`constant coefficients for the Heideman-Hogan sequence for K`): print(`Try: EmilieRec(1,N);`): elif nargs=1 and args[1]=EmilieRecG then print(`EmilieRecG(K,N) : guesses a linear recurrence equation with`): print(`constant coefficients for the Heideman-Hogan sequence for SYMBOLIC K`): print(`Try: EmilieRecG(K,N);`): elif nargs=1 and args[1]=EmilieS then print(`EmilieS(K,x,Z): The conjectured expression for the Emilie(K,x) in terms of`): print(` Z=x^K. Here K,x,Z are symbols`): print(`Note that subs({K=K0,Z=x^K0},EmilieS(K,x,Z)); should be Emilie(K0,x); `): print(`for any numeric K0`): print(`For example, try: EmilieS(K,x,Z);`); elif nargs=1 and args[1]=findCrec then print(`findCrec(f,N): Finds a linear recurrence equation with`): print(`constant coefficients for the sequence f`): print(`For example try: findCrec([1$20],N);`): elif nargs=1 and args[1]=GlobalPaul then print(`GlobalPaul(K,n): Given symbolic K and n conjecutures`): print(`the first 6K terms of the Heideman-Hogan sequence`): print(`Try: GlobalPaul(K,n);`): elif nargs=1 and args[1]=GrabPolHead then print(`GrabPolHead(L,n): grabs the beginning of the list L`): print(`that is a polynomial (if found) together with the number of`): print(`terms it agrees with`): print(`For example, try:`): print(`GrabPolHead([1$8,seq(i^3,i=1..13)],n);`): elif nargs=1 and args[1]=GuessPol then print(`GuessPol(L,n,s0): guesses a polynomial of degree d in n for`): print(` the list L, such that L[i]=P[i] for i>=s0 for example, try: `): print(`GuessPol([(seq(i,i=1..10),n,1);`): elif nargs=1 and args[1]=GuessPWP then print(`GuessPWP(L,n): guesses a piece-wise polynomial for a sequenec L`): print(`as far as it goes`): print(`starting at L[1], it outputs a list whose entries are`): print(`[[a,b],pol] which means that L[i]=pol(i) for a<=i<=b`): print(`For example, try:`): print(`GuessPWP([1$10,2$10],n); `): elif nargs=1 and args[1]=GuessR then print(`GuessR(L,x): Given a list of numbers L`): print(`guesses a rational function whose first`): print(`nops(L) terms are given by L`): print(`for example, try: GuessR([1$30],x);`): print(`and you should get 1/(1-x) `): print(`since the Maclaurin expansion of 1/(1-x) starts with 1+x+x^2+x^3+ ...`): elif nargs=1 and args[1]=GuessR1 then print(`GuessR1(L,p,q,x): Given a list of numbers L`): print(`guesses a rational function in x, with numerator degree p`): print(`and denominator degree q`): print(`whose first`): print(`nops(L) terms, in its Maclaurin expansion, are given by `): print(`the entries of L.`): print(`For example, try: GuessR1([1$30],0,1,x);`): print(`and you should get 1/(1-x) `): print(`since the Maclaurin expansion of 1/(1-x) starts with 1+x+x^2+x^3+ ...`): elif nargs=1 and args[1]=Paul then print(`Paul(K,n): guesses a piece-wise polynomial (in n) beginning`): print(`to the Heideman-Hogan sequence for k=2K+1, for example,`): print(`try: Paul(5,n);`): else print(`There is no such thing as`, args): fi: end: ez:=proc(): print(`anK(n,K), an1(n), GuessR1(L,p,q,x), GuessR(L,x)`): print(`Emilie(K,x), Mekh(x,K) `): print(`A1(K,x), B1(K,x), C1(K,x), D1(K,x), E1(K,x), CheckE(K,L) `): print(`EmilieS(K,x,Z), Emilie1(K,x,Z, EmilieS2(K,x,Z) `): end: an1:=proc(n) option remember: if n<=3 then 1: else (an1(n-1)*an1(n-2)+an1(n-1)+ an1(n-2))/an1(n-3): fi: end: anK:=proc(n,K) local k:option remember: k:=2*K+1: if n<=k then 1: else (anK(n-1,K)*anK(n-k+1,K)+anK(n-(k-1)/2,K)+ anK(n-(k+1)/2,K))/anK(n-k,K): fi: end: GuessR1:=proc(L,p,q,x) local a,b,T,B,i,var,gu,eq: T:=add(a[i]*x^i,i=0..p): B:=add(b[i]*x^i,i=0..q): var:={seq(a[i],i=0..p),seq(b[i],i=0..q)}: gu:=expand(add(L[i+1]*x^i,i=0..p+q+11)*B-T): eq:={seq(coeff(gu,x,i),i=0..p+q+5)}: var:=solve(eq,var): if var=NULL or subs(var,B)=0 then RETURN(FAIL): else gu:=normal(subs(var,T)/subs(var,B)): RETURN(sort(numer(gu)) /sort(denom(gu)) ): fi: end: #GuessR(L,x): Given a list of numbers L #guesses a rational function whose first #nops(L) terms are given by L #for example, try: GuessR([1$30],x); GuessR:=proc(L,x) local p,q,S1: for S1 from 0 to nops(L)-14 do for p from 0 to S1 do for q from 0 to S1-p do if GuessR1(L,p,q,x)<>FAIL then RETURN(GuessR1(L,p,q,x)): fi: od: od: od: FAIL: end: Emilie:=proc(K,x) local L, k,n: k:=2*K+1: L:=[seq(anK(n,K),n=1..6*k+10)]: GuessR1(L,3*k-4,3*k-3,x); end: w:=proc(K): 2*K^2+8*K+3:end: Mekh:=proc(K,x): (1-x^(2*K))*(1-w(K)*x^(2*K)+x^(4*K)):end: A1:=proc(K,x): normal((x^(2*K)-1)/(x-1)):end: B1:=proc(K,x) local i: expand(x^(2*K)*add((w(K)-2*i)*x^i,i=0..K)): end: C1:=proc(K,x) local i: expand(x^(3*K+1)*add((w(K)-2*K-2*(i+1)*(i+2))*x^i,i=0..K-2)): end: D1:=proc(K,x) local i: expand(x^(5*K-1)*add((2*K+1+2*(i+1)*(i+2))/x^i,i=0..K-1)):end: E1:=proc(K,x) local i: expand(x^(6*K-1)*add((2*i+3)/x^i,i=0..K-1)):end: EmilieC:=proc(K,x) : sort(A1(K,x)-B1(K,x)-C1(K,x)+D1(K,x)+E1(K,x))/Mekh(K,x):end: CheckEmilie:=proc(K,L) local gu,x,k,i: k:=2*K+1: gu:=Emilie(K,x) : gu:=taylor(gu,x=0,L+1): gu:=[seq(coeff(gu,x,i),i=0..L)]: gu:=[seq(gu[i]*gu[i-k]-gu[i-1]*gu[i-k+1]-gu[i-K]-gu[i-K-1],i=k+1..L)]: evalb(gu=[0$(L-k)]): end: As:=proc(K,x): normal((x^(2*K)-1)/(x-1)):end: Bs:=proc(K,x) local i: normal(sum((w(K)-2*i)*x^(i+2*K),i=0..K)): end: Cs:=proc(K,x) local i: normal(sum((w(K)-2*K-2*(i+1)*(i+2))*x^(3*K+1+i),i=0..K-2)): end: Ds:=proc(K,x) local i: normal(sum((2*K+1+2*(K-i)*(K-i+1))*x^(4*K+i),i=0..K-1)):end: Es:=proc(K,x) local i: normal(sum((2*(K-i)+1)*x^(5*K+i),i=0..K-1)):end: MoneS:=proc(K,x) : normal(As(K,x)-Bs(K,x)-Cs(K,x)+Ds(K,x)+Es(K,x)):end: EmilieS:=proc(K,x,Z) local T,B: T:= -(1-2*x+4*Z^4-4*Z^2-Z^6+8*Z^4*x^2-24*Z^4*x*K-4*Z^4*x*K^2+2*Z^4*x^2*K^2-8*Z^2*x^2*K+16*Z^4*x^2*K+16*Z^2*x*K+4*Z^2*x*K^2-2*Z^ 2*x^2*K^2+x^2-2*Z^2*K^2+2*Z^3*x^2+10*Z^2*x+2*Z^4*K^2+2*Z^3*x-2*Z^5*x^2-6*Z^2*x^2+8*Z^4*K-8*Z^2*K-3*Z^6*x^2-12*Z^4*x-2*Z^5*x +4*Z^6*x)/(x-1)^3: B:=(1-Z^2)*(1-w(K)*Z^2+Z^4): T/B: end: EmilieS1:=proc(K,x,Z) local luE,luO,T,B: luE:= -1+2*x-8*Z^4*x^2+2*Z^2*K^2-10*Z^2*x-2*Z^4*K^2+6*Z^2*x^2-8*Z^4*K+8*Z^2*K+3*Z^6*x^2+12*Z^4*x-4*Z^6*x+4*Z^2+Z^6-x^2-4*Z^4+24*Z ^4*x*K+4*Z^4*x*K^2-2*Z^4*x^2*K^2+8*Z^2*x^2*K-16*Z^4*x^2*K-16*Z^2*x*K-4*Z^2*x*K^2+2*Z^2*x^2*K^2: luO:=-2*Z^2*x^2-2*Z^2*x+2*Z^4*x^2+2*Z^4*x: T:=-expand(luE+luO*Z): B:=(1-Z^2)*(1-w(K)*Z^2+Z^4)*(1-x)^3: T/B: end: EmilieS2:=proc(K,x,Z) local luE,luO,B: luE:= -1+2*x-8*Z^4*x^2+2*Z^2*K^2-10*Z^2*x-2*Z^4*K^2+6*Z^2*x^2-8*Z^4*K+8*Z^2*K+3*Z^6*x^2+12*Z^4*x-4*Z^6*x+4*Z^2+Z^6-x^2-4*Z^4+24*Z ^4*x*K+4*Z^4*x*K^2-2*Z^4*x^2*K^2+8*Z^2*x^2*K-16*Z^4*x^2*K-16*Z^2*x*K-4*Z^2*x*K^2+2*Z^2*x^2*K^2: luO:=-2*Z^2*x^2-2*Z^2*x+2*Z^4*x^2+2*Z^4*x: luE:=subs(Z=Z^(1/2),luE); luO:=subs(Z=Z^(1/2),luO); B:=(1-Z)*(1-w(K)*Z+Z^2)*(1-x)^3: luE/B,luO/B: end: #GuessPol1(L,d,n,s0): guesses a polynomial of degree d in n for # the list L, such that L[i]=P[i] for i>=s0 for example, try: #GuessPol1([(seq(i,i=1..10),1,n,1); GuessPol1:=proc(L,d,n,s0) local P,i,a,eq,var: if d>=nops(L)-s0-2 then ERROR(`the list is too small`): fi: P:=add(a[i]*n^i,i=0..d): var:={seq(a[i],i=0..d)}: eq:={seq(subs(n=i,P)-L[i],i=s0..s0+d+3)}: var:=solve(eq,var): if var=NULL then RETURN(FAIL): fi: subs(var,P): end: #GuessPol(L,n,s0): guesses a polynomial of degree d in n for # the list L, such that L[i]=P[i] for i>=s0 for example, try: #GuessPol([(seq(i,i=1..10),n,1); GuessPol:=proc(L,n,s0) local d,gu: for d from 0 to nops(L)-s0-3 do gu:=GuessPol1(L,d,n,s0): if gu<>FAIL then RETURN(gu): fi: od: FAIL: end: #GrabPolHead(L,n): grabs the beginning of the list L #that is a polynomial (if found) together with the number of #terms it agrees with GrabPolHead:=proc(L,n) local L1,d,pol,i: pol:=FAIL: for d from 0 to nops(L)-4 while pol=FAIL do L1:=[op(1..d+4,L)]: pol:=GuessPol1(L1,d,n,1): od: if pol=FAIL then RETURN(FAIL): fi: for i from 1 to nops(L) do if L[i]<>subs(n=i,pol) then RETURN(pol,i-1): fi: od: pol,nops(L): end: #GuessPWP(L,n): guesses a piece-wise polynomial for a sequenec L #as far as it goes #starting at L[1], it outputs a list whose entries are #[[a,b],pol] which means that L[i]=pol(i) for a<=i<=b #For example, try: #GuessPWP([1$10,2$10],n) GuessPWP:=proc(L,n) local L1,pol,gu,mu,kodem: gu:=[]: L1:=L: mu:=GrabPolHead(L1,n): if mu=FAIL then RETURN(FAIL): fi: kodem:=0: while mu<>FAIL do pol:=mu[1]: gu:=[ op(gu), [ [kodem+1,kodem+mu[2]], expand(subs(n=n-kodem,pol)) ] ]: kodem:=kodem+mu[2]: L1:=[op(kodem+1..nops(L),L)]: mu:=GrabPolHead(L1,n): od: gu: end: #Paul(K,n): guesses a piece-wise polynomial beginning #to the Hindeman-Hogan sequence for k=2K+1, for example, #try: Paul(5,n); Paul:=proc(K,n) local L, n1: L:=[seq(anK(n1,K),n1=1..7*K+20)]: GuessPWP(L,n): end: #GlobalPaul(K,n): Given symbolic K and n conjecutures #the first 6K terms of the Heideman-Hogan sequence #Try: GlobalPaul(K,n); GlobalPaul:=proc(K,n) local K1,GU,LU,a,b,pol,i,j,LU1: GU:=[]: for K1 from 10 to 20 do GU:=[op(GU),[op(1..5,Paul(K1,n))]]: od: LU:=[]: for i from 1 to 5 do a:=GuessPol( [seq(GU[j][i][1][1],j=1..nops(GU))],K,1): b:=GuessPol( [seq(GU[j][i][1][2],j=1..nops(GU))],K,1): pol:=GuessPol( [seq(GU[j][i][2],j=1..nops(GU))],K,1): if a=FAIL or b=FAIL or pol=FAIL then RETURN(FAIL): fi: a:=expand(subs(K=K-9,a)): b:=expand(subs(K=K-9,b)): pol:=expand(subs(K=K-9,pol)): LU:=[op(LU),[[a,b],pol]]: od: for K1 from 1 to 20 do LU1:=subs(K=K1,LU): if [seq( seq(subs(n=i,LU1[j][2]),i=LU1[j][1][1]..LU1[j][1][2]) ,j=1..5)] <>[seq(anK(i,K1),i=1..6*K1+1)] then print(`It didn't work out at K=`, K1): RETURN(LU): fi: od: LU: end: Yafe:=proc(ope,N) local i,ope1,coe1,L: if ope=0 then RETURN(1,0): fi: ope1:=expand(ope): L:=degree(ope1,N): coe1:=coeff(ope1,N,L): ope1:=normal(ope1/coe1): ope1:=normal(ope1): ope1:= convert( [seq(factor(coeff(ope1,N,i))*N^i,i=ldegree(ope1,N)..degree(ope1,N))],`+`): factor(coe1),ope1: end: #findrec1(f,DEGREE,ORDER,n,N): guesses a recurrence operator annihilating #the sequence f of degree DEGREE and order ORDER #For example, try: findrec([seq(i,i=1..10)],0,2,n,N); findrec1:=proc(f,DEGREE,ORDER,n,N) local ope,var,eq,i,j,n0,kv,var1,eq1,mu,a: option remember: if (1+DEGREE)*(1+ORDER)+5+ORDER>nops(f) then ERROR(`Insufficient data for a recurrence of order`,ORDER, `degree`,DEGREE): fi: ope:=0: var:={}: for i from 0 to ORDER do for j from 0 to DEGREE do ope:=ope+a[i,j]*n^j*N^i: var:=var union {a[i,j]}: od: od: eq:={}: for n0 from 1 to nops(f)-ORDER do eq1:=0: for i from 0 to ORDER do eq1:=eq1+subs(n=n0,coeff(ope,N,i))*op(n0+i,f): od: eq:= eq union {eq1}: od: var1:=solve(eq,var): kv:={}: for i from 1 to nops(var1) do mu:=op(i,var1): if op(1,mu)=op(2,mu) then kv:= kv union {op(1,mu)}: fi: od: ope:=subs(var1,ope): if ope=0 then RETURN(FAIL): fi: ope:={seq(coeff(expand(ope),kv[i],1),i=1..nops(kv))} minus {0}: if nops(ope)>1 then RETURN(Yafe(ope[1],N)[2]): elif nops(ope)=1 then RETURN(Yafe(ope[1],N)[2]): else RETURN(FAIL): fi: end: #findCrec(f,N): Finds a linear recurrence equation with #constant coefficients for the sequence f #For example try: findCrec([1$20],N); findCrec:=proc(f,N) local d,gu,n: gu:=FAIL: for d from 0 to nops(f)-6 do gu:=findrec1(f,0,d,n,N): if gu<>FAIL then RETURN(gu): fi: od: FAIL: end: anKS:=proc(K,L) local n1:[seq(anK(n1,K),n1=1..L)]:end: #EmilieRec(K,N) : guesses a linear recurrence equation with #constant coefficients for the Heideman-Hogan sequence for K #Try: EmilieRec(1,N); EmilieRec:=proc(K,N) local gu,n1: gu:=[seq(anK(n1,K),n1=1..12*K+30)]: findCrec(gu,N): end: #EmilieRecG(K,N) : guesses a linear recurrence equation with #constant coefficients for the Heideman-Hogan sequence for symbolic K #Try: EmilieRecG(K,N); EmilieRecG:=proc(K,N) local K1,lu,i,j,z: lu:=[seq(EmilieRec(K1,N),K1=1..6)]: add(GuessPol([seq(coeff(lu[i],N,2*i*j),i=1..nops(lu))],K,1)*N^(2*K*j),j=0..3): end: #EmilieRecG1(K,z) : guesses a linear recurrence equation with #constant coefficients for the Heideman-Hogan sequence for symbolic K #Try: EmilieRecG(K,z); EmilieRecG1:=proc(K,z) local K1,lu,i,j,N: lu:=[seq(EmilieRec(K1,N),K1=1..6)]: add(GuessPol([seq(coeff(lu[i],N,2*i*j),i=1..nops(lu))],K,1)*z^j,j=0..3): end: #EmiliePaul(K,n): completes the proof of Paul Heideman and Emilie Hogan's #beautiful conjecture EmiliePaul:=proc(K,n) local lu,gu,i,j,z: print(`Theorem:`): print(`(Cojectured and alomost proved by Paul Heideman and Emilie Hogan,`): print(`in undergraduate research advised by Jim Propp, at the U. of Wisc.)`): print(``): print(` Let K be a positive integer`): print(`Define an integer sequence a(n) (n>=0) by the non-linear recurrence`): print(``): print(a(n)=(a(n-1)*a(n-2*K)+a(n-K)+ a(n-K-1))/a(n-2*K-1)): print(`subject to the initial conditions a(i)=1 for 0<=i<=2K`): print(`Then lo-and-behold all the terms are integers `): print(``): print(`Completion of the proof by Shalosh B. Ekhad `): lu:=GlobalPaul(K,n): gu:=EmilieRecG1(K,z): print(`Let b(n) be the sequence annihilated by the linear`): print(`recurrence equation with constant coefficients`): print(add(coeff(gu,z,i)*b(n+K*i),i=0..degree(gu,z))=0 ): print(`With the following initial conditions`): for j from 1 to nops(lu) do print(`For n in the discrete interval`): print(lu[j][1] ): print(`it equals the polynomial`): print(lu[j][2]): od: print(`Note that b(n) is well-defined and manifestly an integer`): print(` (by induction)`): print(` I claim that b(n)=a(n).`): print(`All we have to prove is that b(n) satisfies the same non-linear`): print(`recurrence as a(n), with the same initial conditions`): print(`The initial conditions are right, of course, and Paul and Emilie`): print(`have already proved that if `): print(b(n)*b(n-2*K-1)-b(n-1)*b(n-2*K)-b(n-K)-b(n-K-1)=0): print(`is true for n<=6K, then it is true for ever after.`): print(`So it only remains to prove this for n<=6K`): print(`But this is a routine verification`): print(`using the above explicit expressions for b(n), and is indeed true.`): print(` QED`): end: