compactf.red 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. module compactf; % Algorithms for compacting algebraic expressions.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1991 The RAND Corporation. All Rights Reserved.
  4. fluid '(frlis!* mv!-vars!*);
  5. global '(!*trcompact);
  6. switch trcompact;
  7. % Interface to REDUCE simplifier.
  8. put('compact,'simpfn,'simpcompact);
  9. symbolic procedure simpcompact u;
  10. begin scalar bool;
  11. if null u or null cdr u
  12. then rerror(compact,1,
  13. list("Wrong number of arguments to compact"));
  14. if null !*exp then <<rmsubs(); bool := !*exp := t>>;
  15. u := errorset!*(list('simpcompact1,mkquote u),nil);
  16. if bool then !*exp := nil;
  17. if errorp u then rerror(compact,2,"Compact error");
  18. return car u
  19. end;
  20. symbolic procedure simpcompact1 u;
  21. begin scalar v,x,y,w;
  22. v := simp!* car u;
  23. u := cadr u;
  24. if idp u
  25. then if eqcar(x := get(u,'avalue),'list)
  26. then u := cadr x
  27. else typerr(u,"list")
  28. else if getrtype u eq 'list then u := cdr u
  29. else typerr(u,"list");
  30. u := for each j in u collect
  31. << w:=t;
  32. if eqcar(j,'equal) or eqcar(j,'replaceby) then
  33. << if eqcar(y:=caddr j,'when) then
  34. <<w:=compactbool formbool(caddr y,nil,'algebraic);
  35. y:=cadr y>>;
  36. j:= {'difference,cadr j,y}>>;
  37. % propagate free variables.
  38. if(y:=compactfmatch2 j) then
  39. <<j:=sublis(for each x in y collect x.cadr x,j);
  40. j:=sublis(for each x in y collect cadr x.x,j)>>;
  41. j.w>>;
  42. for each j in u do v := compactsq(v,simp!* car j,cdr j);
  43. return v
  44. end;
  45. symbolic procedure compactbool w;
  46. % Reform condtion w for later evaluation and substitution.
  47. % Without this reform (list (quote ~)(quote x)) would not
  48. % be substituted by subst('(((~ x).y)..)... .
  49. if atom w then w else
  50. if eqcar(w,'list) and cdr w and cadr w='(quote !~) then
  51. {'quote,{'!~,cadr caddr w}} else
  52. compactbool car w . compactbool cdr w;
  53. % True beginning of compacting routines.
  54. symbolic procedure compactsq(u,v,c);
  55. % U is a standard quotient, v a standard quotient for equation v=0.
  56. % Result is a standard quotient for u reduced wrt v=0.
  57. begin
  58. if denr v neq 1
  59. then msgpri("Relation denominator",prepf denr v,"discarded",
  60. nil,nil);
  61. v := numr v;
  62. return multsq(compactf(numr u,v,c) ./ 1,
  63. 1 ./ compactf(denr u,v,c))
  64. end;
  65. symbolic procedure compactf(u,v,c);
  66. % U is a standard form, v a standard form for an equation v=0.
  67. % C is a condition for applying v.
  68. % Result is a standard form for u reduced wrt v=0.
  69. begin scalar x; integer n;
  70. if !*trcompact
  71. then <<prin2t "*** Arguments on entering compactf:";
  72. mathprint mk!*sq !*f2q u;
  73. mathprint mk!*sq !*f2q v>>;
  74. while x neq u do <<x := u; u := compactf0(u,v,c); n := n+1>>;
  75. if !*trcompact and n>2
  76. then <<prin2 " *** Compactf looped ";prin2 n; prin2t " times">>;
  77. return u
  78. end;
  79. symbolic procedure compactf0(u,v,c);
  80. begin scalar x,y,w;
  81. x := kernels u;
  82. y := kernels v;
  83. if not smemq('!~,v) then return compactf1(u,v,x,y);
  84. for each p in compactfmatch(x,y) do
  85. if p and not smemq('!~,w:=sublis(p,c)) and eval w and
  86. not smemq('!~,w:=numr subf(v,p)) then
  87. u:=compactf1(u,w,x,kernels w);
  88. return u;
  89. end;
  90. symbolic procedure compactfmatch(x,y);
  91. % Finds all possible matches between free variables in
  92. % kernels of list x and pattern list y, including incomplete,
  93. % inconsistent and the empty match.
  94. if null x or null y then '(nil) else
  95. begin scalar y1,z,r;
  96. z:=compactfmatch(x,cdr y);
  97. if not smemq('!~,car y) then return z;
  98. y1:=car y; y:= cdr y;
  99. r:=for each x1 in x join
  100. for each w in compactfmatch1(x1,y1) join
  101. for each q in compactfmatch(delete(x1,x),sublis(w,y)) collect
  102. union(w,q);
  103. return union(r,z);
  104. end;
  105. symbolic procedure compactfmatch1(x,y);
  106. if car y = '!~ then {{y.x}} else
  107. if pairp x and car x=car y then
  108. mcharg(cdr x,cdr y,car y)
  109. where frlis!* =nconc(compactfmatch2 y,frlis!*);
  110. symbolic procedure compactfmatch2 y;
  111. if atom y then nil else
  112. if car y = '!~ then {y} else
  113. append(compactfmatch2(car y),compactfmatch2(cdr y));
  114. symbolic procedure compactf1(u,v,x,y);
  115. begin scalar z;
  116. % x := kernels u;
  117. % y := kernels v;
  118. z := intersection(x,y); % find common vars.
  119. if null z then return u;
  120. % Unfortunately, it's too expensive in space to generate all perms.
  121. % as in this example:
  122. % l:={-c31*c21+c32*c22+c33*c23+c34*c24=t1};
  123. % x:= -c31*c21+c32*c22+c33*c23+c34*c24;
  124. % compact(x,l); % out of heap space
  125. % for each j in permutations z do u := compactf11(u,v,x,y,j);
  126. return compactf11(u,v,x,y,z)
  127. % return u
  128. end;
  129. symbolic procedure compactf11(u,v,x,y,z);
  130. begin scalar w;
  131. if domainp u then return u;
  132. y := append(z,setdiff(y,z)); % vars in eqn.
  133. x := append(setdiff(x,z),y); % all vars.
  134. x := setkorder x;
  135. u := reorder u; % reorder expressions.
  136. v := reorder v;
  137. z := comfac!-to!-poly comfac u;
  138. u := quotf(u,z);
  139. u := remchkf(u,v,y);
  140. w := compactf2(u,mv!-reduced!-coeffs sf2mv(v,y),y);
  141. if termsf w < termsf u then u := w;
  142. % Now reduce z (required, e.g. for compact(u1*(h0+h1),{h0+h1=z1}))
  143. if not kernlp z
  144. then <<z := remchkf(z,v,y);
  145. w := compactf2(z,mv!-reduced!-coeffs sf2mv(v,y),y);
  146. if termsf w < termsf z then z := w>>;
  147. u := multf(z,u);
  148. setkorder x;
  149. u := reorder u;
  150. if !*trcompact
  151. then <<prin2t "*** Value on leaving compactf11:";
  152. mathprint mk!*sq !*f2q u>>;
  153. return u
  154. end;
  155. symbolic procedure remchkf(u,v,vars);
  156. % This procedure returns u after checking if a smaller remainder
  157. % results after division by v. It is potentially inefficient, since
  158. % we check all the way down the list, term by term. However, the
  159. % process terminates when we no longer have any relevant kernels.
  160. (if domainp x or null intersection(kernels u,vars) then x
  161. else lt x .+ remchkf(red x,v,vars))
  162. where x=remchkf1(u,v);
  163. symbolic procedure remchkf1(u,v);
  164. begin integer n;
  165. n := termsf u;
  166. v := xremf(u,v,n);
  167. if null v or termsf(v := car v)>=n then return u
  168. else if !*trcompact then prin2t "*** Remainder smaller";
  169. return v
  170. end;
  171. symbolic procedure xremf(u,v,m);
  172. % Returns the quotient and remainder of U divided by V, or NIL if
  173. % the number of terms in the remainder exceeds M.
  174. % The goal is to keep terms u+terms z<=m.
  175. % There is some slop in the count, so one must check sizes on
  176. % leaving.
  177. begin integer m1,m2,n; scalar x,y,z;
  178. if domainp v then return list cdr qremd(u,v);
  179. m2 := termsf u;
  180. a: if m<= 0 then return nil
  181. else if domainp u then return list addf(z,u)
  182. else if mvar u eq mvar v
  183. then if (n := ldeg u-ldeg v)<0 then return list addf(z,u)
  184. else <<x := qremf(lc u,lc v);
  185. y := multpf(lpow u,cdr x);
  186. m := m+m1;
  187. z := addf(z,y);
  188. m1 := termsf z;
  189. m := m-m1+m2;
  190. u := if null car x then red u
  191. else addf(addf(u,multf(if n=0 then v
  192. else multpf(mvar u .** n,v),
  193. negf car x)), negf y);
  194. m2 := termsf u;
  195. m := m-m2;
  196. go to a>>
  197. else if not ordop(mvar u,mvar v) then return list addf(z,u);
  198. m := m+m1;
  199. x := xremf(lc u,v,m);
  200. if null x then return nil;
  201. z := addf(z,multpf(lpow u,car x));
  202. m1 := termsf z;
  203. m := m-m1;
  204. u := red u;
  205. go to a
  206. end;
  207. symbolic procedure compactf2(u,v,vars);
  208. % U is standard form for expression, v for equation. W is ordered
  209. % list of variables in v. Result is a compacted form for u.
  210. if domainp u then u
  211. else if mvar u memq vars then compactf3(u,v,vars)
  212. else lpow u .* compactf2(lc u,v,vars) .+ compactf2(red u,v,vars);
  213. symbolic procedure compactf3(u,v,vars);
  214. begin scalar mv!-vars!*;
  215. mv!-vars!* := vars;
  216. return mv2sf(mv!-compact(sf2mv(u,vars),v,nil),vars)
  217. end;
  218. endmodule;
  219. end;