crshort.red 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  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. symbolic procedure length_reduction_1(arglist)$
  9. % Do one length-reducing combination of two equations
  10. begin scalar pdes,l,l1,cpu,gc$
  11. cpu:=time()$ gc:=gctime()$
  12. pdes:=car arglist$
  13. if expert_mode then l:=selectpdes(pdes,2)
  14. else l:=pdes$
  15. if (l1:=shorten_pdes(l,caddr arglist)) then
  16. <<for each a in cdr l1 do pdes:=delete(a,pdes)$
  17. for each a in car l1 do
  18. if a then pdes:=eqinsert(a,pdes)$
  19. for each a in car l1 do
  20. if a then dec_fct_check(a,pdes)$
  21. l:=list(pdes,cadr arglist)>>
  22. else l:=nil$
  23. %if print_ and !*time then <<
  24. % write " time : ", time() - cpu,
  25. % " ms GC time : ", gctime() - gc," ms "
  26. %>>$
  27. return l$
  28. end$
  29. %-------------------
  30. symbolic procedure shorten_pdes(des,vl)$
  31. begin scalar mi,h,p1,p1rl,p1le,p2,pc,newp$
  32. if pairp des and pairp cdr des then <<
  33. repeat <<
  34. % find the pair of pdes not yet reduced with each other
  35. % with the lowest product of their number of terms % printlength's
  36. mi:=nil;
  37. pc:=des;
  38. while cdr pc do <<
  39. p1:=car pc;pc:=cdr pc;
  40. if flagp(p1,'to_eval) then <<
  41. p1rl:=get(p1,'rl_with);
  42. % p1le:=get(p1,'printlength);
  43. p1le:=get(p1,'terms);
  44. for each p2 in pc do
  45. if flagp(p2,'to_eval) and
  46. (not member(p2,p1rl)) and
  47. ((null mi) or
  48. % (car mi > (p1le*get(p2,'printlength))))
  49. % then mi:=list(p1le*get(p2,'printlength),p1,p2)
  50. (car mi > (p1le*get(p2,'terms))))
  51. then mi:=list(p1le*get(p2,'terms),p1,p2)
  52. >>
  53. >>$
  54. if mi then <<
  55. newp:=shorten(cadr mi,caddr mi);
  56. if null newp then add_rl_with(cadr mi,caddr mi);
  57. >>
  58. >> until (null mi) or newp; % if not possible then already returned with nil
  59. if mi then <<
  60. p1:=0;
  61. % for each pc in cdr newp do p1:=p1+get(pc,'length);
  62. for each pc in cdr newp do p1:=p1+get(pc,'terms);
  63. mi:=(<<h:=for each pc in car newp collect
  64. if zerop pc then <<nequ_:=add1 nequ_;nil>> else
  65. mkeq(pc,fctsort union(get(cadr mi,'fcts),
  66. get(caddr mi,'fcts)),
  67. vl,allflags_,t);
  68. % for each pc in h do if pc then p1:=p1-get(pc,'length);
  69. for each pc in h do if pc then p1:=p1-get(pc,'terms);
  70. h
  71. >> . cdr newp);
  72. if print_ then <<
  73. for each h in cdr newp do <<write h," "$typeeq h>>$
  74. for each h in car mi do if null h then
  75. <<write "This gives identity 0=0."$terpri()>>
  76. else
  77. <<write h," "$typeeq h>>$
  78. write "Length reduction is ",p1," term"$
  79. if p1 neq 1 then write"s"
  80. >>;
  81. for each pc in cdr newp do setprop(pc,nil);
  82. >>;
  83. >>;
  84. return mi
  85. end$
  86. %-------------------
  87. symbolic procedure partition_1(l,la)$
  88. % l is an equation,
  89. % returning (l1 . l2) where
  90. % l1=partitioning of equation l into ((lpow1.lc1),(lpow2.lc2),...)
  91. % l2=(lpow1,lpow2,...)
  92. % This works currently only for l that are linear in elem. of la
  93. begin scalar l1,l3;
  94. l:=reorder !*a2f l;
  95. while pairp l and member(l3:=car lpow l,la) do <<
  96. l1:=cons((l3 . !*f2a lc l), l1)$
  97. l:= red l;
  98. >>;
  99. return if l then (append(l1,list(1 . !*f2a l)) .
  100. append(la,list(1))) % inhomogeneous case
  101. else (l1 . la) % homogeneous case
  102. end$
  103. %-------------------
  104. symbolic procedure partition_2(de,l)$
  105. % dropping from de all parts that can not be matched by the other
  106. % equation, a list of ftem-functions and their derivatives from
  107. % the other equation is l
  108. begin scalar newde,dropped,n;
  109. % dropped is the number of terms that can not be matched and
  110. % which are therefore dropped
  111. dropped:=0$
  112. while de do <<
  113. n:=no_of_terms cdar de$
  114. if member(caar de,l) then newde:=cons(cons(n,car de),newde)
  115. else dropped:=dropped+n;
  116. de:=cdr de
  117. >>;
  118. return (dropped . newde)
  119. end$
  120. %-------------------
  121. symbolic procedure strip(d)$
  122. begin
  123. scalar h;
  124. d:= if not pairp d then list d else
  125. if car d='QUOTIENT then cadr d else
  126. if car d = 'PLUS then cdr d
  127. else list(d)$
  128. return
  129. for each h in d collect !*a2f h
  130. end$
  131. %-------------------
  132. symbolic procedure shorten(de1,de2)$
  133. % shorten the two pdes with each other
  134. % returns a dotted pair, where car is a list of the values of new pdes
  135. % and cdr is a list of names of pdes to be dropped
  136. begin scalar a,b,l1,l2,l1ul2,l1ml2,l2ml1,l1il2,oldorder,
  137. de1p,de2p,dropped1,dropped2,termsof1,termsof2,tr_short,
  138. dne,flip,n1,n2,ql,maxcancel;
  139. %tr_short:=t;
  140. l1:=for each a in get(de1,'derivs) collect
  141. if length car a = 1 then caar a else cons('DF,car a)$ % all derivs of de1
  142. l2:=for each a in get(de2,'derivs) collect
  143. if length car a = 1 then caar a else cons('DF,car a)$ % all derivs of de2
  144. de1p:=get(de1,'val)$
  145. de2p:=get(de2,'val)$
  146. l1ml2:=setdiff(l1,l2); % l1 - l2
  147. l2ml1:=setdiff(l2,l1); % l2 - l1
  148. l1il2:=setdiff(l1,l1ml2); % intersection
  149. l1ul2:=union(l1,l2); % union
  150. if tr_short then <<
  151. write"before substitution:"$terpri()$
  152. write"l1=",l1$ terpri()$
  153. write"l2=",l2$ terpri()$
  154. write"de1p=",de1p$terpri()$
  155. write"de2p=",de2p$terpri()$
  156. write"l1ml2=",l1ml2$terpri()$
  157. write"l2ml1=",l2ml1$terpri()$
  158. write"l1il2=",l1il2$terpri()$
  159. write"l1ul2=",l1ul2$terpri()$
  160. >>;
  161. % substituting derivatives by a new variable to become kernels
  162. for each a in l1ml2 do if pairp a then <<
  163. b:=gensym()$
  164. l1:=subst(b,a,l1)$
  165. l1ul2:=subst(b,a,l1ul2)$
  166. de1p:=subst(b,a,de1p)
  167. >>$
  168. for each a in l2ml1 do if pairp a then <<
  169. b:=gensym()$
  170. l2:=subst(b,a,l2)$
  171. l1ul2:=subst(b,a,l1ul2)$
  172. de2p:=subst(b,a,de2p)
  173. >>$
  174. for each a in l1il2 do if pairp a then <<
  175. b:=gensym()$
  176. l1:=subst(b,a,l1)$
  177. l2:=subst(b,a,l2)$
  178. l1ul2:=subst(b,a,l1ul2)$
  179. de1p:=subst(b,a,de1p)$
  180. de2p:=subst(b,a,de2p)
  181. >>$
  182. if tr_short then <<
  183. write"after substitution:"$terpri()$
  184. write"l1=",l1$ terpri()$
  185. write"l2=",l2$ terpri()$
  186. write"de1p=",de1p$terpri()$
  187. write"de2p=",de2p$terpri()$
  188. write"l1ml2=",l1ml2$terpri()$
  189. write"l2ml1=",l2ml1$terpri()$
  190. write"l1il2=",l1il2$terpri()$
  191. write"l1ul2=",l1ul2$terpri()$
  192. >>;
  193. %--- writing both equations as polynomials in elements of l1ul2
  194. oldorder:=setkorder l1ul2;
  195. de1p:=partition_1(de1p,l1); l1:=cdr de1p; de1p:=car de1p;
  196. de2p:=partition_1(de2p,l2); l2:=cdr de2p; de2p:=car de2p;
  197. setkorder oldorder;
  198. %--- l1,l2 can now have the element 1 in case of inhomogeneous de's
  199. l1ul2:=nil;
  200. l1il2:=nil;
  201. %--- Partitioning each equation into 2 parts, one part that can
  202. %--- be matched by the other equation and one that can not.
  203. de1p:=partition_2(de1p,l2)$ dropped1:=car de1p; de1p:=cdr de1p;
  204. de2p:=partition_2(de2p,l1)$ dropped2:=car de2p; de2p:=cdr de2p;
  205. termsof1:=no_of_terms get(de1,'val)$
  206. termsof2:=no_of_terms get(de2,'val)$
  207. if tr_short then <<
  208. write"---------"$terpri()$
  209. write"de1:",de1," with ",termsof1," terms"$terpri()$
  210. write"dropped:",dropped1$terpri()$
  211. a:=de1p;
  212. while a do <<
  213. write "caar =",caar a;terpri()$
  214. write "cadar=",cadar a;terpri()$
  215. write "cddar=", algebraic write lisp cddar a;terpri()$
  216. a:=cdr a;
  217. >>;terpri()$
  218. write"de2:",de2," with ",termsof2," terms"$terpri()$
  219. write"dropped:",dropped2$terpri()$
  220. a:=de2p;
  221. while a do <<
  222. write "caar =",caar a;terpri()$
  223. write "cadar=",cadar a;terpri()$
  224. write "cddar=",algebraic write lisp cddar a;terpri()$
  225. a:=cdr a;
  226. >>;terpri()$
  227. >>;
  228. % One can do a stronger restriction:% The maximum that can be
  229. % canceled is sum of min of terms ofthe de1p,de2p sublists
  230. % corresponding to the coefficients of different ftem functions/deriv.
  231. a:=de1p; b:=de2p; n2:=nil;
  232. while a do <<
  233. n1:=if (caar a)<(caar b) then caar a else caar b;
  234. % n1 is min of terms of the coefficients of the same ftem function/der.
  235. n2:=cons(2*n1,n2);
  236. a:=cdr a; b:=cdr b;
  237. >>$
  238. % maxcancel is the maximal number of cancellations in all the
  239. % remaining runs of short depending on the current run.
  240. maxcancel:=list(0);
  241. n1:=0;
  242. while n2 do <<
  243. n1:=n1+car n2;
  244. n2:=cdr n2;
  245. maxcancel:=cons(n1,maxcancel);
  246. >>;
  247. if (null de1p) or (null de2p) or
  248. (((car maxcancel)<termsof1) and
  249. ((car maxcancel)<termsof2) ) then return nil;
  250. if termsof1<termsof2 then <<
  251. dne:=dropped1;
  252. n1:=termsof1;
  253. n2:=termsof2
  254. >> else <<
  255. flip:=t;
  256. a:=de1p; de1p:=de2p; de2p:=a;
  257. dne:=dropped2;
  258. n1:=termsof2;
  259. n2:=termsof1
  260. >>$
  261. if n1=1 then << % one equation has only a single term
  262. a:=cadar de1p; % e.g. g0030
  263. b:=de2p;
  264. while b and (cadar b neq a) do b:=cdr b;
  265. a:=if null b then nil % that term does not turn up in other equation
  266. else << % it does turn up --> success
  267. de1p:=cddar de1p;
  268. de2p:=cddar b;
  269. t
  270. >>
  271. >> else
  272. repeat << % one shortening
  273. if tr_short then <<write"cadar de1p=",cadar de1p$terpri()>>$
  274. b:=short(ql,strip cddar de1p,strip cddar de2p,n1,
  275. 2*(caar de1p),car maxcancel-cadr maxcancel,cadr maxcancel)$
  276. if b then <<
  277. ql:=car b;
  278. a:=cdr b;
  279. if a then << % the result
  280. de1p:=!*f2a car a;
  281. de2p:=!*f2a cdr a;
  282. >> else <<
  283. de1p:=cdr de1p;
  284. de2p:=cdr de2p;
  285. >>;
  286. maxcancel:=cdr maxcancel;
  287. >> else a:=nil;
  288. >> until (null b) or % failure
  289. a or % success
  290. null de1p$ % the case of exact balance
  291. return
  292. if null a then nil
  293. else << % numerator and denominator are de1p, de2p
  294. %--- computing the shorter new equation
  295. if flip then <<a:=get(de2,'val); b:=get(de1,'val)>>
  296. else <<a:=get(de1,'val); b:=get(de2,'val)>>$
  297. ql:=if termsof1>termsof2 then de1
  298. else de2;
  299. if print_ then <<
  300. n1:=mkid(reval eqname_,reval nequ_)$
  301. algebraic write"The new equation ",n1," := ",
  302. de2p*(if flip then de2 else de1) -
  303. de1p*(if flip then de1 else de2)," replaces "
  304. >>$
  305. a:=reval list('PLUS,
  306. list('MINUS,
  307. if de1p=1 then b
  308. else list('TIMES,de1p,b)),
  309. if de2p=1 then a
  310. else list('TIMES,de2p,a) )$
  311. (list a . list(ql))
  312. >>
  313. end$
  314. %-------------------
  315. symbolic procedure clean_num(qc,j)$
  316. begin
  317. scalar qc1,nall$
  318. return
  319. if 2*(cdaar qc)<=j then t else <<
  320. qc1:=car qc; % the representative and list to proportional factors
  321. nall:=cdar qc1;
  322. while cdr qc1 do
  323. if (cdadr qc1)+nall<=j then rplacd(qc1,cddr qc1)
  324. else qc1:=cdr qc1;
  325. if qc1=car qc then t else nil % whether empty or not after cleaning
  326. >>
  327. end$
  328. %--------------------
  329. symbolic procedure clean_den(qc,j)$
  330. begin
  331. scalar qcc$
  332. qcc:=qc$
  333. while cdr qc do
  334. if clean_num(cdr qc,j) then rplacd(qc,cddr qc)
  335. else qc:=cdr qc$
  336. return null cdr qcc % Are there any numerators left?
  337. end$
  338. %--------------------
  339. symbolic procedure short(ql,d1,d2,n1,n1_now,max_save_now,
  340. max_save_later)$
  341. begin
  342. % d1,d2 are two subexpressions of two expressions with n1,n2 terms
  343. % ql is the list of quotients
  344. % drp is the number of terms dropped as they can not cancel anything
  345. % dne is the number terms of d1 already done, including those dropped
  346. % mi is the minimum of n1,n2
  347. scalar nall,d1cop,d2cop,m,j,e1,q,qq,qc,dcl,nu,preqc,ldcl,lnu,tr_short,mi$
  348. %tr_short:=t;
  349. mi:=n1;
  350. m:=0;
  351. nall:=0;
  352. d1cop:=d1;
  353. % n1_now is the maximum number of terms cancelling each other
  354. % in this run of short based on 2*(number of remaining terms of d1
  355. % still to check).
  356. % max_save_now is the maximum number of cancellations based
  357. % on 2*min(terms of d1, min terms of d2)
  358. j:=if n1_now<max_save_now then n1_now
  359. else max_save_now$
  360. % The following j-value is the minimal number of cancellations
  361. % of a quotient by now in order to lead to a reduction.
  362. % mi is the minimal umber of cancelled terms at the end = number
  363. % of terms of the shorter equation.
  364. % max_save_later is the maximal number of cancelling terms in all
  365. % later runs of short.
  366. j:=mi-j-max_save_later$
  367. repeat << % for each term of d1
  368. n1_now:=n1_now-2;
  369. e1:=car d1cop; d1cop:=cdr d1cop;
  370. d2cop:=d2;
  371. while d2cop and (nall+m<=n1) do << % for each term of d2
  372. q:=cancel(e1 ./ car d2cop); % otherwise already successful
  373. d2cop:=cdr d2cop;
  374. %--- dropping a numerical factors
  375. dcl:=cdr q; % dcl is the denominator of the current quotient
  376. if numberp dcl then <<ldcl:=dcl;dcl:=1>>
  377. else <<
  378. ldcl:=dcl;
  379. repeat ldcl:=lc ldcl until numberp ldcl$% or car ldcl = '!:RN!:$
  380. dcl:=car cancel(dcl ./ ldcl)
  381. >>;
  382. nu:=car q; % nu is the numerator of the current quotient
  383. if numberp nu then <<lnu:=nu;nu:=1>>
  384. else <<
  385. lnu:=nu;
  386. repeat lnu:=lc lnu until numberp lnu$% or car ldcl = '!:RN!:$
  387. nu:=car cancel(nu ./ lnu)
  388. >>;
  389. % - ql is a list of denominator classes: (dcl1 dcl2 dcl3 ...)
  390. % - each denominator class dcli is a dotted pair (di . nclist) where
  391. % - di is the denominator and
  392. % - nclist is a list of numerator classes.
  393. % Each numerator class is a list with
  394. % - first element: (ncl . n) where ncl is the numerator
  395. % up to a rational numerical factor and n is the number of
  396. % occurences of ncl (up to a rational numerical factor)
  397. % - further elements: (nfi . ni) where nfi is the numerical
  398. % proportionality factor and ni the number of occurences
  399. % of this factor
  400. %---- search for the denominator class
  401. qc:=ql;
  402. while qc and (dcl neq caar qc) do qc:=cdr qc;
  403. if null qc then % denominator class not found
  404. if j <= 0 then % add denominator class, here nall,m are not
  405. % assigned as it would only play a role if
  406. % one equation had only one term but that
  407. % is covered as special case
  408. ql:=cons((dcl . list(list((nu . 1),((lnu . ldcl) . 1)))), ql)
  409. else % too late to add this denominator
  410. else << % denominator class has been found
  411. %---- now search of the numerator class
  412. qc:=cdar qc; % qc is the list of numerator classes nclist
  413. while qc and (nu neq caaar qc) do <<preqc:=qc; qc:=cdr qc>>;
  414. if null qc then % numerator class not found
  415. if j leq 0 then % add numerator class
  416. rplacd(preqc,list(list((nu . 1),((lnu . ldcl) . 1))) )
  417. else % too late to add this numerator
  418. else <<% numerator class found
  419. nall:=cdaar qc + 1; % increasing the total number of occur.
  420. rplacd(caar qc,nall);
  421. %---- now search for the numerical factor
  422. qq:=(lnu . ldcl);
  423. qc:=cdar qc;
  424. while qc and (qq neq caar qc) do <<preqc:=qc;qc:=cdr qc>>;
  425. if null qc then << % numerical factor not found
  426. m:=1; rplacd(preqc,list((qq . 1)))
  427. >> else <<
  428. m:=add1 cdar qc$ rplacd(car qc,m)
  429. >>
  430. >> % numerator class found
  431. >> % denominator class found
  432. >>$ % all terms of d2
  433. j:=if n1_now<max_save_now then n1_now
  434. else max_save_now$
  435. j:=mi-j-max_save_later$
  436. if j>0 then <<
  437. while ql and clean_den(car ql,j) do ql:=cdr ql;
  438. if ql then <<
  439. qc:=ql;
  440. while cdr qc do
  441. if clean_den(cadr qc,j) then rplacd(qc,cddr qc)
  442. else qc:=cdr qc
  443. >>
  444. >>;
  445. if tr_short then <<
  446. terpri();write length ql," denominators";
  447. >>
  448. >> % all terms of d1
  449. until (null d1cop) or % everything divided
  450. (nall+m>n1) or % successful: saving > cost
  451. ((j > 0) and (null ql))$
  452. % all denominators are too rare and are canceled
  453. return
  454. if ((j > 0) and (null ql)) then nil
  455. else
  456. if m+nall<=mi then (ql . nil)
  457. else (ql . q)
  458. end$ % of short
  459. endmodule$
  460. %tr length_reduction_1$
  461. %tr shorten_pdes$
  462. %tr shorten$
  463. %tr short$
  464. %tr partition_1,partition_2$
  465. end$
  466. % moegliche Verbesserungen:
  467. % - auch subtrahieren, wenn 0 Gewinn (Zyklus!)
  468. % - kann Zyklus mit decoupling geben
  469. % - evtl erst alle Quotienten bestimmen, dann die Heuristik:
  470. % . erst wo nur die kleinere Gleichung mit ftem-Funktionen multipliziert
  471. % wird
  472. % . wo nur die kleinere Gleichung multipliziert wird
  473. % . alle Quotienten werden auf Hauptnenner gebracht und der mit der
  474. % groessten Potenz mit der die kuerzere Gleichung multipliziert wird,
  475. % ist der erste
  476. % - Erweiterung auf nichtlin. Probleme
  477. % - Erweiterung auf mehrere Gleichungen
  478. % - counter example:
  479. % 0 = +a+b+c
  480. % 0 = -b +d+e
  481. % 0 = -c-d +f
  482. % 0 = -a -e-f
  483. % combining any 2 gives a longer one
  484. % the sum of all 4 is even zero.
  485. % - In order not to run into a cycle with decouple one could use
  486. % dec_hist_list but that costs memory.