taybasic.red 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. module TayBasic;
  2. %*****************************************************************
  3. %
  4. % Functions that implement the basic operations
  5. % on Taylor kernels
  6. %
  7. %*****************************************************************
  8. exports addtaylor, addtaylor1, invtaylor, invtaylor1, makecoeffpairs,
  9. makecoeffs, makecoeffs0, multtaylor, multtaylor1,
  10. multtaylorsq, negtaylor, negtaylor1, quottaylor, quottaylor1$
  11. imports
  12. % from the REDUCE kernel:
  13. addsq, invsq, lastpair, mvar, multsq, negsq, neq, nth, numr,
  14. over, quotsq, reversip, subtrsq, union,
  15. % from the header module:
  16. !*tay2q, common!-increment, get!-degree, invert!-powerlist,
  17. make!-Taylor!*, multintocoefflist, prune!-coefflist,
  18. smallest!-increment, subtr!-degrees, subs2coefflist, TayCfPl,
  19. TayCfSq, TayCoeffList, TayFlags, TayFlagsCombine, TayGetCoeff,
  20. Taylor!-kernel!-sq!-p, Taylor!:, TayMakeCoeff, TayOrig,
  21. TayTemplate, TayTpElVars, TpDegreeList, TpNextList,
  22. % from module Tayintro:
  23. confusion, Taylor!-error, Taylor!-error!*,
  24. % from module Tayutils:
  25. add!.comp!.tp!., add!-degrees, enter!-sorted, exceeds!-order,
  26. inv!.tp!., min2!-order, mult!.comp!.tp!., replace!-next,
  27. taydegree!-strict!<!=;
  28. fluid '(!*taylorkeeporiginal)$
  29. symbolic procedure multtaylorsq (tay, sq);
  30. %
  31. % multiplies the s.q. sq into the Taylor kernel tay.
  32. % value is a Taylor kernel.
  33. % no check for variable dependency is done!
  34. %
  35. if null tay or null numr sq then nil
  36. else make!-Taylor!* (
  37. multintocoefflist (TayCoeffList tay, sq),
  38. TayTemplate tay,
  39. if !*taylorkeeporiginal and TayOrig tay
  40. then multsq (sq, TayOrig tay)
  41. else nil,
  42. TayFlags tay)$
  43. symbolic smacro procedure degree!-union (u, v);
  44. union (u, v)$ % works for the moment;
  45. symbolic procedure addtaylor(u,v);
  46. %
  47. % u and v are two Taylor kernels
  48. % value is their sum, as a Taylor kernel
  49. %
  50. (if null tp then confusion 'addtaylor
  51. else addtaylor!*(u,v,car tp))
  52. where tp := add!.comp!.tp!.(u,v);
  53. symbolic procedure addtaylor!-as!-sq(u,v);
  54. begin scalar tp;
  55. return
  56. if Taylor!-kernel!-sq!-p u and Taylor!-kernel!-sq!-p v and
  57. (tp := add!.comp!.tp!.(mvar numr u,mvar numr v))
  58. then !*tay2q addtaylor!*(mvar numr u,mvar numr v,car tp)
  59. else addsq(u,v)
  60. end;
  61. symbolic procedure addtaylor!*(u,v,tp);
  62. make!-Taylor!*
  63. (cdr z,replace!-next(tp,car z),
  64. if !*taylorkeeporiginal and TayOrig u and TayOrig v
  65. then addsq(TayOrig u,TayOrig v)
  66. else nil,
  67. TayFlagsCombine(u,v))
  68. where z := addtaylor1(tp,TayCoeffList u,TayCoeffList v);
  69. symbolic procedure addtaylor1(tmpl,l1,l2);
  70. %
  71. % Returns the coefflist that is the sum of coefflists l1, l2.
  72. %
  73. begin scalar cff,clist,tn,tp;
  74. tp := TpDegreeList tmpl;
  75. tn := TpNextList tmpl;
  76. %
  77. % The following is necessary to ensure that the rplacd below
  78. % doesn't do any harm to the list in l1.
  79. %
  80. clist := for each cc in l1 join
  81. if not null numr TayCfSq cc
  82. then if not exceeds!-order(tn,TayCfPl cc)
  83. then {TayMakeCoeff(TayCfPl cc,TayCfSq cc)}
  84. else <<tn := min2!-order(tn,tp,TayCfPl cc);nil>>;
  85. for each cc in l2 do
  86. if not null numr TayCfSq cc
  87. then if not exceeds!-order(tn,TayCfPl cc)
  88. then <<cff := assoc(TayCfPl cc,clist);
  89. if null cff then clist := enter!-sorted(cc,clist)
  90. else rplacd(cff,addsq(TayCfSq cff,TayCfSq cc))>>
  91. else tn := min2!-order(tn,tp,TayCfPl cc);
  92. return tn . subs2coefflist clist
  93. end;
  94. symbolic procedure negtaylor u;
  95. make!-Taylor!* (
  96. negtaylor1 TayCoeffList u,
  97. TayTemplate u,
  98. if !*taylorkeeporiginal and TayOrig u
  99. then negsq TayOrig u else nil,
  100. TayFlags u)$
  101. symbolic procedure negtaylor1 tcl;
  102. for each cc in tcl collect
  103. TayMakeCoeff (TayCfPl cc, negsq TayCfSq cc)$
  104. symbolic procedure multtaylor(u,v);
  105. %
  106. % u and v are two Taylor kernels,
  107. % result is their product, as a Taylor kernel.
  108. %
  109. (if null tps then confusion 'multtaylor
  110. else multtaylor!*(u,v,tps))
  111. where tps := mult!.comp!.tp!.(u,v,nil);
  112. symbolic procedure multtaylor!-as!-sq(u,v);
  113. begin scalar tps;
  114. return
  115. if Taylor!-kernel!-sq!-p u and Taylor!-kernel!-sq!-p v and
  116. (tps := mult!.comp!.tp!.(mvar numr u,mvar numr v,nil))
  117. then !*tay2q multtaylor!*(mvar numr u,mvar numr v,tps)
  118. else multsq(u,v)
  119. end;
  120. symbolic procedure multtaylor!*(u,v,tps);
  121. make!-Taylor!*
  122. (cdr z,replace!-next(car tps,car z),
  123. if !*taylorkeeporiginal and TayOrig u and TayOrig v
  124. then multsq (TayOrig u, TayOrig v)
  125. else nil,
  126. TayFlagsCombine(u,v))
  127. where z := multtaylor1(car tps,TayCoeffList u,TayCoeffList v);
  128. symbolic procedure multtaylor1(tmpl,l1,l2);
  129. %
  130. % Returns the coefflist that is the product of coefflists l1, l2,
  131. % with respect to Taylor template tp.
  132. %
  133. begin scalar cff,pl,rlist,sq,tn,tp;
  134. tp := TpDegreeList tmpl;
  135. tn := TpNextList tmpl;
  136. for each cf1 in l1 do
  137. for each cf2 in l2 do <<
  138. pl := add!-degrees(TayCfPl cf1,TayCfPl cf2);
  139. if not exceeds!-order(tn,pl) then <<
  140. sq := multsq(TayCfSq cf1,TayCfSq cf2);
  141. if not null numr sq then <<
  142. cff := assoc(pl,rlist);
  143. if null cff
  144. then rlist := enter!-sorted(TayMakeCoeff(pl,sq),rlist)
  145. else rplacd(cff,addsq(TayCfSq cff,sq))>>>>
  146. else tn := min2!-order(tn,tp,pl)>>;
  147. return tn . subs2coefflist rlist
  148. end;
  149. comment Implementation of Taylor division.
  150. We use the following algorithm:
  151. Suppose the numerator and denominator are of the form
  152. ----- -----
  153. \ k \ l
  154. f(x) = > a x , g(x) = > b x ,
  155. / k / l
  156. ----- -----
  157. k>=k0 l>=l0
  158. respectively. The quotient is supposed to be
  159. -----
  160. \ m
  161. h(x) = > c x .
  162. / m
  163. -----
  164. m>=m0
  165. Clearly: m0 = k0 - l0. This follows immediately from
  166. f(x) = g(x) * h(x) by comparing lowest order terms.
  167. This equation can now be written:
  168. ----- ----- -----
  169. \ k \ l+m \ n
  170. > a x = > b c x = > b c x .
  171. / k / l m / n-m m
  172. ----- ----- -----
  173. k>=k0 l>=l0 m0<=m<=n-l0
  174. m>=m0 n>=l0+m0
  175. Comparison of orders leads immediately to
  176. -----
  177. \
  178. a = > b c , n>=l0+m0 .
  179. n / n-m m
  180. -----
  181. m0<=m<=n-l0
  182. We write the last term of the series separately:
  183. -----
  184. \
  185. a = > b c + b c , n>=l0+m0 ,
  186. n / n-m m l0 n-l0
  187. -----
  188. m0<=m<n-l0
  189. which leads immediately to the recursion formula
  190. / ----- \
  191. 1 | \ |
  192. c = ----- | a - > b c | .
  193. n-l0 b | n / n-m m |
  194. l0 \ ----- /
  195. m0<=m<n-l0
  196. Finally we shift n by l0 and obtain
  197. / ----- \
  198. 1 | \ |
  199. c = ----- | a - > b c | . (*)
  200. n b | n+l0 / n-m+l0 m |
  201. l0 \ ----- /
  202. m0<=m<n
  203. For multidimensional Taylor series we can use the same
  204. expression if we interpret all indices as appropriate
  205. multiindices.
  206. For computing the reciprocal of a Taylor series we use
  207. the formula (*) above with f(x) = 1, i.e. lowest order
  208. coefficient = 1, all others = 0;
  209. symbolic procedure quottaylor(u,v);
  210. %
  211. % Divides Taylor series u by Taylor series v.
  212. % Like invtaylor, it depends on ordering of the coefficients
  213. % according to the degree of the expansion variables (lowest first).
  214. %
  215. (if null tps then confusion 'quottaylor
  216. else quottaylor!*(u,v,tps))
  217. where tps := mult!.comp!.tp!.(u,v,t);
  218. symbolic procedure quottaylor!-as!-sq(u,v);
  219. begin scalar tps;
  220. return
  221. if Taylor!-kernel!-sq!-p u and Taylor!-kernel!-sq!-p v and
  222. (tps := mult!.comp!.tp!.(mvar numr u,mvar numr v,t))
  223. then !*tay2q quottaylor!*(mvar numr u,mvar numr v,tps)
  224. else quotsq(u,v)
  225. end;
  226. symbolic procedure quottaylor!*(u,v,tps);
  227. make!-Taylor!*(
  228. cdr z,replace!-next(car tps,car z),
  229. if !*taylorkeeporiginal and TayOrig u and TayOrig v
  230. then quotsq (TayOrig u, TayOrig v)
  231. else nil,
  232. TayFlagsCombine(u,v))
  233. where z := quottaylor1(car tps,TayCoeffList u,TayCoeffList v);
  234. symbolic procedure quottaylor1(tay,lu,lv);
  235. %
  236. % Does the real work, called also by the expansion procedures.
  237. % Returns the coefflist.
  238. %
  239. Taylor!:
  240. begin scalar clist,il,lminu,lminv,aminu,aminv,ccmin,coefflis,tp,tn;
  241. tp := TpDegreeList tay;
  242. tn := TpNextList tay;
  243. lu := prune!-coefflist lu;
  244. if null lu then return tn . nil;
  245. lminu := TayCfPl car lu;
  246. for each el in cdr lu do
  247. if not null numr TayCfSq el then
  248. lminu := taydegree!-min2(lminu,TayCfPl el);
  249. aminu := if lminu neq TayCfPl car lu then TayGetCoeff(lminu,lu)
  250. else TayCfSq car lu;
  251. lv := prune!-coefflist lv;
  252. if null lv then Taylor!-error!*('not!-a!-unit,'quottaylor);
  253. il := common!-increment(smallest!-increment lu,
  254. smallest!-increment lv);
  255. aminv := TayCfSq car lv; % first element is that of lowest degree
  256. lminv := TayCfPl car lv;
  257. for each cf in cdr lv do
  258. if not taydegree!-strict!<!=(lminv,TayCfPl cf)
  259. then Taylor!-error('not!-a!-unit,'quottaylor);
  260. ccmin := subtr!-degrees(lminu,lminv);
  261. clist := {TayMakeCoeff(ccmin,quotsq(aminu,aminv))};
  262. coefflis := makecoeffs(ccmin,tn,il);
  263. if null coefflis then return tn . clist;
  264. for each cc in cdr coefflis do begin scalar sq;
  265. sq := subtrsq(TayGetCoeff(add!-degrees(cc,lminv),lu),
  266. addcoeffs(clist,lv,ccmin,cc));
  267. if exceeds!-order(tn,cc)
  268. then tn := min2!-order(tn,tp,cc)
  269. else if not null numr sq
  270. then clist := TayMakeCoeff(cc,quotsq(sq,aminv)) . clist;
  271. end;
  272. return tn . subs2coefflist reversip clist
  273. end;
  274. symbolic procedure taydegree!-min2(u,v);
  275. %
  276. % (TayPowerList, TayPowerList) -> TayPowerList
  277. %
  278. % returns minimum of both powerlists
  279. %
  280. for i := 1 : length u collect begin scalar l1,l2;
  281. l1 := nth(u,i);
  282. l2 := nth(v,i);
  283. return
  284. for j := 1 : length l1 collect
  285. Taylor!: min2(nth(l1,j),nth(l2,j))
  286. end;
  287. symbolic procedure makecoeffshom(cmin,lastterm,incr);
  288. if null cmin then '(nil)
  289. else Taylor!:
  290. for i := 0 step incr until lastterm join
  291. for each l in makecoeffshom(cdr cmin,lastterm - i,incr) collect
  292. (car cmin + i) . l;
  293. symbolic procedure makecoeffshom0(nvars,lastterm,incr);
  294. if nvars=0 then '(nil)
  295. else Taylor!:
  296. for i := 0 step incr until lastterm join
  297. for each l in makecoeffshom0(nvars - 1,lastterm - i,incr) collect
  298. i . l;
  299. symbolic procedure makecoeffs(plmin,dgl,il);
  300. %
  301. % plmin the list of the smallest terms, dgl the degreelist
  302. % of the largest term, il the list of increments.
  303. % It returns an ordered list of all index lists matching this
  304. % requirement.
  305. %
  306. Taylor!:
  307. if null plmin then '(nil)
  308. else for each l1 in makecoeffs(cdr plmin,cdr dgl,cdr il) join
  309. for each l2 in makecoeffshom(
  310. car plmin,
  311. car dgl - get!-degree car plmin - car il,
  312. car il)
  313. collect (l2 . l1);
  314. symbolic procedure makecoeffs0(tp,dgl,il);
  315. %
  316. % tp is a Taylor template,
  317. % dgl a next list (m1 ... ),
  318. % il the list of increments (i1 ... ).
  319. % It returns an ordered list of all index lists matching the
  320. % requirement that for every element ni: 0 <= ni < mi and ni is
  321. % a multiple of i1
  322. %
  323. Taylor!:
  324. if null tp then '(nil)
  325. else for each l1 in makecoeffs0(cdr tp,cdr dgl,cdr il) join
  326. for each l2 in makecoeffshom0(length TayTpElVars car tp,
  327. car dgl - car il,
  328. car il)
  329. collect (l2 . l1);
  330. symbolic procedure makecoeffpairs1(plmin,pl,lmin,il);
  331. Taylor!:
  332. if null pl then '((nil))
  333. else for each l1 in makecoeffpairs1(
  334. cdr plmin,
  335. cdr pl,cdr lmin,cdr il) join
  336. for each l2 in makecoeffpairshom(car plmin,
  337. car pl,car lmin,- car il)
  338. collect (car l2 . car l1) . (cdr l2 . cdr l1)$
  339. symbolic procedure makecoeffpairs(plmin,pl,lmin,il);
  340. reversip cdr makecoeffpairs1(plmin,pl,lmin,il);
  341. symbolic procedure makecoeffpairshom(clow,chigh,clmin,inc);
  342. if null clmin then '((nil))
  343. else Taylor!:
  344. for i := car chigh step inc until car clow join
  345. for each l in makecoeffpairshom(cdr clow,cdr chigh,cdr clmin,inc)
  346. collect (i . car l) . ((car chigh + car clmin - i) . cdr l);
  347. symbolic procedure addcoeffs(cl1,cl2,pllow,plhigh);
  348. begin scalar s,il;
  349. s := nil ./ 1;
  350. il := common!-increment(smallest!-increment cl1,
  351. smallest!-increment cl2);
  352. for each p in makecoeffpairs(pllow,plhigh,caar cl2,il) do
  353. s := addsq(s,multsq(TayGetCoeff(car p,cl1),
  354. TayGetCoeff(cdr p,cl2)));
  355. return s
  356. % return for each p in makecoeffpairs(ccmin,cc,caar cl2,dl) addsq
  357. % multsq(TayGetCoeff(car p,cl1),TayGetCoeff(cdr p,cl2));
  358. end;
  359. symbolic procedure invtaylor u;
  360. %
  361. % Inverts a Taylor series expansion,
  362. % depends on ordering of the coefficients according to the
  363. % degree of the expansion variables (lowest first)
  364. %
  365. if null u then confusion 'invtaylor
  366. else begin scalar tps;
  367. tps := inv!.tp!. u;
  368. return make!-Taylor!*(
  369. invtaylor1(car tps,TayCoeffList u),
  370. car tps,
  371. if !*taylorkeeporiginal and TayOrig u
  372. then invsq TayOrig u
  373. else nil,
  374. TayFlags u);
  375. end;
  376. symbolic procedure invtaylor1(tay,l);
  377. %
  378. % Does the real work, called also by the expansion procedures.
  379. % Returns the coefflist.
  380. %
  381. Taylor!:
  382. begin scalar clist,amin,ccmin,coefflis,il;
  383. l := prune!-coefflist l;
  384. if null l then Taylor!-error!*('not!-a!-unit,'invtaylor);
  385. amin := TayCfSq car l; % first element must have lowest degree
  386. ccmin := TayCfPl car l;
  387. for each cf in cdr l do
  388. if not taydegree!-strict!<!=(ccmin,TayCfPl cf)
  389. then Taylor!-error('not!-a!-unit,'invtaylor);
  390. il := smallest!-increment l;
  391. ccmin := invert!-powerlist ccmin;
  392. clist := {TayMakeCoeff(ccmin,invsq amin)};
  393. coefflis := makecoeffs(ccmin,TpNextList tay,il);
  394. if not null coefflis
  395. then for each cc in cdr coefflis do begin scalar sq;
  396. sq := addcoeffs(clist,l,ccmin,cc);
  397. if not null numr sq
  398. then clist := TayMakeCoeff(cc,negsq quotsq(sq,amin))
  399. . clist;
  400. end;
  401. return subs2coefflist reversip clist
  402. end;
  403. endmodule;
  404. end;