tayutils.red 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. module TayUtils;
  2. %*****************************************************************
  3. %
  4. % Utility functions that operate on Taylor kernels
  5. %
  6. %*****************************************************************
  7. exports add!-degrees, add!.comp!.tp!., check!-for!-cst!-Taylor,
  8. comp!.tp!.!-p, delete!-superfluous!-coeffs, enter!-sorted,
  9. exceeds!-order, exceeds!-order!-variant, find!-non!-zero,
  10. get!-cst!-coeff, inv!.tp!., is!-neg!-pl, min2!-order,
  11. mult!.comp!.tp!., rat!-kern!-pow, replace!-next,
  12. subtr!-degrees, subtr!-tp!-order, taydegree!<,
  13. taydegree!-strict!<!=, taymincoeff, tayminpowerlist,
  14. Taylor!*!-constantp, Taylor!*!-nzconstantp, Taylor!*!-onep,
  15. Taylor!*!-zerop, TayTpmin2, tp!-greaterp, truncate!-coefflist,
  16. truncate!-Taylor!*;
  17. imports
  18. % from the REDUCE kernel:
  19. ./, gcdn, geq, lastpair, mkrn, neq, nth, numr, reversip,
  20. % from the header module:
  21. !*tay2q, get!-degree, get!-degreelist, make!-cst!-powerlist,
  22. Make!-Taylor!*, nzerolist, prune!-coefflist, TayCfPl, TayCfSq,
  23. TayCoeffList, TayGetCoeff, TayFlags, Taylor!:, TayOrig,
  24. TayTemplate, TayTpElNext, TayTpElOrder, TayTpElPoint,
  25. TayTpElVars, TpDegreeList, TpNextList,
  26. % from module Tayintro:
  27. confusion,
  28. % from module TayUtils:
  29. TayCoeffList!-zerop;
  30. symbolic procedure add!-degrees (dl1, dl2);
  31. %
  32. % calculates the element-wise sum of two degree lists dl1, dl2.
  33. %
  34. Taylor!:
  35. begin scalar dl,u,v,w;
  36. while dl1 do <<
  37. u := car dl1;
  38. v := car dl2;
  39. w := nil;
  40. while u do <<
  41. w := (car u + car v) . w;
  42. u := cdr u;
  43. v := cdr v>>;
  44. dl := reversip w . dl;
  45. dl1 := cdr dl1;
  46. dl2 := cdr dl2>>;
  47. return reversip dl
  48. end;
  49. symbolic procedure subtr!-degrees(dl1,dl2);
  50. %
  51. % calculates the element-wise difference of two degree lists dl1, dl2.
  52. %
  53. Taylor!:
  54. begin scalar dl,u,v,w;
  55. while dl1 do <<
  56. u := car dl1;
  57. v := car dl2;
  58. w := nil;
  59. while u do <<
  60. w := (car u - car v) . w;
  61. u := cdr u;
  62. v := cdr v>>;
  63. dl := reversip w . dl;
  64. dl1 := cdr dl1;
  65. dl2 := cdr dl2>>;
  66. return reversip dl
  67. end;
  68. symbolic procedure find!-non!-zero pl;
  69. %
  70. % pl is a power list. Returns pair (n . m) of position of first
  71. % non zero degree.
  72. %
  73. begin scalar u; integer n, m;
  74. n := 1;
  75. loop:
  76. m := 1;
  77. u := car pl;
  78. loop2:
  79. if not (car u = 0) then return (n . m);
  80. u := cdr u;
  81. m := m + 1;
  82. if not null u then goto loop2;
  83. pl := cdr pl;
  84. n := n + 1;
  85. if null pl then confusion 'find!-non!-zero;
  86. goto loop
  87. end$
  88. symbolic procedure lcmn(n,m);
  89. %
  90. % returns the least common multiple of two integers m,n.
  91. %
  92. n*(m/gcdn(n,m));
  93. symbolic smacro procedure get!-denom expo;
  94. if atom expo then 1 else cddr expo;
  95. symbolic procedure get!-denom!-l expol;
  96. <<for each el in cdr expol do
  97. result := lcmn(result,get!-denom el);
  98. result>>
  99. where result := get!-denom car expol;
  100. symbolic procedure get!-denom!-ll(dl,pl);
  101. if null dl then nil
  102. else lcmn(car dl,get!-denom!-l car pl)
  103. . get!-denom!-ll(cdr dl, cdr pl);
  104. symbolic procedure smallest!-increment cfl;
  105. if null cfl then confusion 'smallest!-increment
  106. else begin scalar result;
  107. result := for each l in TayCfPl car cfl collect get!-denom!-l l;
  108. for each el in cdr cfl do
  109. result := get!-denom!-ll(result,TayCfPl el);
  110. return for each n in result collect if n=1 then n else mkrn(1,n);
  111. end;
  112. symbolic procedure common!-increment(dl1,dl2);
  113. begin scalar result,l;
  114. loop:
  115. l := lcmn(get!-denom car dl1,get!-denom car dl2);
  116. result := (if l=1 then l else mkrn(1,l)) . result;
  117. dl1 := cdr dl1;
  118. dl2 := cdr dl2;
  119. if not null dl1 then goto loop
  120. else if not null dl2 then confusion 'common!-increment
  121. else return reversip result
  122. end;
  123. symbolic procedure min2!-order(nextlis,ordlis,dl);
  124. %
  125. % (List of Integers, List of Integers, TayPowerList) -> Boolean
  126. %
  127. % nextlis is the list of TayTpElNext numbers,
  128. % ordlis the list if TayTpElOrder numbers,
  129. % dl the degreelist of a coefficient.
  130. % Dcecrease the TayTpElNext number if the degree is greater than
  131. % the order, but smaller than the next.
  132. % Returns the corrected nextlis.
  133. %
  134. if null nextlis then nil
  135. else (Taylor!: (if dg > car ordlis then min2(dg,car nextlis)
  136. else car nextlis) where dg := get!-degree car dl)
  137. . min2!-order(cdr nextlis,cdr ordlis,cdr dl);
  138. symbolic procedure replace!-next(tp,nl);
  139. %
  140. % Given a template and a list of exponents, returns a template
  141. % with the next part replaced.
  142. %
  143. if null tp then nil
  144. else {TayTpElVars car tp,
  145. TayTpElPoint car tp,
  146. TayTpElOrder car tp,
  147. car nl}
  148. . replace!-next(cdr tp,cdr nl);
  149. symbolic procedure comp!.tp!.!-p (u, v);
  150. %
  151. % Checks templates of Taylor kernels u and v for compatibility,
  152. % i.e. whether variables and expansion points match.
  153. % Returns t if possible.
  154. %
  155. begin;
  156. u := TayTemplate u; v := TayTemplate v;
  157. if length u neq length v then return nil;
  158. loop:
  159. if not (TayTpElVars car u = TayTpElVars car v
  160. and TayTpElPoint car u = TayTpElPoint car v)
  161. then return nil;
  162. u := cdr u; v := cdr v;
  163. if null u then return t;
  164. goto loop
  165. end$
  166. symbolic procedure add!.comp!.tp!.(u,v);
  167. %
  168. % Checks templates of Taylor kernels u and v for compatibility
  169. % when adding them, i.e. whether variables and expansion points
  170. % match.
  171. % Returns either a list containing a new Taylor template whose
  172. % degrees are the minimum of the corresponding degrees of u and v,
  173. % or nil if variables or expansion point(s) do not match.
  174. %
  175. Taylor!:
  176. begin scalar w;
  177. u := TayTemplate u; v := TayTemplate v;
  178. if length u neq length v then return nil;
  179. if null u then return {nil};
  180. loop:
  181. if not (TayTpElVars car u = TayTpElVars car v
  182. and TayTpElPoint car u = TayTpElPoint car v)
  183. then return nil
  184. else w := {TayTpElVars car u,
  185. TayTpElPoint car u,
  186. min2(TayTpElOrder car u,TayTpElOrder car v),
  187. min2(TayTpElNext car u,TayTpElNext car v)}
  188. . w;
  189. u := cdr u; v := cdr v;
  190. if null u then return {reversip w};
  191. goto loop
  192. end;
  193. symbolic procedure taymindegreel(pl,dl);
  194. Taylor!:
  195. if null pl then nil
  196. else min2(get!-degree car pl,car dl)
  197. . taymindegreel(cdr pl,cdr dl);
  198. symbolic procedure get!-min!-degreelist cfl;
  199. Taylor!:
  200. if null cfl then confusion 'get!-min!-degreelist
  201. else if null cdr cfl then get!-degreelist TayCfPl car cfl
  202. else taymindegreel(TayCfPl car cfl,
  203. get!-min!-degreelist cdr cfl);
  204. symbolic procedure mult!.comp!.tp!.(u,v,div!?);
  205. %
  206. % Checks templates of Taylor kernels u and v for compatibility
  207. % when multiplying or dividing them, i.e., whether variables and
  208. % expansion points match. The difference to addition is that
  209. % in addition to the new template it returns two degreelists
  210. % and two nextlists to be used by truncate!-coefflist which
  211. % are made up so that the kernels have the same number of terms.
  212. %
  213. Taylor!:
  214. begin scalar cf1,cf2,next1,next2,ord1,ord2,w,
  215. !#terms!-1,!#terms!-next,dl1,dl2,mindg;
  216. cf1 := prune!-coefflist TayCoeffList u;
  217. if null cf1 then dl1 := nzerolist length TayTemplate u
  218. else dl1 := get!-min!-degreelist cf1;
  219. cf2 := prune!-coefflist TayCoeffList v;
  220. if null cf2 then dl2 := nzerolist length TayTemplate v
  221. else dl2 := get!-min!-degreelist cf2;
  222. u := TayTemplate u; v := TayTemplate v;
  223. if length u neq length v then return nil;
  224. if null u then return {nil,nil,nil,nil,nil};
  225. loop:
  226. if not (TayTpElVars car u = TayTpElVars car v
  227. and TayTpElPoint car u = TayTpElPoint car v)
  228. then return nil;
  229. mindg := if div!? then car dl1 - car dl2 else car dl1 + car dl2;
  230. !#terms!-1 := min2(TayTpElOrder car u - car dl1,
  231. TayTpElOrder car v - car dl2);
  232. !#terms!-next := min2(TayTpElNext car u - car dl1,
  233. TayTpElNext car v - car dl2);
  234. ord1 := (!#terms!-1 + car dl1) . ord1;
  235. ord2 := (!#terms!-1 + car dl2) . ord2;
  236. next1 := (!#terms!-next + car dl1) . next1;
  237. next2 := (!#terms!-next + car dl2) . next2;
  238. w := {TayTpElVars car u,TayTpElPoint car u,
  239. mindg + !#terms!-1,mindg + !#terms!-next}
  240. . w;
  241. u := cdr u; v := cdr v; dl1 := cdr dl1; dl2 := cdr dl2;
  242. if null u then return {reversip w,
  243. reversip ord1,
  244. reversip ord2,
  245. reversip next1,
  246. reversip next2};
  247. goto loop
  248. end;
  249. symbolic procedure inv!.tp!. u;
  250. %
  251. % Checks template of Taylor kernel u for inversion. It returns a
  252. % template (to be used by truncate!-coefflist)
  253. % which is made up so that the resulting kernel has the correct
  254. % number of terms.
  255. %
  256. Taylor!:
  257. begin scalar w,cf,!#terms!-1,!#terms!-next,dl,mindg;
  258. cf := prune!-coefflist TayCoeffList u;
  259. if null cf then dl := nzerolist length TayTemplate u
  260. else dl := get!-degreelist TayCfPl car cf;
  261. u := TayTemplate u;
  262. if null u then return {nil,nil};
  263. loop:
  264. mindg := - car dl;
  265. !#terms!-1 := TayTpElOrder car u - car dl;
  266. !#terms!-next := TayTpElNext car u - car dl;
  267. w := {TayTpElVars car u,TayTpElPoint car u,mindg + !#terms!-1,
  268. mindg + !#terms!-next}
  269. . w;
  270. u := cdr u; dl := cdr dl;
  271. if null u then return {reversip w};
  272. goto loop
  273. end;
  274. symbolic smacro procedure taycoeff!-before(cc1,cc2);
  275. %
  276. % (TayCoeff, TayCoeff) -> Boolean
  277. %
  278. % returns t if coeff cc1 is ordered before cc2
  279. % both are of the form (degreelist . sq)
  280. %
  281. taydegree!<(TayCfPl cc1,TayCfPl cc2);
  282. symbolic procedure taydegree!<(u,v);
  283. %
  284. % (TayPowerList, TayPowerList) -> Boolean
  285. %
  286. % returns t if coefflist u is ordered before v
  287. %
  288. Taylor!:
  289. begin scalar u1,v1;
  290. loop:
  291. u1 := car u;
  292. v1 := car v;
  293. loop2:
  294. if car u1 > car v1 then return nil
  295. else if car u1 < car v1 then return t;
  296. u1 := cdr u1;
  297. v1 := cdr v1;
  298. if not null u1 then go to loop2;
  299. u := cdr u;
  300. v := cdr v;
  301. if not null u then go to loop
  302. end;
  303. symbolic procedure taydegree!-strict!<!=(u,v);
  304. %
  305. % (TayPowerList, TayPowerList) -> Boolean
  306. %
  307. % returns t if every component coefflist u is less or equal than
  308. % respective component of v
  309. %
  310. Taylor!:
  311. begin scalar u1,v1;
  312. loop:
  313. u1 := car u;
  314. v1 := car v;
  315. loop2:
  316. if car u1 > car v1 then return nil;
  317. u1 := cdr u1;
  318. v1 := cdr v1;
  319. if not null u1 then go to loop2;
  320. u := cdr u;
  321. v := cdr v;
  322. if not null u then go to loop;
  323. return t
  324. end;
  325. symbolic procedure exceeds!-order(ordlis,cf);
  326. %
  327. % (List of Integers, TayPowerlist) -> Boolean
  328. %
  329. % Returns t if the degrees in coefficient cf are greater or
  330. % equal than those in the degreelist ordlis
  331. %
  332. if null ordlis then nil
  333. else Taylor!:(get!-degree car cf >= car ordlis)
  334. or exceeds!-order(cdr ordlis,cdr cf);
  335. symbolic procedure exceeds!-order!-variant(ordlis,cf);
  336. %
  337. % (List of Integers, TayPowerlist) -> Boolean
  338. %
  339. % Returns t if the degrees in coefficient cf are greater or
  340. % equal than those in the degreelist ordlis
  341. %
  342. if null ordlis then nil
  343. else Taylor!:(get!-degree car cf > car ordlis)
  344. or exceeds!-order!-variant(cdr ordlis,cdr cf);
  345. symbolic procedure enter!-sorted (u, alist);
  346. %
  347. % (TayCoeff, TayCoeffList) -> TayCoeffList
  348. %
  349. % enters u into the alist alist according to the standard
  350. % ordering for the car part
  351. %
  352. if null alist then {u}
  353. else if taycoeff!-before (u, car alist) then u . alist
  354. else car alist . enter!-sorted (u, cdr alist)$
  355. symbolic procedure delete!-superfluous!-coeffs(cflis,pos,n);
  356. %
  357. % (TayCoeffList, Integer, Integer) -> TayCoeffList
  358. %
  359. % This procedure deletes all coefficients of a TayCoeffList cflis
  360. % whose degree in position pos exceeds n.
  361. %
  362. Taylor!:
  363. for each cc in cflis join
  364. (if get!-degree nth(TayCfPl cc,pos) > n then nil else {cc});
  365. symbolic procedure truncate!-coefflist (cflis, dl);
  366. %
  367. % (TayCoeffList, List of Integers) -> TayCoeffList
  368. %
  369. % Deletes all coeffs from coefflist cflis that are equal or greater
  370. % in degree than the corresponding degree in the degreelist dl.
  371. %
  372. begin scalar l;
  373. for each cf in cflis do
  374. if not exceeds!-order (dl, TayCfPl cf) then l := cf . l;
  375. return reversip l
  376. end;
  377. symbolic procedure TayTp!-min2(tp1,tp2);
  378. %
  379. % finds minimum (w.r.t. Order and Next parts) of compatible
  380. % templates tp1 and tp2
  381. %
  382. Taylor!:
  383. if null tp1 then nil
  384. else if not (TayTpElVars car tp1 = TayTpElVars car tp2 and
  385. TayTpElPoint car tp1 = TayTpElPoint car tp2)
  386. then confusion 'TayTpmin2
  387. else {TayTpElVars car tp1,TayTpElPoint car tp2,
  388. min2(TayTpElOrder car tp1,TayTpElOrder car tp2),
  389. min2(TayTpElNext car tp1,TayTpElNext car tp2)}
  390. . TayTp!-min2(cdr tp1,cdr tp2);
  391. symbolic procedure truncate!-Taylor!*(tay,ntp);
  392. %
  393. % tcl is a coefflist for template otp
  394. % truncate it to coefflist for template ntp
  395. %
  396. Taylor!:
  397. begin scalar nl,ol,l,tp,tcl,otp;
  398. tcl := TayCoeffList tay;
  399. otp := TayTemplate tay;
  400. tp := for each pp in pair(ntp,otp) collect
  401. {TayTpElVars car pp,
  402. TayTpElPoint car pp,
  403. min2(TayTpElOrder car pp,TayTpElOrder cdr pp),
  404. min2(TayTpElNext car pp,TayTpElNext cdr pp)};
  405. nl := TpNextList tp;
  406. ol := TpDegreeList tp;
  407. for each cf in tcl do
  408. if not null numr TayCfSq cf
  409. % then ((if not exceeds!-order(nl,pl) then l := cf . l
  410. % else nl := min2!-order(nl,ol,pl))
  411. then ((if not exceeds!-order!-variant(ol,pl) then l := cf . l
  412. else nl := min2!-order(nl,ol,pl))
  413. where pl := TayCfPl cf);
  414. return make!-Taylor!*(reversip l,replace!-next(tp,nl),
  415. TayOrig tay,TayFlags tay)
  416. end;
  417. symbolic procedure tp!-greaterp(tp1,tp2);
  418. %
  419. % Given two templates tp1 and tp2 with matching variables and
  420. % expansion points this function returns t if the expansion
  421. % order wrt at least one variable is greater in tp1 than in tp2.
  422. %
  423. if null tp1 then nil
  424. else Taylor!: (TayTpElOrder car tp1 > TayTpElOrder car tp2)
  425. or tp!-greaterp(cdr tp1,cdr tp2);
  426. symbolic procedure subtr!-tp!-order(tp1,tp2);
  427. %
  428. % Given two templates tp1 and tp2 with matching variables and
  429. % expansion points this function returns the difference in their
  430. % orders.
  431. %
  432. Taylor!:
  433. if null tp1 then nil
  434. else (TayTpElOrder car tp1 - TayTpElOrder car tp2)
  435. . subtr!-tp!-order(cdr tp1,cdr tp2);
  436. comment Procedures to non-destructively modify Taylor templates;
  437. symbolic procedure addto!-all!-TayTpElOrders(tp,nl);
  438. Taylor!:
  439. if null tp then nil
  440. else {TayTpElVars car tp,
  441. TayTpElPoint car tp,
  442. TayTpElOrder car tp + car nl,
  443. TayTpElNext car tp + car nl} .
  444. addto!-all!-TayTpElOrders(cdr tp,cdr nl);
  445. symbolic procedure taymincoeff cflis;
  446. %
  447. % Returns degree of first non-zero coefficient
  448. % or 0 if there isn't any.
  449. %
  450. if null cflis then 0
  451. else if not null numr TayCfSq car cflis
  452. then get!-degree car TayCfPl car cflis
  453. else taymincoeff cdr cflis;
  454. symbolic procedure tayminpowerlist cflis;
  455. %
  456. % Returns degreelist of first non-zero coefficient of TayCoeffList
  457. % cflis or a list of zeroes if there isn't any.
  458. %
  459. if null cflis then confusion 'tayminpowerlist
  460. else tayminpowerlist1(cflis,length TayCfPl car cflis);
  461. symbolic procedure tayminpowerlist1(cflis,l);
  462. if null cflis then nzerolist l
  463. else if null numr TayCfSq car cflis
  464. then tayminpowerlist1(cdr cflis,l)
  465. else get!-degreelist TayCfPl car cflis;
  466. symbolic procedure get!-cst!-coeff tay;
  467. TayGetCoeff(make!-cst!-powerlist TayTemplate tay,TayCoeffList tay);
  468. symbolic procedure Taylor!*!-constantp tay;
  469. Taylor!*!-constantp1(make!-cst!-powerlist TayTemplate tay,
  470. TayCoeffList tay);
  471. symbolic procedure Taylor!*!-constantp1(pl,tcf);
  472. if null tcf then t
  473. else if TayCfPl car tcf = pl
  474. then TayCoeffList!-zerop cdr tcf
  475. else if not null numr TayCfSq car tcf then nil
  476. else Taylor!*!-constantp1(pl,cdr tcf);
  477. symbolic procedure check!-for!-cst!-Taylor tay;
  478. begin scalar pl,tc;
  479. pl := make!-cst!-powerlist TayTemplate tay;
  480. tc := TayCoeffList tay;
  481. return if Taylor!*!-constantp1(pl,tc) then TayGetCoeff(pl,tc)
  482. else !*tay2q tay
  483. end;
  484. symbolic procedure Taylor!*!-nzconstantp tay;
  485. Taylor!*!-nzconstantp1(make!-cst!-powerlist TayTemplate tay,
  486. TayCoeffList tay);
  487. symbolic procedure Taylor!*!-nzconstantp1(pl,tcf);
  488. if null tcf then nil
  489. else if TayCfPl car tcf = pl
  490. then if null numr TayCfSq car tcf then nil
  491. else TayCoeffList!-zerop cdr tcf
  492. else if TayCfPl car tcf neq pl and
  493. not null numr TayCfSq car tcf
  494. then nil
  495. else Taylor!*!-nzconstantp1(pl,cdr tcf);
  496. symbolic procedure Taylor!*!-onep tay;
  497. Taylor!-onep1(make!-cst!-powerlist TayTemplate tay,TayCoeffList tay);
  498. symbolic procedure Taylor!-onep1(pl,tcf);
  499. if null tcf then nil
  500. else if TayCfPl car tcf = pl
  501. then if TayCfSq car tcf = (1 ./ 1)
  502. then TayCoeffList!-zerop cdr tcf
  503. else nil
  504. else if null numr TayCfSq car tcf
  505. then Taylor!*!-nzconstantp1(pl,cdr tcf)
  506. else nil;
  507. symbolic procedure is!-neg!-pl pl;
  508. %
  509. % Returns t if any of the exponents in pl is negative.
  510. %
  511. Taylor!:
  512. if null pl then nil
  513. else if get!-degree car pl < 0 then t
  514. else is!-neg!-pl cdr pl;
  515. symbolic procedure rat!-kern!-pow(x,pos);
  516. %
  517. % check that s.f. x is a kernel to a rational power.
  518. % if pos is t allow only positive exponents.
  519. % returns pair (kernel . power)
  520. %
  521. begin scalar y; integer n;
  522. if domainp x or not null red x or not (lc x=1) then return nil;
  523. n := ldeg x;
  524. x := mvar x;
  525. Taylor!:
  526. if eqcar(x,'sqrt) then return (cadr x . mkrn(1,2)*n)
  527. else if eqcar(x,'expt) and (y := simprn{caddr x})
  528. then if null pos or (y := car y)>0
  529. then return (cadr x . (y*n))
  530. else return nil
  531. else return (x . n)
  532. end;
  533. endmodule;
  534. end;