crunder.red 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. %********************************************************************
  2. module underdetde$
  3. %********************************************************************
  4. % Routines for the solution of underdetermiined ODEs and PDEs
  5. % Author: Thomas Wolf
  6. % August 1998, February 1999
  7. symbolic procedure undetlinode(arglist)$
  8. % parametric solution of underdetermined ODEs
  9. begin scalar l,l1,p,pdes,forg,s$
  10. pdes:=car arglist$
  11. forg:=cadr arglist$
  12. if expert_mode then <<l1:=selectpdes(pdes,1);flag(l1,'to_under)>>
  13. else l1:=cadddr arglist$
  14. while l1 do
  15. if null (p:=get_ulode(l1)) then l1:=nil
  16. else <<
  17. l:=underode(p,pdes)$
  18. p:=car p$
  19. if null l then <<remflag1(p,'to_under);l1:=delete(p,l1)>>
  20. else <<
  21. if print_ then <<
  22. write"Parametric solution of the underdetermined ODE ",p$
  23. terpri();
  24. write"giving the new ODEs "$
  25. s:=l;
  26. while s do <<
  27. write car s;
  28. s:=cdr s;
  29. if s then write ","
  30. >>$
  31. terpri()
  32. >>$
  33. pdes:=drop_pde(p,pdes,nil)$
  34. for each s in l do pdes:=eqinsert(s,pdes)$
  35. l:=list(pdes,forg)$
  36. l1:=nil;
  37. >>
  38. >>$
  39. return l$
  40. end$
  41. symbolic procedure undetlinpde(arglist)$
  42. % parametric solution of underdetermined PDEs
  43. begin scalar l,l1,p,pdes,forg$
  44. pdes:=car arglist$
  45. forg:=cadr arglist$
  46. if expert_mode then <<l1:=selectpdes(pdes,1);flag(l1,'to_under)>>
  47. else l1:=cadddr arglist$
  48. while l1 do
  49. if null (p:=get_ulpde(l1)) then l1:=nil
  50. else <<
  51. l:=underpde(p,pdes)$ % l has to be the list of new pdes
  52. p:=car p$
  53. if null l then <<remflag1(p,'to_under);l1:=delete(p,l1)>>
  54. else <<
  55. pdes:=drop_pde(p,pdes,nil)$
  56. for each s in l do pdes:=eqinsert(s,pdes)$
  57. l:=list(pdes,forg)$
  58. l1:=nil;
  59. >>
  60. >>$
  61. return l$
  62. end$
  63. symbolic procedure get_ulode(pdes)$
  64. begin scalar h,best_ulode;
  65. for each p in pdes do
  66. if flagp(p,'to_under) then
  67. if null (h:=ulodep(p)) then remflag1(p,'to_under)
  68. else
  69. if ((null best_ulode) or (car h < car best_ulode)) then best_ulode:=h;
  70. return if best_ulode then cdr best_ulode
  71. else nil
  72. end$
  73. symbolic procedure get_ulpde(pdes)$
  74. begin scalar h,best_ulpde;
  75. for each p in pdes do
  76. if flagp(p,'to_under) then
  77. if null (h:=ulpdep(p)) then remflag1(p,'to_under)
  78. else
  79. if ((null best_ulpde) or (car h < car best_ulpde)) then best_ulpde:=h;
  80. return if best_ulpde then cdr best_ulpde
  81. else nil
  82. end$
  83. symbolic procedure ulodep(p)$
  84. begin
  85. scalar tr_ulode,drvs,ulode,allvarf,minord,dv,f,x,h,found,minordf,totalorder$
  86. % minord and minordf are currently not needed later on
  87. % tr_ulode:=t;
  88. % Is it an underdetermined linear ODE for the allvarfcts?
  89. drvs:=get(p,'derivs)$
  90. ulode:=t$
  91. allvarf:=get(p,'allvarfcts);
  92. if tr_ulode then <<
  93. write"allvarf=",allvarf$
  94. terpri()$
  95. >>$
  96. minord:=1000;
  97. if not (allvarf and cdr allvarf) then ulode:=nil
  98. else % at least two allvar-fcts
  99. while ulode and drvs do <<
  100. dv:=caar drvs;
  101. f:=car dv$
  102. if tr_ulode then <<
  103. write"car drvs=",car drvs," dv=",dv," f=",f,
  104. " member(f,allvarf)=",member(f,allvarf)$
  105. terpri()$
  106. >>$
  107. if member(f,allvarf) then
  108. if (cdar drvs neq 1) or % not linear
  109. % x is already determined and it is not x:
  110. (cdr dv and ((x and (x neq cadr dv) ) or
  111. % there are other differentiation variables:
  112. ((cddr dv) and ((not fixp caddr dv) or
  113. cdddr dv )) )
  114. ) then << % no ODE:
  115. ulode:=nil;
  116. if tr_ulode then <<
  117. write"new ulode=",ulode$
  118. terpri()$
  119. >>$
  120. >> else % can be an ODE
  121. if null cdr dv then % f has no derivatives
  122. if not member(f,found) then ulode:=nil % no ODE --> substitition
  123. else % f has already been found with a
  124. % consequently higher x-derivative
  125. else % this is an x-derivative of f
  126. if null x then << % x had not yet been determined
  127. if tr_ulode then <<
  128. write"null x"$
  129. terpri()$
  130. >>$
  131. found:=cons(f,found)$
  132. x:=cadr dv;
  133. minordf:=car dv;
  134. if null cddr dv then minord:=1
  135. else minord:=caddr dv;
  136. totalorder:=minord
  137. >> else % x has already been determined
  138. if not member(f,found) then << % only leading derivatives matter
  139. found:=cons(f,found)$ % and the first deriv. of f is leading
  140. if null cddr dv then h:=1
  141. else h:=caddr dv;
  142. totalorder:=totalorder+h;
  143. if h<minord then <<
  144. minord:=h;
  145. minordf:=car dv
  146. >>
  147. >> else
  148. else % not member(f,allvarf)
  149. if null x or % then there are only derivatives
  150. % of non-allvarfcts left
  151. member(x,fctargs f) then ulode:=nil; % no x-dependent non-allvarfcts
  152. if tr_ulode then <<
  153. write"found=",found," minord=",minord," minordf=",minordf$
  154. terpri()$
  155. >>$
  156. drvs:=cdr drvs;
  157. >>$
  158. if tr_ulode then <<
  159. write"ulode=",ulode$
  160. terpri()$
  161. >>$
  162. return if ulode then {totalorder,p,x,minord,minordf}
  163. else nil
  164. end$ % of ulodep
  165. symbolic procedure ulpdep_(p)$
  166. begin
  167. scalar tr_ulpde,drvs,drv,ulpde,allvarf,allvarfcop,
  168. vld,vl,v,pde,fn,f,no_of_drvs,no_of_tms,ordr,maxordr,parti$
  169. %tr_ulpde:=t;
  170. % Is it an underdetermined linear PDE for the allvarfcts?
  171. drvs:=get(p,'derivs)$
  172. ulpde:=t$
  173. allvarf:=get(p,'allvarfcts);
  174. if tr_ulpde then <<
  175. write"allvarf=",allvarf$
  176. terpri()$
  177. >>$
  178. if not (allvarf and cdr allvarf) then ulpde:=nil
  179. else << % at least two allvar-fcts
  180. allvarfcop:=allvarf$
  181. no_of_tms:=0; % total number of terms of all diff operators
  182. vl:=get(p,'vars)$
  183. while ulpde and allvarfcop do <<
  184. % extracting the differential operator for car allvarfcop
  185. pde:=get(p,'val);
  186. fn:=car allvarfcop; allvarfcop:=cdr allvarfcop;
  187. for each f in allvarf do
  188. if f neq fn then pde:=subst(0,f,pde);
  189. pde:=reval pde;
  190. % Is pde linear in fn?
  191. if not lin_check(pde,{fn}) then <<
  192. if tr_ulpde then <<write"not linear in ",f$terpri()>>$
  193. ulpde:=nil
  194. >> else <<
  195. % add up the number of terms
  196. no_of_tms:=no_of_tms + no_of_terms(pde)$
  197. % What are all variables in pde? This is needed to test later
  198. % whether they are disjunct from all variables from another
  199. % diff. operator
  200. vld:=nil;
  201. for each v in vl do if not freeof(pde,v) then vld:=cons(v,vld);
  202. % What is the number of derivatives of fn?
  203. % What order is the highest derivative of fn?
  204. no_of_drvs:=0;
  205. for each drv in drvs do
  206. if fn=caar drv then <<
  207. ordr:=absdeg(cdar drv);
  208. if (no_of_drvs=0) or (ordr>maxordr) then maxordr:=ordr;
  209. no_of_drvs:=add1 no_of_drvs;
  210. >>;
  211. % collect the differential operators with properties in parti
  212. parti:=cons({pde,fn,vld,no_of_drvs,maxordr},parti);
  213. >>
  214. >>;
  215. if no_of_tms neq get(p,'terms) then <<
  216. if tr_ulpde then <<
  217. write"not a lin. homog. PDE"$terpri()
  218. >>$
  219. ulpde:=nil; % not a lin. homog. PDE
  220. >>$
  221. if tr_ulpde then <<
  222. write"parti="$
  223. prettyprint parti$
  224. >>$
  225. >>$
  226. return if null ulpde then nil
  227. else parti
  228. end$
  229. symbolic procedure ulpdep(p)$
  230. begin
  231. scalar tr_ulpde,drvs,drv,ulpde,parti,pde,
  232. difop1,difop2,commu,disjun,totalcost$
  233. %tr_ulpde:=t;
  234. % Is it an underdetermined linear PDE for the allvarfcts?
  235. drvs:=get(p,'derivs)$
  236. ulpde:=ulpdep_(p)$
  237. if ulpde then <<
  238. parti:=ulpde$ ulpde:=t$
  239. % Find a differential operator pde in parti
  240. pde:=nil;
  241. for each difop1 in parti do <<
  242. commu:=t;
  243. % which does commute with all other diff. operators
  244. for each difop2 in parti do
  245. if (cadr difop1 neq cadr difop2) and
  246. (not zerop reval {'DIFFERENCE,subst(car difop1,cadr difop2,car difop2),
  247. subst(cadr difop1,cadr difop2,
  248. subst(car difop2,cadr difop1,car difop1))})
  249. then <<
  250. commu:=nil;
  251. if tr_ulpde then <<
  252. write"no commutation of:"$terpri()$
  253. prettyprint difop1$
  254. write"and "$terpri()$
  255. prettyprint difop2
  256. >>
  257. >>$
  258. % and is variable-disjunct with at least one other diff. operator
  259. if commu then <<
  260. disjun:=nil;
  261. for each difop2 in parti do
  262. if (cadr difop1 neq cadr difop2) and
  263. freeoflist(caddr difop1,caddr difop2) then disjun:=t;
  264. if disjun then
  265. if null pde then pde:=difop1 else
  266. if ( car cddddr difop1) < (car cddddr pde) or % minimal maxord
  267. (((car cddddr difop1) = (car cddddr pde)) and % minimal number of terms
  268. ((cadddr difop1) < (cadddr pde)) ) then pde:=difop1
  269. >>
  270. >>;
  271. if null pde then ulpde:=nil
  272. >>;
  273. if tr_ulpde then <<
  274. write"ulpde=",ulpde$
  275. terpri()$
  276. >>$
  277. % as a first try we take as cost for the PDE p the sum of all orders
  278. % of all derivatives of all functions in p
  279. totalcost:=0;
  280. for each drv in drvs do totalcost:=totalcost+absdeg(cdar drv);
  281. return if ulpde then {totalcost,p,pde,parti}
  282. else nil
  283. end$ % of ulpdep
  284. symbolic procedure min_ord_f(ode,allvarf,vl)$
  285. begin scalar minord,minordf,newallvarf,f,h,tr_ulode$
  286. % tr_ulode:=t;
  287. % does any function not occur anymore?
  288. % Which function does occur with lowest derivative: minord, minordf?
  289. minord:=1000;
  290. minordf:=nil;
  291. newallvarf:=nil;
  292. for each f in allvarf do <<
  293. h:=ld_deriv_search(ode,f,vl)$
  294. if tr_ulode then <<
  295. write"ld_deriv_search(",f,")=",h$
  296. terpri()$
  297. >>$
  298. if not zerop cdr h then << % otherwise f does not occur anymore in ode
  299. newallvarf:=cons(f,newallvarf)$
  300. h:=car h$
  301. h:=if null h then 0 else
  302. if null cdr h then 1 else cadr h$ % asuming that car h = x
  303. if h<minord then <<minord:=h;minordf:=f>>
  304. >>
  305. >>$
  306. return {minord,minordf,newallvarf}
  307. end$
  308. symbolic procedure underode(pchar,pdes)$
  309. % pchar has the form {p,x,minord,minordf}
  310. begin
  311. scalar tr_ulode,p,x,allvarf,orgallvarf,ode,noallvarf,vl,
  312. minord,minordf,adj,f,h,newf,sol,sublist,rtnlist$
  313. % tr_ulode:=t;
  314. p :=car pchar;
  315. x :=cadr pchar;
  316. minord :=caddr pchar;
  317. minordf:=cadddr pchar;
  318. allvarf:=get(p,'allvarfcts);
  319. orgallvarf:=allvarf;
  320. ode:=get(p,'val);
  321. noallvarf:=length(allvarf);
  322. vl:=get(p,'vars);
  323. while (minord>0) and
  324. (length(allvarf)=noallvarf) do <<
  325. if tr_ulode then <<
  326. write "x=",x," minord=",minord," minordf=",minordf,
  327. " allvarf=", allvarf$
  328. terpri()$
  329. >>$
  330. repeat <<
  331. adj:=intpde(ode,allvarf,vl,x,t);
  332. if tr_ulode then <<
  333. write"adj=",adj$
  334. terpri()$
  335. >>$
  336. h:=nil;
  337. for each f in allvarf do if not freeof(cadr adj,f) then h:=cons(f,h);
  338. if null h then % exact ode --> should do better then what is done now
  339. ode:=reval {'TIMES,x,ode};
  340. >> until h;
  341. minordf:=cadr min_ord_f(ode,h,vl)$
  342. % a new function (potential) is needed:
  343. newf:=newfct(fname_,vl,nfct_)$
  344. nfct_:=add1 nfct_;
  345. if tr_ulode then <<
  346. algebraic write"eqn=",{'LIST,{'PLUS,{'DF,newf,x},lisp cadr adj}}$
  347. algebraic write"var=",{'LIST,minordf }
  348. >>$
  349. sol:=cadr solveeval list({'LIST,{'PLUS,{'DF,newf,x},cadr adj}},
  350. {'LIST,minordf } );
  351. allvarf:=delete(minordf,allvarf)$
  352. allvarf:=cons(newf,allvarf)$
  353. % assuming that there is exacly one solution to the lin. alg. equation
  354. if tr_ulode then <<
  355. terpri()$
  356. write"sol=",sol$
  357. terpri()$
  358. >>$
  359. sublist:=cons(sol,sublist)$
  360. ode:=reval num reval
  361. {'PLUS,newf,{'MINUS,subst(caddr sol,cadr sol,car adj)}}$
  362. if tr_ulode then algebraic(write"ode=",ode)$
  363. h:=min_ord_f(ode,allvarf,vl)$
  364. minord:=car h; minordf:=cadr h; allvarf:=caddr h;
  365. if minord=0 then
  366. sublist:=cons(cadr solveeval list({'LIST,ode},{'LIST,minordf}),sublist)$
  367. if tr_ulode then <<
  368. write"allvarf=",allvarf," minord=",minord," minordf=",minordf$
  369. terpri()$
  370. >>$
  371. >>$
  372. if (minord neq 0) and (not zerop ode) then rtnlist:=list ode;
  373. ode:=nil;
  374. if tr_ulode then <<write"rtnlist=", rtnlist;terpri()>>$
  375. if tr_ulode then algebraic(write"sublist=",cons('LIST,sublist));
  376. while sublist do <<
  377. if member(cadar sublist,orgallvarf) then
  378. rtnlist:=cons(reval num reval {'PLUS,cadar sublist,
  379. {'MINUS,caddar sublist}},rtnlist)$
  380. sublist:=cdr reval cons('LIST,
  381. subst(caddar sublist,cadar sublist,cdr sublist))$
  382. if tr_ulode then algebraic(write"sublist=",cons('LIST,sublist))
  383. >>$
  384. allvarf:=smemberl(allvarf,rtnlist)$
  385. if tr_ulode then <<
  386. write"allvarf=",allvarf$
  387. terpri()$
  388. >>$
  389. for each h in allvarf do ftem_:=fctinsert(h,ftem_)$
  390. if tr_ulode then algebraic(write"rtnlist=",cons('LIST,rtnlist));
  391. h:=for each h in rtnlist collect
  392. mkeq(h,union(get(p,'fcts),allvarf),vl,allflags_,t,list(0),nil,pdes)$
  393. if print_ then terpri()$
  394. return h
  395. end$
  396. symbolic procedure underpde(pchar,pdes)$
  397. % pchar has the form {p,difop,parti} where p is the name of the equation,
  398. % difop is the main differential operator in p and parti is a partition
  399. % of p, i.e. the list of all differential operators. Each differential
  400. % operator has the form
  401. % {pde,fn,vld,no_of_drvs,maxordr}
  402. % where pde are all terms in p with fn, vld is a list of all variables
  403. % in pde, no_of_dervs is the number of different derivatives of fn,
  404. % maxord is the maximal order of derivatives of fn (order of pde)
  405. begin
  406. scalar tr_ulpde,ldo,parti,fn,lcond,difop,h,fl,eqlist,vl$
  407. % has to return list of new pde just like in underode
  408. % tr_ulpde:=t;
  409. ldo:=cadr pchar;
  410. parti:=caddr pchar$
  411. vl:=get(car pchar,'vars)$
  412. fn:=cadr ldo$
  413. lcond:={fn}$
  414. if tr_ulpde then <<
  415. write"ldo="$prettyprint parti$
  416. write"parti="$prettyprint parti
  417. >>$
  418. for each difop in parti do
  419. if cadr difop neq fn then <<
  420. h:=newfct(fname_,vl,nfct_)$
  421. nfct_:=add1 nfct_$
  422. if print_ then terpri()$
  423. fl:=cons(h,fl)$
  424. eqlist:=cons(cons({cadr difop,h},
  425. reval {'DIFFERENCE,cadr difop,subst(h,fn,car ldo)}),
  426. eqlist)$
  427. lcond:=cons(subst(h,cadr difop,car difop),lcond)
  428. >>$
  429. eqlist:=cons(cons(append(get(car pchar,'fcts),fl),
  430. cons('PLUS,lcond)),eqlist)$
  431. if tr_ulpde then <<
  432. write"eqlist="$prettyprint eqlist$
  433. >>$
  434. h:=for each h in eqlist collect
  435. mkeq(cdr h,car h,get(car pchar,'vars),allflags_,t,list(0),nil,pdes)$
  436. if print_ then terpri()$
  437. return h
  438. end$
  439. endmodule$
  440. end$