laplace.red 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. module laplace; % Package for Laplace and inverse Laplace transforms.
  2. % Authors: C. Kazasov, M. Spiridonova, V. Tomov.
  3. % Date: 24 October 1988.
  4. % Revisions:
  5. %
  6. % 2 Dec 1988. Commented out rule for sqrt(-x), since it interferes
  7. % with integrator.
  8. % 20 Nov 1988. Converted to lower case and tabs removed.
  9. %
  10. %*******************************************************************
  11. %* *
  12. %* L A P L A C E 2.0 *
  13. %* *
  14. %* AN EXPERIMENTAL PACKAGE FOR PERFORMING IN REDUCE 3 *
  15. %* DIRECT AND INVERSE LAPLACE TRANSFORMATIONS *
  16. %* *
  17. %* SOFIA UNIVERSITY - B U L G A R I A *
  18. %* *
  19. %*******************************************************************
  20. create!-package('(laplace),'(contrib laplace));
  21. fluid '(!*exp !*limitedfactors !*mcd !*rounded depl!* kord!*
  22. transvar!*);
  23. global '(lpsm!* lpcm!* lpshm!* lpchm!* lpse!* lpce!* lpshe!* lpche!*
  24. lpexpt!* ile1!* ile2!* ile3!* ile4!* ile5!* lpvar!* ilvar!*
  25. lpshift!* !*lmsg !*lmon !*ltrig !*lhyp !*ldone !*lione );
  26. switch lhyp,lmon,ltrig;
  27. % Default value:
  28. !*lmsg:= t;
  29. put('intl,'simpfn,'simpiden);
  30. put('one, 'simpfn,'simpiden);
  31. put('delta,'simpfn,'simpiden);
  32. put('gamma,'simpfn,'simpiden);
  33. %*******************************************************************
  34. %* *
  35. %* DIRECT LAPLACE TRANSFORMATION *
  36. %* *
  37. %*******************************************************************
  38. put('laplace, 'simpfn, 'simplaplace);
  39. lpsm!*:='( ((minus !=x))
  40. (nil depends (reval (quote !=x)) lpvar!* )
  41. (minus (times (one (minus !=x)) (sin !=x)) ) nil );
  42. lpcm!*:='( (( minus !=x ))
  43. (nil depends (reval (quote !=x)) lpvar!* )
  44. (times (one (minus !=x)) (cos !=x)) nil );
  45. lpshm!*:='( ((minus !=x))
  46. (nil depends (reval (quote !=x)) lpvar!* )
  47. (minus (times (one (minus !=x)) (sinh !=x)) ) nil );
  48. lpchm!*:='( (( minus !=x ))
  49. (nil depends (reval (quote !=x)) lpvar!* )
  50. (times (one (minus !=x)) (cosh !=x)) nil );
  51. lpse!*:= '( (!=x) (nil depends (reval(quote !=x)) lpvar!* )
  52. (times (one !=x) (quotient (difference (expt e (times i !=x))
  53. (expt e (minus (times i !=x))) )
  54. (times 2 i) ) ) nil ) ;
  55. lpce!*:= '( (!=x) (nil depends (reval(quote !=x)) lpvar!* )
  56. (times (one !=x) (quotient (plus (expt e (times i !=x))
  57. (expt e (minus (times i !=x))) )
  58. 2 ) ) nil ) ;
  59. lpshe!*:= '( (!=x) (nil depends (reval(quote !=x)) lpvar!* )
  60. (times (one !=x) (quotient (difference (expt e !=x)
  61. (expt e (minus !=x)) )
  62. 2 ) ) nil );
  63. lpche!*:= '( (!=x) (nil depends (reval(quote !=x)) lpvar!* )
  64. (times (one !=x) (quotient (plus (expt e !=x)
  65. (expt e (minus !=x)) )
  66. 2 ) ) nil );
  67. lpexpt!*:= '( (e (plus !=x !=y)) (nil . t)
  68. (times (expt e !=x) (expt e !=y) (one (plus !=x !=y)) ) nil );
  69. symbolic procedure simplaplace u;
  70. % Main procedure for Laplace transformation.
  71. % U is in prefix form: (<expr> <lp.var> <il.var>), where
  72. % <expr> is the object function,
  73. % <lp.var> is the var. of the object function (intern. lp!&),
  74. % <il.var> is the var. of the laplace transform(intern. il!&),
  75. % and can be omitted - then il!& is assumed.
  76. % Returns a standard quotient of Laplace transform.
  77. begin scalar v,w,svfg,transvar!*;
  78. if null subfg!* then return mksq('laplace . u, 1);
  79. if cddr u and null idp(w:=caddr u) or null idp(v:=cadr u)
  80. then go to err;
  81. v:= caaaar simp v;
  82. transvar!* := w; % Needed for returning a Laplace form.
  83. % Should the following be an error?
  84. if null transvar!* then transvar!* := 'il!&;
  85. if null idp v then go to err;
  86. u:= car u ;
  87. % Make environment for Laplace transform.
  88. svfg:=!*exp . !*mcd ;
  89. !*mcd:=nil; !*exp:=t;
  90. kord!*:= 'lp!& . 'il!& . kord!* ;
  91. put('one,'simpfn,'lpsimp1);
  92. put('gamma,'simpfn,'lpsimpg);
  93. if !*ldone then put('expt,'opmtch,lpexpt!*.get('expt,'opmtch));
  94. if !*lmon then
  95. << put('sin,'opmtch, lpse!* . get('sin,'opmtch));
  96. put('cos,'opmtch, lpce!* . get('cos,'opmtch));
  97. put('sinh,'opmtch, lpshe!* . get('sinh,'opmtch));
  98. put('cosh,'opmtch, lpche!* . get('cosh,'opmtch)) >>
  99. else
  100. << put('sin,'opmtch, lpsm!* . get('sin,'opmtch));
  101. put('cos,'opmtch, lpcm!* . get('cos,'opmtch));
  102. put('sinh,'opmtch, lpshm!* . get('sinh,'opmtch));
  103. put('cosh,'opmtch, lpchm!* . get('cosh,'opmtch)) >>;
  104. lpvar!*:= v; lpshift!*:=t;
  105. if v neq 'lp!& then kord!*:=v . kord!*;
  106. for each x in depl!* do if v memq cdr x then rplacd(x,'lp!& . cdr x);
  107. u:= laplace1 list(u,v);
  108. if w then u:=subf(numr u, list('il!& . w));
  109. % Restore old env.
  110. for each x in depl!* do
  111. if 'lp!& memq cdr x then rplacd(x,delete('lp!&,cdr x));
  112. put('one,'simpfn,'simpiden);
  113. put('gamma,'simpfn,'simpiden);
  114. kord!*:= cddr kord!*;
  115. put('sin,'opmtch, cdr get('sin,'opmtch) );
  116. put('cos,'opmtch, cdr get('cos,'opmtch) );
  117. put('sinh,'opmtch, cdr get('sinh,'opmtch) );
  118. put('cosh,'opmtch, cdr get('cosh,'opmtch) );
  119. if !*ldone then put('expt,'opmtch,cdr get('expt,'opmtch) );
  120. if erfg!* then << erfg!*:=nil; go to ret >>;
  121. put('laplace,'simpfn,'simpiden);
  122. !*exp:=car svfg; svfg:=cdr svfg; if !*exp then u:=resimp u;
  123. !*mcd:=svfg; if !*mcd then u:=resimp u;
  124. put('laplace,'simpfn,'simplaplace);
  125. % ret: return reorder numr u ./ reorder denr u ;
  126. ret: return u ;
  127. err: msgpri("Laplace operator incorrect",nil,nil,nil,t);
  128. end ;
  129. put('sin,'lpfn,'(quotient k (plus (expt il!& 2) (expt k 2) )) );
  130. put('cos,'lpfn,'(quotient il!& (plus (expt il!& 2) (expt k 2) )) );
  131. put('sinh,'lpfn,'(quotient k (plus (expt il!& 2)
  132. (minus (expt k 2)) )) );
  133. put('cosh,'lpfn,'(quotient il!& (plus (expt il!& 2)
  134. (minus (expt k 2)) )) );
  135. put('one,'lpfn,'(quotient 1 il!&) );
  136. put('expt,'lpfn,'(quotient (times (expt k d) (gamma (plus d 1)) )
  137. (expt il!& (plus d 1)) ) );
  138. put('delta,'lpfn, 1 );
  139. symbolic procedure laplace1 u;
  140. % Car u is in pref. form, cadr u is the var of the object function.
  141. % Returns standard quotient of Laplace transform.
  142. begin scalar v,w,z;
  143. v := cadr u;
  144. u := car u;
  145. z:= simp!* u;
  146. if denr z neq 1 then z := simp prepsq z; % *SQ must have occurred.
  147. if denr z neq 1 then rederr list(u,"has non-trivial denominator");
  148. z := numr z;
  149. if v neq 'lp!& then << kord!*:=cdr kord!*;
  150. z:=subla(list(v.'lp!&),z); z:=reorder z >>;
  151. if erfg!* then return !*kk2q list
  152. ('laplace, subla(list('lp!& . lpvar!*), u), lpvar!*,transvar!*);
  153. w:= nil ./ 1; u:=z; !*exp:=nil;
  154. while u do
  155. if domainp u
  156. then << w:=addsq(w, lpdom u); u:=nil >>
  157. else << w:=addsq(w, if (z:=lptermx lt u) then z
  158. else !*kk2q list('laplace, subla
  159. (list('lp!&.lpvar!*),prepsq !*t2q lt u),lpvar!*,transvar!*));
  160. u:= red u >>;
  161. return w;
  162. end;
  163. symbolic procedure lptermx u ;
  164. % U is standard term, which may contain integer power of lp!&.
  165. % Returns standard quot or nil, if Laplace transform is impossible.
  166. begin scalar w ; integer n ;
  167. if tvar u neq 'lp!& then return lpterm u
  168. else if fixp cdar u
  169. then if (n:=cdar u)>0 then nil else return lpunknown u
  170. else return lpterm
  171. ( (list('expt,'lp!&,prepsq(cdar u ./ 1)) to 1) .* cdr u );
  172. if (w:=lpform cdr u) then nil else return nil ;
  173. a: % We use here the rule:
  174. % laplace(x*fun(x),x)=-df(laplace(fun(x),x),il!&) ,or
  175. % laplace(x**n*fun(x),x)=(-1)**n*df(laplace(fun(x),x),il!&,n);
  176. if n=0 then return w;
  177. w:=negsq diffsq(w,'il!&);
  178. n:=n-1; go to a;
  179. end;
  180. symbolic procedure lpdom u ;
  181. % We use here the rule: laplace(const,lp!&)=const/lp!&.
  182. % U is domain. Returns standard quotient.
  183. !*t2q (('il!& to -1) .* u) ;
  184. symbolic procedure lpform u ;
  185. % U is standard form, not containing integer powers of lp!&.
  186. % Returns standard quot or nil, if Laplace transform is impossible.
  187. begin scalar y,z ;
  188. if domainp u
  189. then return lpdom u
  190. else if red u
  191. then return
  192. ( if (y:=lpterm lt u) and (z:=lpform red u)
  193. then addsq(y,z) else nil )
  194. else return lpterm lt u ;
  195. end ;
  196. symbolic procedure lpterm u ;
  197. % U is standard term, not containing integer powers of lp!&.
  198. % Returns standard quot or nil, if Laplace transform is impossible.
  199. begin scalar v,w,w1,y,z ;
  200. v:=car u; % l.pow. - the first factor.
  201. w:=cdr u; % l.coeff. - i.e. st.f.
  202. if atom (y:=car v) or atom car y % I.e. atom or Lisp func.
  203. then if not depends(y,'lp!&)
  204. then return if (z:=lpform w)
  205. then multpq(v,z) else nil
  206. else if atom y then return lpunknown u
  207. else if car y = 'expt
  208. then return lpexpt(v,nil,w) else nil % Go next.
  209. else return if not depends(prepsq(y./1),'lp!&)
  210. then if (z:=lpform w)
  211. then multpq(v,z) else nil
  212. else lpunknown u;
  213. % We can't handle v now, because nothing is known for w for now.
  214. if domainp w then return lpfunc(v,w);
  215. % If we have sum, and off exp.
  216. if cdr w then return if (y:=lpterm list(v,car w)) and
  217. (z:=lpterm(v . cdr w))then addsq(y,z) else nil;
  218. w1:=cdar w; % l.coeff - i.e. st.f.
  219. w :=caar w; % l.pow. - the second factor.
  220. if not depends(if domainp(y:=car w) then y else prepsq(y./1),'lp!&)
  221. then return if (z:=lpterm(v.w1)) then multpq(w,z) else nil
  222. else if car y = 'expt then return lpexpt(w,v,w1);
  223. % Now we have multiply of two functions.
  224. if caar v = 'one and caar w = 'one
  225. then return lpmult1(v,w,w1)
  226. else return lpunknown u;
  227. end ;
  228. symbolic procedure lpunknown u ;
  229. % Try to apply any previously given let rules for Laplace operator.
  230. % U is standard term.
  231. % Returns standard quotient or nil if matching not successful.
  232. begin scalar d,z;
  233. if domainp (d:=cdr u) and not !:onep d
  234. then (u:= !*p2q car u) else (u:= !*t2q u);
  235. u:= list('laplace, prepsq u, 'lp!&,transvar!*);
  236. if get('laplace,'opmtch) and (z:=opmtch u)
  237. then << !*exp:=t;
  238. put('laplace,'simpfn,'laplace1);
  239. z:=simp z; !*exp:=nil;
  240. put('laplace,'simpfn,'simplaplace) >>;
  241. if null z then return if !*lmsg
  242. then msgpri("Laplace for", subla(list('lp!& . lpvar!*), cadr u),
  243. if !*lmon or atom cadr u then "not known"
  244. else "not known - try ON LMON",nil,nil)
  245. else nil;
  246. z:=subla(list('lp!&.lpvar!*), z);
  247. return if domainp d and not !:onep d then multsq(z,d./1) else z;
  248. end ;
  249. symbolic procedure lpsimp1 u ;
  250. % Simplify the one-function. % U is in prefix form.
  251. % Returns standard quotient or nil ./ 1 if an error occurs.
  252. begin scalar v,l,r ;
  253. v:=subla(list(lpvar!* . 'lp!&),u);
  254. if not depends(car v,'lp!&) then return 1 ./ 1;
  255. v:= car simpcar v; % Standard form.
  256. if mvar v neq 'lp!& then << !*mcd:=t; v:=subf(v,nil); !*mcd:=nil;
  257. v:=multf(car v, recipf!* cdr v) >>;
  258. if not(mvar v eq 'lp!& and !:onep ldeg v)
  259. then go to err;
  260. l:=lc v; r:=red v; % Standard form.
  261. if null r then if minusf l then go to err else return 1 ./ 1;
  262. v:=if minusf l then multsq(negf r ./ 1, 1 ./ negf l)
  263. else multsq(r ./ 1, 1 ./ l);
  264. if not minusf numr v then return 1 ./ 1;
  265. if null lpshift!* then go to err
  266. else return mksq(list('one,prepsq addsq(!*k2q 'lp!&, v)), 1);
  267. err: if !*lmsg then msgpri("Laplace induces", 'one.u,
  268. " which is not allowed", nil, 'hold);
  269. return nil ./ 1;
  270. end ;
  271. symbolic procedure lpsimpg u ;
  272. % Simplifies gamma(k), if k is rational and semiinteger.
  273. % U is in prefix form. Returns standard quotient.
  274. begin scalar n,v ;
  275. u:= car simpcar u;
  276. if domainp u and eqcar(u,'!:rn!:) and (cddr u = 2) % Semiint.
  277. then return if (n:=cadr u) = 1
  278. then mksq(list('sqrt,'pi),1)
  279. else if n > 0 then
  280. << v:='!:rn!: . difference(n,2) . 2 ;
  281. resimp !*t2q ( (list('gamma,rnprep!: v) to 1) .* v ) >>
  282. else % N negative.
  283. resimp !*t2q ( (list('gamma,rnprep!:('!:rn!:.plus(n,2) . 2)) to 1)
  284. .* ('!:rn!:.(-2).(-n)) )
  285. else return mksq(list('gamma,prepsq(u./1)),1);
  286. end ;
  287. symbolic procedure lpmult1 (u,v,w) ;
  288. % Perform: one(l1*lp!&-r1)*one(l2*lp!&-r2) = one(l*lp!&-r),
  289. % where l,r are those for the rightmost shifted one-function.
  290. % U and v are standard powers for one-func., w is leading coeff.
  291. % Returns standard quotient if all coeff. are domains, otherwise nil.
  292. begin scalar u1,v1,l1,r1,l2,r2 ;
  293. u1:= car simp cadar u;
  294. v1:= car simp cadar v;
  295. l1:=lc u1; l2:=lc v1;
  296. r1:=red u1; r2:=red v1;
  297. if domainp l1 and domainp l2 and domainp r1 and domainp r2
  298. then if !:minusp adddm(multdm(r1,l2), !:minus multdm(r2,l1))
  299. then return lpterm(u . w)
  300. else return lpterm(v . w)
  301. else return lpunknown list(u, v.w);
  302. end ;
  303. symbolic procedure lpexpt (u,v,w) ;
  304. % Perform the rule: laplace(e**(l*lp!&)*fun(lp!&), lp!&) =
  305. % sub(il!&=il!&-l, laplace(fun(lp!&),lp!&)),
  306. % or call lpfunc for gamma-function.
  307. % U is lpow for expt-func, v is other lpow or nil. W is lcoeff.
  308. % Returns standard quotient or nil.
  309. begin scalar p,q,r,z,l,la ;
  310. r:=cdr u; % Degree for expt-func.
  311. p:=cadar u; % First arg for expt.
  312. q:=caddar u; % Second arg for expt.
  313. if depends(p,'lp!&) then go to gamma;
  314. !*exp:=t; q:=car simp q;
  315. if mvar q neq 'lp!& then << !*mcd:=t; q:=subf(q,nil); !*mcd:=nil;
  316. q:=multf(car q, recipf!* cdr q) >>;
  317. if not !:onep r then q:=multf(q,r); !*exp:=nil;
  318. if not(mvar q eq 'lp!& and !:onep ldeg q)
  319. then return if null v then lpunknown(u . w)
  320. else lpunknown list(u, v . w);
  321. if (r:=red q) then
  322. << if !*ldone then << !*exp:=t;
  323. w:=multf(w, car lpsimp1 list prepsq(q./1)); !*exp:=nil >>;
  324. q:=list(lt q); r:=!*p2q(list('expt,p,prepsq(r./1)) to 1) >>;
  325. if p neq 'e then q:=multf(q, !*kk2f list('log,p) );
  326. z:= if null v then lpform w else lpterm(v.w);
  327. if null z then return nil;
  328. l:= prepsq !*f2q lc q;
  329. la:=list('il!& . list('difference,'il!&,l) );
  330. % Provide for those forms that contain the true transform variable.
  331. if not(transvar!* eq 'il!&)
  332. then z := subsq(z,list(transvar!* . 'il!&));
  333. z:=subf(numr z,la);
  334. return if r then multsq(r,z) else z;
  335. gamma: % Check and call lpfunc for gamma-func.
  336. return if null v
  337. then if domainp w
  338. then lpfunc(u,w)
  339. else % if off exp
  340. % if red w then if (z:=lpexpt(u,v,list(car w)) ) and
  341. % (l:=lpexpt(u,v,cdr w)) then addsq(z,l) else nil else
  342. if not depends((l:=mvar w),'lp!&)
  343. then if (z:=lpexpt(u,nil,lc w))
  344. then multpq(lpow w,z) else nil
  345. else if not atom l and car l = 'expt
  346. then lpexpt(lpow w,u,lc w)
  347. else lpunknown(u . w)
  348. else lpunknown list(u, v . w);
  349. end ;
  350. symbolic procedure lpfunc (u,v) ;
  351. % Perform Laplace transform for intl-operator and simple functions:
  352. % expt(arg,const), sin,cos,sinh,cosh,one,
  353. % with args: k*lp!&-tau, where k>0, tau>=0 are const.
  354. % U is standard power, v a domain element.
  355. % Returns standard quotient or nil.
  356. begin scalar ld,fn,w,var,ex,k,tau,c ;
  357. ld:=cdr u; % Degree of func.
  358. w:=car u; % Func in prefix form.
  359. fn:=car w; % Name of func.
  360. lintl: if fn neq 'intl then go to lexpt;
  361. % Perform Laplace(intl(<expr>,<var>,0,lp!&), lp!&).
  362. if not ( !:onep ld and cadddr w =0 and
  363. car cddddr w = 'lp!& and idp(var:=caddr w) )
  364. then return if !*lmsg then msgpri("Laplace integral",
  365. subla(list('lp!& . lpvar!*), prepsq !*p2q u),
  366. "not allowed", nil, nil) else nil;
  367. ex:= subla(list(var . 'lp!&), cadr w);
  368. lpshift!*:=nil; w:= laplace1 list(ex,'lp!&); lpshift!*:=t;
  369. return if w then multsq(multd(v,!*p2f('il!& to -1))./1, w) else nil;
  370. lexpt: if fn neq 'expt then go to lfunc;
  371. % Perform Laplace(expt,(k*lp!&-tau),d), for d - not int. const.
  372. ld:= multf(ld, car simp caddr w);
  373. if minusf(addd(1,ld)) or depends(prepsq(ld./1), 'lp!&)
  374. then return lpunknown(u.v);
  375. ld:= prepsq !*f2q ld;
  376. lfunc: % Perform Laplace transform for simple and one-function.
  377. if fn = 'expt or (fn = 'one) or !:onep ld
  378. then nil else return lpunknown(u.v);
  379. !*exp:=t; ex:= car simp cadr w; !*exp:=nil;
  380. if not( mvar ex = 'lp!& and !:onep ldeg ex )
  381. then return lpunknown(u.v);
  382. k:=lc ex; tau:=red ex;
  383. if minusf k or (null lpshift!* and tau) then return
  384. if !*lmsg then msgpri("Laplace for",
  385. subla(list('lp!&.lpvar!*), w),"not allowed",nil,nil) else nil;
  386. if tau and not minusf tau then return lpunknown(u.v);
  387. c:= prepsq !*f2q k;
  388. % Ind. lpfn gives Laplace transform for func(k*lp!&).
  389. if (w:= get(fn,'lpfn))
  390. then w:=car simp subla(list('k.c, 'd.ld), w);
  391. return if null w
  392. then lpunknown(u.v)
  393. else if null tau
  394. then multd(v, w) ./ 1
  395. else multd(v, multf( w,!*kk2f list
  396. ('expt,'e,prepsq multsq(!*k2q 'il!&, quotsq(tau./1, k./1)) )
  397. ) ) ./ 1 ;
  398. end ;
  399. % Tables for Explicit Transforms for Delta Function. Note explicit
  400. % construction for difference of arguments to reflect parser.
  401. algebraic;
  402. for all x,y,z let laplace(z*delta x,x,y) = sub(x=0,z);
  403. for all k,x,y,z let laplace(z*delta(x+(-k)),x,y) = e**(y*-k)*sub(x=k,z);
  404. for all x,y let laplace(df(delta x,x),x,y) = y;
  405. for all n,x,y let laplace(df(delta x,x,n),x,y) = y**n;
  406. for all k,x,y let laplace(df(delta(x+(-k)),x),x,y) = y*e**(-k*y);
  407. for all k,n,x,y let laplace(df(delta(x+(-k)),x,n),x,y) = y**n*e**(-k*y);
  408. symbolic;
  409. %*******************************************************************
  410. %* *
  411. %* INVERSE LAPLACE TRANSFORMATION *
  412. %* *
  413. %*******************************************************************
  414. put('invlap, 'simpfn, 'simpinvlap);
  415. ile1!*:='( (e (times i !=x))
  416. (nil depends(reval (quote !=x)) lpvar!*)
  417. (plus (cos !=x) (times i (sin !=x))) nil );
  418. ile2!*:='( (e (minus (times i !=x)))
  419. (nil depends(reval (quote !=x)) lpvar!*)
  420. (difference (cos !=x) (times i (sin !=x))) nil );
  421. ile3!*:='( (e !=x )
  422. (nil depends(reval (quote !=x)) lpvar!*)
  423. (plus (cosh !=x) (sinh !=x)) nil );
  424. ile4!*:='( (e (minus !=x))
  425. (nil depends(reval (quote !=x)) lpvar!*)
  426. (difference (cosh !=x) (sinh !=x)) nil );
  427. ile5!*:='( (e (plus !=x !=y))
  428. (nil and (not(depends(reval(quote !=x)) (quote i)))
  429. (depends(reval(quote !=y)) (quote i)) )
  430. (times (expt e !=x) (expt e !=y)) nil );
  431. symbolic procedure simpinvlap u ;
  432. % Main procedure for inverse Laplace transformation.
  433. % U is in prefix form: (<expr> <il.var> <lp.var>) ,where
  434. % <expr> is the laplace transform,
  435. % <il.var> is the var. of the Laplace transform (intern. il!&),
  436. % <lp.var> is the var. of the object function (intern. lp!&),
  437. % and can be omitted - then lp!& is assumed.
  438. % Returns a standard quotient of inverse Laplace transform.
  439. begin scalar v,w,svfg ;
  440. if null subfg!* then return mksq('invlap . u, 1);
  441. if cddr u and null idp(w:=caddr u) then go to err;
  442. v:= caaaar simp cadr u;
  443. transvar!* := w;
  444. if null idp v then go to err;
  445. u:= car u ;
  446. % Make environment for invlap transform.
  447. svfg:=!*exp . !*mcd ;
  448. !*mcd:=nil; !*exp:=nil;
  449. kord!*:= 'il!& . 'lp!& . kord!* ;
  450. put('gamma,'simpfn,'lpsimpg);
  451. put('one,'simpfn,'ilsimp1);
  452. ilvar!*:=v; if v neq 'il!& then kord!*:=v.kord!*;
  453. for each x in depl!* do if v memq cdr x then rplacd(x,'il!& . cdr x);
  454. u:= invlap1 list(u,v);
  455. put('invlap,'simpfn,'simpiden);
  456. if w then << lpvar!*:=w; u:=subla(list('lp!& . w), u) >>
  457. else lpvar!*:='lp!& ;
  458. if !*ltrig or !*lhyp then << !*exp:=t;
  459. if !*lhyp then put('expt,'opmtch,ile3!*.ile4!*.get('expt,'opmtch));
  460. if !*ltrig then put('expt,'opmtch,ile1!*.ile2!*.get('expt,'opmtch));
  461. put('expt,'opmtch, ile5!*.get('expt,'opmtch));
  462. u:= simp prepsq u;
  463. if !*ltrig and !*lhyp
  464. then put('expt,'opmtch, cdr cddddr get('expt,'opmtch))
  465. else put('expt,'opmtch, cdddr get('expt,'opmtch)) >>
  466. else u:= resimp u;
  467. % Restore old env.
  468. for each x in depl!* do
  469. if 'il!& memq cdr x then rplacd(x,delete('il!&,cdr x));
  470. !*exp:=car svfg; svfg:=cdr svfg;
  471. if !*exp and not(!*ltrig or !*lhyp) then u:=resimp u;
  472. !*mcd:=svfg; if !*mcd then u:=resimp u;
  473. put('invlap,'simpfn,'simpinvlap);
  474. put('one,'simpfn,'simpiden);
  475. put('gamma,'simpfn,'simpiden);
  476. kord!*:= cddr kord!*;
  477. % return reorder numr u ./ reorder denr u ;
  478. return u;
  479. err: msgpri("Invlap operator incorrect",nil,nil,nil,t);
  480. end;
  481. symbolic procedure invlap1 u;
  482. % Car U is in prefix form, cadr u is the var of the Laplace transform.
  483. % Returns standard quotient of inverse Laplace transform.
  484. begin scalar v,w,z;
  485. v := cadr u;
  486. u := car u;
  487. z:= simp!* u;
  488. if denr z neq 1 then z := simp prepsq z; % *SQ must have occurred.
  489. if denr z neq 1 then rederr list(u,"has non-trivial denominator");
  490. z := numr z;
  491. u := z;
  492. if v neq 'il!& then << kord!*:=cdr kord!*;
  493. u:=subla(list(v.'il!&),u); u:=reorder u >>;
  494. w:= nil ./ 1;
  495. while u do
  496. if domainp u
  497. then << w:=addsq(w, !*t2q((list('delta,'lp!&) to 1) .* u) );
  498. u:= nil >>
  499. else << w:=addsq(w, if (z:=ilterm (lt u,1,1,nil)) then z
  500. else !*kk2q list('invlap, subla
  501. (list('il!&.ilvar!*),prepsq !*t2q lt u), ilvar!*,transvar!*));
  502. u:= red u >>;
  503. return w;
  504. end;
  505. symbolic procedure ilterm (u, numf, denf, rootl) ;
  506. % U is standard term, numf is standard form, with one term, and
  507. % contains only powers from numerator of expression, depends on il!&,
  508. % but not exponent. Denf is standard form, with one term, and
  509. % contains only powers from denominator of expression, depends on il!&
  510. % but not exponent. Rootl is assoc. list of: (<root> . <multiplity>).
  511. % Returns standard quotient, or nil if inverse Laplace transform is
  512. % impossible.
  513. begin scalar v,v1,v2,w,y,z,p,p1 ;
  514. v:=car u; w:=cdr u; v1:=car v; v2:=cdr v;
  515. if not depends(if domainp v1 then v1 else prepsq(v1./1), 'il!&)
  516. then return if (z:=ilform(w,numf,denf,rootl))
  517. then multpq (v,z) else nil;
  518. % V depends on il!&.
  519. if atom v1 then return ilunknown(u,numf,denf)
  520. else if atom car v1 % I.e. Lisp func.
  521. then return if car v1 = 'expt
  522. then ilexpt(v,nil,w,numf,denf,rootl)
  523. else if domainp w
  524. then ilexptfn(v,w,numf,denf)
  525. else if cdr w then if(y:=ilterm(list(v,lt w),numf,denf,rootl))
  526. and (z:=ilterm(v.cdr w,numf,denf,rootl))
  527. then addsq(y,z) else nil
  528. else ilterm(list(lpow w,v.(lc w)),numf,denf,rootl);
  529. % May be infinite recursion above, if mult. of two unknown func.
  530. % Mvar is atom 'il!& or standard form, since exp off.
  531. if numberp v2 and fixp v2
  532. then if v2 > 0 then if atom v1 then return
  533. ilform(w, multf(!*p2f v,numf), denf, rootl) else nil
  534. else return ilroot(v, w, numf, denf, rootl)
  535. else return ilexpt(list('expt, if domainp v1 then v1 else
  536. prepsq(v1./1), prepsq(v2./1)) to 1, nil, w, numf, denf, rootl);
  537. % Now v1 remains as a standard form and v2>0.
  538. v:= if !:onep v2 then v1 else !*p2f v;
  539. if red v1 then
  540. << !*exp:=t; y:=numr subf(v,nil); z:=y;
  541. while z do if domainp z then z:=nil
  542. else if ldeg z < 0 then if depends
  543. (if domainp(p1:=mvar z) then p1 else prepsq(p1 ./1), 'il!&)
  544. then << p:=t; z:=nil >> else z:=addf(lc z, red z)
  545. else z:=addf(lc z,red z);
  546. if p then w:=multf(y, w) else numf:=multf(v,numf);
  547. !*exp:=nil >> else numf:=multf(v,numf);
  548. return ilform(w,numf,denf,rootl);
  549. end;
  550. symbolic procedure ilform (u, numf, denf, rootl) ;
  551. % U is a standard form. Numf, denf, rootl are the same as in ILTERM.
  552. % Returns standard quotient or nil if invlap is impossible.
  553. begin scalar y,z ;
  554. return if domainp u
  555. then if (z:=ilresid(numf,denf,rootl))
  556. then multsq(u ./ 1, z) else nil
  557. else if null red u
  558. then ilterm(lt u,numf,denf,rootl)
  559. else if (y:=ilterm(lt u,numf,denf,rootl)) and
  560. (z:=ilform(red u,numf,denf,rootl))
  561. then addsq(y,z) else nil;
  562. end ;
  563. symbolic procedure ilunknown (u, numf, denf) ;
  564. % We try here to apply any previously given let rules for Laplace
  565. % operator. U is standard term, numf, denf are the same.
  566. % Returns standard quotient or nil if matching not successful.
  567. begin scalar d,z;
  568. if domainp (d:=cdr u) then if !:onep d
  569. then u:=!*t2q u else u:=!*p2q car u
  570. else u:=!*t2q u;
  571. if numf neq 1 then u:=multsq(u, numf./1);
  572. if denf neq 1 then u:=multsq(u,1 ./denf);
  573. u:= list('invlap, prepsq u,'il!&,transvar!*);
  574. if get('invlap,'opmtch) and (z:=opmtch u)
  575. then << !*exp:=t;
  576. put('invlap,'simpfn,'invlap1);
  577. z:=simp z; !*exp:=nil;
  578. put('invlap,'simpfn,'simpinvlap) >>;
  579. if null z and !*lmsg then msgpri("Invlap for",
  580. subla(list('il!& . ilvar!*), cadr u),
  581. "not known", nil, nil);
  582. return if null z then nil
  583. else if domainp d and not !:onep d
  584. then multsq(z, d ./ 1) else z;
  585. end ;
  586. symbolic procedure ilsimp1 u ;
  587. % Simplify the one-function. U is in prefix form.
  588. % Returns standard quotient.
  589. if atom car u then 1 ./ 1 else mksq('one . u, 1);
  590. symbolic procedure ilexpt (u, v, w, numf, denf, rootl) ;
  591. % Perform the rule: invlap(e**(-l*il!&)*fun(il!&), il!&) =
  592. % sub(lp!&=lp!&-l, invlap(fun(il!&),il!&)), for l > 0,
  593. % or call ilfunc for gamma-function.
  594. % U is lpow for expt-function, v is other lpow or nil,
  595. % W is lcoeff (standard form), numf, denf, rootl are the same.
  596. % Returns standard quotient or nil.
  597. begin scalar p,q,r,z,l ;
  598. r:=cdr u; % Degree for expt-func.
  599. p:=cadar u; % First arg for expt.
  600. q:=caddar u; % Second arg for expt.
  601. if depends(p,'il!&)then go to gamma;
  602. !*exp:=t; q:=car simp q;
  603. if mvar q neq 'il!& then << !*mcd:=t; q:=subf(q,nil); !*mcd:=nil;
  604. q:=multf(car q, recipf!* cdr q) >>;
  605. if not !:onep r then q:=multf(q,r); !*exp:=nil;
  606. if not((mvar q = 'il!&) and !:onep ldeg q and minusf lc q)
  607. then return if null v then ilunknown(u.w,numf,denf)
  608. else ilunknown(list(u,v.w),numf,denf);
  609. if (r:=red q) then<< q:=list(lt q);
  610. r:=!*p2q(list('expt,p,prepsq(r./1)) to 1) >>;
  611. if p neq 'e then q:=multf(q, !*kk2f list('log,p) );
  612. z:= if null v then ilform(w,numf,denf,rootl)
  613. else ilterm(v.w,numf,denf,rootl);
  614. if null z then return nil;
  615. l:= list('plus, 'lp!&, prepsq((lc q)./1));
  616. z:= subf(numr z, list('lp!& . l) ) ; % Standard quotient.
  617. % If you want shifted one-func. to remain always in obj. func.
  618. if !*lione then z:=multsq(z, !*kk2q list('one,l) );
  619. return if r then multsq(r,z) else z ;
  620. gamma: % Check and call ilfunc if gamma-func. case.
  621. return if null v
  622. then if domainp w
  623. then ilexptfn(u,w,numf,denf)
  624. else if red w
  625. then if (z:=ilexpt(u,nil,list(car w),numf,denf,rootl)) and
  626. (l:=ilexpt(u,nil,cdr w,numf,denf,rootl))
  627. then addsq(z,l) else nil
  628. else if not depends(if domainp(l:=mvar w) then l
  629. else prepsq(l./1), 'il!&)
  630. then if (z:=ilexpt(u,nil,lc w,numf,denf,rootl))
  631. then multpq(lpow w,z) else nil
  632. else if not atom l and (car l = 'expt)
  633. then ilexpt(lpow w,u,lc w,numf,denf,rootl)
  634. else if atom l or not atom car l
  635. then ilterm(list(lpow w,u.(lc w)),numf,denf,rootl)
  636. else ilunknown(u.w,numf,denf)
  637. else ilunknown(list(u,v.w),numf,denf) ;
  638. end ;
  639. symbolic procedure ilexptfn (u, v, numf, denf) ;
  640. % Perform invlap for expt function - i.e., gamma-function case.
  641. % U is standard power for expt, v is domain, numf, denf the same.
  642. % Returns standard quotient or nil.
  643. begin scalar ex,dg,fn,k,a,b,y,d ;
  644. ex:=car u; dg:=cdr u; fn:=car ex;
  645. if fn neq 'expt then go to unk;
  646. d:=caddr ex; if atom(ex:=cadr ex) then k:=t;
  647. !*exp:=t; ex:=car simp ex;
  648. dg:=multd(dg,car simp d); a:=lc ex;
  649. if not(domainp a and !:onep a) then
  650. << ex:=multf(ex, recipf!* a);
  651. a:=!*kk2f list('expt,prepsq(a./1),prepsq(dg./1)) >>;
  652. b:=red ex; !*exp:=nil;
  653. if (mvar ex neq 'il!&) or (ldeg ex neq 1) or
  654. depends(prepsq(b./1),'il!&) then go to unk;
  655. if (numf=1) and (denf=1) then go to ret;
  656. % We must have identical monomials in numf, denf and in expt-func.
  657. y:= multf(multf(numf, !*kk2f list('expt,
  658. prepsq(ex./1),prepsq(dg./1)) ), recipf!* denf);
  659. if cdr y or (lc lc y neq 1) or (car mvar lc y neq 'expt)
  660. or (not k and (mvar y neq ex))
  661. or (k and (mvar y neq mvar ex)) then go to unk;
  662. dg:=addd(ldeg y,dg);
  663. ret: if minusf dg then d:=prepsq(negf dg ./ 1) else go to unk;
  664. if (y:=get(fn,'ilfn))
  665. then y:=car simp subla(list('d.d), y) else go to unk;
  666. if b then y:=multd(v, multf(y, !*kk2f list
  667. ('expt,'e,prepsq(multf(!*k2f 'lp!&,negf b) ./1)) ))
  668. else y:=multd(v, y);
  669. return if domainp a and !:onep a then y./1 else multf(a,y)./1;
  670. unk: return ilunknown(u.v, numf, denf);
  671. end ;
  672. put('expt,'ilfn,'(quotient (expt lp!& (plus d (minus 1))) (gamma d)));
  673. symbolic procedure addrootl (root,mltpl,rootl) ;
  674. % Add roots with multiplity at head of rootl - an assoc. list.
  675. begin scalar parr ;
  676. parr:=assoc(root,rootl);
  677. if parr then << mltpl:= mltpl + cdr parr;
  678. rootl:= delete(parr,rootl) >>;
  679. return (root . mltpl) . rootl ;
  680. end ;
  681. symbolic procedure recipf!* u ;
  682. % U is standard form. Returns st.f. for u to (-1), by off mcd.
  683. begin scalar d;
  684. if domainp u then if !:onep u then return 1
  685. else if !:onep negf u then return -1
  686. else if fieldp u then nil
  687. else if (d:=get(dmode!*,'i2d))
  688. then u:=apply1(d,u) else u:=mkratnum u
  689. else return if cdr u then !*p2f(u to (-1))
  690. else multf(!*p2f(mvar u to (-ldeg u)), recipf!* lc u);
  691. return dcombine(1,u,'quotient);
  692. end ;
  693. symbolic procedure ilroot (u, v, numf, denf, rootl) ;
  694. % Find the roots of polynomial of first and second degree.
  695. % U is standard power - the polynomial, v is the remaining st.f.
  696. % Numf, denf, rootl are the same. Returns standard quot or nil.
  697. begin scalar dg,ex,a,b,c,z,x1,x2 ;
  698. dg:=-cdr u; ex:=car u; % dg>0;
  699. if atom ex then return ilform(v,numf,
  700. multf(!*p2f('il!& to dg),denf), addrootl(nil,dg,rootl) );
  701. if atom car ex then return ilunknown(u.v,numf,denf);
  702. !*exp:=t; ex:=subf(ex,nil); !*exp:=nil;
  703. if not depends(prepsq ex, 'il!&) then return
  704. if (z:=ilform(v,numf,denf,rootl)) then multpq(u,z) else nil;
  705. ex:=car ex;
  706. if ldeg ex > 2 then return il3pol(u,v,numf,denf,rootl);
  707. a:=lc ex;
  708. if depends(prepsq(a./1),'il!&)
  709. then return ilunknown(u.v,numf,denf);
  710. if not(domainp a and !:onep a) then
  711. << !*exp:=t; a:=recipf!* a; ex:=multf(ex,a);
  712. if dg>1 then a:=exptf(a,dg); !*exp:=nil >>;
  713. if ldeg ex = 2 then go to lbin;
  714. lmon: if (b:=red ex)
  715. then << rootl:=addrootl(negf b, dg, rootl);
  716. denf:= if !:onep dg then multf(ex, denf)
  717. else multpf(ex to dg, denf) >>
  718. else << rootl:=addrootl(nil, dg, rootl);
  719. denf:= multpf('il!& to dg, denf) >>;
  720. go to ret;
  721. lbin: if (b:=red ex)
  722. then if domainp b then << c:=b; b:=nil >>
  723. else if mvar b = 'il!& then << c:=red b; b:=lc b >>
  724. else << c:=b; b:=nil >>
  725. else c:=nil ;
  726. if depends(prepsq(b./1),'il!&) or depends(prepsq(c./1),'il!&)
  727. then return ilunknown(u.v,numf,denf);
  728. if null b and null c
  729. then << rootl:=addrootl(nil, 2*dg, rootl);
  730. denf:=multpf('il!& to (2*dg), denf) >>
  731. else << !*exp:=t; b:=multd('!:rn!: . ((-1) . 2), b);
  732. c:=numr simp list('sqrt,prepsq(addf(multf(b,b),negf c)./1));
  733. x1:=addf(b,c); x2:=addf(b,negf c); !*exp:=nil;
  734. if x1 = x2 then << rootl:=addrootl(x1,2*dg,rootl);
  735. x1:=(('il!& to 1).*1) .+ negf x1;
  736. denf:=multpf(x1 to (2*dg),denf) >>
  737. else << rootl:=addrootl(x2,dg,addrootl(x1,dg,rootl));
  738. x1:=(('il!& to 1).*1) .+ negf x1;
  739. x2:=(('il!& to 1).*1) .+ negf x2;
  740. if not !:onep dg then
  741. << x1:=!*p2f(x1 to dg); x2:=!*p2f(x2 to dg) >>;
  742. denf:=multf(x2,multf(x1,denf)) >> >>;
  743. ret: z:=ilform(v,numf,denf,rootl);
  744. return if (domainp a and !:onep a) then z
  745. else if null z then nil else multsq(a./1, z);
  746. end ;
  747. symbolic procedure il3pol (u, v, numf, denf, rootl) ;
  748. % Find the roots of polynomial of third and higher degree.
  749. % U is standard power - the polynomial, v is the remaining st.f.
  750. % Numf, denf, rootl are the same. Returns standard quot or nil.
  751. (begin scalar a,d,p,y,z ;
  752. if !*rounded then go to unk;
  753. d:=-cdr u; p:=car u;
  754. !*exp:=t; !*mcd:=t;
  755. % We must now convert rationals, if any, to standard quotients.
  756. % Since MCD was previously off, we must use limitedfactors here,
  757. % since the regular factorization turns EZGCD on.
  758. !*limitedfactors := t;
  759. y:=p; p:=nil./1;
  760. while y do if domainp y then << p:=addsq(p,!*d2q y); y:=nil >>
  761. else << a:=1; z:=list car y; % S.F. with 1 term only.
  762. while not domainp z do
  763. << a:=multf(a,!*p2f lpow z); z:=lc z >>;
  764. p:=addsq(p,multsq(a./1,!*d2q z)); y:=red y >>;
  765. if ((a:=cdr p) neq 1) and (d neq 1) then a:=exptf(a,d);
  766. z := fctrf car p;
  767. !*exp:=nil; !*mcd:=nil;
  768. if length z = 2 then go to unk; % No factors.
  769. if car z neq 1 then errach list(car z,"found in IL3POL");
  770. z:=cdr z; y:=v;
  771. while z do << p:= caar z;
  772. if cdar z neq 1 then p := exptf(p,cdar z);
  773. if d neq 1 then p:=exptf(p,d);
  774. y:=multf(y,recipf!* p); z:=cdr z >>;
  775. y:=ilform(y,numf,denf,rootl);
  776. if null y then go to unk
  777. else return if a = 1 then y else multsq(a./1, y);
  778. unk: return ilunknown(u.v,numf,denf);
  779. end) where !*limitedfactors := !*limitedfactors;
  780. symbolic procedure ilresid (numf, denf, rootl) ;
  781. % Apply the residue theorem at last.
  782. % Numf, denf, rootl are standard forms. Returns standard quot or nil.
  783. begin scalar n,d,ndeg,ddeg,m,x,y,z,w ;
  784. !*exp:=t; n:=numr subf(numf,nil); !*exp:=nil;
  785. z:=nil ./ 1; w:=nil ./ 1; x:=n; % Result accumulated in w.
  786. while x and not domainp x do
  787. << y:=car x; x:=cdr x;
  788. if depends(prepsq(cdr y./1),'il!&) or (caar y neq 'il!&
  789. and depends(caar y,'il!&) )
  790. then if (z:=ilterm(y,1,denf,rootl))
  791. then << w:=addsq(w,z); n:=delete(y,n) >>
  792. else x:=nil >> ;
  793. if null z then return ;
  794. % Now n is polynomial of il!& with constant coeff.
  795. ndeg:=if not domainp n and mvar n = 'il!& then ldeg n else 0;
  796. !*exp:=t; d:=numr subf(denf,nil); !*exp:=nil;
  797. ddeg:=if not domainp d and mvar d = 'il!& then ldeg d else 0;
  798. if ndeg < ddeg then go to resid;
  799. !*exp:=t; y:=qremf(n,d); !*exp:=nil;
  800. n:=cdr y; x:=car y; % N is remainder polynomial.
  801. while x do if domainp x
  802. then << w:=addsq(w, !*t2q(('(delta lp!&) to 1).* x)); x:=nil >>
  803. else if mvar x neq 'il!&
  804. then << w:=addsq(w, multsq(!*kk2q '(delta lp!&), !*t2q lt x) );
  805. x:=red x >>
  806. else << w:=addsq(w, multsq(!*kk2q list('df,list('delta,'lp!&),
  807. 'lp!&,ldeg x), lc x ./ 1) ); x:=red x >> ;
  808. resid: if null rootl then return w ;
  809. x:=caar rootl; m:=cdar rootl;
  810. if null x then y:=!*p2f('il!& to m)
  811. else << y:=(('il!& to 1) .* 1) .+ negf x;
  812. if m neq 1 then y:=!*p2f(y to m) >>;
  813. !*exp:=t; y:=numr subf(y,nil);
  814. y:=car qremf(d,y); !*exp:=nil; % D is quotient - remainder = 0.
  815. z:=multpf('(expt e (times il!& lp!&)) to 1, n); % Numerator.
  816. y:=recipf!* y;
  817. z:=multf(z,y) ./ 1;
  818. while (m:=m-1) > 0 do z:=diffsq(z, 'il!&);
  819. x:= if null x then 0 else prepsq(x./1); % Root in prefix form.
  820. !*exp:=t; z:=subf(numr z, list('il!&.x)); % One residue as st.q.
  821. if not depends(prepsq z, 'lp!&)
  822. then z:=multsq(z, !*kk2q '(one lp!&));
  823. if (m:=cdar rootl) > 2 then while (m:=m-1) > 1 do
  824. z:=multf(car z,'!:rn!: . 1 . m)./1;
  825. w:=addsq(w,z); !*exp:=nil;
  826. rootl:=cdr rootl; go to resid;
  827. end;
  828. endmodule;
  829. end;