laplace.red 41 KB

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