####################################################################### ## ZEILBERGER: Save this file as ZEILBERGER. To use it, stay in the # ## same directory, get into Maple (by typing: maple ) # ## and then type: read ZEILBERGER : # ## Then follow the instructions given there # ## # ## Written by Mohamud Mohammed and Doron Zeilberger, # ## Rutgers University , # ## mohamudm at math dot rutgers dot edu. # ## zeilberg at math dot rutgers dot edu. # ####################################################################### print(`Written by Mohamud Mohammed and Doron Zeilberger.`): print(`First Written: July 22, 2004; tested for Maple 8 and 9. `): print(`Version of Aug. 10, 2004. `): print(): print(`This is ZEILBERGER, A Maple package`): print(`that implements the new-improved (and simplified) Zeilberger`): print(`algorithm for single-sum definite hypergeometric summation.`): print(`It does what zeil does in EKHAD and Zeilberger in the built-in`): print(`Maple package SumTools[Hypergeometric]. `): print(`It is one of the two packages`): print(`that accompany the article: Sharp Upper Bounds for the `): print(`Orders of the Recurrences Outputted by Zeilberger's algorithm`): print(`by Mohamud Mohammed and Doron Zeilberger,`): print(`available from the authors' websites. `): print(`The most current version is available on WWW at:`): print(` http://www.math.rutgers.edu/~zeilberg .`): print(`Please report all bugs to: zeilberg at math dot rutgers dot edu .`): print(): print(`For general help, and a list of the available functions,`): print(` type "ezra();". For specific help type "ezra(procedure_name)" .`): print(): ezra:=proc() if args=NULL then print(` ZEILBERGER: `): print(` A Maple package for `): print(` finding recurrences satisfied by definite hypergeomeric sums . `): print(`Using the Simplified Zeilberger algorithm.`): print(` For help with a specific procedure, type ezra(procedure_name); `): print(`The main procedure is Doron . `): print(): fi: if nargs=1 and args[1]=Doron then print(` Doron(F,k,n,N): Given a hypergeometric term F in the `): print(` variables k and n, and a symbol N for the shift operator in n:`): print(` [i.e. Nf(n):=f(n+1)], returns an operator ope(n,N) and`): print(` a certificate, a rational function R(n,k)`): print(` such that G(n,k):=R(n,k)*F(n,k) `): print(` satisfies ope(N,n)F(k,n)=G(n,k+1)-G(n,k)`): print(` A hypergeometric term is a product of factorials of the form`): print(`(an+bk+c)! where a is an integer, b is an integer,`): print(`and c is symbolic, times a polynomial in (n,k) times x^k for some`): print(`numeric or symbolic x times y^n for some numeric or symbolic y`): print(`One can also use binomial(n,k) and RF(a,k) (where RF(a,k))`): print(`is the rising factorial a(a+1)...(a+k-1) .`): print(``): print(` For example, try:`): print(` Doron(binomial(n,k)^2,k,n,N);`): print(` Doron(binomial(n,k)^3*2^k*(n^3+k),k,n,N);`): print(` Doron(1/k!^3/(n-k)!*(n^3+k),k,n,N);`): print(` Doron(RF(a,k)*RF(n,k),k,n,N);`): fi: if nargs=1 and args[1]=preDoron1 then print(` preDoron1(F,k,n,N): Given a hypergeometric term F in the `): print(`variables k and n, and a symbol N for the shift operator in n:`): print(` [i.e. Nf(n):=f(n+1)], returns an operator ope(n,N) and`): print(` a pre-certificate, a polynomial R(n,k)`): print(`from which one can construct the certifiate G(n,k)`): print(` such that ope(N,n)F(k,n)=G(n,k+1)-G(n,k)`): print(` A hypergeometric term is a product of factorials of the form`): print(`(an+bk+c)! where a is a NON-negative integer, b is an integer,`): print(`and c is symbolic, times a polynomial in (n,k) times x^k for some`): print(`numeric or symbolic x`): print(`One can also use binomial(n,k) and RF(a,k) (where RF(a,k))`): print(`is the rising factorial a(a+1)...(a+k-1) .`): print(``): print(` For example, try:`): print(` preDoron1(binomial(n,k)^2,k,n,N);`): print(` preDoron1(binomial(n,k)^3*2^k*(n^3+k),k,n,N);`): print(` preDoron1(1/k!^3/(n-k)!*(n^3+k),k,n,N);`): print(` preDoron1(RF(a,k)*RF(n,k),k,n,N);`): fi: end: ez:=proc():print(`RatioH(Ali,Bli,Cli,Dli,n,L,i) `): print(`c(Ali,Bli,Cli,Dli,POL,e,n,L)`): print(` a(Num,Den,z,k,n,L) , b(Num,Den,k,n,L) :`): print(`Equ1(Num,Den,POL,z,k,n,L,e,X)`): print(`Z1a(Ali,Bli,Cli,Dli,POL,z,k,n,N)`): print(`Z1(F,k,n,N),(F=[Num,Den,Pol,z]) `): print(`Z1L(F,k,n,L,N),(F=[Num,Den,Pol,z]) `): print(`Z1aL(Ali,Bli,Cli,Dli,POL,z,k,n,L,N)`): print(`hafokh(F,k,n)`): print(`preDoron1(F,k,n,N)`): print(`RecEq(F,k,n,N,low1,high1)`): end: RF:=proc(a,n):(a+n-1)!/(a-1)!:end: rf:=proc(a,n) local i: if n<0 then 0 elif n=0 then 1 else convert([seq(a+i,i=0..n-1)],`*`) fi: end: RatioH:=proc(Num,Den,n,L,i) local j: convert([seq( rf(Num[j]+1,i*coeff(Num[j],n,1)),j=1..nops(Num))],`*`)* convert([seq( rf( subs(n=n+i,Den[j])+1,(L-i)*coeff(Den[j],n,1)),j=1..nops(Den))],`*`): end: c:=proc(Num,Den,POL,e,n,L,w) local i:convert( [seq(e[i]*subs(n=n+i,POL)*RatioH(Num,Den,n,L,i)*w^i,i=0..L)],`+`): end: a:=proc(Num,Den,z,k,n,L) local j,gu: gu:=z: for j from 1 to nops(Num) do if coeff(Num[j],k,1) > 0 then gu:=gu*rf(Num[j]+1,coeff(Num[j],k,1)): fi: od: for j from 1 to nops(Den) do if coeff(Den[j],k,1) < 0 then gu:=gu*rf(subs({n=n+L,k=k+1},Den[j])+1,-coeff(Den[j],k,1)): fi: od: gu: end: b:=proc(Num,Den,k,n,L) local j,gu: gu:=1: for j from 1 to nops(Num) do if coeff(Num[j],k,1) < 0 then gu:=gu*rf(subs(k=k+1,Num[j])+1,-coeff(Num[j],k,1)): fi: od: for j from 1 to nops(Den) do if coeff(Den[j],k,1) > 0 then gu:=gu*rf(subs({n=n+L},Den[j])+1,coeff(Den[j],k,1)): fi: od: gu: end: Equ1:=proc(Num,Den,POL,z,k,n,L,e,X): a(Num,Den,z,k,n,L)*X(k+1)- subs(k=k-1,b(Num,Den,k,n,L))*X(k)- c(Num,Den,POL,e,n,L): end: yafe:=proc(ope,N) local i,ope1:ope1:=expand(ope): convert( [seq(factor(coeff(ope1,N,i))*N^i,i=ldegree(ope1,N)..degree(ope1,N))],`+`): end: FindDeg:=proc(a1,b1,c1,k) local degX,lam,A,B,d: degX:=degree(c1,k)-max(degree(a1,k),degree(b1,k)): if degree(a1,k)=degree(b1,k) and coeff(expand(a1),k,degree(a1,k))=coeff(expand(b1),k,degree(b1,k)) then lam:=coeff(expand(b1),k,degree(b1,k)): B:=coeff(expand(b1),k,degree(b1,k)-1): A:=coeff(expand(a1),k,degree(a1,k)-1): d:=normal((B-A)/lam): if type(d,integer) then degX:=max(degX+1,d): else degX:=degX+1: fi: fi: degX: end: Z1L:=proc(F,k,n,L,N) local e,x,j,degX,X,a1,b1,c1,gu,var1, var,ope,lu,mu,cert,eq,eqTry,varTry,Num,Den,POL,z,w: Num:=F[1]: Den:=F[2]: POL:=F[3]: z:=F[4]:w:=F[5]: ope:=convert([seq(e[j]*N^j,j=0..L)],`+`): a1:=a(Num,Den,z,k,n,L): b1:=subs(k=k-1,b(Num,Den,k,n,L)): c1:=c(Num,Den,POL,e,n,L,w): degX:=FindDeg(a1,b1,c1,k): X:=convert([seq(x[j]*k^j,j=0..degX)],`+`): gu:=expand(a1*subs(k=k+1,X)-b1*X-c1): var1:={seq(x[j],j=0..degX),seq(e[j],j=0..L)}: eq:={seq(coeff(gu,k,j),j=0..degree(gu,k))}: if type(z,symbol) then eqTry:=subs({z=2, n=5/3},eq): else eqTry:=subs(n=5/3,eq): fi: varTry:=solve(eqTry,var1): if subs(varTry,ope)=0 then RETURN(FAIL): fi: if type(z,symbol) then eqTry:=subs({z=3,n=7/5},eq): else eqTry:=subs(n=7/5,eq): fi: if subs(varTry,ope)=0 then RETURN(FAIL): fi: print(`Most likely there is an operator of order`, L, `Please be patinet.`): var:=solve(eq,var1): mu:=subs(var,ope),subs(var,X): if mu[1]=0 then RETURN(FAIL): fi: if mu[2]=0 then RETURN(mu): fi: lu:=normal(mu[1]/mu[2]): ope:=yafe(numer(lu),N): cert:=factor(denom(lu)): ope,cert: end: Z1:=proc(F,k,n,N) local L,gu: gu:=Z1L(F,k,n,0,N): for L from 1 while gu=FAIL do gu:=Z1L(F,k,n,L,N): od: gu: end: ####converting to the input needed by Z1### FindFactorial:=proc(Prod1) local Prod2,i,lu,lu1,lu2: Prod2:=factor(Prod1): if type(Prod2,function) and op(0,Prod2)=factorial then RETURN(Prod1): fi: for i from 1 to nops(Prod2) do lu:=op(i,Prod2): if type(lu,function) and op(0,lu)=factorial then RETURN(lu): fi: if type(lu,`^`) then lu1:=op(1,lu): lu2:=op(2,lu): if type(lu1,function) and op(0,lu1)=factorial then if not type(lu2,integer) and lu2>0 then RETURN(FAIL): else RETURN(lu1): fi: fi: fi: od: FAIL: end: FindPower:=proc(Prod1,k) local Prod2,i,lu: Prod2:=factor(Prod1): if Prod2=1 then RETURN(FAIL): fi: if type(Prod2,`^`) and degree(op(2,Prod1),k)=1 then RETURN(Prod1): fi: for i from 1 to nops(Prod2) do lu:=op(i,Prod2): if type(lu,`^`) and degree(op(2,lu),k)=1 then RETURN(lu): fi: od: FAIL: end: preDoron1:=proc(F,k,n,N) local F1: F1:=simplify(normal(convert(F,factorial)),power): F1:=hafokh(F1,k,n): if F1=FAIL then print(`Bad input`): RETURN(FAIL): fi: Z1(F1,k,n,N): end: Doron:=proc(F,k,n,N) local lu, F1,b1,kadima,L,ope,cert,c0: F1:=normal(convert(F,factorial)): F1:=hafokh(F1,k,n): lu:=preDoron1(F,k,n,N): L:=degree(lu[1],N): b1:=b(F1[1],F1[2],k,n,L): kadima:=RatioH(F1[1],F1[2],n,L,0): ope:=lu[1]: cert:=normal(lu[2]/kadima*subs(k=k-1,b1)/F1[3]): c0:=coeff(ope,N,degree(ope,N)): c0:=coeff(c0,n,degree(c0,n)): ope:=yafe(ope/c0,N): cert:=cert/c0: [ope,cert]: end: #RecEq(F,k,n,N,low1,high1): a recurrence equation for #sum(F(n,k),k=low1..high1) where low1 and high1 have the form #a+b*n, with b a non0negative integer RecEq:=proc(F1,k,n,N,low1,high1) local lu,ope,cert,i,i1,gu,F: F:=convert(F1,factorial): lu:=Doron(F,k,n,N): ope:=lu[1]: cert:=lu[2]: gu:=0: for i from 0 to degree(ope,N) do gu:=coeff(ope,N,i)* (-convert([seq(subs({n=n+i,k=low1+i1},F),i1=0..coeff(low1,n,1)*i-1)],`+`) +convert([seq(subs({n=n+i,k=high1+i1},F),i1=1..coeff(high1,n,1)*i)],`+`)): od: gu:=gu+ subs(k=high1+1,cert)*subs(k=high1+1,F)- subs(k=low1,cert)*subs(k=low1,F): gu:=normal(simplify(normal(gu))): ope,gu: end: hafokh:=proc(F,k,n) local F1,Num,Den,POL,z,F1t,F1b,lu,lu1,lu2,i,w, PosNum,NegNum,PosDen,NegDen: F1:=factor(normal(F)): F1t:=factor(numer(F1)): F1b:=factor(denom(F1)): Num:=[]: lu:=FindFactorial(F1t): while lu<>FAIL do lu1:=op(lu): if degree(lu1,{n,k})>1 or not type(coeff(lu1,k,1),integer) or not type(coeff(lu1,n,1),integer) then RETURN(FAIL): fi: Num:=[op(Num),lu1]: F1t:=normal(F1t/lu): lu:=FindFactorial(F1t): od: z:=1: lu:=FindPower(F1t,k): while lu<>FAIL do lu1:=op(1,lu): lu2:=op(2,lu): if degree(lu2,k)>1 then RETURN(FAIL): else z:=z*lu1^coeff(lu2,k,1): F1t:=normal(simplify(normal(F1t/lu1^(k*coeff(lu2,k,1))))): fi: lu:=FindPower(F1t,k): od: w:=1: lu:=FindPower(F1t,n): while lu<>FAIL do lu1:=op(1,lu): lu2:=op(2,lu): if degree(lu2,n)>1 then RETURN(FAIL): else w:=w*lu1^coeff(lu2,n,1): F1t:=normal(simplify(normal(F1t/lu1^(n*coeff(lu2,n,1))))): fi: lu:=FindPower(F1t,n): od: POL:=F1t: Den:=[]: lu:=FindFactorial(F1b): while lu<>FAIL do lu1:=op(lu): if degree(lu1,{n,k})>1 or not type(coeff(lu1,k,1),integer) or not type(coeff(lu1,n,1),integer) then RETURN(FAIL): fi: Den:=[op(Den),lu1]: F1b:=normal(F1b/lu): lu:=FindFactorial(F1b): od: lu:=FindPower(F1b,k): while lu<>FAIL do lu1:=op(1,lu): lu2:=op(2,lu): if degree(lu2,k)>1 then RETURN(FAIL): else z:=z/lu1^coeff(lu2,k,1): F1b:=normal(simplify(normal(F1b/lu1^(k*coeff(lu2,k,1))))): fi: lu:=FindPower(F1b,k): od: lu:=FindPower(F1b,n): while lu<>FAIL do lu1:=op(1,lu): lu2:=op(2,lu): if degree(lu2,k)>1 then RETURN(FAIL): else w:=w/lu1^coeff(lu2,n,1): F1b:=normal(simplify(normal(F1b/lu1^(n*coeff(lu2,n,1))))): fi: lu:=FindPower(F1b,n): od: POL:=normal(POL/F1b): if degree(POL,{n,k})=FAIL then RETURN(FAIL): fi: PosNum:=[]: NegNum:=[]: for i from 1 to nops(Num) do if coeff(Num[i],n,1)<0 then NegNum:=[op(NegNum),Num[i]]: else PosNum:=[op(PosNum),Num[i]]: fi: od: PosDen:=[]: NegDen:=[]: for i from 1 to nops(Den) do if coeff(Den[i],n,1)<0 then NegDen:=[op(NegDen),Den[i]]: else PosDen:=[op(PosDen),Den[i]]: fi: od: Num:=[op(PosNum),seq(expand((-1)*NegDen[i]-1),i=1..nops(NegDen))]: Den:=[op(PosDen),seq(expand((-1)*NegNum[i]-1),i=1..nops(NegNum))]: z:=z*(-1)^(add(coeff(NegDen[i],k,1),i=1..nops(NegDen)) +add(coeff(NegNum[i],k,1),i=1..nops(NegNum))): w:=w*(-1)^(add(coeff(NegDen[i],n,1),i=1..nops(NegDen)) +add(coeff(NegNum[i],n,1),i=1..nops(NegNum))): [Num,Den,POL,z,w]: end: