1 /* Zeilberger's algorithm */
3 /* RISC Institute, Linz, Austria */
4 /* by Fabrizio Caruso */
8 /* Routine that generates a parametrized function */
9 parShiftAux(f,n,parName,degree,count) :=
10 if count = degree then
11 parName[count] * subst(n+count,n,f)
13 parName[count]*subst(n+count,n,f) +
14 parShiftAux(f,n,parName,degree,count+1);
17 /* Short name macro for parShift */
18 parShift(f,n,parName,degree) ::=
19 buildq([f,n,parName,degree],
20 parShiftAux(f,n,parName,degree,0));
24 /* It normalizes a solution by clearing the denominators */
25 normalizeGZ(Gsol,Zsol) :=
26 block([i,lcm,Gres,Zres],
28 for i : 1 thru length(Gsol) do
30 lcm : lcm(lcm,denom(Gsol[i]))
32 for i : 1 thru length(Zsol) do
34 lcm : lcm(lcm,denom(Zsol[i]))
41 for i : 1 thru length(Gsol) do
42 Gres : endcons(factor(Gsol[i] * lcm), Gres),
43 for i : 1 thru length(Zsol) do
44 Zres : endcons(factor(Zsol[i] * lcm), Zres),
51 /* Constant Factor correction for the Zeilberger solutions */
52 constFactCorr(sol,constFact,var) :=
53 block([num,den,res,i,j,numCorr,denCorr],
54 num : first(constFact),
55 den : second(constFact),
59 /* Remark: length(sol)-1 = ZAnsatzDegree */
61 for i : 1 thru length(sol) do
65 numCorr : numCorr * subst(var+j-1,var,num),
68 for j : 1 thru length(sol)-i do
69 denCorr : denCorr * subst(var+length(sol)-1-j,var,den),
71 res : endcons(factor(sol[i]/numCorr/denCorr),res)
80 /* Separates the Gosper and Zeilberger Ansatz coefficients */
81 separateGZVerboseOpt(Gres,GLength,ZLength,mode) :=
87 if mode>= verbose then
89 print("Gres : " , Gres),
90 print("GLength : " , GLength),
91 print("ZLength : " , ZLength)
93 for i : 1 thru GLength do
96 print("Inserting ", Gres[i], " in the Gosper-list"),
97 GList : endcons(rhs(Gres[i]),GList)
100 for i : GLength+1 thru GLength+ZLength do
102 if mode>=verbose then
103 print("Inserting ", Gres[i], " in the Zeilberger-list"),
104 ZList : endcons(rhs(Gres[i]),ZList)
108 return([GList,ZList])
114 /* It creates the specific polynomial p */
118 for i : 0 thru length(ZAnsatzCoeff)-1 do
119 Spec : subst(factor(expand(ZAnsatzCoeff[i+1])),'_z[i],Spec),
123 printParGosperSummary(p,sysSol,mode) :=
125 print("--------------------------"),
126 print("Zeilberger-related summary"),
127 print("(1) reconstructed p : ", p),
128 print("(2) dimension of the solution : ", length(sysSol)),
129 if mode>= verbose then
130 print("(3) solution : ", sysSol)
134 /* Zeilberger's algorithm ("Parametrized" Gosper's algorithm) */
135 parGosperVerboseOpt(f,k,n,ZAnsatzDegree,mode) :=
138 parF, /* Parametrized function */
139 parFRat, /* Parametrized quotient function */
140 nF,nFTrivial, numNF,denNF,constDenNF,
141 GosperForm, /* Gosper form */
142 p,q,r, /* Gosper form's polynomials */
143 GAnsatzDegree, /* Gosper Ansatz' degree */
144 Gpoly, /* Gosper polynomial */
145 sysSol, /* Solution to the Gosper system */
146 normSysSol, /* Normalized solution to the Gosper system */
147 SpSysSol, /* Specific solution to the Gosper system */
148 GAnsatzCoeff, /* Gosper Ansatz coefficients */
149 ZAnsatzCoeff, /* Zeilberger Ansatz coeffiecients */
150 GZAnsatzCoeff, /* Couple (GAnsatzCoeff,ZAnsatzCoeff) */
151 GosperSol, /* Solution to the Gosper equation */
152 tlscope, /* Solution to the telescoping problem */
153 _g, /* Gosper Ansatz coefficients */
154 _z, /* Zeilberger Ansatz coefficients */
165 if not(dependent(f,n)) and ZAnsatzDegree>0 and warnings then
167 print("---------------------------------------------"),
169 print("The input does not depend on ",n,"."),
170 print("Maybe you should first try Gosper's algorithm."),
171 print("---------------------------------------------")
175 if ZAnsatzDegree = 0 then
177 if mode>=verbose then
178 print("Invoking Gosper's algorithm"),
179 GosperSol : GosperVerboseOpt(f,k,mode),
180 if GosperSol=NO_HYP_SOL then
183 if GosperSol = NON_HYPERGEOMETRIC then
184 return([NON_PROPER_HYPERGEOMETRIC])
186 return([[GosperSol,[1]]])
189 nFTrivial : niceForm(f,n,'_z,ZAnsatzDegree,k),
191 if nFTrivial = [] then
193 if warnings then print(f, " is not hypergeometric in ", n),
194 return([NON_PROPER_HYPERGEOMETRIC])
200 if mode >= verbose then
202 print("NICE FORM : ", nF),
203 print("constant parts : [", nFTrivial[2], ",", nFTrivial[3],"]")
207 denNF : factor(denom(nF)),
209 if mode >= very_verbose then
210 print("denNF : ", factor(denNF)),
212 if mode >= very_verbose then
213 print("Considering now : ", factor(f/denNF)),
215 parFRat : shiftQuoOnlyHyp(factor(f/denNF),k), /* We temporarily forget about the factor numNF */
219 if warnings then print(f, " is not hypergeometric in ", k),
220 return([NON_PROPER_HYPERGEOMETRIC])
224 if mode >= verbose then
225 print("--- Shift quotient computed! : " , parFRat),
228 /* Computation of the Gosper form */
230 GosperForm: makeGosperFormVerboseOpt(parFRat,k,mode-1),
233 gfP: takeP(GosperForm),
235 if mode >= very_verbose then
236 print("gfP :", factor(gfP)),
239 p: gfP * numNF, /* Now we remember that we "forgot" the factor numNF and compute the real p */
241 q: takeQ(GosperForm),
243 r: takeR(GosperForm),
245 if mode>= verbose then
253 /* Solution of the Gosper equation */
254 GAnsatzDegree: AnsatzDegreeVerboseOpt(p,q,r,k,mode-1),
259 if integerp(GAnsatzDegree) and GAnsatzDegree >= 0 then
260 Gpoly: GosperPoly(p,q,r,k,'_g,GAnsatzDegree),
263 if mode >= very_verbose then
264 print("Gosper's equation : ", Gpoly),
272 /* --------------------------------------------------------------------- */
274 if mod_test and (ZAnsatzDegree<=mod_threshold) then
276 modulus : mod_big_prime,
277 test_Gpoly : polymod(subst(ev_point,n,Gpoly),mod_big_prime),
281 if test_Gpoly = 0 then
284 if mode>= very_verbose then
285 print("modulus : ", modulus),
286 sysSol : SolveZSysVerboseOpt(test_Gpoly,
287 '_g,GAnsatzDegree+1,'_z,ZAnsatzDegree+1,k,
288 modular_linear_solver,mode-1),
291 if mode>= very_verbose then
292 print("numerical sysSol : ", sysSol),
295 if mode >= verbose then
296 print("no solution in the numerical test!"),
300 if mode >= verbose then
302 print("solution found in the numerical test!"),
303 print("sysSol : ", sysSol)
306 /* End of numerical test */
307 /* --------------------------------------------------------------------- */
310 sysSol : SolveZSysVerboseOpt(Gpoly,'_g,GAnsatzDegree+1,'_z,ZAnsatzDegree+1,k,
311 linear_solver,mode-1),
313 if mode>= very_verbose then
317 print("%rnum_list : ", %rnum_list)
320 if warnings and length(sysSol)>1 then
322 print("------------------------------------------------------------"),
324 print("Multiple solutions have been found."),
325 print("A lower order might probably work and yield fewer solutions."),
326 print("------------------------------------------------------------")
329 SpSysSol : sysSol, /* non-sense? */
332 for i: 1 thru length(sysSol) do
334 if mode>=very_verbose then
336 print("Solution no. ", i),
339 SpSysSol : sysSol[i],
342 GZAnsatzCoeff:separateGZVerboseOpt(SpSysSol,GAnsatzDegree+1,ZAnsatzDegree+1,
345 GAnsatzCoeff: GZAnsatzCoeff[1],
346 ZAnsatzCoeff: GZAnsatzCoeff[2],
348 if mode>=very_verbose then
350 print("GAnsatzCoeff : ", GAnsatzCoeff),
351 print("ZAnsatzCoeff : ", ZAnsatzCoeff)
355 ZAnsatzCoeff : constFactCorr(ZAnsatzCoeff,[nFTrivial[2],nFTrivial[3]],n),
357 if mode>=very_verbose then
358 print("correction : ",[nFTrivial[2],nFTrivial[3]]),
362 constDenNF : product(subst(n+i-1,n,nFTrivial[3]),i,1,ZAnsatzDegree),
365 if mode>=very_verbose then
367 print("constDenNF : ", constDenNF),
368 print("CORRECTED ZAnsatzCoeff : ", ZAnsatzCoeff)
371 GZAnsatzCoeff : normalizeGZ(GAnsatzCoeff,ZAnsatzCoeff),
372 GAnsatzCoeff : GZAnsatzCoeff[1],
374 ZAnsatzCoeff : GZAnsatzCoeff[2],
380 SolDeg : getDegrees(SpSysSol,GAnsatzDegree+1,ZAnsatzDegree+1,n),
381 print("Degrees of the Gosper parameters"),
382 prettyPrint(SolDeg[1]),
384 print("Degrees of the Zeilberger parameters"),
385 prettyPrint(SolDeg[2])
390 /* GSol: factor(expand(sol2Poly(GAnsatzCoeff,k))), */
391 GSol : sol2Poly(GAnsatzCoeff,k),
392 if mode>= verbose then
393 print("GSol : ", GSol),
400 tlscope : factor(GSol * r / gfP / denNF / constDenNF),
404 if trivial_solutions or (not(tlscope=0) and
405 not(apply("and",map(lambda([x],is(x=0)),ZAnsatzCoeff)))) then
408 if simplified_output then
409 allSols : endcons([ratsimp(tlscope),ZAnsatzCoeff],allSols)
411 allSols : endcons([tlscope,ZAnsatzCoeff],allSols)
416 print("----------------------------------------"),
418 print("The algorithm has discarted a trivial solution"),
419 print("with zero certificate."),
421 if mode>= very_verbose then
422 print("The coefficients of the recurrence are: ", ZAnsatzCoeff),
423 print("----------------------------------------")
427 print("-------------------------------------------"),
429 print("The algorithm has discarted a trivial solution"),
430 print("whose recurrence only has zero coefficients."),
432 if mode>= very_verbose then
434 print("The certificate is: "),
437 print("-------------------------------------------")
441 if mode>=summary then
443 printGosperSummary(parFRat,GosperForm,GAnsatzDegree,Gpoly,GSol,mode-1),
444 printParGosperSummary(p,sysSol,mode)
453 /* It builds the l.h.s. of the recursion of the summmand */
454 /* out of the solution of "parGosper" */
455 makeRecursionAux(f,ZCoeff,n,count) :=
460 makeRecursionAux(subst(n+1,n,f),Rest(ZCoeff),n,count-1) ;
463 /* Front-end macro of makeRecursionAux */
464 makeRecursion(f,ZCoeff,n) ::=
466 makeRecursionAux(f,ZCoeff,n,length(ZCoeff))
470 UnEvMakeRecursion(f,n,ord) :=
472 rec : concat(concat("a[",0,"]"),"f(n,k)"),
473 for i : 1 thru ord do
474 rec : concat(rec, "+", concat(concat("a[",i,"]"),concat("f(",string(n+i),",k)"))),
478 /* It builds the l.h.s. of the recursion of the summmand */
479 /* out of the solution of "parGosper" */
480 makeRecursionOpAux(f,ZCoeff,n,count,upperBound) :=
481 if count = upperBound then
482 first(ZCoeff) * eta[n]^count ( f )
484 first(ZCoeff) * eta[n]^count ( f ) +
485 makeRecursionOpAux(f,Rest(ZCoeff),n,count+1,upperBound) ;
488 /* Front-end macro of makeRecursionAux */
489 makeRecursionOp(f,ZCoeff,n) :=
492 makeRecursionOpAux(f,ZCoeff,n,count,length(ZCoeff))
496 printZeilbergerSummary(f,parGRes) :=
499 print("---------------------------"),
500 print("Iterated-Zeilberger summary"),
501 print(UnEvMakeRecursion(f,n,length(parGRes[1][2])-1)," = ",
502 Delta[k]("cert(n,k)"*"f(n,k)")),
505 print("f(n,k) = ", f),
507 print("cert(n,k) = ", parGRes[1][1]),
511 for i : 0 thru length(parGRes[1][2])-1 do
512 print("a[",i,"] = ", parGRes[1][2][i+1])
516 /* Front-end of the Zeilberger's algorithm with verbosity option */
517 ZeilbergerVerboseOpt(f,k,n,mode) :=
525 if Gosper_in_Zeilberger then
530 if warnings and not(dependent(f,n)) then
532 print("-------------------------------------------------"),
534 print(f, " does not depend on ", n,"."),
535 print("The flag Gosper_in_Zeilberger is set to false."),
536 print("You might find a solution with Gosper's algorithm"),
537 print("-------------------------------------------------")
545 if mode>= verbose then
546 print( "max_ord : " , max_ord ) ,
548 for ord : start step 1 while (parGRes = []) and ( ord <= max_ord ) do
550 if mode>= verbose then
552 print("----------------------------------------"),
553 print("Searching a recurrence with order : " , ord )
556 parGRes : parGosperVerboseOpt(f,k,n,ord,mode-1),
557 if mode >= verbose then
559 print("Gosper result with order : ", ord, " is : "),
564 if mode >= summary then
565 printZeilbergerSummary(f,parGRes),
572 /* Non verbose version of Zeilberger's algorithm */
573 ZeilbergerSummary([args]):=
578 if length(args)=3 then
579 ZeilbergerVerboseOpt(f,k,n,summary)
581 parGosperVerboseOpt(f,k,n,fourth(args),summary)
585 /* Non verbose version of Zeilberger's algorithm */
586 ZeilbergerVerbose([args]):=
591 if length(args)=3 then
592 ZeilbergerVerboseOpt(f,k,n,verbose)
594 parGosperVerboseOpt(f,k,n,fourth(args),verbose)
598 /* Non verbose version of Zeilberger's algorithm */
599 ZeilbergerVeryVerbose([args]):=
604 if length(args)=3 then
605 ZeilbergerVerboseOpt(f,k,n,very_verbose)
607 parGosperVerboseOpt(f,k,n,fourth(args),very_verbose)
611 /* Non verbose version of Zeilberger's algorithm */
612 ZeilbergerExtra([args]):=
617 if length(args)=3 then
618 ZeilbergerVerboseOpt(f,k,n,extra)
620 parGosperVerboseOpt(f,k,n,fourth(args),extra)
624 /* Non verbose version of Zeilberger's algorithm */
630 if length(args)=3 then
631 ZeilbergerVerboseOpt(f,k,n,nonverbose)
633 parGosperVerboseOpt(f,k,n,fourth(args),nonverbose)
637 /* Short name macro for verbose parGosper */
638 parGosperVerbose(f,k,n,degree)::=
639 buildq([f,k,n,degree],
640 parGosperVerboseOpt(f,k,n,degree,verbose));
643 /* Short name macro for very verbose parGosper */
644 parGosperVeryVerbose(f,k,n,degree)::=
645 buildq([f,k,n,degree],
646 parGosperVerboseOpt(f,k,n,degree,very_verbose));
649 /* Short name macro for the linear system version of parGosper */
650 parGosperExtra(f,k,n,degree) ::=
651 buildq([f,k,n,degree],
652 parGosperVerboseOpt(f,k,n,degree,extra));
654 /* Short name macro for the summary version of parGosper */
655 parGosperSummary(f,k,n,degree) ::=
656 buildq([f,k,n,degree],
657 parGosperVerboseOpt(f,k,n,degree,summary));
660 /* Short name for the non-verbose version of parGosper */
661 parGosperNonVerbose(f,k,n,degree) ::=
662 buildq([f,k,n,degree],
663 parGosperVerboseOpt(f,k,n,degree,nonverbose));
665 parGosper(f,k,n,order) ::=
666 buildq([f,k,n,order],
667 parGosperVerboseOpt(f,k,n,order,nonverbose));
669 /* Pretty print of a list */
673 for i : 1 step 1 thru len do