taysimp.red 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. module TaySimp;
  2. %*****************************************************************
  3. %
  4. % The special Taylor simplification functions
  5. %
  6. %*****************************************************************
  7. exports taysimpp, taysimpsq, taysimpsq!*, expttayrat, expttayrat1;
  8. imports
  9. % from the REDUCE kernel:
  10. !*f2q, !*k2q, !*p2f, !*p2q, !*t2q, addsq, apply1, denr,
  11. domainp, evenp, exptsq, invsq, kernp, mk!*sq, mkrn, multf,
  12. multpq, multsq, mvar, nth, numr, over, pdeg, prepsq, quotsq,
  13. reversip, sfp, simp, simp!*, tc, to, tpow,
  14. % from the header module:
  15. !*q2TayExp, !*tay2f, !*tay2q, !*tayexp2q, comp!.tp!.!-p,
  16. cst!-taylor!*, has!-Taylor!*, find!-non!-zero,
  17. get!-degreelist, has!-TayVars, invert!-powerlist,
  18. make!-cst!-coefflis, make!-cst!-powerlist, make!-Taylor!*,
  19. prune!-coefflist, resimptaylor, TayCfPl, TayCfSq,
  20. TayCoeffList, TayFlags, TayGetCoeff, Taylor!-kernel!-sq!-p,
  21. Taylor!*p, Taylor!:, TayMakeCoeff, taymultcoeffs, TayOrig,
  22. TayTemplate, TayTpElNext, TayTpElPoint, TayTpElVars,
  23. TpNextList,
  24. % from module Tayintro:
  25. confusion, Taylor!-error, Taylor!-error!*,
  26. % from module Tayutils:
  27. addto!-all!-TayTpElOrders, get!-cst!-coeff, smallest!-increment,
  28. Taylor!*!-nzconstantp, Taylor!*!-zerop,
  29. % from module Tayinterf:
  30. taylorexpand, taylorexpand!-sf,
  31. % from module Taybasic:
  32. addtaylor, addtaylor!-as!-sq, invtaylor, makecoeffpairs,
  33. makecoeffs0, multtaylor, multtaylor!-as!-sq, multtaylorsq,
  34. quottaylor!-as!-sq;
  35. fluid '(!*taylorautoexpand !*taylorkeeporiginal)$
  36. comment The procedures in this module provide the higher taylor
  37. manipulation machinery. Given any s.q. (s.f.,...) they
  38. return the equivalent Taylor kernel (disguised as a s.q.)
  39. if the argument contains a Taylor kernel and everything
  40. else may be Taylor expanded.
  41. Otherwise the Taylor kernels in the argument are only
  42. partially combined (but as far as possible);
  43. symbolic procedure taysimpsq u;
  44. %
  45. % The argument u is any standard quotient.
  46. % numerator and denominator are first simplified independently,
  47. % then the quotient is built.
  48. % We have four possible cases here, as both expressions
  49. % may or may not be Taylor kernels.
  50. %
  51. begin scalar nm,dd;
  52. dd := taysimpf denr u;
  53. if null numr dd then Taylor!-error('zero!-denom,'taysimpsq)
  54. else if Taylor!-kernel!-sq!-p dd
  55. then return taysimpf multf(numr u,!*tay2f invtaylor mvar numr dd);
  56. nm := taysimpf numr u;
  57. return
  58. if Taylor!-kernel!-sq!-p nm
  59. then if not has!-TayVars(mvar numr nm,dd)
  60. then !*tay2q resimptaylor
  61. multtaylorsq(mvar numr nm,invsq dd)
  62. else if Taylor!*!-nzconstantp mvar numr nm
  63. then quotsq(get!-cst!-coeff mvar numr nm,dd)
  64. else if null !*taylorautoexpand or has!-Taylor!* dd
  65. then quotsq(nm,dd)
  66. else taysimpsq!*
  67. quottaylor!-as!-sq(
  68. nm,
  69. taylorexpand(dd,TayTemplate mvar numr nm))
  70. else quotsq(nm,dd)
  71. end;
  72. symbolic procedure taysimpsq!* u;
  73. %
  74. % Variant of taysimpsq that does not automatically expand
  75. % non-Taylor expressions
  76. %
  77. taysimpsq u where !*taylorautoexpand := nil;
  78. symbolic procedure taysimpf u;
  79. %
  80. % u is a standard form which may contain Taylor subexpressions;
  81. % value is a standard form
  82. %
  83. begin scalar tay,notay,x,flg;
  84. %
  85. % Remember the definition of a s.f.:
  86. % it is either a domain element,
  87. % or it's car is a standard term and it's cdr is a s.f.
  88. %
  89. notay := nil ./ 1;
  90. while u do
  91. %
  92. % Split the constituents of the s.f. into non-Taylor and
  93. % Taylor parts. Taylor s.t.'s are simplified accordingly.
  94. % A domain element can never be a Taylor kernel.
  95. %
  96. <<if domainp u then notay := addsq(!*f2q u,notay)
  97. else if not has!-Taylor!* car u
  98. then notay := addsq(notay,!*t2q car u)
  99. else <<x := taysimpt car u;
  100. if Taylor!-kernel!-sq!-p x
  101. then if null tay then tay := mvar numr x
  102. else if comp!.tp!.!-p(tay,mvar numr x)
  103. then tay := addtaylor(tay,mvar numr x)
  104. else <<flg := t;
  105. %
  106. % flg indicates that there are
  107. % Taylor kernels whose templates
  108. % are not compatible
  109. %
  110. notay := addsq(notay,x)>>
  111. else notay := addsq(notay,x)>>;
  112. u := if domainp u then nil else cdr u>>;
  113. %
  114. % tay is now a Taylor kernel or nil.
  115. %
  116. % We first make sure that it is not actually a constant.
  117. %
  118. if not null tay and not null TayOrig tay and null numr TayOrig tay
  119. then return notay
  120. %
  121. % If tay is nil, return the non-taylor parts.
  122. %
  123. else if null numr notay and not null tay then return !*tay2q tay
  124. else if null tay or Taylor!*!-zerop tay then return notay;
  125. %
  126. % Otherwise the non-taylor parts (if the are non-nil)
  127. % must be expanded if !*taylorautoexpand is non-nil.
  128. % The only exception are terms that do not contain
  129. % any of the Taylor variables: these are always expanded.
  130. %
  131. if Taylor!*!-nzconstantp tay and not has!-Taylor!* notay
  132. then return addsq(get!-cst!-coeff tay,notay)
  133. else if null !*taylorautoexpand and has!-TayVars(tay,notay)
  134. then return addsq(!*tay2q tay,notay);
  135. if flg then return addsq(!*tay2q tay,notay)
  136. else <<
  137. notay := taylorexpand(notay,TayTemplate tay);
  138. return taysimpsq!* addtaylor!-as!-sq(notay,!*tay2q tay)>>
  139. end;
  140. symbolic procedure taysimpt u;
  141. %
  142. % u is a standard term containing one or more Taylor kernels,
  143. % value is the simplified Taylor expression (also as a s.f.).
  144. %
  145. begin scalar rest,pow;
  146. %
  147. % Since the coefficient of a term is a s.f.
  148. % we call taysimpf on it.
  149. %
  150. rest := taysimpf tc u;
  151. if null numr rest then return rest;
  152. pow := tpow u;
  153. %
  154. % Then we have to distinguish three cases:
  155. % the case where no Taylor kernel appears was already caught
  156. % by taysimpf before taysimpt was called.
  157. %
  158. % If combination of different Taylor kernels is impossible
  159. % return them separately
  160. %
  161. % Remark: the call to SMEMQLP checks if rest contains one of
  162. % the Taylor variables if it is not a Taylor kernel.
  163. %
  164. return if not has!-Taylor!* pow
  165. then if Taylor!-kernel!-sq!-p rest
  166. then multpowerintotaylor(pow,mvar numr rest)
  167. else multpq(pow,rest)
  168. else <<pow := taysimpp pow;
  169. if not has!-Taylor!* rest and Taylor!-kernel!-sq!-p pow
  170. then if has!-TayVars(mvar numr pow,rest)
  171. then if !*taylorautoexpand
  172. then taysimpsq!* multtaylor!-as!-sq(pow,
  173. % taylorexpand(rest,TayTemplate mvar numr pow))
  174. %
  175. % the above is not entirely correct. the expansion should be done
  176. % in a way so that the result of the multiplication has same order
  177. % as pow
  178. %
  179. taylorexpand!-sf(tc u,
  180. TayTemplate mvar numr pow,
  181. nil))
  182. else multsq(pow,rest)
  183. else !*tay2q multtaylorsq(mvar numr pow,rest)
  184. else multtaylor!-as!-sq(pow,rest)>>
  185. end;
  186. symbolic procedure multpowerintotaylor (p, tk);
  187. %
  188. % p is a standard power, tk a Taylor kernel
  189. % value is p expanded to a Taylor kernel multiplied by tk
  190. % this requires Taylor expansion of p if it contains
  191. % at least one of the expansion variables
  192. %
  193. % Remark: the call to SMEMQLP checks if p contains one of
  194. % the Taylor variables.
  195. %
  196. if not has!-TayVars(tk,p)
  197. then !*tay2q multtaylorsq(tk,!*p2q p)
  198. else if !*taylorautoexpand
  199. % then taysimpsq!*
  200. % multtaylor!-as!-sq(!*tay2q tk,
  201. % taylorexpand(!*p2q p,TayTemplate tk))
  202. %
  203. % here the same comment as above applies
  204. %
  205. then taysimpsq!*
  206. multtaylor!-as!-sq(!*tay2q tk,
  207. taylorexpand!-sf(!*p2f p,TayTemplate tk,nil))
  208. else if Taylor!*!-nzconstantp tk
  209. then multpq(p,get!-cst!-coeff tk)
  210. else multpq(p,!*tay2q tk);
  211. symbolic procedure taysimpp u;
  212. %
  213. % u is a standard power containing a Taylor expression,
  214. % value is the simplified Taylor expression, as a s.f.
  215. %
  216. % We begin by isolating base and exponent.
  217. % First we simplify them separately.
  218. % Remember that the exponent is always an integer,
  219. % base is a kernel.
  220. %
  221. % If the main variable of the power is a kernel made of one
  222. % of the functions known to the Taylor simplifier, call
  223. % the appropriate simplification function.
  224. % (There is a user hook here!)
  225. %
  226. if null car u or null pdeg u then confusion 'taysimpp
  227. else if sfp car u then !*p2q u
  228. %%%% taysimpsq exptsq(taysimpf car u,cdr u)
  229. else if not taylor!*p car u
  230. then ((if kernp x
  231. then if (x := mvar numr x) = car u then !*p2q u
  232. else if cdr u=1 then !*k2q x
  233. else taysimpp(x .** cdr u)
  234. else if cdr u=1 then x
  235. else taysimpsq exptsq(x,cdr u))
  236. where x := (taysimpmainvar car u))
  237. %
  238. % We know how to raise a Taylor series to a rational power:
  239. % positive integer --> multiply
  240. % negative integer --> multiply and invert
  241. % Zero exponent should not appear: should be already simplified
  242. % to 1 by the standard simplifier
  243. %
  244. else if not fixp pdeg u or pdeg u = 0 then confusion 'taysimpp
  245. else if not null TayOrig car u and null numr TayOrig car u
  246. then (nil ./ 1)
  247. else !*tay2q
  248. if pdeg u = 1 then car u else expttayi(car u,cdr u)$
  249. symbolic procedure taysimpmainvar u;
  250. if not sfp u then taysimpkernel u
  251. else !*f2q taysimpf u;
  252. symbolic procedure taysimpkernel u;
  253. begin scalar fn, x;
  254. u := simp!* u;
  255. if not kernp u then return u
  256. else << x := mvar numr u;
  257. if atom x or Taylor!*p x then return u;
  258. fn := get (car x, 'taylorsimpfn);
  259. return if null fn then u
  260. else apply1 (fn, x)>>
  261. end;
  262. symbolic procedure expttayi(u,i);
  263. %
  264. % raise Taylor kernel u to integer power i
  265. % algorithm is a scheme that computes powers of two.
  266. %
  267. begin scalar v,flg;
  268. if i<0 then <<i := -i; flg := t>>;
  269. v := if evenp i then cst!-Taylor!*(1 ./ 1,TayTemplate u)
  270. else <<i := i - 1; u>>;
  271. while (i:=i/2)>0 do <<u := multtaylor(u,u);
  272. if not evenp i then v := multtaylor(v,u)>>;
  273. return if flg then invtaylor v else v
  274. end;
  275. comment non-integer powers of Taylor kernels;
  276. comment The implementation of expttayrat follows the algorithm
  277. quoted by Knuth in the second volume of `The Art of
  278. Computer Programming', extended to the case of series in
  279. more than one variable.
  280. Assume you want to compute the series W(x) where
  281. W(x) = V(x)**alpha
  282. Differentiation of this equation gives
  283. W'(x) = alpha * V(x)**alpha * V'(x) .
  284. You make now the ansatz
  285. -----
  286. \ n
  287. W(x) = > W x ,
  288. / n
  289. -----
  290. substitute this into the above equation and compare
  291. powers of x. This yields the recursion formula
  292. n-1
  293. -----
  294. 1 \ m m
  295. W = ----- > (alpha (1 - ---) - --- ) W V .
  296. n V / n n m n-m
  297. 0 -----
  298. m=0
  299. The first coefficient must be calculated directly, it is
  300. W = V ** alpha .
  301. 0 0
  302. To use this for series in more than one variable you have to
  303. calculate all partial derivatives: n and m refer then to the
  304. corresponding component of the multi index. Looking closely
  305. one finds that there is an ambiguity: the same coefficient
  306. can be calculated using any of the partial derivatives. The
  307. only restriction is that the corresponding component of the
  308. multi index must not be zero, since we have to divide by it.
  309. We resolve this ambiguity by simply taking the first nonzero
  310. component.
  311. We use it here only for the case that alpha is a rational
  312. number;
  313. symbolic procedure expttayrat(tay,rat);
  314. %
  315. % tay is a Taylor kernel, rat is a s.q. of two integers
  316. % value is tay ** rat
  317. % algorithm as quoted by Knuth
  318. %
  319. Taylor!:
  320. begin scalar clist,tc,tp;
  321. %
  322. % First of all we have to find out if we can raise the leading
  323. % term to the power rat.
  324. % If so we calculate the reciprocal of this leading coefficient
  325. % and multiply all other terms with it.
  326. % This guarantees that the resulting Taylor kernel starts with
  327. % coefficient 1.
  328. %
  329. if not Taylor!*p tay then return simp!* {'expt,tay,mk!*sq rat};
  330. tc := prune!-coefflist TayCoeffList tay;
  331. tp := TayTemplate tay;
  332. %
  333. % Find first non-zero coefficient.
  334. %
  335. if null tc
  336. then if minusp numr rat
  337. then Taylor!-error!*('not!-a!-unit,'expttayrat)
  338. else <<tp := for each tpel in tp collect begin scalar w;
  339. w := TayTpElNext tpel * !*q2TayExp rat;
  340. return {TayTpElVars tpel,
  341. TayTpElPoint tpel,
  342. w - mkrn(1,denr rat),
  343. w};
  344. end;
  345. clist := make!-cst!-coefflis(nil ./ 1,tp)>>
  346. else begin scalar c0,l,l1;
  347. c0 := car tc;
  348. l1 := for each ll in TayCfPl c0 collect
  349. for each p in ll collect (p * !*q2TayExp rat);
  350. l := invert!-powerlist TayCfPl c0;
  351. tp := addto!-all!-TayTpElOrders(tp,get!-degreelist l);
  352. l := TayMakeCoeff(l,invsq TayCfSq c0);
  353. %
  354. % We divide the rest of the kernel (without the leading term)
  355. % by the leading term.
  356. %
  357. l := for each el in cdr tc collect taymultcoeffs(el,l);
  358. clist := expttayrat1(tp,l,rat);
  359. %
  360. % Next we multiply the resulting Taylor kernel by the leading
  361. % coefficient raised to the power rat.
  362. %
  363. c0 := TayMakeCoeff(l1,simp!* {'expt,mk!*sq TayCfSq c0,
  364. {'quotient,numr rat,denr rat}});
  365. clist := for each el in clist collect taymultcoeffs(el,c0);
  366. tp := addto!-all!-TayTpElOrders(tp,get!-degreelist l1);
  367. end;
  368. %
  369. % Finally we fill in the original expression
  370. %
  371. return make!-Taylor!*(
  372. clist,
  373. tp,
  374. if !*taylorkeeporiginal and TayOrig tay
  375. then simp {'expt,prepsq TayOrig tay,
  376. {'quotient,car rat,cdr rat}}
  377. else nil,
  378. TayFlags tay)
  379. end;
  380. symbolic procedure expttayrat1(tp,tcl,rat);
  381. Taylor!:
  382. begin scalar clist,coefflis,il,l0,rat1;
  383. rat1 := addsq(rat,1 ./ 1);
  384. %
  385. % Now we compute the coefficients
  386. %
  387. l0 := make!-cst!-powerlist tp;
  388. clist := {TayMakeCoeff(l0,1 ./ 1)};
  389. tcl := TayMakeCoeff(l0,1 ./ 1) . tcl;
  390. il := smallest!-increment tcl;
  391. coefflis := makecoeffs0(tp,TpNextList tp,il);
  392. if null coefflis then return clist;
  393. for each cc in cdr coefflis do
  394. begin scalar s,pos,pp,q,n,n1;
  395. s := nil ./ 1;
  396. pos := find!-non!-zero cc;
  397. n := nth(nth(cc,car pos),cdr pos);
  398. pp := makecoeffpairs(l0,cc,l0,il);
  399. for each p in pp do begin scalar v,w;
  400. v := TayGetCoeff(cdr p,tcl);
  401. w := TayGetCoeff(car p,clist);
  402. %
  403. % The following line is a short cut for efficiency.
  404. %
  405. if null numr v or null numr w then return;
  406. w := multsq(w,v);
  407. n1 := nth(nth(car p,car pos),cdr pos);
  408. q := quotsq(!*TayExp2q(-n1),!*TayExp2q n);
  409. s := addsq(s,multsq(addsq(rat,multsq(q,rat1)),w))
  410. end;
  411. if not null numr s then clist := TayMakeCoeff(cc,s) . clist
  412. end;
  413. return reversip clist
  414. end;
  415. endmodule;
  416. end;