laplace.red 42 KB

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