crsimp.red 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. %********************************************************************
  2. module simplifications$
  3. %********************************************************************
  4. % Routines for simplifications, contradiction testing
  5. % and substitution of functions
  6. % Author: Andreas Brand
  7. % 1991 1993 1994
  8. % Updates, changes, additions by Thomas Wolf
  9. %
  10. % $Id: crsimp.red,v 1.17 1998/06/25 18:16:41 tw Exp tw $
  11. %
  12. symbolic procedure signchange(g)$
  13. % ensure, that the first term is positive
  14. if pairp g then
  15. if (car g='MINUS) then cadr g
  16. else if (car g='PLUS) and (pairp cadr g) and (caadr g='MINUS)
  17. then reval list('MINUS,g)
  18. else g
  19. else g$
  20. symbolic procedure simplifyterm(p,ftem)$
  21. % simplify a single factor p of g=p*q*r*...=0
  22. if (ftem:=smemberl(ftem,p)) then
  23. if pairp p and member(car p,'(MINUS SQRT QUOTIENT))
  24. then simplifyterm(cadr p,ftem)
  25. else if pairp p and (car p='EXPT) then
  26. if smemberl(ftem,cadr p) then simplifyterm(cadr p,ftem)
  27. else 1
  28. else if member((p:=signchange p),ineq_) then 1
  29. else p
  30. else if not p or zerop p then 0
  31. else 1$
  32. symbolic procedure contradictioncheck(s,pdes)$
  33. begin scalar v,p$
  34. if s then
  35. while pdes do
  36. <<p:=car pdes$pdes:=cdr pdes$
  37. v:=get(p,'val)$
  38. if pairp v and (car v='TIMES) then
  39. (if member(s,cdr v) then
  40. <<v:=delete(s,cdr v)$
  41. update(p,if length v=1 then car v else cons('TIMES,v),
  42. get(p,'fcts),get(p,'vars),nil,list(0))>>)
  43. else if s=v then
  44. <<raise_contradiction(v,nil)$
  45. pdes:=nil>>
  46. >>$
  47. return contradiction_$
  48. end$
  49. symbolic procedure raise_contradiction(g,text)$
  50. <<contradiction_:=t$
  51. if print_ then
  52. <<terpri()$if text then write text
  53. else write "contradiction : "$
  54. deprint list g>> >>$
  55. symbolic procedure simplifypde(g,ftem,tofactor)$
  56. % simplify g=0
  57. begin scalar h,l,ruli$
  58. if rulelist_ then g:=reval evalwhereexp list(rulelist_,g)$
  59. ruli:=start_let_rules()$
  60. g:=reval aeval g$
  61. stop_let_rules(ruli)$
  62. if g and not zerop g and not (ftem:=smemberl(ftem,g)) then
  63. <<raise_contradiction(g,nil)$g:=1>>
  64. else if pairp g then
  65. if member(car g,'(EXPT QUOTIENT MINUS SQRT)) then
  66. g:=simplifypde(cadr g,ftem,tofactor)
  67. else if member(car g,'(LOG LN LOGB LOG10)) then
  68. g:=simplifypde(reval list('PLUS,cadr g,-1),ftem,tofactor)
  69. else if tofactor then
  70. <<if car g='TIMES
  71. then l:=for each a in cdr g join
  72. cdr reval list('FACTORIZE,a)
  73. else l:=cdr reval list('FACTORIZE,g)$
  74. while l do
  75. <<if not member(car l,cdr l) then
  76. h:=union(list simplifyterm(car l,ftem),h)$
  77. l:=cdr l>>$
  78. h:=delete(1,h)$
  79. if null h then
  80. <<raise_contradiction(g,nil)$
  81. g:=1>>
  82. else
  83. if pairp cdr h then g:=cons('TIMES,reverse h)
  84. else g:=car h>>$
  85. return g$
  86. end$
  87. symbolic procedure fcteval(p,less_vars)$
  88. % looks for a function which can be eliminated
  89. % if one is found, it is stored in p as (coeff_of_f.f)
  90. % if less_vars neq nil then the expr. to be substituted
  91. % must have only fcts. of less vars
  92. % 'to_eval neq nil iff not checked yet for substitution
  93. % of if subst. possible
  94. % i.e. 'to_eval=nil if checked and not possible
  95. % 'fcteval_lin includes subst. with coefficients that do not
  96. % include ftem functions/constants
  97. % 'fcteval_nca includes subst. with non-vanishing coefficients
  98. % and therefore no case distinctions (linearity)
  99. % 'fcteval_nli includes subst. with possibly vanishing coefficients
  100. % and therefore case distinctions (non-linearity)
  101. begin scalar ft,a,b,fl,li,nc,nl,f,cpf,fv,fc$
  102. if flagp(p,'to_eval) then <<
  103. b:=get(p,'not_to_eval)$ % functions that replace a derivative
  104. if (not get(p,'fcteval_lin)) and
  105. (not get(p,'fcteval_nca)) and
  106. (not get(p,'fcteval_nli)) then <<
  107. ft:=get(p,'allvarfcts)$
  108. if null ft then <<
  109. ft:=get(p,'rational)$
  110. % drop all functions f from ft for which there is another
  111. % function which is a function of all variables of f + at
  112. % least one extra variable
  113. for each f in ft do <<
  114. cpf:=get(p,'fcts)$
  115. fv:=fctargs f$
  116. while cpf and
  117. (not_included(fv,fc:=fctargs car cpf) or
  118. (length fv >= length fc) ) do
  119. cpf:=cdr cpf;
  120. if null cpf then fl:=cons(f,cpf)
  121. >>$
  122. ft:=fl$
  123. >>$
  124. if ft then <<
  125. if (not less_vars) or
  126. (not cdr ft) or
  127. (zerop get(p,'nvars)) then <<
  128. % either all functions allowed or only one fnc of all vars
  129. for each f in ft do
  130. if (f neq b) and linear_fct(p,f) then <<
  131. % only linear algebr. fcts
  132. a:=reval coeffn(get(p,'val),f,1)$
  133. if fl:=smemberl(delete(f,get(p,'fcts)),a) then
  134. if freeofzero(a,fl,get(p,'vars)) then nc:=cons(cons(a,f),nc)
  135. else nl:=cons(cons(a,f),nl)
  136. else
  137. li:=cons(cons(a,f),li)
  138. >>$
  139. if li then put(p,'fcteval_lin,reverse li); % else
  140. if nc then put(p,'fcteval_nca,reverse nc); % else
  141. if nl then put(p,'fcteval_nli,reverse nl);
  142. if not (li or nc or nl) then remflag1(p,'to_eval)
  143. >>
  144. >>$
  145. >>$
  146. return (get(p,'fcteval_lin) or
  147. get(p,'fcteval_nca) or
  148. get(p,'fcteval_nli) )
  149. >>
  150. end$
  151. symbolic procedure freeofzero(p,ft,vl)$
  152. % gets p (factorized), if p does not vanish identically
  153. if null ft then p
  154. else
  155. begin scalar a,b,fr,pri$
  156. pri:=print_$
  157. print_:=nil$
  158. for each s in cdr reval list('FACTORIZE,p) do
  159. a:=union(list simplifyterm(s,ft),a)$
  160. if length a>1 then p:=cons('TIMES,a)$
  161. while a do
  162. if null smemberl(ft,car a) or member(car a,ineq_) then a:=cdr a
  163. else if pairp cdr
  164. (b:=union(for each s in separ(car a,ft,vl) collect cdr s,nil)) then
  165. <<fr:=nil$
  166. while b do if freeofzero(car b,ft,vl) then <<b:=nil$fr:=t>>
  167. else b:=cdr b$
  168. if fr then a:=cdr a
  169. else <<a:=nil$p:=nil>> >>
  170. else <<a:=nil$p:=nil>>$
  171. print_:=pri$
  172. return p
  173. end$
  174. symbolic procedure get_subst(l,length_limit,less_vars,no_df)$
  175. %
  176. % get the most simple pde from l which leads to a function substitution
  177. % if less_vars neq nil: the expr. to subst. has only fcts. of less vars
  178. % if no_df neq nil: the expr. to subst. has no derivatives
  179. begin scalar p,l1,l2,m,ntms,mdu$
  180. % mdu=(1:lin, 2:nca, 3:nli)
  181. % drop all equations longer than length_limit
  182. if length_limit then <<
  183. while l do
  184. if get(car l,'length)>length_limit then l:=nil
  185. else <<
  186. l1:=cons(car l,l1)$
  187. l:=cdr l
  188. >>$
  189. l:=reverse l1
  190. >>$
  191. % l is now the list of equations <= length_limit
  192. % next: substitution only if no_df=nil or
  193. % no derivative of any function occurs
  194. if no_df then <<
  195. for each s in l do
  196. <<l2:=get(s,'derivs)$
  197. while l2 do
  198. if pairp(cdaar l2) then
  199. <<l2:=nil;
  200. l1:=cons(s,l1)>>
  201. else l2:=cdr l2>>$
  202. l:=setdiff(l,l1)>>$
  203. % next: restrict to substitutions, if any,
  204. % that have a coefficient without ftem-dependence
  205. l1:=nil;
  206. for each s in l do
  207. if fcteval(s,less_vars) and
  208. get(s,'fcteval_lin) then l1:=cons(s,l1)$
  209. if l1 then <<l:=l1;mdu:=1>>
  210. else <<
  211. % at least substitutions that do not lead to subcases?
  212. for each s in l do
  213. if get(s,'fcteval_nca) then l1:=cons(s,l1)$
  214. if l1 then <<l:=l1;mdu:=2>>
  215. else mdu:=3
  216. >>$
  217. % next: find an equation with as many as possible variables
  218. % and few as possible terms for substitution
  219. m:=-1$
  220. for each s in l do <<
  221. l1:=get(s,'nvars);
  222. if get(s,'starde) then l1:=sub1 l1;
  223. if l1>m then m:=l1$
  224. >>$
  225. while m>=0 do <<
  226. l1:=l$
  227. ntms:=10000000$
  228. while l1 do
  229. if ((get(car l1,'nvars) -
  230. if get(car l1,'starde) then 1
  231. else 0) = m ) and
  232. fcteval(car l1,less_vars) and
  233. (get(car l1,'terms) < ntms) then <<
  234. p:=car l1$
  235. l1:=cdr l1$
  236. ntms:=get(p,'terms)$
  237. >> else l1:=cdr l1$
  238. m:=if p then -1
  239. else sub1 m
  240. >>$
  241. if p then return if mdu=1 then {mdu,p,car get(p,'fcteval_lin)} else
  242. if mdu=2 then {mdu,p,car get(p,'fcteval_nca)} else
  243. {mdu,p,car get(p,'fcteval_nli)}
  244. end$
  245. symbolic procedure ineqsplit(q,ftem)$
  246. % q into factors and
  247. % drop quotients
  248. begin scalar l$
  249. if pairp q and (car q='QUOTIENT) then q:=cadr q$
  250. q:=cdr reval list('FACTORIZE,q)$
  251. for each s in q do
  252. if smemberl(ftem,s) then
  253. <<s:=signchange s$
  254. if not member(s,l) then l:=cons(s,l)>>$
  255. return l$
  256. end$
  257. symbolic procedure ineqsubst(new,old,ftem)$
  258. % tests all q's in ineq_ for subst(new, old,q)=0
  259. % result: nil, if 0 occurs
  260. % otherwise list of the subst(car p,...)
  261. begin scalar l,a$
  262. while ineq_ do
  263. if not my_freeof(car ineq_,old) then
  264. <<a:=simplifyterm(reval reval subst(new, old,car ineq_),ftem)$
  265. if zerop a then
  266. <<if print_ then
  267. <<terpri()$write "contradiction from the substitution:"$
  268. eqprint list('EQUAL,old,new)$
  269. write "because of the non-vanishing expression:"$
  270. eqprint car ineq_>>$
  271. contradiction_:=t$
  272. l:=nil$
  273. ineq_:=nil>>
  274. else
  275. <<l:=union(ineqsplit(a,ftem),l)$
  276. ineq_:=cdr ineq_>> >>
  277. else
  278. <<l:=cons(car ineq_,l)$
  279. ineq_:=cdr ineq_>>$
  280. ineq_:=reverse l$
  281. end$
  282. symbolic procedure do_one_subst(ex,f,a,ftem,vl,level,eqn)$
  283. % substitute f by ex in a
  284. begin scalar l,l1,p,oldstarde$
  285. l:=get(a,'val)$
  286. oldstarde:=get(a,'starde)$
  287. if pairp l and (car l='TIMES) then l:=cdr l
  288. else l:=list l$
  289. while l do << % for each factor
  290. if smember(f,car l) then <<
  291. p:=reval reval subst(ex,f,car l)$
  292. if not p or zerop p then <<l:=list nil$l1:=list 0>>
  293. else <<
  294. if pairp p and (car p='QUOTIENT) then p:=cadr p$
  295. l1:=if no_of_terms(p)>max_factor then cons(p,l1)
  296. else
  297. append(reverse cdr reval list('FACTORIZE,p),l1)
  298. >>
  299. >> else l1:=cons(car l,l1)$
  300. l:=cdr l
  301. >>$
  302. l:=nil$
  303. while l1 do <<
  304. if not member(car l1,cdr l1) then
  305. l:=union(list simplifyterm(car l1,ftem),l)$
  306. l1:=cdr l1
  307. >>$
  308. l:=delete(1,l)$
  309. if null l then <<
  310. if print_ then <<
  311. terpri()$ % new
  312. write"Substitution of "$
  313. fctprint list f$
  314. if cdr get(eqn,'fcts) then <<
  315. write " by an expression in "$terpri()$
  316. fctprint delete(f,get(eqn,'fcts))
  317. >>$
  318. write " found in ",eqn," : "$
  319. eqprint(list('EQUAL,f,ex))
  320. >>$
  321. raise_contradiction(get(a,'val),
  322. "leads to a contradiction in : ")$
  323. a:=nil
  324. >> else <<
  325. if pairp cdr l then l:=cons('TIMES,l)
  326. else l:=car l$
  327. if get(a,'level) neq level then
  328. a:=mkeq(l,ftem,vl,allflags_,nil,list(0))
  329. else <<
  330. for each b in allflags_ do flag(list a,b)$
  331. if null update(a,l,ftem,vl,nil,list(0)) then <<
  332. setprop(a,nil)$
  333. a:=nil
  334. >>
  335. >>$
  336. put(a,'level,level)
  337. >>$
  338. if oldstarde and not get(a,'starde) then put(a,'dec_with,nil);
  339. return a$
  340. end$
  341. symbolic procedure do_subst(md,p,l,pde,ftem,forg,vl,plim)$
  342. % md is the mode of substitution, needed in case of an ISE
  343. % Substitute a function in all pdes
  344. begin scalar f,fl,h,ex,res,slim,too_large,was_subst,ps,
  345. ruli,ise,cf,vl,nof,stde$ %,l$
  346. % l:=get(p,'fcteval_lin)$
  347. % if null l then l:=get(p,'fcteval_nca)$
  348. % if null l then l:=get(p,'fcteval_nli)$
  349. % if l then << % l:=car l$
  350. f:=cdr l$
  351. cf:=car l$
  352. if get(p,'starde) then ise:=t;
  353. slim:=get(p,'length)$
  354. ruli:=start_let_rules()$
  355. ex:=reval aeval list('QUOTIENT,
  356. list('PLUS,list('MINUS,get(p,'val)),
  357. list('TIMES,cf,f)),
  358. cf)$
  359. if not ise then ineqsubst(ex,f,ftem)$
  360. if not contradiction_ then <<
  361. if not ise then <<
  362. fl:=delete(f,smemberl(ftem_,ex))$ % functions occuring in ex
  363. forg:=for each h in forg collect
  364. if atom h then
  365. if f=h then <<put(h,'fcts,fl)$was_subst:=t$list('EQUAL,f,ex)>>
  366. else h
  367. else
  368. if (car h='EQUAL) and member(f,get(cadr h,'fcts)) then <<
  369. put(cadr h,'fcts,union(fl,delete(f,get(cadr h,'fcts))))$
  370. was_subst:=t$
  371. reval subst(ex,f,h)
  372. >> else h$
  373. >>$
  374. if expert_mode then <<
  375. ps:=promptstring!*$
  376. promptstring!*:="pdes selected for substitution: "$
  377. l:=xread nil$
  378. promptstring!*:=ps$
  379. if idp l then <<if not member(l,pde) then l:=nil>>
  380. else if pairp l then
  381. if car l='!*comma!* then l:=intersection(pde,cdr l)
  382. else l:=nil
  383. else l:=nil$
  384. if not_included(pde,l) then too_large:=t$
  385. if not l then <<
  386. terpri()$
  387. write "This is not a pde (e.g. e2) or a list of pdes (e.g. e1,e2,e3)"
  388. >>
  389. >> else l:=delete(p,pde)$
  390. % Do the substitution in all suitable equations
  391. if ise then <<
  392. h:=nil;
  393. vl:=get(p,'vars)$
  394. fl:=get(p,'fcts)$
  395. nof:=cdr get(p,'starde)$
  396. while l do <<
  397. if (stde:=get(car l,'starde)) and
  398. (nof<=cdr stde) and
  399. (not not_included(vl,get(car l,'vars))) and
  400. (not not_included(fl,get(car l,'fcts))) then h:=cons(car l,h);
  401. l:=cdr l
  402. >>$
  403. l:=h;
  404. >>$
  405. while l and not contradiction_ do <<
  406. if member(f,get(car l,'fcts)) then
  407. if not expert_mode and plim and (slim*get(car l,'length)>plim)
  408. then too_large:=t
  409. else <<
  410. pde:=eqinsert(do_one_subst(ex,f,car l,ftem,vl,get(p,'level),p),
  411. delete(car l,pde))$
  412. for each h in pde do drop_rl_with(car l,h);
  413. put(car l,'rl_with,nil);
  414. for each h in pde do drop_dec_with(car l,h,'dec_with_rl);
  415. put(car l,'dec_with_rl,nil);
  416. flag(list car l,'to_int);
  417. was_subst:=t
  418. >>$
  419. l:=cdr l
  420. >>$
  421. if print_ and (not contradiction_) and was_subst then <<
  422. terpri()$write "Substitution of "$
  423. fctprint list f$
  424. if cdr get(p,'fcts) then <<
  425. write " by an "$
  426. if ise then write"(separable) "$
  427. write "expression in "$terpri()$
  428. fctprint delete(f,get(p,'fcts))
  429. >>$
  430. write " found in ",p," : "$
  431. eqprint(list('EQUAL,f,ex))
  432. >>$
  433. % To avoid using p repeatedly for substitutions of different
  434. % functions in the same equations:
  435. if ise then <<
  436. put(p,'fcteval_lin,nil);
  437. put(p,'fcteval_nca,nil);
  438. put(p,'fcteval_nli,nil);
  439. remflag1(p,'to_eval)$ % otherwise 'fcteval_??? would be computed again
  440. md:=md; % only in order to do something with md if the next
  441. % statement is commented out
  442. % if too_large then
  443. % if md=1 then put(p,'fcteval_lin,list((cf . f))) else
  444. % if md=2 then put(p,'fcteval_nca,list((cf . f))) else
  445. % put(p,'fcteval_nli,list((cf . f)))$
  446. % could probably unnecessarily be repeated
  447. >>;
  448. % delete f and p if not anymore needed
  449. if (not ise) and
  450. (not too_large) and
  451. (not contradiction_) then <<
  452. if not assoc(f,depl_copy_) then
  453. depl!*:=delete(assoc(f,depl!*),depl!*)$
  454. was_subst:=t$ % in the sense that pdes have been updated
  455. ftem_:=delete(f,ftem_)$
  456. pde:=delete(p,pde)$
  457. setprop(p,nil)
  458. >>$
  459. % if was_subst then
  460. res:=list(pde,forg)
  461. % also if not used to delete the pde if the function to be
  462. % substituted does not appear anymore
  463. >>$
  464. stop_let_rules(ruli)$
  465. % >>$
  466. if not contradiction_ then return cons(was_subst,res)$
  467. end$
  468. symbolic procedure make_subst(pdes,forg,vl,l1,length_limit,pdelimit,
  469. less_vars,no_df,no_cases,lin_subst,
  470. mingrowth,cost_limit)$
  471. % make a subst.
  472. % l1 is the list of possible "candidates"
  473. begin scalar p,q,r,l,h,cop,cases_,w,md$ % ,ineq
  474. if expert_mode then l1:=selectpdes(pdes,1)$
  475. again:
  476. if (mingrowth and (w:=search_subs(l1,cost_limit,no_cases))) or
  477. ((null mingrowth) and
  478. (w:=get_subst(l1,length_limit,less_vars,no_df))) then
  479. if ( car w = 1) or
  480. ((lin_subst=nil) and
  481. ( (car w = 2) or
  482. ((car w = 3) and
  483. member(caaddr w,ineq_) ) ) ) then <<
  484. l:=do_subst(car w,cadr w,caddr w,pdes,ftem_,forg,vl,pdelimit)$
  485. if l and null car l then << % not contradiction but not used
  486. l1:=delete(cadr w,l1);
  487. if l1 then <<
  488. pdes:=cadr l;
  489. forg:=caddr l;
  490. l:=nil;
  491. goto again
  492. >>
  493. >>;
  494. if l then l:=cdr l
  495. >> else
  496. if (null lin_subst) and (null no_cases) then <<
  497. md:=car w; % md = type of substitution, needed in case of ISE
  498. p:=cadr w; % p = the equation
  499. w:=caddr w; % w = (coeff . function)
  500. % make an equation from the coefficient
  501. q:=mkeq(car w,get(p,'fcts),get(p,'vars),allflags_,t,list(0))$
  502. % and an equation from the remainder
  503. r:=mkeq(list('PLUS,get(p,'val),
  504. list('TIMES,car w,
  505. list('MINUS,cdr w))),
  506. get(p,'fcts),get(p,'vars),allflags_,t,list(0))$
  507. if contradiction_ then <<
  508. contradiction_:=nil$
  509. h:=get(q,'val)$
  510. if pairp h and (car h='TIMES) then ineq_:=union(cdr h,ineq_)
  511. else ineq_:=union(list h,ineq_)$
  512. setprop(q,nil)$
  513. setprop(r,nil)$
  514. l:=do_subst(md,p,w,pdes,ftem_,forg,vl,pdelimit)$
  515. if print_ then write"therefore no special investigation"$
  516. if l and null car l then << % not contradiction but not used
  517. l1:=delete(p,l1);
  518. if l1 then <<
  519. pdes:=cadr l;
  520. forg:=caddr l;
  521. l:=nil;
  522. goto again
  523. >>
  524. >>;
  525. if l then l:=cdr l
  526. >> else <<
  527. cop:=backup_pdes(pdes,forg)$
  528. remflag1(p,'to_eval)$
  529. if print_ then <<
  530. terpri()$
  531. write "for the substitution of ",cdr w," by ",p$
  532. write " we have to consider the case : "$
  533. eqprint list('EQUAL,0,car w)
  534. >>$
  535. pdes:=eqinsert(q,delete(p,pdes))$
  536. pdes:=eqinsert(r,pdes)$
  537. level_:=cons(1,level_)$
  538. print_level()$
  539. h:=get(q,'val)$ % to add it to ineq_ afterwards
  540. l:=crackmain(pdes,ineq_,forg,vl)$
  541. level_:=cons(2,level_)$
  542. if print_ then <<
  543. print_level()$
  544. terpri()$
  545. write "now back to the substitution of ",cdr w," by ",p$
  546. >>$
  547. pdes:=restore_pdes(cop)$
  548. if pairp h and (car h='TIMES) then ineq_:=union(cdr h,ineq_)
  549. else ineq_:=union(list h,ineq_)$
  550. setprop(q,nil);
  551. setprop(r,nil);
  552. if contradiction_ then <<
  553. contradiction_:=nil$
  554. l:=do_subst(md,p,w,pdes,ftem_,forg,vl,pdelimit)$
  555. if l and null car l then << % not contradiction but not used
  556. l1:=delete(p,l1);
  557. if l1 then <<
  558. pdes:=cadr l;
  559. forg:=caddr l;
  560. l:=nil;
  561. goto again
  562. >>
  563. >>;
  564. if l then l:=cdr l
  565. >> else <<
  566. cases_:=t$
  567. cop:=nil; % to save memory
  568. h:=crackmain(pdes,ineq_,forg,vl)$
  569. if contradiction_ then contradiction_:=nil
  570. else l:=union(h,l)
  571. >>
  572. >>$
  573. >>$
  574. return if contradiction_ then nil % list(nil,nil)
  575. else if cases_ then list l
  576. else l$
  577. end$
  578. symbolic procedure get_fact_pde(pdes)$
  579. % look for pde in pdes which can be factorized
  580. begin scalar m,p,pv,fdegl,pdeg,h,f,fcc,fcl,tf,pmdeg,fmdeg,tfm,fm,pm$
  581. m:=0; % counts how often the factor occurs that occurs most
  582. while pdes do <<
  583. p:=car pdes$ pdes:=cdr pdes$
  584. pv:=get(p,'val)$
  585. if pairp pv and (car pv='TIMES) then <<
  586. pv:=cdr pv$ % the list of factors in p
  587. fdegl:=for each f in pv collect
  588. pde_degree(f,smemberl(get(p,'rational),f))$
  589. pdeg:=for each h in fdegl sum h$
  590. for each f in pv do <<
  591. % counting how often f has occured as factor
  592. fcc:=fcl$
  593. while fcc and (caar fcc neq f) do fcc:=cdr fcc$
  594. if fcc then <<
  595. h:=add1 cadar fcc;
  596. rplaca(cdar fcc,h);
  597. >> else <<
  598. fcl:=cons({f,1,p},fcl);
  599. h:=1
  600. >>;
  601. tf:=nil;
  602. % Is f the best factor so far and p the best equation?
  603. if ( h>m ) or
  604. ((h=m ) and
  605. (( pdeg < pmdeg ) or
  606. (( pdeg = pmdeg ) and
  607. ((car fdegl < fmdeg ) or
  608. ((car fdegl = fmdeg ) and
  609. ((tf:=no_of_terms(f)) < tfm) ) ) ) ) ) then <<
  610. m:=h;
  611. fm:=f;
  612. pm:=p;
  613. pmdeg:=pdeg;
  614. fmdeg:=car fdegl;
  615. tfm:=if tf then tf
  616. else no_of_terms(f)$
  617. >>$
  618. fdegl:=cdr fdegl
  619. >>
  620. >>$
  621. >>$
  622. return if m=0 then nil
  623. else <<
  624. put(pm,'val,cons('TIMES,cons(fm,delete(fm,cdr get(pm,'val)))))$
  625. pm
  626. >>
  627. end$
  628. algebraic procedure start_let_rules$
  629. begin scalar ruli;
  630. ruli:={};
  631. let explog_$
  632. if sin(!%x)**2+cos(!%x)**2 neq 1 then <<ruli:=cons(1,ruli);let trig1_>> else ruli:=cons(0,ruli)$
  633. if cosh(!%x)**2 neq (sinh(!%x)**2 + 1) then <<ruli:=cons(1,ruli);let trig2_>> else ruli:=cons(0,ruli)$
  634. if sin(!%x)*tan(!%x/2)+cos(!%x) neq 1 then <<ruli:=cons(1,ruli);let trig3_>> else ruli:=cons(0,ruli)$
  635. if sin(!%x)*cot(!%x/2)-cos(!%x) neq 1 then <<ruli:=cons(1,ruli);let trig4_>> else ruli:=cons(0,ruli)$
  636. if cos(2*!%x) + 2*sin(!%x)**2 neq 1 then <<ruli:=cons(1,ruli);let trig5_>> else ruli:=cons(0,ruli)$
  637. if sin(2*!%x) neq 2*cos(!%x)*sin(!%x) then <<ruli:=cons(1,ruli);let trig6_>> else ruli:=cons(0,ruli)$
  638. if sinh(2*!%x) neq 2*sinh(!%x)*cosh(!%x) then <<ruli:=cons(1,ruli);let trig7_>> else ruli:=cons(0,ruli)$
  639. if cosh(2*!%x) neq 2*cosh(!%x)**2-1 then <<ruli:=cons(1,ruli);let trig8_>> else ruli:=cons(0,ruli)$
  640. return ruli;
  641. end$
  642. algebraic procedure stop_let_rules(ruli)$
  643. begin
  644. clearrules explog_$
  645. if first ruli = 1 then clearrules trig8_$ ruli:=rest ruli$
  646. if first ruli = 1 then clearrules trig7_$ ruli:=rest ruli$
  647. if first ruli = 1 then clearrules trig6_$ ruli:=rest ruli$
  648. if first ruli = 1 then clearrules trig5_$ ruli:=rest ruli$
  649. if first ruli = 1 then clearrules trig4_$ ruli:=rest ruli$
  650. if first ruli = 1 then clearrules trig3_$ ruli:=rest ruli$
  651. if first ruli = 1 then clearrules trig2_$ ruli:=rest ruli$
  652. if first ruli = 1 then clearrules trig1_$
  653. end$
  654. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  655. % procedures for finding an optimal substitution %
  656. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  657. symbolic procedure fbts(a,b)$
  658. % fbts ... first better than second
  659. (cadr a <= cadr b) and
  660. (caddr a <= caddr b) and
  661. (cadddr a <= cadddr b);
  662. symbolic procedure list_subs(p,fevl,fli,mdu)$
  663. % p is an equation, fevl a substitution list of p,
  664. % fli is a list of lists (f,p1,p2,..) where
  665. % f is a function,
  666. % pi are lists (eqn,nco,nte,mdu) where
  667. % eqn is an equation that can be used for substituting f
  668. % nco is the number of terms of the coefficient of f in the eqn
  669. % nte is the number of terms without f in the eqn
  670. % mdu is the kind of substitution (1:lin, 2:nca, 3:nli)
  671. begin
  672. scalar a,f,nco,nte,cpy,cc,ntry;
  673. for each a in fevl do <<
  674. f:=cdr a;
  675. nco:=no_of_terms(car a);
  676. nte:=get(p,'terms);
  677. nte:=if nte=1 then 0
  678. else nte-nco$
  679. % Is there already any substitution list for f?
  680. cpy:=fli;
  681. while cpy and (f neq caar cpy) do cpy:=cdr cpy$
  682. ntry:={p,nco,nte,mdu}$
  683. if null cpy then fli:=cons({f,ntry},fli) % no, there was not
  684. else << % yes, there was one
  685. cc:=cdar cpy$
  686. while cc and (null fbts(car cc,ntry)) do cc:=cdr cc$
  687. if null cc then << % ntry is at least in one criterium better
  688. % than a known one
  689. rplaca(cpy,cons(f,cons(ntry,cdar cpy)));
  690. cc:=cdar cpy$ % just the list of derivatives with ntry as the first
  691. while cdr cc do
  692. if fbts(ntry,cadr cc) then rplacd(cc,cddr cc)
  693. else cc:=cdr cc$
  694. >>
  695. >>
  696. >>;
  697. return fli
  698. end$
  699. algebraic procedure cwrno(n,r)$
  700. % number of terms of (a1+a2+..+an)**r if ai are pairwise prime
  701. % number of combinations of r factors out of n possible factors
  702. % with repititions and without order = (n+r-1 over r)
  703. <<n:=n+r-1;
  704. % The rest of the procedure computes binomial(n,r).
  705. if 2*r>n then k:=n-r;
  706. for i:=1:r product (n+1-i)/i
  707. >>$
  708. symbolic procedure besu(ic1,mdu1,ic2,mdu2)$
  709. % Is the first substitution better than the second?
  710. ((mdu1<mdu2) and (ic1<=ic2)) or
  711. ((mdu1=mdu2) and (ic1< ic2)) or
  712. % ########## difficult + room for improvement as the decision is
  713. % actually dependent on how precious memory is
  714. % (more memory --> less cases and less time):
  715. ((mdu1=2) and (ic1<(ic2+ 4))) or
  716. ((mdu1=3) and (ic1<(ic2+25)))$
  717. symbolic procedure search_subs(pdes,cost_limit,no_cases)$
  718. begin
  719. scalar fli,p,el,f,fpl,dv,drf,d,ffl,hp,ff,nco,be,s,nte,ic,fp,
  720. rm,mc,subli,mdu,tr_search$
  721. % at first find the list of all functions that could be substituted
  722. % together with a list of pdes, the number of terms in the coeff and
  723. % the type of substitution
  724. % tr_search:=t$
  725. for each p in pdes do fcteval(p,nil)$
  726. fp:=pdes;
  727. while fp and
  728. ((get(car fp,'terms)>2) or
  729. (null get(car fp,'fcteval_lin)) ) do fp:=cdr fp;
  730. if fp then return {1,car fp,car get(car fp,'fcteval_lin)}$
  731. for each p in pdes do <<
  732. fli:=list_subs(p,get(p,'fcteval_lin),fli,1)$
  733. fli:=list_subs(p,get(p,'fcteval_nca),fli,2)$
  734. if null no_cases then fli:=list_subs(p,get(p,'fcteval_nli),fli,3)$
  735. >>$
  736. if tr_search then <<
  737. write"equations substitution: (eqn, no of coeff. t., no of other t., mdu)"$
  738. terpri()$
  739. for each el in fli do <<write el;terpri()>>$
  740. >>$
  741. if fli then
  742. if (null cdr fli) and % one function
  743. (null cddar fli) then % one equation, i.e. no choice
  744. return <<
  745. fli:=cadar fli; % fli is now (eqn,nco,nte,mdu)
  746. mdu:=cadddr fli;
  747. {mdu,car fli,car get(car fli,if mdu = 1 then 'fcteval_lin else
  748. if mdu = 2 then 'fcteval_nca else
  749. 'fcteval_nli) }
  750. >> else
  751. % (more than 1 fct.) or (only 1 function and more than 1 eqn.)
  752. for each el in fli do << % for any function to be substituted
  753. % (for the format of fli see proc list_subs)
  754. f:=car el$ el:=cdr el$
  755. % el is now a list of possible eqn.s to use for subst. of f
  756. fpl:=nil$ % fpl will be a list of lists (p,hp,a1,a2,..) where
  757. % p is an equation that involves f,
  758. % hp the highest power of f in p
  759. % ai are lists {ff,cdr d,nco} where ff is a derivative of f,
  760. % cdr d its power and nco the number of coefficients
  761. for each p in pdes do << % for each equation in which f could be subst.
  762. dv:=get(p,'derivs)$ % ((fct var1 n1 ...).pow)
  763. drf:=nil$
  764. for each d in dv do
  765. if caar d = f then drf:=cons(d,drf)$
  766. % drf is now the list of powers of derivatives of f in p
  767. ffl:=nil$ % ffl will be a list of derivatives of f in p
  768. % together with the power of f and number of
  769. % terms in the coeff.
  770. if drf then << % f occurs in this equation and we estimate the increase
  771. hp:=0$
  772. for each d in drf do <<
  773. if cdar d then ff:=cons('DF,car d)
  774. else ff:=caar d;
  775. nco:=no_of_terms(coeffn(get(p,'val),ff,cdr d));
  776. if cdr d > hp then hp:=cdr d$
  777. ffl:=cons({ff,cdr d,nco},ffl);
  778. >>
  779. >>;
  780. if drf then fpl:=cons(cons(p,cons(hp,ffl)),fpl);
  781. >>$
  782. % now all information about all occurences of f is collected and for
  783. % all possible substitutions of f the cost will be estimated and the
  784. % cheapest substitution for f will be determined
  785. be:=nil; % be will be the best equation with an associated min. cost mc
  786. for each s in el do <<
  787. % for each possible equation that can be used to subst. for f
  788. % number of terms of (a1+a2+..+an)**r = n+r-1 over r
  789. % f = (a1+a2+..+a_nte) / (b1+b2+..+b_nco)
  790. nco:=cadr s;
  791. nte:=caddr s;
  792. ic:= - get(car s,'terms); % ic will be the cost associated with
  793. % substituting f by car s and car s
  794. % will be dropped after the substitution
  795. for each fp in fpl do
  796. if (car s) neq (car fp) then <<
  797. rm:=get(car fp,'terms); % to become the number of terms without f
  798. hp:=cadr fp;
  799. ic:=ic - rm; % as the old eqn. car fp will be replaced
  800. for each ff in cddr fp do << % for each power of each deriv. of f
  801. ic:=ic + (caddr ff)* % number of terms of coefficient of ff
  802. cwrno(nte,cadr ff)* % (numerator of f)**(power of ff)
  803. cwrno(nco,hp - cadr ff); % (denom. of f)**(hp - power of ff)
  804. rm:=rm - caddr ff; % caddr ff is the number of terms with ff
  805. >>;
  806. % Now all terms containing f in car fp have been considered. The
  807. % remaining terms are multiplied with (denom. of f)**hp
  808. ic:=ic + rm*cwrno(nco,hp)
  809. >>;
  810. % Is this substitution better than the best previous one?
  811. if (null be) or besu(ic,cadddr s,mc,mdu) then
  812. <<be:=car s; mc:=ic; mdu:=cadddr s>>;
  813. >>;
  814. % It has been estimated that the substitution of f using the
  815. % best eqn be has an additional cost of ic terms
  816. if tr_search and (length el > 1) then <<
  817. terpri()$
  818. write"Best substitution for ",f," : ",{ic,f,be,mdu}$
  819. >>$
  820. if (null cost_limit) or (ic<cost_limit) then
  821. subli:=cons({ic,mdu,f,be},subli)$
  822. >>$
  823. % Now pick the best substitution
  824. if subli then <<
  825. s:=car subli;
  826. subli:=cdr subli;
  827. for each el in subli do
  828. if besu(car el,cadr el,car s,cadr s) then s:=el$
  829. if tr_search then <<
  830. terpri()$
  831. write"Optimal substitution:"$terpri()$
  832. write" replace ",caddr s," with the help of ",cadddr s,","$terpri()$
  833. if car s < 0 then write" saving ", - car s," terms, "
  834. else write" with a cost of ",car s," additional terms, "$
  835. terpri()$
  836. write if cadr s = 1 then " linear substitution" else
  837. if cadr s = 2 then " nonlinearity inceasing substitution" else
  838. " with case distinction" $
  839. >>$
  840. el:=get(cadddr s,if (cadr s) = 1 then 'fcteval_lin else
  841. if (cadr s) = 2 then 'fcteval_nca else
  842. 'fcteval_nli);
  843. while (caddr s) neq (cdar el) do el:=cdr el;
  844. return {cadr s,cadddr s,car el}
  845. % = {mdu ,p ,car get(p,'fcteval_???)}
  846. >>$
  847. end$
  848. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  849. % procedures for substitution of a derivative by a new function %
  850. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  851. symbolic procedure check_subst_df(pdes,forg)$
  852. % yields a list of derivatives which occur in all
  853. % pdes and in forg
  854. begin scalar l,l1,l2,n,cp,not_to_substdf$
  855. if pdes then <<
  856. for each s in pdes do l:=union(for each a in get(s,'derivs)
  857. collect car a,l)$ % all derivs
  858. for each s in forg do
  859. if pairp s then l:=union(for each a in all_deriv_search(s,ftem_)
  860. collect car a,l)$
  861. l1:=df_min_list(l)$
  862. l:=nil$
  863. for each s in l1 do
  864. if pairp s and not member(car s,not_to_substdf) then <<
  865. l:=cons(cons('DF,s),l)$
  866. not_to_substdf:=cons(car s,not_to_substdf)
  867. >> $
  868. % Derivatives of functions should only be substituted if the
  869. % function occurs in at least 2 equations
  870. while l do <<
  871. n:=0; % counter
  872. cp:=pdes;
  873. while cp and (n<2) do <<
  874. if member(car l,get(car cp,'fcts)) then n:=add1 n;
  875. cp:=cdr cp
  876. >>;
  877. if n=2 then l2:=cons(car l,l2);
  878. l:=cdr l
  879. >>
  880. >>$
  881. return l2$
  882. end$
  883. symbolic procedure df_min_list(dflist)$
  884. % yields the lowest derivative for each function in the list of
  885. % deriv. dflist.
  886. % e.g. dflist='((f x z) (g x) (g) (f y) (h x y) (h x z))
  887. % ==> result='(f g (h x))
  888. if dflist then
  889. begin scalar l,d,m,lmax$
  890. while dflist do
  891. <<m:=car dflist$
  892. dflist:=cdr dflist$
  893. l:=nil$
  894. while dflist do
  895. <<if (d:=df_min(car dflist,m)) then m:=d
  896. else l:=cons(car dflist,l)$
  897. dflist:=cdr dflist$
  898. >>$
  899. if pairp m and null cdr m then lmax:=cons(car m,lmax)
  900. else lmax:=cons(m,lmax)$
  901. dflist:=l$
  902. >>$
  903. return lmax$
  904. end$
  905. symbolic procedure df_min(df1,df2)$
  906. % yields the minimal derivative of d1,d2
  907. % e.g. df_min('(f x y),'(f x z))='(f x), df_min('(f x z),'(g x))=nil
  908. <<if not pairp df1 then df1:=list df1$
  909. if not pairp df2 then df2:=list df2$
  910. if car df1=car df2 then
  911. if (df1:=df_min1(cdr df1,cdr df2)) then cons(car df2,df1)
  912. else car df2>>$
  913. symbolic procedure df_min1(df1,df2)$
  914. begin scalar l,a$
  915. while df1 do
  916. <<a:=car df1$
  917. if not zerop (a:=min(dfdeg(df1,car df1),dfdeg(df2,car df1))) then
  918. l:=cons(car df1,l)$
  919. if a>1 then l:=cons(a,l)$
  920. df1:=cdr df1$
  921. if df1 and numberp car df1 then df1:=cdr df1>>$
  922. return reverse l$
  923. end$
  924. symbolic procedure dfsubst_forg(p,g,d,forg)$
  925. % substitute the function d in forg by an integral g
  926. % of the function p
  927. for each h in forg collect
  928. if pairp h and member(d,get(cadr h,'fcts)) then
  929. <<put(cadr h,'fcts,
  930. cons(p,delete(d,get(cadr h,'fcts))))$
  931. reval subst(g,d,h)>>
  932. else h$
  933. symbolic procedure expand_INT(p,varlist)$
  934. if null varlist then p
  935. else begin scalar v,n$
  936. v:=car varlist$
  937. varlist:=cdr varlist$
  938. if pairp(varlist) and numberp(car varlist) then
  939. <<n:=car varlist$
  940. varlist:=cdr varlist>>
  941. else n:=1$
  942. for i:=1:n do p:=list('INT,p,v)$
  943. return expand_INT(p,varlist)
  944. end$
  945. endmodule$
  946. end$