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,lcm],
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 */
164 if not(dependent(f,n)) and ZAnsatzDegree>0 and warnings then
166 print("---------------------------------------------"),
168 print("The input does not depend on ",n,"."),
169 print("Maybe you should first try Gosper's algorithm."),
170 print("---------------------------------------------")
174 if ZAnsatzDegree = 0 then
176 if mode>=verbose then
177 print("Invoking Gosper's algorithm"),
178 GosperSol : GosperVerboseOpt(f,k,mode),
179 if GosperSol=NO_HYP_SOL then
182 if GosperSol = NON_HYPERGEOMETRIC then
183 return([NON_PROPER_HYPERGEOMETRIC])
185 return([[GosperSol,[1]]])
188 nFTrivial : niceForm(f,n,'_z,ZAnsatzDegree,k),
190 if nFTrivial = [] then
192 if warnings then print(f, " is not hypergeometric in ", n),
193 return([NON_PROPER_HYPERGEOMETRIC])
199 if mode >= verbose then
201 print("NICE FORM : ", nF),
202 print("constant parts : [", nFTrivial[2], ",", nFTrivial[3],"]")
206 denNF : factor(denom(nF)),
208 if mode >= very_verbose then
209 print("denNF : ", factor(denNF)),
211 if mode >= very_verbose then
212 print("Considering now : ", factor(f/denNF)),
214 parFRat : shiftQuoOnlyHyp(factor(f/denNF),k), /* We temporarily forget about the factor numNF */
218 if warnings then print(f, " is not hypergeometric in ", k),
219 return([NON_PROPER_HYPERGEOMETRIC])
223 if mode >= verbose then
224 print("--- Shift quotient computed! : " , parFRat),
227 /* Computation of the Gosper form */
229 GosperForm: makeGosperFormVerboseOpt(parFRat,k,mode-1),
232 gfP: takeP(GosperForm),
234 if mode >= very_verbose then
235 print("gfP :", factor(gfP)),
238 p: gfP * numNF, /* Now we remember that we "forgot" the factor numNF and compute the real p */
240 q: takeQ(GosperForm),
242 r: takeR(GosperForm),
244 if mode>= verbose then
252 /* Solution of the Gosper equation */
253 GAnsatzDegree: AnsatzDegreeVerboseOpt(p,q,r,k,mode-1),
258 if integerp(GAnsatzDegree) and GAnsatzDegree >= 0 then
259 Gpoly: GosperPoly(p,q,r,k,'_g,GAnsatzDegree),
262 if mode >= very_verbose then
263 print("Gosper's equation : ", Gpoly),
271 /* --------------------------------------------------------------------- */
273 if mod_test and (ZAnsatzDegree<=mod_threshold) then
275 modulus : mod_big_prime,
276 test_Gpoly : polymod(subst(ev_point,n,Gpoly),mod_big_prime),
280 if test_Gpoly = 0 then
283 if mode>= very_verbose then
284 print("modulus : ", modulus),
285 sysSol : SolveZSysVerboseOpt(test_Gpoly,
286 '_g,GAnsatzDegree+1,'_z,ZAnsatzDegree+1,k,
287 modular_linear_solver,mode-1),
290 if mode>= very_verbose then
291 print("numerical sysSol : ", sysSol),
294 if mode >= verbose then
295 print("no solution in the numerical test!"),
299 if mode >= verbose then
301 print("solution found in the numerical test!"),
302 print("sysSol : ", sysSol)
305 /* End of numerical test */
306 /* --------------------------------------------------------------------- */
309 sysSol : SolveZSysVerboseOpt(Gpoly,'_g,GAnsatzDegree+1,'_z,ZAnsatzDegree+1,k,
310 linear_solver,mode-1),
312 if mode>= very_verbose then
316 print("%rnum_list : ", %rnum_list)
319 if warnings and length(sysSol)>1 then
321 print("------------------------------------------------------------"),
323 print("Multiple solutions have been found."),
324 print("A lower order might probably work and yield fewer solutions."),
325 print("------------------------------------------------------------")
328 SpSysSol : sysSol, /* non-sense? */
331 for i: 1 thru length(sysSol) do
333 if mode>=very_verbose then
335 print("Solution no. ", i),
338 SpSysSol : sysSol[i],
341 GZAnsatzCoeff:separateGZVerboseOpt(SpSysSol,GAnsatzDegree+1,ZAnsatzDegree+1,
344 GAnsatzCoeff: GZAnsatzCoeff[1],
345 ZAnsatzCoeff: GZAnsatzCoeff[2],
347 if mode>=very_verbose then
349 print("GAnsatzCoeff : ", GAnsatzCoeff),
350 print("ZAnsatzCoeff : ", ZAnsatzCoeff)
354 ZAnsatzCoeff : constFactCorr(ZAnsatzCoeff,[nFTrivial[2],nFTrivial[3]],n),
356 if mode>=very_verbose then
357 print("correction : ",[nFTrivial[2],nFTrivial[3]]),
361 constDenNF : product(subst(n+i-1,n,nFTrivial[3]),i,1,ZAnsatzDegree),
364 if mode>=very_verbose then
366 print("constDenNF : ", constDenNF),
367 print("CORRECTED ZAnsatzCoeff : ", ZAnsatzCoeff)
370 GZAnsatzCoeff : normalizeGZ(GAnsatzCoeff,ZAnsatzCoeff),
371 GAnsatzCoeff : GZAnsatzCoeff[1],
373 ZAnsatzCoeff : GZAnsatzCoeff[2],
379 SolDeg : getDegrees(SpSysSol,GAnsatzDegree+1,ZAnsatzDegree+1,n),
380 print("Degrees of the Gosper parameters"),
381 prettyPrint(SolDeg[1]),
383 print("Degrees of the Zeilberger parameters"),
384 prettyPrint(SolDeg[2])
389 /* GSol: factor(expand(sol2Poly(GAnsatzCoeff,k))), */
390 GSol : sol2Poly(GAnsatzCoeff,k),
391 if mode>= verbose then
392 print("GSol : ", GSol),
399 tlscope : factor(GSol * r / gfP / denNF / constDenNF),
403 if trivial_solutions or (not(tlscope=0) and
404 not(apply("and",map(lambda([x],is(x=0)),ZAnsatzCoeff)))) then
407 if simplified_output then
408 allSols : endcons([ratsimp(tlscope),ZAnsatzCoeff],allSols)
410 allSols : endcons([tlscope,ZAnsatzCoeff],allSols)
415 print("----------------------------------------"),
417 print("The algorithm has discarted a trivial solution"),
418 print("with zero certificate."),
420 if mode>= very_verbose then
421 print("The coefficients of the recurrence are: ", ZAnsatzCoeff),
422 print("----------------------------------------")
426 print("-------------------------------------------"),
428 print("The algorithm has discarted a trivial solution"),
429 print("whose recurrence only has zero coefficients."),
431 if mode>= very_verbose then
433 print("The certificate is: "),
436 print("-------------------------------------------")
440 if mode>=summary then
442 printGosperSummary(parFRat,GosperForm,GAnsatzDegree,Gpoly,GSol,mode-1),
443 printParGosperSummary(p,sysSol,mode)
452 /* It builds the l.h.s. of the recursion of the summmand */
453 /* out of the solution of "parGosper" */
454 makeRecursionAux(f,ZCoeff,n,count) :=
459 makeRecursionAux(subst(n+1,n,f),Rest(ZCoeff),n,count-1) ;
462 /* Front-end macro of makeRecursionAux */
463 makeRecursion(f,ZCoeff,n) ::=
465 makeRecursionAux(f,ZCoeff,n,length(ZCoeff))
469 UnEvMakeRecursion(f,n,ord) :=
471 rec : concat(concat("a[",0,"]"),"f(n,k)"),
472 for i : 1 thru ord do
473 rec : concat(rec, "+", concat(concat("a[",i,"]"),concat("f(",string(n+i),",k)"))),
477 /* It builds the l.h.s. of the recursion of the summmand */
478 /* out of the solution of "parGosper" */
479 makeRecursionOpAux(f,ZCoeff,n,count,upperBound) :=
480 if count = upperBound then
481 first(ZCoeff) * eta[n]^count ( f )
483 first(ZCoeff) * eta[n]^count ( f ) +
484 makeRecursionOpAux(f,Rest(ZCoeff),n,count+1,upperBound) ;
487 /* Front-end macro of makeRecursionAux */
488 makeRecursionOp(f,ZCoeff,n) :=
491 makeRecursionOpAux(f,ZCoeff,n,count,length(ZCoeff))
495 printZeilbergerSummary(f,parGRes) :=
498 print("---------------------------"),
499 print("Iterated-Zeilberger summary"),
500 print(UnEvMakeRecursion(f,n,length(parGRes[1][2])-1)," = ",
501 Delta[k]("cert(n,k)"*"f(n,k)")),
504 print("f(n,k) = ", f),
506 print("cert(n,k) = ", parGRes[1][1]),
510 for i : 0 thru length(parGRes[1][2])-1 do
511 print("a[",i,"] = ", parGRes[1][2][i+1])
515 /* Front-end of the Zeilberger's algorithm with verbosity option */
516 ZeilbergerVerboseOpt(f,k,n,mode) :=
524 if Gosper_in_Zeilberger then
529 if warnings and not(dependent(f,n)) then
531 print("-------------------------------------------------"),
533 print(f, " does not depend on ", n,"."),
534 print("The flag Gosper_in_Zeilberger is set to false."),
535 print("You might find a solution with Gosper's algorithm"),
536 print("-------------------------------------------------")
544 if mode>= verbose then
545 print( "max_ord : " , max_ord ) ,
547 for ord : start step 1 while (parGRes = []) and ( ord <= max_ord ) do
549 if mode>= verbose then
551 print("----------------------------------------"),
552 print("Searching a recurrence with order : " , ord )
555 parGRes : parGosperVerboseOpt(f,k,n,ord,mode-1),
556 if mode >= verbose then
558 print("Gosper result with order : ", ord, " is : "),
563 if mode >= summary then
564 printZeilbergerSummary(f,parGRes),
571 /* Non verbose version of Zeilberger's algorithm */
572 ZeilbergerSummary([args]):=
577 if length(args)=3 then
578 ZeilbergerVerboseOpt(f,k,n,summary)
580 parGosperVerboseOpt(f,k,n,fourth(args),summary)
584 /* Non verbose version of Zeilberger's algorithm */
585 ZeilbergerVerbose([args]):=
590 if length(args)=3 then
591 ZeilbergerVerboseOpt(f,k,n,verbose)
593 parGosperVerboseOpt(f,k,n,fourth(args),verbose)
597 /* Non verbose version of Zeilberger's algorithm */
598 ZeilbergerVeryVerbose([args]):=
603 if length(args)=3 then
604 ZeilbergerVerboseOpt(f,k,n,very_verbose)
606 parGosperVerboseOpt(f,k,n,fourth(args),very_verbose)
610 /* Non verbose version of Zeilberger's algorithm */
611 ZeilbergerExtra([args]):=
616 if length(args)=3 then
617 ZeilbergerVerboseOpt(f,k,n,extra)
619 parGosperVerboseOpt(f,k,n,fourth(args),extra)
623 /* Non verbose version of Zeilberger's algorithm */
629 if length(args)=3 then
630 ZeilbergerVerboseOpt(f,k,n,nonverbose)
632 parGosperVerboseOpt(f,k,n,fourth(args),nonverbose)
636 /* Short name macro for verbose parGosper */
637 parGosperVerbose(f,k,n,degree)::=
638 buildq([f,k,n,degree],
639 parGosperVerboseOpt(f,k,n,degree,verbose));
642 /* Short name macro for very verbose parGosper */
643 parGosperVeryVerbose(f,k,n,degree)::=
644 buildq([f,k,n,degree],
645 parGosperVerboseOpt(f,k,n,degree,very_verbose));
648 /* Short name macro for the linear system version of parGosper */
649 parGosperExtra(f,k,n,degree) ::=
650 buildq([f,k,n,degree],
651 parGosperVerboseOpt(f,k,n,degree,extra));
653 /* Short name macro for the summary version of parGosper */
654 parGosperSummary(f,k,n,degree) ::=
655 buildq([f,k,n,degree],
656 parGosperVerboseOpt(f,k,n,degree,summary));
659 /* Short name for the non-verbose version of parGosper */
660 parGosperNonVerbose(f,k,n,degree) ::=
661 buildq([f,k,n,degree],
662 parGosperVerboseOpt(f,k,n,degree,nonverbose));
664 parGosper(f,k,n,order) ::=
665 buildq([f,k,n,order],
666 parGosperVerboseOpt(f,k,n,order,nonverbose));
668 /* Pretty print of a list */
672 for i : 1 step 1 thru len do