crshort.red 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. %********************************************************************
  2. module shortening$
  3. %********************************************************************
  4. % Routines for algebraically combining de's to reduce their length
  5. % Author: Thomas Wolf
  6. % Jan 1998
  7. %
  8. % $Id: crshort.red,v 1.4 1998/04/28 21:36:27 arrigo Exp $
  9. %
  10. symbolic procedure alg_length_reduction(arglist)$
  11. % Do one length-reducing combination of two equations
  12. begin scalar pdes,l,l1$ %,cpu,gc$
  13. % cpu:=time()$ gc:=gctime()$
  14. pdes:=car arglist$
  15. if expert_mode then l:=selectpdes(pdes,2)
  16. else l:=pdes$
  17. !*rational_bak := cons(!*rational,!*rational_bak)$
  18. if !*rational then algebraic(off rational)$
  19. if struc_eqn then <<
  20. while l do <<
  21. if is_algebraic(car l) then l1:=cons(car l,l1);
  22. l:=cdr l
  23. >>$
  24. l:=reverse l1
  25. >>$
  26. if l and cdr l and (l1:=err_catch_short(l,caddr arglist,pdes)) then
  27. <<for each a in cdr l1 do pdes:=drop_pde(a,pdes,nil)$
  28. for each a in car l1 do
  29. if a then pdes:=eqinsert(a,pdes)$
  30. for each a in car l1 do
  31. if a then dec_fct_check(a,pdes)$
  32. l:=nil;
  33. for each a in car l1 do if a then l:=cons(a,l);
  34. l:=list(pdes,cadr arglist,l)>>
  35. else l:=nil$
  36. %if print_ and !*time then <<
  37. % write " time : ", time() - cpu,
  38. % " ms GC time : ", gctime() - gc," ms "
  39. %>>$
  40. if !*rational neq car !*rational_bak then
  41. if !*rational then algebraic(off rational) else algebraic(on rational)$
  42. !*rational_bak:= cdr !*rational_bak$
  43. return l$
  44. end$
  45. %-------------------
  46. symbolic procedure err_catch_short(a1,vl,pdes)$
  47. begin scalar h,bak,kernlist!*bak,kord!*bak,mi,newp,p1,bakup_bak;
  48. bak:=max_gc_counter$ max_gc_counter:=my_gc_counter+max_gc_short;
  49. kernlist!*bak:=kernlist!*$
  50. kord!*bak:=kord!*$
  51. bakup_bak:=backup_; backup_:='max_gc_short$
  52. h:=errorset({'shorten_pdes,mkquote a1},nil,nil)
  53. where !*protfg=t;
  54. kernlist!*:=kernlist!*bak$
  55. kord!*:=kord!*bak;
  56. erfg!*:=nil;
  57. max_gc_counter:=bak;
  58. backup_:=bakup_bak;
  59. return
  60. if (errorp h) or (caar h=nil) then nil
  61. else <<
  62. mi:=caar h;
  63. newp:=cdar h;
  64. h:=nil;
  65. p1:=0;
  66. for each pc in cdr newp do p1:=p1+get(pc,'terms);
  67. mi:=(<<h:=for each pc in car newp collect
  68. if zerop pc then <<nequ_:=add1 nequ_;nil>> else
  69. mkeq(pc,fctsort union(get(caddr mi,'fcts),
  70. get(cadddr mi,'fcts)),
  71. vl,allflags_,t,list(0),nil,pdes);
  72. for each pc in h do if pc then p1:=p1-get(pc,'terms);
  73. h
  74. >> . cdr newp);
  75. if print_ then <<
  76. if tr_short then <<
  77. for each h in cdr newp do <<write h,": "$typeeq h>>$
  78. for each h in car mi do if null h then
  79. <<write "This gives identity 0=0."$terpri()>>
  80. else
  81. <<write h,": "$typeeq h>>$
  82. >>$
  83. write "shortening by ",p1," term"$
  84. if p1 neq 1 then write"s"$
  85. terpri()$
  86. >>;
  87. for each pc in cdr newp do drop_pde(pc,nil,nil);
  88. mi
  89. >>
  90. end$
  91. %-------------------
  92. symbolic procedure is_algebraic(p)$
  93. % checks whether the leading derivative is algebraic
  94. % if true and if lex_fc:=nil then all allvar functions turn up
  95. % only algebraically
  96. begin scalar h;
  97. h:=get(p,'derivs)$
  98. return
  99. if null h then t
  100. else <<h:=caar h;
  101. if (pairp h) and (cdr h) then nil
  102. else t
  103. >>
  104. end$
  105. %-------------------
  106. symbolic procedure shorten_pdes(des)$
  107. begin scalar mi,p1,p1rl,p1le,pc,pcc,newp,
  108. l0,l1,l2,l3,l4,version,p1_is_alg$ %,valcp$
  109. if pairp des and pairp cdr des then <<
  110. version:=1;
  111. repeat <<
  112. % find the pair of pdes not yet reduced with each other
  113. % with the lowest product of their number of terms % printlength's
  114. mi:=nil;
  115. pc:=des;
  116. while cdr pc do <<
  117. p1:=car pc;pc:=cdr pc;
  118. if flagp(p1,'to_eval) %and
  119. % ((get(p1,'terms)>1) or <<
  120. % valcp:=get(p1,'val);
  121. % if car valcp='!*sq then valcp:=reval valcp;
  122. % freeof(valcp,'PLUS)
  123. % >>)
  124. then <<
  125. p1rl:=get(p1,'rl_with);
  126. p1le:=get(p1,'terms);
  127. l1:=get(p1,'derivs);
  128. l0:=length l1;
  129. if struc_eqn then p1_is_alg:=is_algebraic(p1)$
  130. pcc:=pc;
  131. while pcc do
  132. if flagp(car pcc,'to_eval ) and
  133. % ((get(car pcc,'terms)>1) or <<
  134. % valcp:=get(car pcc,'val);
  135. % if car valcp='!*sq then valcp:=reval valcp;
  136. % freeof(valcp,'PLUS)
  137. % >>) and
  138. ((not member(car pcc, p1rl )) or
  139. (not member(p1 ,get(car pcc,'rl_with))) ) and
  140. ((null struc_eqn) or
  141. p1_is_alg or
  142. (is_algebraic(car pcc) and
  143. (p1le=get(car pcc,'terms))
  144. ) ) and
  145. <<l2:=get(car pcc,'derivs)$
  146. if version=1 then <<
  147. l3:=length(setdiff(l1,l2))$
  148. if (l0>l3 ) and % necessary requirement
  149. (( null mi ) or
  150. (( car mi) > l3) ) then t
  151. else nil
  152. >> else <<
  153. l3:=length(setdiff(l1,setdiff(l1,l2)))$
  154. l4:=length(union(l1,l2))$
  155. if (l3>0) and
  156. ((null mi) or
  157. ((((car mi)*l4) > ((cadr mi)*l3)))) then t
  158. else nil
  159. >>
  160. >>
  161. then <<mi:=list(l3,l4,p1,car pcc);
  162. if ((version = 1) and (l3= 0)) or
  163. ((version neq 1) and (l3=l4)) then <<pcc:=nil;pc:={nil}>>
  164. else pcc:=cdr pcc
  165. >>
  166. else pcc:=cdr pcc;
  167. >>
  168. >>$
  169. if mi then <<
  170. newp:=shorten(caddr mi,cadddr mi);
  171. if null newp then add_rl_with(caddr mi,cadddr mi)
  172. >>
  173. >> until (null mi) or newp; % if not possible then already returned with nil
  174. >>;
  175. return (mi . newp)
  176. end$
  177. %-------------------
  178. symbolic procedure partition_1(l,la)$
  179. % l is an equation,
  180. % returning (l1 . l2) where
  181. % l1=partitioning of equation l into ((lpow1.lc1),(lpow2.lc2),...)
  182. % l2=(lpow1,lpow2,...)
  183. % This works currently only for l that are linear in elem. of la
  184. begin scalar l1,l3;
  185. l:=reorder !*a2f l;
  186. while pairp l and member(l3:=car lpow l,la) do <<
  187. l1:=cons((l3 . !*f2a lc l), l1)$
  188. l:= red l;
  189. >>;
  190. return if l then (append(l1,list(1 . !*f2a l)) .
  191. append(la,list(1))) % inhomogeneous case
  192. else (l1 . la) % homogeneous case
  193. end$
  194. %-------------------
  195. symbolic procedure partition_2(de,l)$
  196. % dropping from de all parts that can not be matched by the other
  197. % equation, a list of ftem-functions and their derivatives from
  198. % the other equation is l
  199. begin scalar newde,dropped,n;
  200. % dropped is the number of terms that can not be matched and
  201. % which are therefore dropped
  202. dropped:=0$
  203. while de do <<
  204. n:=no_of_terms cdar de$
  205. if member(caar de,l) then newde:=cons(cons(n,car de),newde)
  206. else dropped:=dropped+n;
  207. de:=cdr de
  208. >>;
  209. return (dropped . newde)
  210. end$
  211. %-------------------
  212. symbolic procedure strip(d)$
  213. begin
  214. scalar h;
  215. d:= if not pairp d then list d else
  216. if car d='QUOTIENT then cadr d else
  217. if car d = 'PLUS then cdr d
  218. else list(d)$
  219. return
  220. for each h in d collect !*a2f h
  221. end$
  222. %-------------------
  223. symbolic procedure shorten(de1,de2)$
  224. % shorten the two pdes with each other
  225. % returns a dotted pair, where car is a list of the values of new pdes
  226. % and cdr is a list of names of pdes to be dropped
  227. begin scalar a,b,h,r,s,cp,l1,l2,l1ul2,l1ml2,l2ml1,l1il2,oldorder,
  228. de1p,de2p,termsof1,termsof2,flip,n1,n2,ql,maxcancel,
  229. take_first,non_linear,homo,de2pnew,tr_short_local;
  230. non_linear:=t;
  231. % take_first:=t;
  232. % "=t is not so radical, --> eqn.s are longer and in total it is slower
  233. % tr_short_local:=t;
  234. if tr_short_local then deprint list(get(de1,'val),get(de2,'val))$
  235. if homogen_ and (1=car get(de1,'hom_deg) )
  236. and (1=car get(de2,'hom_deg) )
  237. and ((cadr get(de1,'hom_deg)) neq
  238. (cadr get(de2,'hom_deg)) ) then homo:=t;
  239. if non_linear and null homo then <<
  240. a:=sort_partition(de1,nil,get(de1,'fcts),nil)$
  241. b:=sort_partition(de2,nil,get(de2,'fcts),nil)$
  242. if tr_short_local then <<
  243. write"a=",a$ terpri()$
  244. write"b=",b$ terpri()$
  245. >>;
  246. de1p:=nil;
  247. de2p:=nil;
  248. for each h in a do <<
  249. s:=car h;
  250. cp:=b;
  251. % Does s occur in b?
  252. while cp and (s neq caar cp) do cp:=cdr cp;
  253. if cp then <<
  254. r:=if (pairp s) or (numberp s) then gensym() else s;
  255. %--- dropping the ftem-depending factors once at the beginning
  256. de1p:=cons(cons(cadr h,
  257. cons(r,
  258. reval list('QUOTIENT,
  259. if cadr h>1 then cons('PLUS,caddr h)
  260. else caaddr h,
  261. s)
  262. )),
  263. de1p);
  264. de2p:=cons(cons(cadar cp,
  265. cons(r,
  266. reval list('QUOTIENT,
  267. if cadar cp>1 then cons('PLUS,caddar cp)
  268. else car caddar cp,
  269. s)
  270. )),
  271. de2p);
  272. % %--- not dropping the ftem-depending factors
  273. % de1p:=cons(cons(cadr h,cons(r,if cadr h>1 then cons('PLUS,caddr h)
  274. % else caaddr h )),de1p);
  275. % de2p:=cons(cons(cadar cp,cons(r,if cadar cp>1 then cons('PLUS,caddar cp)
  276. % else car caddar cp )),de2p);
  277. if tr_short_local then <<
  278. write"de1p=",de1p$terpri()$
  279. write"de2p=",de2p$terpri()$
  280. >>
  281. >>
  282. >>
  283. >> else <<
  284. de1p:=get(de1,'val)$
  285. de2p:=get(de2,'val)$
  286. if homo then << % multiplication with flin_ functions is forbidden
  287. a:=get(de1,'derivs)$
  288. h:=nil$
  289. while a do <<
  290. if not freeoflist(car a,flin_) then h:=cons(car a,h);
  291. a:=cdr a
  292. >>
  293. >> else h:=get(de1,'derivs)$
  294. l1:=for each a in h collect
  295. if length car a = 1 then caar a else cons('DF,car a)$ % all derivs of de1
  296. if homo then << % multiplication with flin_ functions is forbidden
  297. a:=get(de2,'derivs)$
  298. h:=nil$
  299. while a do <<
  300. if not freeoflist(car a,flin_) then h:=cons(car a,h);
  301. a:=cdr a
  302. >>
  303. >> else h:=get(de2,'derivs)$
  304. l2:=for each a in h collect
  305. if length car a = 1 then caar a else cons('DF,car a)$ % all derivs of de2
  306. l1ml2:=setdiff(l1,l2); % l1 - l2
  307. l2ml1:=setdiff(l2,l1); % l2 - l1
  308. l1il2:=setdiff(l1,l1ml2); % intersection
  309. l1ul2:=union(l1,l2); % union
  310. if tr_short_local then <<
  311. write"before substitution:"$terpri()$
  312. write"l1=",l1$ terpri()$
  313. write"l2=",l2$ terpri()$
  314. write"de1p=",de1p$terpri()$
  315. write"de2p=",de2p$terpri()$
  316. write"l1ml2=",l1ml2$terpri()$
  317. write"l2ml1=",l2ml1$terpri()$
  318. write"l1il2=",l1il2$terpri()$
  319. write"l1ul2=",l1ul2$terpri()$
  320. >>;
  321. % substituting derivatives by a new variable to become kernels
  322. for each a in l1ml2 do if pairp a then <<
  323. b:=gensym()$
  324. l1:=subst(b,a,l1)$
  325. l1ul2:=subst(b,a,l1ul2)$
  326. de1p:=subst(b,a,de1p)
  327. >>$
  328. for each a in l2ml1 do if pairp a then <<
  329. b:=gensym()$
  330. l2:=subst(b,a,l2)$
  331. l1ul2:=subst(b,a,l1ul2)$
  332. de2p:=subst(b,a,de2p)
  333. >>$
  334. for each a in l1il2 do if pairp a then <<
  335. b:=gensym()$
  336. l1:=subst(b,a,l1)$
  337. l2:=subst(b,a,l2)$
  338. l1ul2:=subst(b,a,l1ul2)$
  339. de1p:=subst(b,a,de1p)$
  340. de2p:=subst(b,a,de2p)
  341. >>$
  342. if tr_short_local then <<
  343. write"after substitution:"$terpri()$
  344. write"l1=",l1$ terpri()$
  345. write"l2=",l2$ terpri()$
  346. write"de1p=",de1p$terpri()$
  347. write"de2p=",de2p$terpri()$
  348. write"l1ml2=",l1ml2$terpri()$
  349. write"l2ml1=",l2ml1$terpri()$
  350. write"l1il2=",l1il2$terpri()$
  351. write"l1ul2=",l1ul2$terpri()$
  352. >>;
  353. %--- writing both equations as polynomials in elements of l1ul2
  354. oldorder:=setkorder l1ul2;
  355. de1p:=partition_1(de1p,l1); l1:=cdr de1p; de1p:=car de1p;
  356. de2p:=partition_1(de2p,l2); l2:=cdr de2p; de2p:=car de2p;
  357. setkorder oldorder;
  358. %--- l1,l2 can now have the element 1 in case of inhomogeneous de's
  359. l1ul2:=nil;
  360. l1il2:=nil;
  361. %--- Partitioning each equation into 2 parts, one part that can
  362. %--- be matched by the other equation and one that can not.
  363. % de1p:=partition_2(de1p,l2)$ dropped1:=car de1p; de1p:=cdr de1p;
  364. % de2p:=partition_2(de2p,l1)$ dropped2:=car de2p; de2p:=cdr de2p;
  365. de1p:=cdr partition_2(de1p,l2)$
  366. de2p:=cdr partition_2(de2p,l1)$
  367. >>$
  368. if (null de1p) or (null de2p) then return nil;
  369. termsof1:=no_of_terms get(de1,'val)$
  370. termsof2:=no_of_terms get(de2,'val)$
  371. if tr_short_local then <<
  372. write"---------"$terpri()$
  373. write"de1:",de1," with ",termsof1," terms"$terpri()$
  374. a:=de1p;
  375. while a do <<
  376. write "caar =",caar a;terpri()$
  377. write "cadar=",cadar a;terpri()$
  378. write "cddar=", algebraic write lisp cddar a;terpri()$
  379. a:=cdr a;
  380. >>;terpri()$
  381. write"de2:",de2," with ",termsof2," terms"$terpri()$
  382. a:=de2p;
  383. while a do <<
  384. write "caar =",caar a;terpri()$
  385. write "cadar=",cadar a;terpri()$
  386. write "cddar=",algebraic write lisp cddar a;terpri()$
  387. a:=cdr a;
  388. >>;terpri()$
  389. >>;
  390. % One can do a stronger restriction: The maximum that can be
  391. % canceled is sum of min of terms of the de1p,de2p sublists
  392. % corresponding to the coefficients of different ftem functions/deriv.
  393. a:=de1p; b:=de2p; n2:=nil;
  394. while a do <<
  395. n1:=if (caar a)<(caar b) then caar a else caar b;
  396. % n1 is min of terms of the coefficients of the same ftem function/der.
  397. n2:=cons(2*n1,n2);
  398. a:=cdr a; b:=cdr b;
  399. >>$
  400. % maxcancel is the maximal number of cancellations in all the
  401. % remaining runs of short depending on the current run.
  402. maxcancel:=list(0);
  403. n1:=0;
  404. while n2 do <<
  405. n1:=n1+car n2;
  406. n2:=cdr n2;
  407. maxcancel:=cons(n1,maxcancel);
  408. >>;
  409. if ((car maxcancel)<termsof1) and
  410. ((car maxcancel)<termsof2) then return nil;
  411. if homo and (cadr get(de1,'hom_deg)<cadr get(de2,'hom_deg)) then flip:=nil else
  412. if homo and (cadr get(de1,'hom_deg)>cadr get(de2,'hom_deg)) then flip:= t else
  413. if (termsof1<termsof2) or
  414. (struc_eqn and
  415. (n1=n2) and
  416. (null is_algebraic(de2))
  417. ) then flip:=nil
  418. else flip:=t;
  419. if flip then <<
  420. a:=de1p; de1p:=de2p; de2p:=a;
  421. n1:=termsof2;
  422. n2:=termsof1
  423. >> else <<
  424. n1:=termsof1;
  425. n2:=termsof2
  426. >>;
  427. if (n1=1) and (length de1p = 1)
  428. and ((atom cddar de1p) or (caddar de1p neq 'PLUS)) then <<
  429. % one equation has only a single term which is not a product of sums
  430. a:=cadar de1p; % e.g. g0030
  431. b:=de2p;
  432. while b and (cadar b neq a) do b:=cdr b;
  433. if tr_short_local then <<
  434. write"one is a 1-term equation"$terpri()$
  435. write"a=",a$terpri()$
  436. write"b=",b$terpri()$
  437. write"de1p.1=",de1p$terpri()$
  438. write"de2p.1=",de2p$terpri()$
  439. >>$
  440. a:=if null b then nil % that term does not turn up in other equation
  441. else << % it does turn up --> success
  442. de1p:=cddar de1p;
  443. de2p:=cddar b;
  444. if tr_short_local then <<
  445. write"de1p.2=",de1p$terpri()$
  446. write"de2p.2=",de2p$terpri()$
  447. >>$
  448. if homo then <<
  449. if pairp de2p and car de2p='PLUS then de2p:= cdr de2p
  450. else de2p:=list de2p;
  451. for each a in de2p do <<
  452. r:=algebraic(a/de1p); % otherwise already successful
  453. if freeoflist(algebraic den r,ftem_) then
  454. de2pnew:=cons(r,de2pnew)
  455. >>;
  456. de2p:=if null de2pnew then <<b:=nil;nil>> else
  457. if cdr de2pnew then cons('PLUS,de2pnew)
  458. else car de2pnew;
  459. de1p:=1
  460. >>;
  461. de2p % does only matter whether nil or not
  462. >>
  463. >> else <<
  464. repeat << % one shortening
  465. if tr_short_local then <<write"cadar de1p=",cadar de1p$terpri()>>$
  466. b:=short(ql,strip cddar de1p,strip cddar de2p,n1,
  467. 2*(caar de1p),car maxcancel-cadr maxcancel,
  468. cadr maxcancel,take_first,homo)$
  469. % take_first:=car b; b:=cdr b; % to activate see end of short()
  470. if b then <<
  471. ql:=car b;
  472. a:=cdr b;
  473. if a and take_first then << % the result
  474. de1p:=!*f2a car a;
  475. de2p:=!*f2a cdr a;
  476. >> else <<
  477. de1p:=cdr de1p;
  478. de2p:=cdr de2p;
  479. >>;
  480. maxcancel:=cdr maxcancel;
  481. >> else a:=nil;
  482. >> until (null b) or % failure
  483. a and take_first or % success
  484. null de1p$ % the case of exact balance
  485. if b and (null take_first) then <<
  486. % search of the best shortening
  487. r:=0; % highest number of saved terms so far
  488. de1p:=nil; % numerator of the best quotient so far
  489. de2p:=nil; % denominator of the best quotient so far
  490. while ql do <<
  491. s:=cdar ql;
  492. while s do <<
  493. cp:=car s;
  494. h:=cdar cp; % nall in short()
  495. while cdr cp do <<
  496. if (cdadr cp)+h>r then <<
  497. r:=(cdadr cp)+h;
  498. de1p:=!*f2a caar cp;
  499. if caaadr cp neq 1 then de1p:=reval {'TIMES,de1p,caaadr cp};
  500. de2p:=!*f2a caar ql;
  501. if cdaadr cp neq 1 then de2p:=reval {'TIMES,de2p,cdaadr cp};
  502. >>;
  503. rplacd(cp,cddr cp)
  504. >>;
  505. s:=cdr s;
  506. >>;
  507. ql:=cdr ql;
  508. >>
  509. >>
  510. >>;
  511. return
  512. if null b or (take_first and null a) then nil
  513. else << % numerator and denominator are de1p, de2p
  514. %--- computing the shorter new equation
  515. if flip then <<a:=get(de2,'val); b:=get(de1,'val)>>
  516. else <<a:=get(de1,'val); b:=get(de2,'val)>>$
  517. ql:=if termsof1>termsof2 then de1
  518. else de2;
  519. if print_ then <<
  520. if null car recycle_eqns then n1:=mkid(eqname_,nequ_)
  521. else n1:=caar recycle_eqns$
  522. if tr_short then
  523. algebraic write"The new equation ",n1," = ",
  524. de2p*(if flip then de2 else de1) -
  525. de1p*(if flip then de1 else de2)," replaces "
  526. >>$
  527. a:=reval list('PLUS,
  528. list('MINUS,
  529. if de1p=1 then b
  530. else list('TIMES,de1p,b)),
  531. if de2p=1 then a
  532. else list('TIMES,de2p,a) )$
  533. if in_cycle(cons(11,if flip then {
  534. get(de2,'printlength),length get(de2,'fcts),de2p,
  535. get(de1,'printlength),length get(de1,'fcts),de1p}
  536. else {
  537. get(de1,'printlength),length get(de1,'fcts),de1p,
  538. get(de2,'printlength),length get(de2,'fcts),de2p}))
  539. then nil
  540. else (list a . list(ql))
  541. >>
  542. end$
  543. %-------------------
  544. symbolic procedure clean_num(qc,j)$
  545. begin
  546. scalar qc1,nall$
  547. return
  548. if 2*(cdaar qc)<=j then t else <<
  549. qc1:=car qc; % the representative and list to proportional factors
  550. nall:=cdar qc1;
  551. while cdr qc1 do
  552. if (cdadr qc1)+nall<=j then rplacd(qc1,cddr qc1)
  553. else qc1:=cdr qc1;
  554. if qc1=car qc then t else nil % whether empty or not after cleaning
  555. >>
  556. end$
  557. %--------------------
  558. symbolic procedure clean_den(qc,j)$
  559. begin
  560. scalar qcc$
  561. qcc:=qc$
  562. while cdr qc do
  563. if clean_num(cdr qc,j) then rplacd(qc,cddr qc)
  564. else qc:=cdr qc$
  565. return null cdr qcc % Are there any numerators left?
  566. end$
  567. %--------------------
  568. symbolic procedure short(ql,d1,d2,n1,n1_now,max_save_now,
  569. max_save_later,take_first,homo)$
  570. begin
  571. % d1,d2 are two subexpressions of two expressions with n1,n2 terms
  572. % ql is the list of quotients
  573. % drp is the number of terms dropped as they can not cancel anything
  574. % dne is the number terms of d1 already done, including those dropped
  575. % mi is the minimum of n1,n2
  576. % homo=t then non-linear equations --> must check that d2 is not
  577. % multiplied with ftem_ dependent factor
  578. scalar nall,d1cop,d2cop,m,j,e1,q,qq,qc,dcl,nu,preqc,ldcl,lnu,mi,tr_short_local;
  579. %tr_short_local:=t;
  580. mi:=n1;
  581. m:=0;
  582. nall:=0;
  583. d1cop:=d1;
  584. % n1_now is the maximum number of terms cancelling each other
  585. % in this run of short based on 2*(number of remaining terms of d1
  586. % still to check).
  587. % max_save_now is the maximum number of cancellations based
  588. % on 2*min(terms of d1, min terms of d2)
  589. j:=if n1_now<max_save_now then n1_now
  590. else max_save_now$
  591. % The following j-value is the minimal number of cancellations
  592. % of a quotient by now in order to lead to a reduction.
  593. % mi is the minimal umber of cancelled terms at the end = number
  594. % of terms of the shorter equation.
  595. % max_save_later is the maximal number of cancelling terms in all
  596. % later runs of short.
  597. j:=mi-j-max_save_later$
  598. repeat << % for each term of d1
  599. n1_now:=n1_now-2;
  600. e1:=car d1cop; d1cop:=cdr d1cop;
  601. d2cop:=d2;
  602. while d2cop and (nall+m<=n1) do << % for each term of d2
  603. q:=cancel(e1 ./ car d2cop); % otherwise already successful
  604. d2cop:=cdr d2cop;
  605. %--- dropping a numerical factors
  606. dcl:=cdr q; % dcl is the denominator of the current quotient
  607. if numberp dcl then <<ldcl:=dcl;dcl:=1>>
  608. else <<
  609. ldcl:=dcl;
  610. repeat ldcl:=lc ldcl until numberp ldcl$% or car ldcl = '!:RN!:$
  611. dcl:=car cancel(dcl ./ ldcl)
  612. >>;
  613. nu:=car q; % nu is the numerator of the current quotient
  614. if numberp nu then <<lnu:=nu;nu:=1>> else
  615. if homo and not freeoflist(nu,ftem_) then nu:=nil
  616. else <<
  617. lnu:=nu;
  618. repeat lnu:=lc lnu until numberp lnu$% or car ldcl = '!:RN!:$
  619. nu:=car cancel(nu ./ lnu)
  620. >>;
  621. if (lnu>1000000000) or (ldcl>1000000000) then
  622. if tr_short then <<
  623. write" Num. factors grew too large in shortening."$
  624. terpri()
  625. >> else else
  626. if nu then <<
  627. % - ql is a list of denominator classes: (dcl1 dcl2 dcl3 ...)
  628. % - each denominator class dcli is a dotted pair (di . nclist) where
  629. % - di is the denominator and
  630. % - nclist is a list of numerator classes.
  631. % Each numerator class is a list with
  632. % - first element: (ncl . n) where ncl is the numerator
  633. % up to a rational numerical factor and n is the number of
  634. % occurences of ncl (up to a rational numerical factor)
  635. % - further elements: (nfi . ni) where nfi is the numerical
  636. % proportionality factor and ni the number of occurences
  637. % of this factor
  638. %---- search for the denominator class
  639. qc:=ql;
  640. while qc and (dcl neq caar qc) do qc:=cdr qc;
  641. if null qc then % denominator class not found
  642. if j <= 0 then % add denominator class, here nall,m are not
  643. % assigned as it would only play a role if
  644. % one equation had only one term but that
  645. % is covered as special case
  646. ql:=cons((dcl . list(list((nu . 1),((lnu . ldcl) . 1)))), ql)
  647. else % too late to add this denominator
  648. else << % denominator class has been found
  649. %---- now search of the numerator class
  650. qc:=cdar qc; % qc is the list of numerator classes nclist
  651. while qc and (nu neq caaar qc) do <<preqc:=qc; qc:=cdr qc>>;
  652. if null qc then % numerator class not found
  653. if j leq 0 then % add numerator class
  654. rplacd(preqc,list(list((nu . 1),((lnu . ldcl) . 1))) )
  655. else % too late to add this numerator
  656. else <<% numerator class found
  657. nall:=cdaar qc + 1; % increasing the total number of occur.
  658. rplacd(caar qc,nall);
  659. %---- now search for the numerical factor
  660. qq:=(lnu . ldcl);
  661. qc:=cdar qc;
  662. while qc and (qq neq caar qc) do <<preqc:=qc;qc:=cdr qc>>;
  663. if null qc then << % numerical factor not found
  664. m:=1; rplacd(preqc,list((qq . 1)))
  665. >> else <<
  666. m:=add1 cdar qc$ rplacd(car qc,m)
  667. >>
  668. >> % numerator class found
  669. >> % denominator class found
  670. >> % not (homo and ftem_ - dep. factor for d2)
  671. >>$ % all terms of d2
  672. j:=if n1_now<max_save_now then n1_now
  673. else max_save_now$
  674. j:=mi-j-max_save_later$
  675. if j>0 then <<
  676. while ql and clean_den(car ql,j) do ql:=cdr ql;
  677. if ql then <<
  678. qc:=ql;
  679. while cdr qc do
  680. if clean_den(cadr qc,j) then rplacd(qc,cddr qc)
  681. else qc:=cdr qc
  682. >>
  683. >>;
  684. if tr_short_local then <<
  685. terpri();write length ql," denominators";
  686. >>;
  687. % If there is only one quotient left and no new one can be added
  688. % (because of j>0) then take_first:=t
  689. % The following lines need only be un-commented but a test
  690. % showed no speed up, only slight slowing down
  691. %
  692. % if (null take_first) and
  693. % (j > 0) and % no new quotients will be added
  694. % ql and (null cdr ql) and % only one denominator class
  695. % (null cddar ql) and % only one numerator class in cdar ql
  696. % % the numerator class is cadar ql
  697. % (1=cdar cadar ql) then take_first:=t
  698. >> % all terms of d1
  699. until (null d1cop) or % everything divided
  700. (take_first and (nall+m>n1)) or % successful: saving > cost
  701. ((j > 0) and (null ql))$ % all quotients are too rare --> end
  702. return
  703. % cons(take_first,
  704. if ((j > 0) and (null ql)) then nil
  705. else
  706. if m+nall<=mi then (ql . nil)
  707. else (ql . q)
  708. % )
  709. end$ % of short
  710. symbolic procedure drop_lin_dep(arglist)$
  711. % drops linear dependent equations
  712. begin scalar pdes,tr_drop,p,cp,incre,newpdes,m,h,s,r,a,v,
  713. vli,indp,indli,conli,mli,success$
  714. % the pdes are assumed to be sorted by the number of terms,
  715. % shortest come first
  716. % vli is the list of all `independent variables' v in this lin. algebra
  717. % computation, i.e. a list of all different products of powers of
  718. % derivatives of ftem functions and constants
  719. % format: ((product1, v1, sum1),(product2, v2, sum2),...)
  720. % where sumi is the sum of all terms of all equations multiplied
  721. % with the multiplier of that equation
  722. % indli is a list marking whether equations are necessarily lin
  723. % indep. because they involve a `variable' v not encountered yet
  724. % mli is the list of multipliers of the equations
  725. pdes:=car arglist$
  726. % tr_drop:=t$
  727. if pdes and cdr pdes then <<
  728. while pdes do <<
  729. p:=car pdes; pdes:=cdr pdes; newpdes:=cons(p,newpdes);
  730. m:=gensym()$
  731. a:=sort_partition(p,nil,get(p,'fcts),nil);
  732. if tr_drop then <<write "new eqn:"$prettyprint a;
  733. write"multiplier for this equation: m=",m$terpri()
  734. >>$
  735. indp:=nil;
  736. for each h in a do <<
  737. s:=car h;
  738. % Does s occur in vli?
  739. % Adding the terms multiplied with the multiplier to the corresp. sum
  740. cp:=vli;
  741. while cp and (s neq caar cp) do cp:=cdr cp;
  742. if tr_drop then <<
  743. write"searched for: s=",s$terpri();
  744. if cp then write"found: car cp=",car cp$terpri()$
  745. >>$
  746. if cp then <<r:=cadar cp;
  747. incre:=reval {'QUOTIENT,
  748. {'TIMES,m,r,
  749. if cadr h>1 then cons('PLUS,caddr h)
  750. else caaddr h},
  751. s};
  752. rplaca(cddar cp,cons(incre,caddar cp))
  753. >>
  754. else <<r:=if (pairp s) or (numberp s) then gensym() else s;
  755. indp:=s;
  756. incre:=reval {'QUOTIENT,
  757. {'TIMES,m,r,
  758. if cadr h>1 then cons('PLUS,caddr h)
  759. else caaddr h},
  760. s};
  761. vli:=cons({s,r,{incre}},vli)
  762. >>;
  763. if tr_drop then <<
  764. write"corresponding symbol: r=",r$terpri()$
  765. write"upd: incre=",incre$terpri()$
  766. write"vli="$prettyprint vli
  767. >>$
  768. >>;
  769. mli:=cons(m,mli);
  770. indli:=cons(indp,indli)
  771. >>$
  772. % Formulating a list of conditions
  773. while vli do <<
  774. v:=caddar vli; vli:=cdr vli;
  775. conli:=cons(if cdr v then cons('PLUS,v)
  776. else car v,
  777. conli)
  778. >>;
  779. % Now the investigation of linear independence
  780. pdes:=nil; % the new list of lin. indep. PDEs
  781. while cdr newpdes do <<
  782. if tr_drop then <<
  783. terpri()$
  784. if car indli then write"lin. indep. without search of ",car newpdes,
  785. " due to the occurence of ",car indli
  786. else write"lin. indep. investigation for ",car newpdes$
  787. >>;
  788. if car indli then pdes:=cons(car newpdes,pdes)
  789. else <<
  790. s:=cdr solveeval {cons('LIST,subst(1,car mli,conli)),cons('LIST,cdr mli)};
  791. if s then <<drop_pde(car newpdes,nil,nil)$ % lin. dep.
  792. success:=t$
  793. if print_ then <<
  794. terpri()$
  795. write"Eqn. ",car newpdes,
  796. " has been dropped due to linear dependence."$
  797. >>
  798. >>
  799. else <<pdes:=cons(car newpdes,pdes); % lin. indep.
  800. if tr_drop then <<
  801. terpri()$
  802. write"Eqn. ",car newpdes," is lin. indep."$
  803. >>
  804. >>;
  805. >>;
  806. newpdes:=cdr newpdes;
  807. indli:=cdr indli;
  808. conli:=subst(0,car mli,conli);
  809. mli:=cdr mli
  810. >>;
  811. pdes:=cons(car newpdes,pdes)
  812. >>;
  813. return if success then list(pdes,cadr arglist)
  814. else nil
  815. end$
  816. symbolic procedure find_1_term_eqn(arglist)$
  817. % checks whether a linear combination of the equations can produce
  818. % an equation with only one term
  819. if not lin_problem then nil else
  820. begin scalar pdes,tr_drop,p,cp,incre,m,h,s,r,a,v,
  821. vli,indp,indli,conli,mli,mpli,success,
  822. sli,slilen,maxlen,newconli,newpdes,newp,fl,vl$
  823. %tr_drop:=t$
  824. if tr_drop then terpri()$
  825. pdes:=car arglist$
  826. newpdes:=pdes$
  827. %---------------------------------
  828. % if struc_eqn then <<
  829. % cp:=pdes;
  830. % while cp do <<
  831. % if is_algebraic(car cp) then r:=cons(car cp,r)
  832. % else s:=cons(car cp,s);
  833. % cp:=cdr cp
  834. % >>;
  835. % r:=nil;
  836. % s:=nil;
  837. % >>$
  838. % Drop all PDEs which have at least two derivs which no other have
  839. %---------------------------------
  840. if pdes and cdr pdes then <<
  841. while pdes do <<
  842. p:=car pdes; pdes:=cdr pdes;
  843. m:=gensym()$
  844. if tr_drop then <<terpri()$write"multiplier m=",m$terpri()>>$
  845. a:=sort_partition(p,nil,get(p,'fcts),nil);
  846. for each h in a do <<
  847. s:=car h;
  848. % Does s occur in vli?
  849. % Adding the terms multiplied with the multiplier to the corresp. sum
  850. cp:=vli;
  851. while cp and (s neq caar cp) do cp:=cdr cp;
  852. if tr_drop then <<
  853. write"searched for: s=",s$terpri();
  854. if cp then <<write"found: car cp=",car cp$terpri()$>>
  855. >>$
  856. if cp then <<r:=cadar cp;
  857. incre:=reval {'QUOTIENT,
  858. {'TIMES,m,%r,
  859. if cadr h>1 then cons('PLUS,caddr h)
  860. else caaddr h},
  861. s};
  862. rplaca(cddar cp,cons(incre,caddar cp))
  863. >>
  864. else <<r:=if (pairp s) or (numberp s) then gensym() else s;
  865. indp:=s;
  866. incre:=reval {'QUOTIENT,
  867. {'TIMES,m,%r,
  868. if cadr h>1 then cons('PLUS,caddr h)
  869. else caaddr h},
  870. s};
  871. vli:=cons({s,r,{incre}},vli)
  872. >>;
  873. if tr_drop then <<
  874. write"corresponding symbol: r=",r$terpri()$
  875. write"upd: incre=",incre$terpri()$
  876. write"vli="$prettyprint vli
  877. >>$
  878. >>;
  879. mli:=cons(m,mli);
  880. mpli:=cons((m . p),mpli);
  881. indli:=cons(indp,indli)
  882. >>$
  883. % Formulating a list of conditions
  884. while vli do <<
  885. sli:=cons(caar vli,sli);
  886. v:=caddar vli; vli:=cdr vli;
  887. conli:=cons(if cdr v then cons('PLUS,v)
  888. else car v,
  889. conli)
  890. >>;
  891. % Now the investigation of the existence of equations with only one
  892. % term
  893. slilen:=length sli;
  894. mli :=cons('LIST, mli);
  895. conli:=cons('LIST,conli);
  896. if tr_drop then <<
  897. write"sli=",sli$terpri()$
  898. algebraic(write"mli=",mli)$
  899. algebraic(write"conli=",conli)$
  900. write"mpli=",mpli$terpri()$
  901. >>;
  902. for h:=1:slilen do << % for each possible single term
  903. newp:=car sli;sli:=cdr sli;
  904. pdes:=newpdes;
  905. while pdes and
  906. ((get(car pdes,'terms)>1) or
  907. (not zerop reval {'DIFFERENCE,get(car pdes,'val),newp})) do
  908. pdes:=cdr pdes;
  909. if null pdes then <<
  910. cp:=conli;
  911. for s:=1:h do cp:=cdr cp;
  912. rplaca(cp,reval {'PLUS,1,car cp});
  913. if tr_drop then <<
  914. write"h=",h$terpri()$
  915. algebraic(write"new conli=",conli)$
  916. >>;
  917. s:=cdr solveeval {conli,mli};
  918. if (null s) and tr_drop then <<write"no success"$terpri()>>$
  919. if s then << % found 1-term equation
  920. if null success then
  921. for each p in newpdes do <<
  922. fl:=union(get(p,'fcts),fl);
  923. vl:=union(get(p,'vars),vl)
  924. >>$
  925. success:=t$
  926. maxlen:=0$
  927. s:=cdar s; % first solution (lin. system), dropping 'LIST
  928. % now find the equation to be replaced by the 1-term-equation
  929. % find the non-vanishing m in s, such that the corresponding p in
  930. % mpli has a maximum number of terms
  931. while s do <<
  932. if caddar s neq 0 then <<
  933. r:=cadar s;
  934. cp:=mpli;
  935. while caar cp neq r do cp:=cdr cp;
  936. if get(cdar cp,'terms)>maxlen then <<
  937. p:=cdar cp; % p will be the equation to be replaced
  938. m:=r;
  939. maxlen:=get(p,'terms);
  940. >>
  941. >>$
  942. s:=cdr s
  943. >>$
  944. % Now replacing the old equation p by the new 1-term equation in conli:
  945. r:=0;
  946. newconli:=nil$
  947. while conli do <<
  948. v:=subst(0,m,car conli)$
  949. conli:=cdr conli$
  950. if r=h then <<
  951. v:=reval {'PLUS,{'TIMES,m,newp},v}$
  952. >>$
  953. newconli:=cons(v,newconli);
  954. r:=add1(r)
  955. >>$
  956. conli:=reverse newconli$
  957. % the new equation:
  958. newp:=mkeq(newp,fl,vl,allflags_,t,list(0),nil,nil);
  959. % last argument is nil as no new inequalities can result
  960. % if new equation has only one term
  961. newpdes:=cons(newp,newpdes);
  962. if print_ then <<
  963. terpri()$
  964. write"The new equation ",newp$ typeeq newp$
  965. write" replaces ",p$ typeeq p$
  966. >>;
  967. drop_pde(p,nil,nil)$
  968. newpdes:=delete(p,newpdes);
  969. % update of mpli:
  970. mpli:=subst(newp,p,mpli)$
  971. if tr_drop then <<
  972. write"mpli=",mpli$terpri()$
  973. >>;
  974. >>; % end of successful find
  975. cp:=conli;
  976. for s:=1:h do cp:=cdr cp;
  977. rplaca(cp,reval {'PLUS,-1,car cp});
  978. >> % if the 1-term PDE is not already known
  979. >>$ % for each possible single term
  980. >>;
  981. return if success then list(newpdes,cadr arglist)
  982. else nil
  983. end$
  984. endmodule$
  985. end$
  986. % moegliche Verbesserungen:
  987. % - auch subtrahieren, wenn 0 Gewinn (Zyklus!)
  988. % - kann Zyklus mit decoupling geben
  989. % - evtl erst alle Quotienten bestimmen, dann die Heuristik:
  990. % . erst wo nur die kleinere Gleichung mit ftem-Funktionen multipliziert
  991. % wird
  992. % . wo nur die kleinere Gleichung multipliziert wird
  993. % . alle Quotienten werden auf Hauptnenner gebracht und der mit der
  994. % groessten Potenz mit der die kuerzere Gleichung multipliziert wird,
  995. % ist der erste
  996. % - Erweiterung auf mehrere Gleichungen
  997. % - counter example:
  998. % 0 = +a+b+c
  999. % 0 = -b +d+e
  1000. % 0 = -c-d +f
  1001. % 0 = -a -e-f
  1002. % combining any 2 gives a longer one
  1003. % the sum of all 4 is even zero.
  1004. % - In order not to run into a cycle with decouple one could use
  1005. % dec_hist_list but that costs memory.