Merge branch 'master' of ssh://git.code.sf.net/p/maxima/code
[maxima.git] / share / contrib / Zeilberger / makeGosperForm.mac
blobaac5f484e4afa96efd08740a49c5c46feaf4d900
1 /* Gosper form routine */
3 /* RISC Institite, Linz, Austria */
4 /* by Fabrizio Caruso            */
7 /* List select wrt a criterion */
8 select(list,crit) := 
9   if list = [] then
10     []
11   else
12      if crit(first(list)) then
13        cons(first(list),select(rest(list),crit))
14      else
15        select(rest(list),crit);
17 /* List split wrt a criterion */
18 splitList(list,crit) := 
19   block([trueList,falseList,i],
20    trueList : [],
21    falseList : [],
22    unless list = [] do 
23       (
24       if crit(first(list)) then
25          trueList : endcons(first(list),trueList)
26       else
27          falseList : endcons(first(list),falseList),
28       list : rest(list)
29       ),
30    return([trueList,falseList])
31    );
33 /* true if a given expr has a given degree */
34 degreeSelect(expr,var,deg) := is(degree(expr,var)=deg);
35    
37 /* integer distance */
38 intDistance(expr1,expr2) := integerp(expr1-expr2);
41 /* It splits a list into a part with a given coefficient and the rest */
42 candSplit(list,coef,constCoef) :=
43   block([candRes,restRes],
44   candRes : [],
45   restRes : [],
46   unless (list = []) do
47     (
48     if (first(first(list))=coef) and integerp(second(first(list))-constCoef) then
49        candRes : endcons(first(list),candRes)
50     else
51        restRes : endcons(first(list),restRes),
52     list : rest(list)
53     ),
54   return([candRes, restRes])
55   );
59 /* It checks whether a factored expression is linear */
60 /* with integer coefficients */
61 integerLinear(expr,var) :=
62   if not(zb_operatorp(expr,"^")) then
63     is(degree(expr,var) < 2)
65 and
66     (integerp(coeff(expr,var,1)))
68   else
69     integerLinear(first(expr),var); 
71 /* Separate the constant and the normalized part of an integer linear*/
72 intLinConstSep(intLin) :=
73   block([i,intLinRes,constRes],
74    intLinRes : [],
75    constRes : 1,
76    for i : 1 thru length(intLin) do
77       (      
78       intLinRes : endcons(first(part(intLin,i)),intLinRes),
79       constRes : constRes * second(part(intLin,i))
80       ),
81    return([intLinRes, constRes])
82   );
85 constSep(intLin) :=
86   block([i,intLinRes,constRes],
87    intLinRes : [],
88    constRes : 1,
89    for i : 1 thru length(intLin) do
90       (      
91       intLinRes : endcons(first(part(intLin,i)),intLinRes),
92       constRes : constRes * second(part(intLin,i))
93       ),
94    return([intLinRes, constRes])
95   );
98 makeGosperForm(expr,k) :=
99   makeGosperFormVerboseOpt(expr,k,nonvernose);
101 makeGosperFormVerboseOpt(expr,k,mode) :=
102   first(makeGosperFormPrHypCheckVerboseOpt(expr,k,mode));
104 makeGosperPrHypCheck(expr,k) :=
105   makeGosperFormPrHypCheckVerboseOpt(expr,k,nonverbose);
107 /* Check Gosper's condition */
108 /* We are assuming that the input is factored */
109 /* into irreducible factors */
110 /* */
111 /* The numerator is q(k) and the denominator is r(k) */
112 makeGosperFormPrHypCheckVerboseOpt(expr,k,mode) :=
113   block(
114   /* Local variables */
115   [num,den,numList,denList,lengthNumList,lengthDenList,
116    test,
117    i__,j,h,minExp,pulledPoly,pPoly,curExp,compPoly,formSign,
118    p,q,r,pList,qList,rList,
119    negNumFlag,negDenFlag,
120    intLinNum,nonIntLinNum,intLinDen,nonIntLinDen,
121    sepNumList,sepDenList,
122    constIntLinNum, constIntLinDen, constSep, 
123    normIntLinNum, normNonIntLinNum, normIntLinDen, normNonIntLinDen,
124    numItem, denItem,
125    numExp,denExp,diff,candListSplit,item,hyp_flag, candNumList, candDenList, intLinNumConst, intLinDenConst, nonIntLinNumConst, nonIntLinDenConst],
127   hyp_flag : true,
128   if(expr=1) then 
129     return([[1,1,1],true]),
132     num:factor(num(expr)),
133     den:factor(denom(expr)),
135     num : num(expr),
136     den : denom(expr),
139   if mode>= verbose then
140     (
141     print(num),
142     print(den)
143     ),
145 negNumFlag : zb_operatorp(num,"-"),
146 negDenFlag : zb_operatorp(den,"-"),
148 if (negNumFlag) then
149   num : -1 * num,
150 if (negDenFlag) then   
151   den : -1 * den,
153 if (negNumFlag and not(negDenFlag))or(not(negNumFlag) and negDenFlag) then
154    (
155    formSign : -1
156    )
157 else
158    formSign : 1,
160 pPoly : 1,
163 sepNumList:intLinSep(num,k),
164 sepDenList:intLinSep(den,k),
166 if mode >= verbose then
168 print("sepNumList : ", sepNumList),
169 print("sepDenList : ", sepDenList)
170 ),  
172 nonIntLinNum : first(sepNumList),
173 intLinNum : second(sepNumList),
174 nonIntLinDen : first(sepDenList),
175 intLinDen : second(sepDenList),
177 p:1,
178 q:1,
179 r:1,
180 pList:[],
181 qList:[],
182 rList:[],
184 if numList # [] or denList # [] then
185   hyp_flag : false,
187 /* Non-integer linear computation */
189 numList : normList(nonIntLinNum,k),
190 denList : normList(nonIntLinDen,k),
192 if mode>= verbose then
194 print("numList : ", numList),
195 print("denList : ", denList)
198 constSep : constSep(numList),
199 normNonIntLinNum : constSep[1],
200 nonIntLinNumConst : constSep[2],
201 if mode>= verbose then
203 print("normIntLinNum : ", normNonIntLinNum),
204 print("intLinNumConst : ", nonIntLinNumConst)
207 constSep : constSep(denList),
208 normNonIntLinDen : constSep[1],
209 nonIntLinDenConst : constSep[2],
210 if mode>= verbose then
212 print("normIntLinDen : ", normNonIntLinDen),
213 print("nonIntLinDenConst : ", nonIntLinDenConst)
216 q : q * nonIntLinNumConst,
217 r : r * nonIntLinDenConst,
219 numList : normNonIntLinNum,
220 denList : normNonIntLinDen,
222 /* entering outer loop */
224 if mode >= verbose then
225   print("denList : ", denList),
226 unless ((numList = []) or (denList = [])) do
227   (
228   denItem : first(denList),
229   if mode >= verbose then
230      print("denItem : ", denItem),
231   candListSplit : splitList(numList,
232                             lambda([x],degreeSelect(x,k,degree(first(denList),k)))
233                            ),
235 candListSplit : splitList(numList,
236                             lambda([x],degreeSelect(x,k,degree(first(denItem),k)))
237                            ),
240   candNumList : first(candListSplit),
242 numList : second(candListSplit),
244 candListSplit : splitList(denList,
245                             lambda([x],degreeSelect(x,k,degree(first(denList),k)))
246                            ),
248 candListSplit : splitList(denList,
249                             lambda([x],degreeSelect(x,k,degree(first(denItem),k)))
250                            ),
254 candDenList : first(candListSplit),
255 denList : second(candListSplit),
259 /*  inner loop */
260   unless candDenList = [] do
261      (
262      denItem : first(candDenList),
263      tempList : candNumList,
264      candNumList : [],
265      unless tempList = [] do
266         (
267         
268     
269      shiftRes : resultant(norm2polyPower(first(tempList)),
270                           expand(subst(k+j,k,norm2polyPower(denItem))),k),
271      if mode >= very_verbose then
272         print("shiftRes : ", shiftRes),
274      factList : poly2list(factor(shiftRes)),
276      intFactList : first(splitList(factList, lambda([y],integerLinear(y,j)and degree(y,j)>0))),
278      solList : makelist(second(first(solve(part(intFactList,i),j))),i,1,length(intFactList)),
280      intSolList : first(splitList(solList,lambda([y],integerp(y) and (y>=0)))),
282      if intSolList # [] then
283          (
284          minSol : apply(min,intSolList), 
286          numExp : second(first(tempList)),
287          denExp : second(denItem),
288          minExp : min(numExp,denExp),
290          if numExp = denExp then
291              (
292              p : p * product(norm2polyPower(subst(k+j,k,denItem)),j,0,minSol-1),
293              
294              denItem : [1,1],
295              tempList : []
296              
297              )
298          else
299              (
300              item : [first(denItem),minExp],
301              
302              p : p * product(norm2polyPower(subst(k+j,k,item)),j,0,minSol-1),
304              if numExp > denExp then
305                 (
306                 candNumList : endcons([first(first(tempList)),numExp-minExp],candNumList),
307                 denItem : [1,1],
308                 tempList : []
309                 )
310              else
311                 (
312                 denItem : [first(denItem), denExp-minExp],
313                 tempList : rest(tempList)
314                 )
315              )
316          )
317      else
318          (
319          if mode>= verbose then
320             print("no positive integer solutions"),
321          candNumList : endcons(first(tempList),candNumList),
322          tempList : rest(tempList)
323          )
325         ),
326      r : r * norm2polyPower(denItem),
327      candDenList : rest(candDenList)
329      ),
331 /* end of inner loop */
332 q : q * product(norm2polyPower(part(candNumList,i__)),i__,1,length(candNumList))
334   ),
335 /* end of outer loop */
336 if mode>= verbose then
338 print("numList : ", numList),
339 print("denList : ", denList)
341 if numList # [] then
342   q : q * product(norm2polyPower(part(numList,i__)),i__,1,length(numList)),
343 if denList # [] then
344   r : r * product(norm2polyPower(part(denList,i__)),i__,1,length(denList)),
346 if mode>= verbose then
348 print("q : ", q),
349 print("r : ", r)
353 /* Integer linear computation */
355 numList : intLinNormList(intLinNum,k), 
357 numList : sort(numList),
359 denList : intLinNormList(intLinDen,k),
361 denList : sort(denList),
363 constSep : intLinConstSep(numList),
364 normIntLinNum : constSep[1],
365 intLinNumConst : constSep[2],
366 if mode>= verbose then
368 print("normIntLinNum : ", normIntLinNum),
369 print("intLinNumConst : ", intLinNumConst)
372 constSep : intLinConstSep(denList),
373 normIntLinDen : constSep[1],
374 intLinDenConst : constSep[2],
375 if mode>= verbose then
377 print("normIntLinDen : ", normIntLinDen),
378 print("intLinDenConst : ", intLinDenConst)
381 numList : normIntLinNum,
382 denList : normIntLinDen,
384   lengthNumList:length(numList),
385   lengthDenList:length(denList),
387 unless ((numList = []) or (denList = [])) do
388   (
389   denItem : first(denList),
391 /* This is an adaptation of Schorn-Riese's Mathematica code */
393 if mode>= verbose then
395 print("denItem : ", denItem),
396 print("numList : ", numList),
397 print("denList : ", denList)
401 candListSplit : splitList(numList,
402                 lambda([x],intDistance(first(x),first(denItem)))),
404 if mode>= verbose then
405   print("num) candListSplit : ", candListSplit),
408 candNumList : first(candListSplit),
410 numList : second(candListSplit),
411 candListSplit : splitList(denList,
412                  lambda([x],intDistance(first(x),first(denItem)))),
414 if mode>= verbose then
415   print("den) candListSplit : ", candListSplit),
418 candDenList : first(candListSplit),
420 denList : second(candListSplit),
421      
423 unless ((candNumList = []) or (candDenList = [])) do
424     (
426     diff : first(first(candNumList))-first(first(candDenList)),
427     if mode>= verbose then
428       (
429       print("diff : ", diff),
430       print("inner cycle) candNumList : ", candNumList),
431       print("inner cycle) candDenList : ", candDenList)
432       ),
433     if not(integerp(diff)) or (integerp(diff) and (diff<0)) then
434        (
435        /* q must be updated here */
436        /* Gosper-condition satisfied */
437       
438        q : q * norm2polyPower(first(candNumList)),
439        candNumList : rest(candNumList)
440        )
441     else
442        (
443        /* Gosper-condition NOT satisfied */
444        /* p must be updated here */
445        numExp:second(first(candNumList)),
446        denExp:second(first(candDenList)),
447        minExp:min(numExp,denExp),
448        
449        p : p * product(subst(k+i__,k,norm2intLin(first(candDenList),k)^minExp),i__,0,diff-1),
450        if mode>= verbose then
451           print("p computed : ", p),
452        if(numExp>denExp) then
453           (
454           item : [first(first(candNumList)),numExp-minExp],          
455           
456           candNumList : cons(item,rest(candNumList)),
457           
458           candDenList : rest(candDenList)
459           )
460        else
461           if(numExp<denExp) then
462              (
463              item : [first(first(candDenList)),denExp-minExp],
464              candNumList : rest(candNumList),
465              candDenList : cons(item,rest(candDenList))
466              )
467           else
468             (
469             candNumList : rest(candNumList),
470             candDenList : rest(candDenList)
471             )
473        )
474     ), /* end inner unless cycle */
476 /* out of inner cycle */
477   
478 if (candNumList # []) then
479  q : q * product(norm2polyPower(part(candNumList,i__)),i__,1,length(candNumList)),
482 if(candDenList # []) then
483  r : r * product(norm2polyPower(part(candDenList,i__)),i__,1,length(candDenList))
485  ), /* end unless */
487 if (numList # []) then
488   q : q*product(norm2polyPower(part(numList,i__)),i__,1,length(numList)),
490 if (denList # []) then
491   r : r*product(norm2polyPower(part(denList,i__)),i__,1,length(denList)),
494 r : subst(k-1,k,r),
496 return([[p,q*formSign*intLinNumConst,r*intLinDenConst],hyp_flag])
499 ); /* end block */
504 makeGosperForm(expr,var) ::=
505   buildq([expr,var],makeGosperFormVerboseOpt(expr,var,nonverbose));
507 makeGosperFormVerbose(expr,var) ::=
508   buildq([expr,var],makeGosperFormVerboseOpt(expr,var,verbose));
513 /* Macro that extracts p out of the Gosper form */
514 takeP(GosperForm) ::=
515   buildq([GosperForm],first(GosperForm));
518 /* Macro that extracts q out of the Gosper form */
519 takeQ(GosperForm) ::=
520   buildq([GosperForm],second(GosperForm));
523 /* Macro that extracts r out of the Gosper form */
524 takeR(GosperForm) ::=
525   buildq([GosperForm],third(GosperForm));