divide.red 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. module divide; % Exact division of standard forms to give a S Q.
  2. % Authors: Mary Ann Moore and Arthur C. Norman.
  3. fluid '(!*trdiv !*trint resid sqrtlist zlist);
  4. exports fquotf,testdivdf,dfquotdf;
  5. imports df2q,f2df,gcdf,interr,multdf,negdf,plusdf,printdf,printsf,
  6. quotf,multsq,invsq,negsq;
  7. % Intended for dividing out known factors as produced by the
  8. % integration program. Horrible and slow, I expect!!
  9. symbolic procedure dfquotdf(a,b);
  10. begin scalar resid;
  11. if (!*trint or !*trdiv) then <<
  12. printc "Dividing out a simple factor of "; printdf b >>;
  13. a:=dfquotdf1(a,b);
  14. if (!*trint or !*trdiv) then <<
  15. printc "Remaining term to be factorised is ";
  16. printdf a >>;
  17. if not null resid then begin
  18. scalar gres,w;
  19. % Make one more check for a zero residue.
  20. if null numr df2q resid then return nil;
  21. if !*trint or !*trdiv then <<
  22. printc "Failure in factorisation:";
  23. printdf resid;
  24. printc "Which should be zero";
  25. w:=resid;
  26. gres:=numr lc w; w:=red w;
  27. while not null w do <<
  28. gres:=gcdf(gres,numr lc w);
  29. w:=red w >>;
  30. printc "I.e. the following vanishes";
  31. printsf gres>>;
  32. interr "Non-exact division due to a log term"
  33. end;
  34. return a
  35. end;
  36. symbolic procedure fquotf(a,b);
  37. % Input: a and b standard quotients with (a/b) an exact
  38. % division with respect to the variables in zlist,
  39. % but not necessarily obviously so. the 'non-obvious' problems
  40. % will be because of (e.g.) square-root symbols in b
  41. % output: standard quotient for (a/b)
  42. % (prints message if remainder is not 'clearly' zero.
  43. % A must not be zero.
  44. begin scalar t1;
  45. if null a then interr "a=0 in fquotf";
  46. t1:=quotf(a,b); %try it the easy way
  47. if not null t1 then return t1 ./ 1; %ok
  48. return df2q dfquotdf(f2df a,f2df b)
  49. end;
  50. symbolic procedure dfquotdf1(a,b);
  51. begin scalar q;
  52. if null b then interr "Attempt to divide by zero";
  53. q:=sqrtlist; %remove sqrts from denominator, maybe.
  54. while not null q do begin
  55. scalar conj;
  56. conj:=conjsqrt(b,car q); %conjugate wrt given sqrt
  57. if not (b=conj) then <<
  58. a:=multdf(a,conj);
  59. b:=multdf(b,conj) >>;
  60. q:=cdr q end;
  61. q:=dfquotdf2(a,b);
  62. resid:=reversip resid;
  63. return q
  64. end;
  65. symbolic procedure dfquotdf2(a,b);
  66. % As above but a and b are distributed forms, as is the result.
  67. if null a then nil
  68. else begin scalar xd,lcd;
  69. xd:=xpdiff(lpow a,lpow b);
  70. if xd='failed then <<
  71. xd:=lt a; a:=red a;
  72. resid:=xd .+ resid;
  73. return dfquotdf2(a,b) >>;
  74. lcd:= !*multsq(lc a,!*invsq lc b);
  75. if null numr lcd then return dfquotdf2(red a,b);
  76. % Should not be necessary;
  77. lcd := xd .* lcd;
  78. xd:=plusdf(a,multdf(negdf (lcd .+ nil),b));
  79. if xd and (lpow xd = lpow a % Again, should not be necessary;
  80. or xpdiff(lpow xd,lpow b) = 'failed)
  81. then <<if !*trint or !*trdiv
  82. then <<printc "Problems in dividing:"; printdf xd>>;
  83. xd := rootextractdf xd;
  84. if !*trint or !*trdiv then printdf xd>>;
  85. return lcd .+ dfquotdf2(xd,b)
  86. end;
  87. symbolic procedure rootextractdf u;
  88. if null u then nil
  89. else begin scalar v;
  90. v := resimp rootextractsq lc u;
  91. return if null numr v then rootextractdf red u
  92. else (lpow u .* v) .+ rootextractdf red u
  93. end;
  94. symbolic procedure rootextractsq u;
  95. if null numr u then u
  96. % else rootextractf numr u ./ rootextractf denr u;
  97. else (rootextractf numr x ./ rootextractf denr x)
  98. where x=subs2q u;
  99. symbolic procedure rootextractf v;
  100. if domainp v then v
  101. else begin scalar u,r,c,x,p;
  102. u := mvar v; p := ldeg v;
  103. r := rootextractf red v;
  104. c := rootextractf lc v;
  105. if null c then return r
  106. else if atom u then return (lpow v .* c) .+ r
  107. else if car u eq 'sqrt
  108. or car u eq 'expt and eqcar(caddr u,'quotient)
  109. and car cdaddr u = 1 and numberp cadr cdaddr u
  110. then <<p := divide(p,if car u eq 'sqrt then 2
  111. else cadr cdaddr u);
  112. if car p = 0
  113. then return if null c then r else (lpow v .* c) .+ r
  114. else if numberp cadr u
  115. then <<c := multd(cadr u ** car p,c); p := cdr p>>
  116. else <<x := simpexpt list(cadr u,car p);
  117. if denr x = 1 then <<c := multf(numr x,c); p := cdr p>>
  118. else p := ldeg v>>>>;
  119. % D. Dahm suggested an additional call of rootextractf on the
  120. % result here. This does cause some expressions to simplify
  121. % sooner, but also leads to infinite loops with expressions
  122. % like (a*x+b)**p.
  123. return if p=0 then addf(c,r)
  124. else if null c then r
  125. else ((u to p) .* c) .+ r
  126. end;
  127. % The following hack makes sure that the results of differentiation
  128. % gets passed through ROOTEXTRACT
  129. % a) This should not be done this way, since the effect is global
  130. % b) Should this be done via TIDYSQRT?
  131. put('df,'simpfn,'simpdf!*);
  132. symbolic procedure simpdf!* u;
  133. begin scalar v,v1;
  134. v:=simpdf u;
  135. v1:=rootextractsq v;
  136. if not(v1=v) then return resimp v1
  137. else return v
  138. end;
  139. symbolic procedure xpdiff(a,b);
  140. %Result is list a-b, or 'failed' if a member of this would be negative.
  141. if null a then if null b then nil
  142. else interr "B too long in xpdiff"
  143. else if null b then interr "A too long in xpdiff"
  144. else if car b>car a then 'failed
  145. else (lambda r;
  146. if r='failed then 'failed
  147. else (car a-car b) . r) (xpdiff(cdr a,cdr b));
  148. symbolic procedure conjsqrt(b,var);
  149. % Subst(var=-var,b).
  150. if null b then nil
  151. else conjterm(lpow b,lc b,var) .+ conjsqrt(red b,var);
  152. symbolic procedure conjterm(xl,coef,var);
  153. % Ditto but working on a term.
  154. if involvesp(xl,var,zlist) then xl .* negsq coef
  155. else xl .* coef;
  156. symbolic procedure involvesp(xl,var,zl);
  157. % Check if exponent list has non-zero power for variable.
  158. if null xl then interr "Var not found in involvesp"
  159. else if car zl=var then car xl neq 0
  160. else involvesp(cdr xl,var,cdr zl);
  161. endmodule;
  162. end;