sub.red 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. module sub; % Functions for substituting in standard forms.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1991 RAND. All rights reserved.
  4. fluid '(!*nosqrts asymplis!* dmode!* ncmp!* wtl!*);
  5. % Evaluation interface.
  6. symbolic procedure subeval u;
  7. % This is the general evaluator for SUB forms. All but the last
  8. % argument are assumed to be substitutions. These can either be
  9. % an explicit rule with a lhs and rhs separated by an equal sign,
  10. % a list of such rules, or something that evaluates to this.
  11. begin scalar x,y,z,ns;
  12. % Separate assignments from expression.
  13. if null(u and cdr u)
  14. then rederr "SUB requires at least 2 arguments"; % F.J. Wright.
  15. (while cdr u do
  16. <<x := reval car u;
  17. if getrtype x eq 'list then u := append(cdr x,cdr u)
  18. else <<if not eqexpr x then errpri2(car u,t);
  19. y := cadr x;
  20. if null getrtype y then y := !*a2kwoweight y;
  21. if getrtype caddr x then ns := (y . caddr x) . ns
  22. else z := (y . caddr x) . z;
  23. u := cdr u>>>>) where !*evallhseqp=nil;
  24. x := aeval car u;
  25. % Next line only makes sense if an nssubfn existed (which it
  26. % currently doesn't. However, subeval2 suffers from the problem
  27. % that its evaluation is sequential.
  28. % if ns then x := subeval2(ns,x);
  29. return subeval1(append(ns,z),x)
  30. end;
  31. symbolic procedure subeval1(u,v);
  32. begin scalar y,z;
  33. if y := getrtype v
  34. then if z := get(y,'subfn) then return apply2(z,u,v)
  35. else rerror(alg,23,
  36. list("No substitution defined for type",y));
  37. u := subsq(simp v,u);
  38. u := subs2 u where !*sub2 = t; % Make sure powers are reduced.
  39. return mk!*sq u
  40. end;
  41. % symbolic procedure subeval2(u,v);
  42. % This function handles sub rules that have a non *sq rhs.
  43. % The corresponding substitution functions are keyed by the
  44. % rtype in an alist stored as a property nssubfn on the rtype
  45. % of the expression in which the substitutions are to be carried out.
  46. % Substitutions are made sequentially.
  47. % begin scalar x,y,z;
  48. % for each s in u do
  49. % <<if null(x := getrtype v) then x := '!*sq;
  50. % y := getrtype cdr s;
  51. % if (z := get(x,'nssubfn)) and (z := atsoc(y,z))
  52. % then v := apply2(cdr z,s,v)
  53. % else v := subeval1(list s,v)>>;
  54. %% else rerror(alg,23,
  55. %% {"No substitution defined for type",y," into type ",x})>>;
  56. % return v
  57. % end;
  58. put('sub,'psopfn,'subeval);
  59. % Explicit substitution code for scalar expressions.
  60. symbolic procedure subsq(u,v);
  61. % We need to use subs2!* to avoid say (I^4-2I^2-1)/(I^2-1) => I^2-1
  62. % instead of a 0/0 error.
  63. begin scalar x;
  64. x := subf(numr u,v);
  65. u := subf(denr u,v);
  66. if null numr subs2!* u
  67. then if null numr subs2!* x then rederr "0/0 formed"
  68. else rederr "Zero divisor";
  69. return quotsq(x,u)
  70. end;
  71. symbolic procedure subs2!* u;
  72. (subs2 u) where !*sub2=!*sub2;
  73. symbolic procedure subf(u,l);
  74. % In REDUCE 3.4, this procedure used to rebind *nosqrts to T.
  75. % However, this can introduce two representations of a sqrt in the
  76. % same calculation. For now then, this rebinding is removed.
  77. begin scalar alglist!*,x;
  78. % Domain may have changed, so next line uses simpatom.
  79. if domainp u then return !*d2q u
  80. else if ncmp!* and noncomexpf u then return subf1(u,l);
  81. x := reverse intersection(for each y in l collect car y,
  82. kernord(u,nil));
  83. x := setkorder x;
  84. u := subf1(reorder u,l);
  85. % if powlis1!* then u := subs2q u;
  86. setkorder x;
  87. return reorder numr u ./ reorder denr u
  88. end;
  89. symbolic procedure noncomexpf u;
  90. not domainp u
  91. and (noncomp mvar u or noncomexpf lc u or noncomexpf red u);
  92. %%% SUBF1 changed so that domain elements are resimplified during a call
  93. %%% to RESIMP even if their tags are the same as dmode*.
  94. %%% This happens only if the domain is flagged
  95. symbolic procedure subf1(u,l);
  96. % U is a standard form,
  97. % L an association list of substitutions of the form
  98. % (<kernel> . <substitution>).
  99. % Value is the standard quotient for substituted expression.
  100. % Algorithm used is essentially the straight method.
  101. % Procedure depends on explicit data structure for standard form.
  102. if null u then nil ./ 1
  103. else if domainp u
  104. then if atom u then if null dmode!* then u ./ 1 else simpatom u
  105. % else if dmode!* eq car u then !*d2q u
  106. else if dmode!* eq car u and
  107. not flagp(dmode!*, 'resimplify) then !*d2q u
  108. else simp prepf u
  109. else begin integer n; scalar kern,m,varstack!*,v,w,x,xexp,y,y1,z;
  110. % Leaving varstack!* unchanged can make the simplifier think
  111. % there is a loop.
  112. z := nil ./ 1;
  113. a0: kern := mvar u;
  114. v := nil;
  115. if assoc(kern,l) and (v := assoc(kern,wtl!*)) then v := cdr v;
  116. if m := assoc(kern,asymplis!*) then m := cdr m;
  117. a: if null u or (n := degr(u,kern))=0 then go to b
  118. else if null m or n<m then y := wtchk(lt u,v) . y;
  119. u := red u;
  120. go to a;
  121. b: if not atom kern and not atom car kern then kern := prepf kern;
  122. if null l then xexp := if kern eq 'k!* then 1 else kern
  123. else if (xexp := subsublis(l,kern)) = kern
  124. and not assoc(kern,asymplis!*)
  125. then go to f;
  126. c: w := 1 ./ 1;
  127. n := 0;
  128. % Make sure exponent is not a variable at this point.
  129. if y and minusp cdaar y then go to h;
  130. if (x := getrtype xexp) eq 'yetunknowntype
  131. then x:= getrtype(xexp:= eval!-yetunknowntypeexpr(xexp,nil));
  132. if x and not(x eq 'list)
  133. then typerr(list(x,xexp),"substituted expression");
  134. % At this point we are simplifying the expression that is
  135. % substituted. Ideally, this should be done in the order
  136. % environment that existed when entering SUB. However, to avoid
  137. % the many code changes that would imply, we make sure
  138. % substituted expression is evaluated in a standard order.
  139. % Note also that SIMP!* here causes problem with HE package --
  140. % We also can't use powlis1!* here, since then match x=0,x^2=1;
  141. % will match all powers of x to zero!
  142. v := setkorder nil;
  143. x := simp xexp;
  144. setkorder v;
  145. x := reordsq x;
  146. % Needed in case substitution variable is in XEXP.
  147. if null l and kernp x and mvar numr x eq kern then go to f
  148. else if null numr x then go to e; %Substitution of 0;
  149. for each j in y do
  150. <<m := cdar j;
  151. w := multsq(subs2 exptsq(x,m-n),w);
  152. n := m;
  153. z := addsq(multsq(w,subf1(cdr j,l)),z)>>;
  154. e: y := nil;
  155. if null u then return z
  156. else if domainp u then return addsq(subf1(u,l),z);
  157. go to a0;
  158. f: sub2chk kern;
  159. for each j in y do z := addsq(multpq(car j,subf1(cdr j,l)),z);
  160. go to e;
  161. h: % Substitution for negative powers.
  162. x := simprecip list xexp;
  163. j: y1 := car y . y1;
  164. y := cdr y;
  165. if y and cdaar y<0 then go to j;
  166. k: m := -cdaar y1;
  167. w := multsq(subs2 exptsq(x,m-n),w);
  168. n := m;
  169. z := addsq(multsq(w,subf1(cdar y1,l)),z);
  170. y1 := cdr y1;
  171. if y1 then go to k else if y then go to c else go to e
  172. end;
  173. symbolic procedure wtchk(u,wt);
  174. % If a weighted variable is substituted for, we need to remove the
  175. % weight of that variable in an expression.
  176. if null wt then u
  177. else (if null x then errach list("weight confusion",u,wt)
  178. else lt x)
  179. where x=quotf(u .+ nil ,!*p2f('k!* .**(wt*tdeg u)));
  180. symbolic procedure subsublis(u,v);
  181. % NOTE: This definition assumes that with the exception of *SQ and
  182. % domain elements, expressions do not contain dotted pairs.
  183. begin scalar x;
  184. return if x := assoc(v,u) then cdr x
  185. % allow for case of sub(sqrt 2=s2,atan sqrt 2).
  186. else if eqcar(v,'sqrt)
  187. and (x := assoc(list('expt,cadr v,'(quotient 1 2)),u))
  188. then cdr x
  189. else if atom v then v
  190. else if not idp car v
  191. then for each j in v collect subsublis(u,j)
  192. else if x := get(car v,'subfunc) then apply2(x,u,v)
  193. else if get(car v,'dname) then v
  194. else if car v eq '!*sq then subsublis(u,prepsq cadr v)
  195. else for each j in v collect subsublis(u,j)
  196. end;
  197. symbolic procedure subsubf(l,expn);
  198. % Sets up a formal SUB expression when necessary.
  199. begin scalar x,y;
  200. for each j in cddr expn do
  201. if (x := assoc(j,l)) then <<y := x . y; l := delete(x,l)>>;
  202. expn := sublis(l,car expn)
  203. . for each j in cdr expn collect subsublis(l,j);
  204. %to ensure only opr and individual args are transformed;
  205. if null y then return expn;
  206. expn := aconc!*(for each j in reversip!* y
  207. collect list('equal,car j,aeval cdr j),expn);
  208. return if l then subeval expn
  209. else mk!*sq !*p2q mksp('sub . expn,1)
  210. end;
  211. % Explicit substitution code for lists.
  212. symbolic procedure listsub(u,v);
  213. makelist for each x in cdr v collect subeval1(u,x);
  214. put('list,'subfn,'listsub);
  215. put('int,'subfunc,'subsubf);
  216. put('df,'subfunc,'subsubf);
  217. endmodule;
  218. end;