simpsqrt.red 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. module simpsqrt; % Simplify square roots.
  2. % Authors: Mary Ann Moore and Arthur C. Norman.
  3. % Heavily modified by J.H. Davenport for algebraic functions.
  4. fluid '(!*galois !*pvar !*tra !*trint basic!-listofallsqrts
  5. gaussiani basic!-listofnewsqrts intvar knowntobeindep
  6. listofallsqrts listofnewsqrts sqrtflag sqrtlist
  7. sqrt!-places!-alist varlist zlist);
  8. % This module should be rewritten in terms of the REDUCE function
  9. % SIMPSQRT.
  10. % remd 'simpsqrt;
  11. exports proper!-simpsqrt,simpsqrti,simpsqrtsq,simpsqrt2,sqrtsave,
  12. newplace,actualsimpsqrt,formsqrt;
  13. symbolic procedure proper!-simpsqrt(exprn);
  14. simpsqrti carx(exprn,'proper!-simpsqrt);
  15. symbolic procedure simpsqrti sq;
  16. begin
  17. scalar u;
  18. if atom sq
  19. then if numberp sq
  20. then return (simpsqrt2 sq) ./ 1
  21. else if (u:=get(sq,'avalue))
  22. then return simpsqrti cadr u
  23. % BEWARE!!! This is VERY system dependent.
  24. else return simpsqrt2((mksp(sq,1) .* 1) .+ nil) ./ 1;
  25. % If it doesn't have an AVALUE then it is itself.
  26. if car sq eq 'times
  27. then return mapply(function multsq,
  28. for each j in cdr sq collect simpsqrti j);
  29. if car sq eq 'quotient
  30. then return multsq(simpsqrti cadr sq,
  31. invsq simpsqrti caddr sq);
  32. if car sq eq 'expt and numberp caddr sq
  33. then if evenp caddr sq
  34. then return simpexpt list(cadr sq,caddr sq / 2)
  35. else return simpexpt
  36. list(mk!*sq simpsqrti cadr sq,caddr sq);
  37. if car sq = '!*sq
  38. then return simpsqrtsq cadr sq;
  39. return simpsqrtsq tidysqrt simp!* sq
  40. end;
  41. symbolic procedure simpsqrtsq sq;
  42. (simpsqrt2 numr sq) ./ (simpsqrt2 denr sq);
  43. symbolic procedure simpsqrt2 sf;
  44. if minusf sf
  45. then if sf iequal -1
  46. then gaussiani
  47. else begin
  48. scalar u;
  49. u:=negf sf;
  50. if numberp u
  51. then return multf(gaussiani,simpsqrt3 u);
  52. % we cannot negate general expressions for the following reason:
  53. % (%%%thesis remark%%%)
  54. % sqrt(x*x-1) under x->1/x gives sqrt(1-x*x)/x=i*sqrt(x*x-1)/x
  55. % under x->1/x gives x*i*sqrt(-1+1/x*x)=i**2*sqrt(x*x-1)
  56. % hence an abysmal catastrophe.
  57. return simpsqrt3 sf
  58. end
  59. else simpsqrt3 sf;
  60. symbolic procedure simpsqrt3 sf;
  61. begin
  62. scalar u;
  63. u:=assoc(sf,listofallsqrts);
  64. if u
  65. then return cdr u;
  66. % now see if 'knowntobeindep'can help.
  67. u:=atsoc(listofnewsqrts,knowntobeindep);
  68. if null u
  69. then go to no;
  70. u:=assoc(sf,cdr u);
  71. if u
  72. then <<
  73. listofallsqrts:=u.listofallsqrts;
  74. return cdr u >>;
  75. no:
  76. u:=actualsimpsqrt sf;
  77. listofallsqrts:=(sf.u).listofallsqrts;
  78. return u
  79. end;
  80. symbolic procedure sqrtsave(u,v,place);
  81. begin
  82. scalar a;
  83. %u is new value of listofallsqrts, v of new.
  84. a:=assoc(place,sqrt!-places!-alist);
  85. if null a
  86. then sqrt!-places!-alist:=(place.(listofnewsqrts.listofallsqrts))
  87. .sqrt!-places!-alist
  88. else rplacd(a,listofnewsqrts.listofallsqrts);
  89. listofnewsqrts:=v;
  90. % throw away things we are not going to need in future.
  91. if not !*galois
  92. then listofallsqrts:=u;
  93. % we cannot guarantee the validity of our calculations.
  94. if listofallsqrts eq u
  95. then return nil;
  96. v:=listofallsqrts;
  97. while not (cdr v eq u) do
  98. v:=cdr v;
  99. rplacd(v,nil);
  100. % listofallsqrts is all those added since routine was entered.
  101. v:=atsoc(listofnewsqrts,knowntobeindep);
  102. if null v
  103. then knowntobeindep:=(listofnewsqrts.listofallsqrts)
  104. . knowntobeindep
  105. else rplacd(v,union(cdr v,listofallsqrts));
  106. listofallsqrts:=u;
  107. return nil
  108. end;
  109. symbolic procedure newplace(u);
  110. % Says to restart algebraic bases at a new place u.
  111. begin
  112. scalar v;
  113. v:=assoc(u,sqrt!-places!-alist);
  114. if null v
  115. then <<
  116. listofallsqrts:=basic!-listofallsqrts;
  117. listofnewsqrts:=basic!-listofnewsqrts >>
  118. else <<
  119. v:=cdr v;
  120. listofnewsqrts:=car v;
  121. listofallsqrts:=cdr v >>;
  122. return if v then v
  123. else listofnewsqrts.listofallsqrts
  124. end;
  125. symbolic procedure mknewsqrt u;
  126. % U is prefix form.
  127. begin scalar v,w;
  128. if not !*galois then go to new;
  129. % no checking required.
  130. v:=addf(!*p2f mksp(!*pvar,2),negf !*q2f tidysqrt simp u);
  131. w:=errorset!*(list('afactor,mkquote v,mkquote !*pvar),t);
  132. if atom w then go to new
  133. else w:=car w; % The actual result of afactor.
  134. if cdr w then go to notnew;
  135. new:
  136. w := mksqrt reval u; % Note that u need not be a canonical
  137. % structure here.
  138. listofnewsqrts:=w . listofnewsqrts;
  139. return !*kk2f w;
  140. notnew:
  141. w:=car w;
  142. v:=stt(w,!*pvar);
  143. if car v neq 1 then errach list("Error in mknewsqrt: ",v);
  144. w:=addf(w,multf(cdr v,(mksp(!*pvar,car v) .* -1) .+nil));
  145. v:=sqrt2top(w ./ cdr v);
  146. w:=quotf(numr v,denr v);
  147. if null w
  148. % We now test to see if the quotient failure is spurious, e.g.,
  149. % as in int(-2x/(sqrt(2x^2+1)-2x^2+1),x); It's not clear this is
  150. % the right place to check though. More information is
  151. % available from the earlier int-sqrt step.
  152. then begin scalar oldprop;
  153. oldprop := get('sqrt,'simpfn);
  154. put('sqrt,'simpfn,'simpsqrt);
  155. v := simp prepsq v;
  156. put('sqrt,'simpfn,oldprop);
  157. if denr v = 1 then w := numr v
  158. end;
  159. if null w then errach list("Division failure in mknewsqrt",u);
  160. return w
  161. end;
  162. symbolic procedure actualsimpsqrt(sf);
  163. if sf iequal -1
  164. then gaussiani
  165. else actualsqrtinner(sf,listofnewsqrts);
  166. symbolic procedure actualsqrtinner(sf,l);
  167. if sf =1 then 1
  168. else if null l
  169. or domainp sf or ldeg sf=1
  170. % Patch by A.C. Norman to prevent recursion errors.
  171. then actualsimpsqrt2 sf
  172. else begin scalar z;
  173. if numberp sf and (z := list('sqrt,sf)) member l
  174. then return !*kk2f z;
  175. z := argof car l;
  176. if z member l then z := !*kk2f car l else z := !*q2f simp z;
  177. if z = -1 then return actualsqrtinner(sf,cdr l);
  178. z:=quotf(sf,z);
  179. if null z then return actualsqrtinner(sf,cdr l)
  180. else return !*multf(!*kk2f car l,actualsimpsqrt z)
  181. end;
  182. symbolic procedure actualsimpsqrt2(sf);
  183. if atom sf
  184. then if null sf
  185. then nil
  186. else if numberp sf
  187. then if sf < 0
  188. then multf(gaussiani,actualsimpsqrt2(- sf))
  189. %Above 2 lines inserted JHD 4 Sept 80;
  190. % test case: SQRT(B*X**2-C)/SQRT(X);
  191. else begin
  192. scalar n;
  193. n:=int!-sqrt sf;
  194. % Changed for conformity with DEC20 LISP JHD July 1982;
  195. if not fixp n
  196. then return mknewsqrt sf
  197. else return n
  198. end
  199. else mknewsqrt(sf)
  200. else begin
  201. scalar form;
  202. form:=comfac sf;
  203. if car form
  204. then return multf((if null cdr sf and (car sf = form)
  205. then formsqrt(form .+ nil)
  206. else simpsqrt2(form .+ nil)),
  207. %The above 2 lines changed by JHD;
  208. %(following suggestions of Morrison);
  209. %to conform to Standard LISP 4 Sept 80;
  210. simpsqrt2 quotf(sf,form .+ nil));
  211. % we have killed common powers.
  212. form:=cdr form;
  213. if form neq 1
  214. then return multf(simpsqrt2 form,
  215. simpsqrt2 quotf(sf,form));
  216. % remove a common factor from the sf.
  217. return formsqrt sf
  218. end;
  219. symbolic procedure int!-sqrt n;
  220. % Return sqrt of n if same is exact, or something non-numeric
  221. % otherwise.
  222. if not numberp n then 'nonnumeric
  223. else if n<0 then 'negative
  224. else if floatp n then sqrt n
  225. else if n<2 then n
  226. else int!-nr(n,(n+1)/2);
  227. symbolic procedure int!-nr(n,root);
  228. % root is an overestimate here. nr moves downwards to root;
  229. begin
  230. scalar w;
  231. w:=root*root;
  232. if n=w then return root;
  233. w:=(root+n/root)/2;
  234. if w>=root then return !*q2f simpsqrt list n;
  235. return int!-nr(n,w)
  236. end;
  237. symbolic procedure formsqrt(sf);
  238. if (null red sf)
  239. then if (lc sf iequal 1) and (ldeg sf iequal 1)
  240. then mknewsqrt mvar sf
  241. else multf(if evenp ldeg sf
  242. then !*p2f mksp(mvar sf,ldeg sf / 2)
  243. else exptf(mknewsqrt mvar sf,ldeg sf),simpsqrt2 lc sf)
  244. else begin
  245. scalar varlist,zlist,sqrtlist,sqrtflag;
  246. scalar v,l,n,w;
  247. % This returns a list, the i-th member of which is
  248. % a list of the factors of multiplicity i (as s.f's);
  249. v:=jsqfree(sf,if intvar and involvesf(sf,intvar) then intvar
  250. else findatom mvar sf);
  251. % intvar is the best thing to do square-free
  252. % decompositions with respect to, but anything
  253. % else will do if intvar is not set.
  254. if null cdr v and null cdar v then return mknewsqrt prepf sf;
  255. % The JSQFREE did nothing.
  256. l:=nil;
  257. n:=0;
  258. while v do <<
  259. n:=n+1;
  260. w:=car v;
  261. while w do <<
  262. l:=list('expt,mk!*sq !*f2q car w,n) . l;
  263. w:=cdr w >>;
  264. v:=cdr v >>;
  265. if null cdr l
  266. then l:=car l
  267. else l:='times.l;
  268. % makes L into a valid prefix form;
  269. return !*q2f simpsqrti l
  270. end;
  271. symbolic procedure findatom pf;
  272. if atom pf
  273. then pf
  274. else findatom argof pf;
  275. endmodule;
  276. end;