tayrevrt.red 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. module TayRevrt;
  2. %*****************************************************************
  3. %
  4. % Functions for reversion of Taylor kernels
  5. %
  6. %*****************************************************************
  7. exports taylorrevert;
  8. imports
  9. % from the REDUCE kernel:
  10. !*a2k, !*q2a, invsq, lastpair, mvar, neq, nth, numr, over,
  11. reval, simp!*, typerr,
  12. % from the header module:
  13. !*TayExp2q, cst!-Taylor!*, make!-cst!-coefficient,
  14. make!-taylor!*, multtaylorsq, prepTayExp, prune!-coefflist,
  15. set!-TayTemplate, TayCfPl, TayCfSq, TayCoeffList,
  16. TayExp!-Quotient, Taylor!:, TayMakeCoeff,
  17. Taylor!-kernel!-sq!-p, TayTemplate, TayTpElNext, TayTpElOrder,
  18. TayTpElPoint, TayTpElVars,
  19. % from module Tayintro:
  20. delete!-nth, Taylor!-error,
  21. % from module Taybasic:
  22. addtaylor, invtaylor, multtaylor, negtaylor,
  23. % from module TaySimp:
  24. expttayrat,
  25. % from module Tayutils:
  26. enter!-sorted, smallest!-increment;
  27. symbolic procedure tayrevert (tay, okrnl, krnl);
  28. %
  29. % Reverts Taylor kernel tay that has okrnl as variable
  30. % into a Taylor kernel that has krnl as variable.
  31. %
  32. % This is the driver procedure; it check whether okrnl
  33. % is valid for this operation and calls tayrevert1 to do the work.
  34. %
  35. begin scalar tp, cfl, x; integer i;
  36. cfl := TayCoeffList tay;
  37. tp := TayTemplate tay;
  38. x := tp;
  39. i := 1;
  40. %
  41. % Loop through the template and make sure that the kernel
  42. % okrnl is present and not part of a homogeneous template.
  43. %
  44. loop:
  45. if okrnl member TayTpElVars car x then <<
  46. if not null cdr TayTpElVars car x then <<
  47. Taylor!-error ('tayrevert,
  48. {"Kernel", okrnl,
  49. "appears in homogenous template", car x});
  50. return
  51. >>
  52. else goto found;
  53. >>
  54. else <<
  55. x := cdr x;
  56. i := i + 1;
  57. if not null x then goto loop
  58. >>;
  59. Taylor!-error
  60. ('tayrevert, {"Kernel", okrnl, "not found in template"});
  61. return;
  62. found:
  63. return tayrevert1 (tp, cfl, car x, i, okrnl, krnl)
  64. end;
  65. symbolic procedure tayrevertreorder (cf, i);
  66. %
  67. % reorders coefflist cf so that
  68. % a) part i of template is put first
  69. % b) the resulting coefflist is again ordered properly
  70. %
  71. begin scalar cf1, pl, sq;
  72. for each pp in cf do <<
  73. pl := TayCfPl pp;
  74. sq := TayCfSq pp;
  75. pl := nth (pl, i) . delete!-nth (pl, i);
  76. cf1 := enter!-sorted (TayMakeCoeff (pl, sq), cf1)
  77. >>;
  78. return cf1
  79. end;
  80. symbolic procedure tayrevertfirstdegreecoeffs (cf, n);
  81. %
  82. % Returns a coefflist that corresponds to the coefficient
  83. % of (the first kernel in the template) ** n.
  84. %
  85. for each el in cf join
  86. if car car TayCfPl el = n and not null numr TayCfSq el
  87. then {TayMakeCoeff (cdr TayCfPl el, TayCfSq el)} else nil;
  88. symbolic procedure tayrevert1(tp,cf,el,i,okrnl,krnl);
  89. %
  90. % This is the procedure that does the real work.
  91. % tp is the old template,
  92. % cf the old coefflist,
  93. % el the element of the template that contains the "old" kernel,
  94. % i its position in the template,
  95. % okrnl the old kernel,
  96. % krnl the new kernel.
  97. %
  98. Taylor!:
  99. begin scalar first,incr,newtp,newcf,newpoint,newel,u,u!-k,v,w,x,x1,n,
  100. expo,upper;
  101. %
  102. % First step: reorder the coefflist as if the okrnl appears
  103. % at the beginning of the template and construct a
  104. % new template by first deleting this element from it.
  105. %
  106. newcf := prune!-coefflist tayrevertreorder (cf, i);
  107. newtp := delete!-nth (tp, i);
  108. %
  109. % Check that the lowest degree of okrnl is -1, 0, or +1.
  110. % For -1, we have a first order pole.
  111. % For 0, reversion is possible only if the coefficient
  112. % of okrnl is a constant w.r.t. the other Taylor variables.
  113. % For +1, we use the algorithm quoted by Knuth,
  114. % in: The Art of Computer Programming, vol2. p. 508.
  115. %
  116. n := car car TayCfPl car newcf;
  117. if n < 0
  118. then tayrevert1pole(tp,cf,el,i,okrnl,krnl,newcf,newtp);
  119. if n = 0
  120. then if not null newtp
  121. then begin scalar xx;
  122. xx := tayrevertfirstdegreecoeffs(newcf,0);
  123. if length xx > 1
  124. then Taylor!-error
  125. ('tayrevert,
  126. "Term with power 0 is a Taylor series");
  127. xx := car xx;
  128. for each el in TayCfPl xx do
  129. for each el2 in el do
  130. if el2 neq 0
  131. then Taylor!-error
  132. ('tayrevert,
  133. "Term with power 0 is a Taylor series");
  134. newpoint := !*q2a TayCfSq xx;
  135. end
  136. else <<newpoint := !*q2a TayCfSq car newcf;
  137. newcf := prune!-coefflist cdr newcf;
  138. n := car car TayCfPl car newcf>>
  139. else newpoint := 0;
  140. tp := {{krnl},newpoint,TayTpElOrder el,TayTpElNext el} . newtp;
  141. first := TayExp!-quotient(1,n);
  142. incr := car smallest!-increment newcf;
  143. expo := first * incr;
  144. if not(expo=1)
  145. then (<<newcf := TayCoeffList newtay;
  146. tp := TayTemplate newtay;
  147. newtp := cdr tp;
  148. tp := {TayTpElVars car tp,
  149. reval {'expt,TayTpElPoint car tp,prepTayExp expo},
  150. TayTpElOrder car tp * expo,
  151. TayTpElNext car tp * expo}
  152. . newtp>>
  153. where newtay := expttayrat(Make!-Taylor!*(newcf,tp,nil,nil),
  154. !*TayExp2q expo));
  155. upper := TayExp!-quotient(TayTpElNext car tp,incr) - 1;
  156. x := tayrevertfirstdegreecoeffs(newcf,incr);
  157. x1 := x := invtaylor make!-Taylor!*(x,newtp,nil,nil);
  158. w := for each pp in TayCoeffList x1 collect
  159. TayMakeCoeff({expo} . TayCfPl pp,TayCfSq pp);
  160. v := mkvect upper;
  161. for j := 2 : upper do
  162. putv(v,j,
  163. multtaylor(
  164. x,
  165. make!-Taylor!*(tayrevertfirstdegreecoeffs(newcf,j*incr),
  166. newtp,nil,nil)));
  167. u := mkvect upper;
  168. putv(u,0,cst!-Taylor!*(1 ./ 1,newtp));
  169. for j := 2 : upper do <<
  170. for k := 1 : j - 2 do begin
  171. u!-k := getv(u,k);
  172. for l := k - 1 step -1 until 0 do
  173. u!-k := addtaylor
  174. (u!-k,
  175. negtaylor
  176. multtaylor(getv(u,l),
  177. getv(v,k - l + 1)));
  178. putv(u,k,u!-k);
  179. end;
  180. u!-k := multtaylorsq(getv(v,j),!*TayExp2q j);
  181. for k := 1 : j - 2 do
  182. u!-k := addtaylor
  183. (multtaylorsq(multtaylor(getv(u,k),
  184. getv(v,j - k)),
  185. !*TayExp2q (j - k)),
  186. u!-k);
  187. u!-k := negtaylor u!-k;
  188. putv(u,j - 1,u!-k);
  189. %
  190. x1 := multtaylor(x1,x); % x1 is now x ** j
  191. for each pp in TayCoeffList
  192. multtaylor(multtaylorsq
  193. (getv(u,j - 1),
  194. invsq !*TayExp2q j),x1) do
  195. w := enter!-sorted (TayMakeCoeff({j * expo}
  196. . TayCfPl pp,TayCfSq pp),
  197. w);
  198. >>;
  199. %
  200. newtp := (car tp) . newtp;
  201. w := enter!-sorted(
  202. make!-cst!-coefficient(simp!* TayTpElPoint el,newtp),
  203. w);
  204. w := Make!-taylor!*(w,newtp,nil,nil);
  205. return if incr = 1 then w
  206. else expttayrat(w,invsq !*TayExp2q incr)
  207. end;
  208. comment The mechanism for a first order pole is very simple:
  209. This corresponds to a first order zero at infinity,
  210. so we invert the original kernel and revert the result;
  211. symbolic procedure tayrevert1pole (tp, cf, el, i, okrnl, krnl,
  212. newcf, newtp);
  213. begin scalar x, y, z;
  214. cf := TayCoeffList invtaylor make!-Taylor!*(cf,tp,nil,nil);
  215. x := tayrevert1 (tp, cf, el, i, okrnl, krnl);
  216. y := TayTemplate x;
  217. if TayTpElPoint car y neq 0
  218. then Taylor!-error ('not!-implemented,
  219. "(Taylor series reversion)")
  220. else <<
  221. set!-TayTemplate (x, {{krnl}, 'infinity, TayTpElOrder car y}
  222. . cdr y);
  223. return x >>
  224. end;
  225. comment The driver routine;
  226. symbolic procedure TaylorRevert (u, okrnl, nkrnl);
  227. (if not Taylor!-kernel!-sq!-p sq
  228. then typerr (u, "Taylor kernel")
  229. else tayrevert (mvar numr sq, !*a2k okrnl, !*a2k nkrnl))
  230. where sq := simp!* u$
  231. flag ('(TaylorRevert), 'opfn);
  232. endmodule;
  233. end;