###################################################################### ## PureRec.txt Save this file as PureRec.txt to use it, # # stay in the # ## same directory, get into Maple (by typing: maple ) # ## and then type: read `PureRec.txt` # ## Then follow the instructions given there # ## # ## Written by Doron Zeilberger, Rutgers University , # ## DoronZeil at gmail dot com # ###################################################################### print(`First Written: Feb. 2022: tested for Maple 2020 `): print(): print(`This is PureRec.txt, A Maple package`): print(`accompanying Shalsoh B. Ekhad and Doron Zeilberger's article: `): print(`Linear-Time and Constant-Space Algorithms to compute Multi-Sequences that arise in Enumerative Combinatorics `): print(): print(`The most current version is available on WWW at:`): print(` http://sites.math.rutgers.edu/~zeilberg/tokhniot/PureRec.txt .`): print(`Please report all bugs to: DoronZeil at gmail dot com .`): print(): 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(` For specific help type "ezra(procedure_name);" `): print(): print(`------------------------------------`): print(`For a list of the STORY functions type: ezraS();`): print(` For specific help type "ezra(procedure_name);" `): print(): print(`------------------------------------`): ezra1:=proc() if args=NULL then print(`The SUPPORTING procedures are`): print(` CheckScheme, CoefD, CoefDc, INIc, INItay, SchemeD`): else ezra(args): fi: end: ezraS:=proc() if args=NULL then print(`The STORY procedures are`): print(` SchemeV`): else ezra(args): fi: end: ezra:=proc() if args=NULL then print(` PureRec.txt: A Maple package for computing with pure recurrence relations using the Apagodu-Zeilberger multivariate extension of the Almkvist-Zeilberger algorithm `): print(`The MAIN procedures are`): print(` EvalScheme, Scheme, SchemeC `): elif nargs=1 and args[1]=CheckScheme then print(`CheckScheme(R,n,x,K1,K2): Checks Scheme(R,n,x,m,M) for K2 different values in [0,K1]^n. Try:`): print(`CheckScheme(1/(1-x[1]-x[2]-x[3]-x[1]*x[2]*x[3])^(1/2),3,x,10,10);`): elif nargs=1 and args[1]=CoefD then print(`CoefD(F,x,m): Inputs a function of x[1], ..., x[n] (where m:=nops(m)) that has a nice Taylor expansion around the origin, and a list m of n (say) non-neg. integers, outputs`): print(`the Taylor coefficient (around the origin, in other words, the MacLaurin coefficient) of x[1]^m[1]*...*x[n]^m[n]. Try:`): print(`CoefD(1/(1-x[1]-x[2]-x[3]-x[4]+x[1]*x[2]*x[3]*x[4]),x,[2,3,4,5]);`): elif nargs=1 and args[1]=EvalScheme then print(`EvalScheme(S,m,M,m0): inputs a scheme S (let n:=nops(S)) in n dimension, phrased in terms of m and M (i.e. the discrete variables are m[1],...,m[n] and the corresponding shift operators are`): print(`M[1],..., M[n], and a list of non-negative integers m0. Evaluats it at m0. Try:`): print(`EvalScheme([ [2/M[1],3/M[2],4/M[3]],[[[1]]],m,M,[2,2,2]);`): print(`EvalScheme([[1/M[1]+1/M[1]^2],[1,1]],m,M,[3]);`): elif nargs=1 and args[1]=INIc then print(`INIc(P,x,L): Given a Laurent polynomial in the list of variables x, (of size k, say) and a list L of size k+1, outputs`): print(`a list-of-lists-....L[m1][m2]..[m[k+1]] is the coefficient of x[1]^m[1]*...*x[k]^m[k] in P^m[k+1]`): print(`The initial conditions up. Try: `): print(`INIc(x[1]+1+x[1],[x[1]],[2,3]);`); elif nargs=1 and args[1]=INItay then print(`INItay(R,x,A): Given a function R in the list of variables x[1],..., x[n] (for some n:=nops(x)) finds the list of lists...of lists, let's call it L, such that for each 0<=a[1]FAIL then RETURN(gu): fi: od: FAIL: end: MAZ:=proc(POL,H,rat,x,n,N,pars) local gu,L: for L from 0 do gu:=MAZ1(POL,H,rat,x,n,N,L,pars): if gu<>FAIL then RETURN(gu): fi: od: end: CheckMAZ:=proc(POL,H,rat,x,n,N,pars) local F,gu,luL,luR,R,ope,i: F:=H*rat^n: gu:=MAZ(POL,H,rat,x,n,N,pars): if gu=FAIL then RETURN(FAIL): fi: ope:=gu[1]: R:=gu[2]: luL:=normal(add(subs(n=n+i,POL)*coeff(ope,N,i)*normal(simplify(subs(n=n+i,F)/F)),i=0..degree(ope,N))): luR:=normal(add( normal(diff(R[i]*F,x[i])/F ), i=1..nops(R))): evalb(normal(luL/luR)=1): end: #MAZ1deg(POL,H,rat,x,n,N,L,pars,deg): Given a polynomial POL of the discrete variable n #and the continuous variables in x #and a pure-hyperexponential function H of the variables in x, and a rational function #Rat of x, and a shift operator N, and a non-neg. integer L #returns FAIL or, if there is one, an operator ope(N,n) of order L and #a list of rational functions R, such that F:=POL*H*rat^n satisfies #ope(N,n)F=sum(diff(F*R[i],x[i]),i=1..nops(R)) . #For example, try MAZ1(1,exp(-x),x,[x],n,N,1,{}) MAZ1deg:=proc(POL,H,rat,x,n,N,L,pars,deg) local s,t,h,e,i,Hbar,gu,X,a,var,q,r,eq,ope,var1,ku,i1,eqN,var1N,opeN,bilti,meka: s:=numer(rat): t:=denom(rat): ope:=add(e[i]*N^i,i=0..L): h:=convert([seq(e[i]*subs(n=n+i,POL)*s^i*t^(L-i),i=0..L)],`+`): Hbar:=H*s^n/t^(n+L): gu:=[]: for i from 1 to nops(x) do gu:=[op(gu),normal(simplify(diff(Hbar,x[i])/Hbar))]: od: q:=[]: r:=[]: for i from 1 to nops(gu) do q:=[op(q),numer(gu[i])]: r:=[op(r),denom(gu[i])]: od: var:={}: X:=[]: for i from 1 to nops(x) do ku:=GenPol(x,a[i],deg[i]): X:=[op(X),ku[1]]: var:=var union ku[2]: od: var:=var union {seq(e[i],i=0..L)}: gu:=h: for i from 1 to nops(x) do gu:=expand(normal(gu-(diff(r[i],x[i])+q[i])*X[i]/r[i]-r[i]*diff(X[i]/r[i],x[i]))): od: eq:=Extract1(numer(gu),x): eqN:=subs(n=9/17,eq): eqN:=subs({seq(pars[i]=1/(i^2+3),i=1..nops(pars))},eqN): var1N:=solve(eqN,var): opeN:=subs(var1N,ope): if opeN=0 then RETURN(FAIL): fi: var1:=solve(eq,var): ope:=subs(var1,ope): X:=subs(var1,X): if ope=0 then RETURN(FAIL): fi: bilti:={}: for i from 1 to nops(var1) do if op(1,op(i,var1))=op(2,op(i,var1)) then bilti:=bilti union {op(1,op(i,var1))}: fi: od: for i from 1 to nops(bilti) do if coeff(ope,bilti[i],1)<>0 then ope:=coeff(ope,bilti[i],1): X:=[seq(coeff(X[i1],bilti[i],1),i1=1..nops(X))]: meka:=coeff(ope,N,degree(ope,N)): ope:=expand(normal(ope/meka)): ope:=yafe(ope,N): X:=[seq(normal(X[i1]/meka/t^L),i1=1..nops(X))]: RETURN(ope,X): fi: od: end: #MAZ(POL,H,rat,x,n,pars,F,A,R) MAZpaper:=proc(POL,H,rat,x,n,pars,A,R) local gu,F,F1,ope,i,N: print(``): F1:=H*rat^n: gu:=MAZ(POL,H,rat,x,n,N,pars): ope:=gu[1]: if gu=FAIL then RETURN(FAIL): fi: print(`A Linear Recurrence Equation for an Integral in`, nops(x), ` variables `): print(``): print(`By Shalosh B. Ekhad `): print(``): print(`Let `): print(F(n,op(x))=F1): print(`and let`, A(n), `be its definite integral of`): print(POL*F(n,op(x))): print(`with respect to the continuous`): print(` variables `, op(x)): print(``): print(A(n) , `satisfies the following homogeneous linear recurrence with`): print(`polynomial coefficients: `): print(``): print(add(coeff(ope,N,i)*A(n+i),i=0..degree(ope,N))=0): print(``): print(`Proof: We cleverly constuct the rational functions`): for i from 1 to nops(gu[2]) do print(R[i](n,op(x))=gu[2][i]): od: print(`With the motive that`): print(add(coeff(ope,N,i)*F(n+i,op(x)),i=0..degree(ope,N))= add(D[x[i]](R[i](n,op(x))*F(n,op(x))),i=1..nops(x))): print(``): print(`(Check!)`): print(`and the theorem follows upon integrating with respect to`, op(x)): print(` QED! `): end: ###END FROM MultiAlmkvistZeilberger #CoefD(F,x,m): Inputs a function of x[1], ..., x[n] (where m:=nops(m)) that has a nice Taylor expansion around the origin, and a list m of n (say) non-neg. integers, outputs #the Taylor coefficient (around the origin, in other words, the MacLaurin coefficient) of x[1]^m[1]*...*x[n]^m[n]. Try: #CoefD(1/(1-x[1]-x[2]-x[3]-x[4]+x[1]*x[2]*x[3]*x[4]),x,[2,3,4,5]); CoefD:=proc(F,x,m) local n,i,F1: n:=nops(m): F1:=F: for i from 1 to n do F1:=taylor(F1,x[i]=0,m[i]+2): F1:=expand(normal(coeff(F1,x[i],m[i]))): od: F1: end: #INItay(R,x,A): Given a function R in the list of variables x[1],..., x[n] (for some n:=nops(x)) finds the list of lists...of lists, let's call it L, such that for each 0<=a[1]n then RETURN(FAIL): fi: if n=1 then RETURN(EvalScheme1(S,m[1],M[1],m0[1])): fi: ope1:=S[1][1]: A1:=-ldegree(ope1,M[1]): if m0[1]CoefD(R,x,pt) then print(`pt failed `): print( [EvalScheme(S,m,M,pt),CoefD(R,x,pt)]): RETURN(false): fi: od: true: end: #SchemeV(R,n,x): A verbose version of Scheme(R,n,x,m,M) with illustration. try: #SchemeV(1/(1-x[1]-x[2]-x[1]*x[2])^(1/3),2,x); SchemeV:=proc(R,n,x) local gu,m,M,F,i,t0,t1, ope,i1,i2,i3,INI,pt: print(`A Pure Recurrence Scheme that enables Linear-Time and Constant-Space Calculation of the Taylor coefficients of the function with`, n, `variables `, seq(x[i],i=1..n)): print(``): print(R): print(``): print(`By Shalosh B. Ekhad `): print(``): print(`Theorem: Let `, F(seq(m[i],i=1..n)), ` be the coefficient of`, mul(x[i]^m[i],i=1..n), ` in the Taylor expansion (around the origing) of the multivariable function (that may also be viewed as a formal power series) of`, seq(x[i],i=1..n) ): print(``): print(R): print(``): t0:=time(): gu:=Scheme(R,n,x,m,M): t1:=time()-t0: print(`The following PURE recurrence relations hold in each of the`, n, `discrete variables`, seq(m[i],i=1..n)): print(``): for i from 1 to n do ope:=gu[1][i]: print(``): print(F(seq(m[i1],i1=1..n))= add(coeff(ope,M[i],-i1)*F(seq(m[i2],i2=1..i-1),m[i]-i1,seq(m[i2],i2=i+1..n)),i1=1..-ldegree(ope,M[i]) ) ): print(``): od: print(``): print(`and in Maple notation `): print(``): for i from 1 to n do ope:=gu[1][i]: print(``): lprint(F(seq(m[i1],i1=1..n))= add(coeff(ope,M[i],-i1)*F(seq(m[i2],i2=1..i-1),m[i]-i1,seq(m[i2],i2=i+1..n)),i1=1..-ldegree(ope,M[i]) ) ): print(``): od: print(``): print(`Subject to the initial conditions`): INI:=gu[2]: if n=1 then print(seq(F(i1)=INI[i1+1],i1=0..nops(INI)-1)): elif n=2 then print(seq(seq(F(i1,i2)=INI[i1+1][i2+1],i2=0..nops(INI[i1+1])-1),i1=0..nops(INI)-1)): elif n=3 then print(seq(seq(seq(F(i1,i2,i3)=INI[i1+1][i2+1][i3+1],i3=0..nops(INI[i1+1][i2+1])-1),i2=0..nops(INI[i1+1])-1),i1=0..nops(INI)-1)): else print(INI): fi: print(``): print(`--------------------------------------------`): print(``): print(`By the way, it took`, t1, `seconds to geneate the scheme. `): print(``): print(`--------------------------------------------`): print(``): t0:=time(): print(`Using this scheme we can compute any value very fast. For example`): pt:=[seq(1000*i1,i1=1..n)]: print(``): print(F(op(pt))=EvalScheme(gu,m,M,pt)): print(``): print(`This took`, time()-t0, `seconds. `): print(``): end: #SchemeD(R,n,x,m,M): Let n be a positive integer (the second input parameter) and let R be a function of x[1],..., x[n] #that has a "nice" Taylor expansion around the origin in n-space, uses the Apagodu-Zeilberger multivariable extension of #the Almkvist-Zeilberger algorithm to output a PURE scheme phrased in terms of the discrete variables m #and the shift operator M for the coefficient of (x[1]*...*x[n])^m #SchemeD(1/(1-x[1]-x[2]-x[3]-x[1]*x[2]*x[3])^(1/2),3,x,m,M); SchemeD:=proc(R,n,x,m,M) local i,j,lu,INI: lu:=MAZ(1,R/mul(x[j],j=1..n),1/mul(x[j],j=1..n),[seq(x[j],j=1..n)],m,M,{})[1]: lu:=expand(1-subs(m=m-degree(lu,M),lu)/M^degree(lu,M)): lu:=add(factor(coeff(lu,M,-j))*M^(-j),j=1..-ldegree(lu,M)): INI:=[seq(CoefD(R,x,[i$n]),i=0..-ldegree(lu,M)-1)]: lu:=subs({M=M[1],m=m[1]},lu): [[lu],INI]: end: