tayintrf.red 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. module TayIntrf;
  2. %*****************************************************************
  3. %
  4. % The interface to the REDUCE simplificator
  5. %
  6. %*****************************************************************
  7. exports simptaylor, simpTaylor!*, taylorexpand$
  8. imports
  9. % from the REDUCE kernel:
  10. !*f2q, aconc!*, denr, depends, diffsq, eqcar, kernp, lastpair,
  11. leq, lprim, mkquote, mksq, multsq, mvar, neq, nth, numr, over,
  12. prepsq, revlis, reversip, simp, simp!*, subs2, subsq, typerr,
  13. % from the header module:
  14. !*tay2q, get!-degree, has!-Taylor!*, has!-TayVars,
  15. make!-Taylor!*, multintocoefflist, resimptaylor, TayCfPl,
  16. TayCfSq, TayCoeffList, TayFlags, TayMakeCoeff, TayOrig,
  17. TayTemplate, TayTpElOrder, TayTpElPoint,
  18. Taylor!-kernel!-sq!-p, taymincoeff,
  19. % from module Tayintro:
  20. replace!-nth, Taylor!-error, var!-is!-nth,
  21. % from module TayExpnd:
  22. taylorexpand,
  23. % from module Tayutils:
  24. delete!-superfluous!-coeffs,
  25. % from module taybasic:
  26. invtaylor1, quottaylor1,
  27. % from module Tayconv:
  28. prepTaylor!*;
  29. fluid '(!*backtrace !*precise !*taylorkeeporiginal !*taylorautocombine
  30. frlis!* subfg!*);
  31. global '(mul!*);
  32. comment The following statement forces all expressions to be
  33. re-simplified if the switch `taylorautocombine' is set to on,
  34. unfortunately, this is not always sufficient;
  35. put ('taylorautocombine, 'simpfg, '((t (rmsubs))));
  36. symbolic procedure simptaylor u;
  37. %
  38. % (PrefixForm) -> s.q.
  39. %
  40. % This procedure is called directly by the simplifier.
  41. % Its argument list must be of the form
  42. % (exp, [var, var0, deg, ...]),
  43. % where [...] indicate one or more occurences.
  44. % This means that exp is to be expanded w.r.t var about var0
  45. % up to degree deg.
  46. % var may also be a list of variables, which means that the
  47. % the expansion takes place in a homogeneous way.
  48. % If var0 is the special atom infinity var is replaced by 1/var
  49. % and the result expanded about 0.
  50. %
  51. % This procedure returns the input if it cannot expand the expression.
  52. %
  53. if remainder(length u,3) neq 1
  54. then Taylor!-error('wrong!-no!-args,'taylor)
  55. else if null subfg!* then mksq('taylor . u,1)
  56. else begin scalar !*precise,arglist,degree,f,ll,result,var,var0;
  57. %
  58. % Allow automatic combination of Taylor kernels.
  59. %
  60. if !*taylorautocombine and not ('taysimpsq memq mul!*)
  61. then mul!* := aconc!*(mul!*,'taysimpsq);
  62. %
  63. % First of all, call the simplifier on exp (i.e. car u),
  64. %
  65. f := simp!* car u;
  66. u := revlis cdr u; % reval instead of simp!* to handle lists
  67. arglist := u;
  68. %
  69. % then scan the rest of the argument list.
  70. %
  71. while not null arglist do
  72. << var := car arglist;
  73. var := if eqcar(var,'list) then cdr var else {var};
  74. % In principle one should use !*a2k
  75. % but typerr (maprin) does not correctly print the atom nil
  76. for each el in var collect begin
  77. el := simp!* el;
  78. if kernp el then return mvar numr el
  79. else typerr(prepsq el,'kernel)
  80. end;
  81. var0 := cadr arglist;
  82. degree := caddr arglist;
  83. if not fixp degree
  84. then typerr(degree,"order of Taylor expansion");
  85. arglist := cdddr arglist;
  86. ll := {var,var0,degree,degree + 1} . ll>>;
  87. %
  88. % Now ll is a Taylor template, i.e. of the form
  89. % ((var_1 var0_1 deg1 next_1) (var_2 var0_2 deg_2 next_2) ...)
  90. %
  91. result := taylorexpand(f,reversip ll);
  92. %
  93. % If the result does not contain a Taylor kernel, return the input.
  94. %
  95. return if has!-Taylor!* result then result
  96. else mksq('taylor . prepsq f . u,1)
  97. end;
  98. put('taylor,'simpfn,'simptaylor)$
  99. %symbolic procedure taylorexpand (f, ll);
  100. % %
  101. % % f is a s.q. that is expanded according to the list ll
  102. % % which has the form
  103. % % ((var_1 var0_1 deg1) (var_2 var0_2 deg_2) ...)
  104. % %
  105. % begin scalar result;
  106. % result := f;
  107. % for each el in ll do
  108. % %
  109. % % taylor1 is the function that does the real work
  110. % %
  111. % result := !*tay2q taylor1 (result, car el, cadr el, caddr el);
  112. % if !*taylorkeeporiginal then set!-TayOrig (mvar numr result, f);
  113. % return result
  114. % end$
  115. symbolic procedure taylor1 (f, varlis, var0, n);
  116. %
  117. % Taylor expands s.q. f w.r.t. varlis about var0 up to degree n.
  118. % var is a list of kernels, which means that the expansion
  119. % takes place in a homogeneous way if there is more than one
  120. % kernel.
  121. % If var0 is the special atom infinity all kernels in varlis are
  122. % replaced by 1/kernel. The result is then expanded about 0.
  123. %
  124. taylor1sq (if var0 eq 'infinity
  125. then subsq (f,
  126. for each krnl in varlis collect
  127. (krnl . list ('quotient, 1, krnl)))
  128. else f,
  129. varlis, var0, n)$
  130. symbolic procedure taylor1sq (f, varlis, var0, n);
  131. %
  132. % f is a standard quotient, value is a Taylor kernel.
  133. %
  134. % First check if it is a Taylor kernel
  135. %
  136. if Taylor!-kernel!-sq!-p f
  137. then if has!-TayVars(mvar numr f,varlis)
  138. %
  139. % special case: f has already been expanded w.r.t. var.
  140. %
  141. then taylorsamevar (mvar numr f, varlis, var0, n)
  142. else begin scalar y, z;
  143. f := mvar numr f;
  144. %
  145. % taylor2 returns a list of the form
  146. % ((deg1 . coeff1) (deg2 . coeff2) ... )
  147. % apply this to every coefficient in f.
  148. % car cc is the degree list of this coefficient,
  149. % cdr cc the coefficient itself.
  150. % Finally collect the new pairs
  151. % (degreelist . coefficient)
  152. %
  153. z :=
  154. for each cc in TayCoeffList f join
  155. for each cc2 in taylor2 (TayCfSq cc, varlis, var0, n)
  156. collect
  157. TayMakeCoeff (append (TayCfPl cc, TayCfPl cc2),
  158. TayCfSq cc2);
  159. %
  160. % Append the new list to the Taylor template and return.
  161. %
  162. y := append(TayTemplate f,list {varlis,var0,n,n+1});
  163. return make!-Taylor!* (z, y, TayOrig f, TayFlags f)
  164. end
  165. %
  166. % Last possible case: f is not a Taylor expression.
  167. % Expand it.
  168. %
  169. else make!-Taylor!* (
  170. taylor2 (f, varlis, var0, n),
  171. list {varlis,var0,n,n+1},
  172. if !*taylorkeeporiginal then f else nil,
  173. nil)$
  174. symbolic procedure taylor2 (f, varlis, var0, n);
  175. begin scalar result,oldklist;
  176. oldklist := get('Taylor!*,'klist);
  177. result := errorset (list ('taylor2e,
  178. mkquote f,
  179. mkquote varlis,
  180. mkquote var0,
  181. mkquote n),
  182. nil, !*backtrace);
  183. put('Taylor!*,'klist,oldklist);
  184. if atom result
  185. then Taylor!-error ('expansion, "(possible singularity!)")
  186. else return car result
  187. end$
  188. symbolic procedure taylor2e (f, varlis, var0, n);
  189. %
  190. % taylor2e expands s.q. f w.r.t. varlis about var0 up to degree n.
  191. % var is a list of kernels, which means that the expansion takes
  192. % place in a homogeneous way if there is more than one kernel.
  193. % The case that var0 is the special atom infinity has to be taken
  194. % care of by the calling function(s).
  195. % Expansion is carried out separately for numerator and
  196. % denominator. This approach has the advantage of not producing
  197. % complicated s.q.'s which usually appear if an s.q. is
  198. % differentiated. The procedure is (roughly) as follows:
  199. % if the denominator of f is free of var
  200. % then expand the numerator and divide,
  201. % else if the numerator is free of var expand the denominator,
  202. % take the reciprocal of the Taylor series and multiply,
  203. % else expand both and divide the two series.
  204. % This fails if there are nontrivial dependencies, e.g.,
  205. % if a variable is declared to depend on a kernel in varlis.
  206. % It is of course necessary that the denominator yields a unit
  207. % in the ring of Taylor series. If not, an error will be
  208. % signalled by invtaylor or quottaylor, resp.
  209. %
  210. if cdr varlis then taylor2hom (f, varlis, var0, n)
  211. else if denr f = 1 then taylor2f (numr f, car varlis, var0, n, t)
  212. else if not depends (denr f, car varlis)
  213. then multintocoefflist (taylor2f (numr f, car varlis, var0, n, t),
  214. 1 ./ denr f)
  215. else if numr f = 1
  216. then delete!-superfluous!-coeffs
  217. (invtaylor1 ({varlis,var0,n,n+1},
  218. taylor2f (denr f, car varlis, var0, n, nil)),
  219. 1, n)
  220. else if not depends (numr f, car varlis)
  221. then multintocoefflist
  222. (invtaylor1 ({varlis,var0,n,n+1},
  223. taylor2f (denr f, car varlis, var0, n, nil)),
  224. !*f2q numr f)
  225. else begin scalar denom; integer n1;
  226. denom := taylor2f (denr f, car varlis, var0, n, nil);
  227. n1 := n + taymincoeff denom;
  228. return
  229. delete!-superfluous!-coeffs
  230. (quottaylor1 ({varlis,var0,n1,n1+1},
  231. taylor2f (numr f, car varlis, var0, n1, t),
  232. denom),
  233. 1, n)
  234. end$
  235. symbolic procedure taylor2f (f, var, var0, n, flg);
  236. %
  237. % taylor2f is the procedure that does the actual expansion
  238. % of the s.f. f.
  239. % It returns a list of the form
  240. % ((deglis1 . coeff1) (deglis2 . coeff2) ... )
  241. % For the use of the parameter `flg' see below.
  242. %
  243. begin scalar x, y, z; integer k;
  244. %
  245. % Calculate once what is needed several times.
  246. % var0 eq 'infinity is a special case that has already been taken
  247. % care of by the calling functions by replacing var by 1/var.
  248. %
  249. if var0 eq 'infinity then var0 := 0;
  250. x := list (var . var0);
  251. y := simp list ('difference, var, var0);
  252. %
  253. % The following is a first attempt to treat expressions
  254. % that have poles at the expansion point.
  255. % Currently nothing more than factorizable poles, i.e.
  256. % factors in the denominator are handled.
  257. % We use the following trick to calculate enough terms: If the
  258. % first l coefficients of the Taylor series are zero we replace n
  259. % by n + 2l. This is necessary since we separately expand
  260. % numerator and denominator of an expression. If the expansion of
  261. % both parts starts with, say, the quadratic term we have to
  262. % expand them up to order (n+2) to get the correct result up to
  263. % order n. However, if the numerator starts with a constant term
  264. % instead, we have to expand up to order (n+4). It is important,
  265. % however, to drop the additional coefficients as soon as they are
  266. % no longer needed. The parameter `flg' is used here to control
  267. % this behaviour. The calling function must pass the value `t' if
  268. % it wants to inhibit the calculation of additional coefficients.
  269. % This is currently the case if the s.q. f has a denominator that
  270. % may contain the expansion variable. Otherwise `flg' is used to
  271. % remember if we already encountered a non-zero coefficient.
  272. %
  273. f := !*f2q f;
  274. z := subs2 subsq (f, x);
  275. if null numr z and not flg then n := n + 1 else flg := t;
  276. y := list TayMakeCoeff ((list list 0), z);
  277. k := 1;
  278. while k <= n and not null numr f do
  279. << f := multsq (diffsq (f, var), 1 ./ k);
  280. % k is always > 0!
  281. % subs2 added to simplify expressions involving roots
  282. z := subs2 subsq (f, x);
  283. if null numr z and not flg then n := n + 2 else flg := t;
  284. if not null numr z then y := TayMakeCoeff(list list k, z) . y;
  285. k := k + 1 >>;
  286. return reversip y
  287. end;
  288. symbolic procedure taylor2hom (f, varlis, var0, n);
  289. %
  290. % Homogeneous expansion of s.q. f wrt the variables in varlis,
  291. % i.e. the sum of the degrees of the kernels is varlis is <= n
  292. %
  293. if null cdr varlis then taylor2e (f, list car varlis, var0, n)
  294. else for each u in taylor2e (f, list car varlis, var0, n) join
  295. for each v in taylor2hom (cdr u,
  296. cdr varlis,
  297. var0,
  298. n - get!-degree TayCfPl car u)
  299. collect list (car TayCfPl car u . TayCfPl car v) . cdr v$
  300. symbolic procedure taylorsamevar (u, varlis, var0, n);
  301. begin scalar tp; integer mdeg, pos;
  302. if cdr varlis
  303. then Taylor!-error ('not!-implemented,
  304. "(homogeneous expansion in TAYLORSAMEVAR)");
  305. tp := TayTemplate u;
  306. pos := car var!-is!-nth (tp, car varlis);
  307. tp := nth (tp, pos);
  308. if TayTpElPoint tp neq var0
  309. then return taylor1 (if not null TayOrig u then TayOrig u
  310. else simp!* prepTaylor!* u,
  311. varlis, var0, n);
  312. mdeg := TayTpElOrder tp;
  313. if n=mdeg then return u
  314. else if n > mdeg
  315. %
  316. % further expansion required
  317. %
  318. then << lprim "Cannot expand further... truncated.";
  319. return u >> ;
  320. return make!-Taylor!* (
  321. for each cc in TayCoeffList u join
  322. if nth (nth (TayCfPl cc, pos), 1) > n
  323. then nil
  324. else list cc,
  325. replace!-nth(TayTemplate u,pos,
  326. {varlis,TayTpElPoint tp,n,n+1}),
  327. TayOrig u, TayFlags u)
  328. end$
  329. comment The `FULL' flag causes the whole term (including the
  330. Taylor!* symbol) to be passed to SIMPTAYLOR!* ;
  331. symbolic procedure simpTaylor!* u;
  332. if TayCoefflist u memq frlis!* or eqcar(TayCoefflist u,'!~)
  333. then !*tay2q u
  334. else <<
  335. %
  336. % Allow automatic combination of Taylor kernels.
  337. %
  338. if !*taylorautocombine and not ('taysimpsq memq mul!*)
  339. then mul!* := aconc!* (mul!*, 'taysimpsq);
  340. !*tay2q resimptaylor u >>$
  341. flag ('(Taylor!*), 'full)$
  342. put ('Taylor!*, 'simpfn, 'simpTaylor!*)$
  343. comment The following is necessary to properly process Taylor kernels
  344. in substitutions;
  345. flag ('(Taylor!*), 'simp0fn);
  346. endmodule;
  347. end;