halfangl.red 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. module halfangl; % Routines for conversion to half angle tangents.
  2. % Author: Steve Harrington.
  3. % Modifications by: John P. Fitch.
  4. fluid '(!*gcd);
  5. exports halfangle,untan;
  6. symbolic procedure transform(u,x);
  7. % Transform the SQ U to remove the 'bad' functions sin, cos, cot etc.
  8. % in favor of half angles.
  9. % Do this with regard to cases like sin(x)*tan(x/2), so attempt to
  10. % limit times we use half angles.
  11. begin scalar zl,tnarg,substlist;
  12. zl := zlist;
  13. while car(tnarg := tan!-function!-in zl)
  14. and halfangle!-confusion(zlist,cadar tnarg)
  15. do <<zl := cdr tnarg;
  16. tnarg := car tnarg;
  17. if eqcar(tnarg,'tan)
  18. then substlist := (gensym() . tnarg) . substlist
  19. else substlist := (gensym() .
  20. list('quotient,1,('tan . cdr tnarg)))
  21. . substlist;
  22. u := subst(caar substlist,tnarg,u)>>;
  23. return if substlist
  24. then simp sublis(substlist,prepsq halfangle(u,x))
  25. % simp prepsq was added so that 1/(e**x*cos(1/e**x)**2)
  26. % for example returns a closed-form result.
  27. else simp prepsq halfangle(u,x)
  28. end;
  29. symbolic procedure tan!-function!-in zz;
  30. % Look at zlist for tangents or cotangents.
  31. <<while zz and not eqcar(car zz,'tan) and not eqcar(car zz,'cot)
  32. do zz := cdr zz;
  33. if null zz then nil . nil else zz>>;
  34. symbolic procedure halfangle!-confusion(zz,tnarg);
  35. % Is there a function in the zlist with twice the tangent argument?
  36. <<while zz and (atom car zz
  37. or not(tnarg = prepsq simp list('quotient,cadar zz,2)))
  38. do zz := cdr zz;
  39. zz>>;
  40. symbolic procedure quotqq(u1,v1);
  41. multsq(u1,invsq(v1));
  42. symbolic procedure !*subtrq(u1,v1);
  43. addsq(u1, negsq(v1));
  44. symbolic procedure !*int2qm(u1);
  45. if u1=0 then nil . 1 else u1 . 1;
  46. symbolic procedure halfangle(r,x);
  47. % Top level procedure for converting;
  48. % R is a rational expression to be converted,
  49. % X the integration variable.
  50. % A rational expression is returned.
  51. quotqq(hfaglf(numr(r),x), hfaglf(denr(r),x));
  52. symbolic procedure hfaglf(p,x);
  53. % Converting polynomials, a rational expression is returned.
  54. if domainp(p) then !*f2q(p)
  55. else subs2q addsq(multsq(exptsq(hfaglk(mvar(p),x), ldeg(p)),
  56. hfaglf(lc(p),x)),
  57. hfaglf(red(p),x));
  58. symbolic procedure hfaglk(k,x);
  59. % Converting kernels, a rational expression is returned.
  60. begin
  61. scalar kt;
  62. if atom k or not member(x,flatten(cdr(k))) then return !*k2q k;
  63. k := car(k) . hfaglargs(cdr(k), x);
  64. if cadr k eq 'pi then return !*k2q k; % Don't consider tan(pi/2).
  65. kt := simp list('tan, list('quotient, cadr(k), 2));
  66. return if car(k) = 'sin
  67. then quotqq(multsq(!*int2qm(2),kt), addsq(!*int2qm(1),
  68. exptsq(kt,2)))
  69. else if car(k) = 'cos
  70. then quotqq(!*subtrq(!*int2qm(1),exptsq(kt,2)),addsq(!*int2qm(1),
  71. exptsq(kt,2)))
  72. else if car(k) = 'tan
  73. then quotqq(multsq(!*int2qm(2),kt), !*subtrq(!*int2qm(1),
  74. exptsq(kt,2)))
  75. else if car(k) = 'cot
  76. then quotqq(!*subtrq(!*int2qm(1),
  77. exptsq(kt,2)),multsq(!*int2qm(2),kt))
  78. else if car(k) = 'sec
  79. then quotqq(addsq(!*int2qm(1), exptsq(kt,2)),
  80. !*subtrq(!*int2qm(1),exptsq(kt,2)))
  81. else if car(k) = 'csc
  82. then quotqq(addsq(!*int2qm(1),exptsq(kt,2)),
  83. %%% !*subtrq(!*int2qm(1),exptsq(kt,2)))
  84. % FJW - was identical to sec!!!
  85. multsq(!*int2qm(2),kt))
  86. else if car(k) = 'sinh then
  87. quotqq(!*subtrq(!*p2q mksp('expt.('e. cdr k),2),
  88. !*int2qm(1)), multsq(!*int2qm(2),
  89. !*p2q mksp('expt . ('e . cdr(k)),1)))
  90. else if car(k) = 'cosh then
  91. quotqq(addsq(!*p2q mksp('expt.('e. cdr k),2),
  92. !*int2qm(1)), multsq(!*int2qm(2),
  93. !*p2q mksp('expt . ('e . cdr(k)),1)))
  94. else if car(k) = 'tanh then
  95. quotqq(!*subtrq(!*p2q mksp('expt.('e. cdr k),2),
  96. !*int2qm(1)), addsq(!*p2q mksp ('expt.('e.cdr(k)),2),
  97. !*int2qm(1)))
  98. else if car(k) = 'coth then
  99. quotqq(addsq(!*p2q mksp('expt.('e.cdr(k)),2), !*int2qm(1)),
  100. !*subtrq(!*p2q mksp('expt.('e . cdr k),2),!*int2qm(1)))
  101. else if car(k) = 'acot then
  102. !*p2q mksp(list('atan, list('quotient, 1, cadr k)),1)
  103. else !*k2q(k); % additional transformation might be added here.
  104. end;
  105. symbolic procedure hfaglargs(l,x);
  106. % Conversion of argument list.
  107. if null l then nil
  108. else prepsq(hfaglk(car(l),x)) . hfaglargs(cdr(l),x);
  109. symbolic procedure untanf x;
  110. % This should be done by a table.
  111. % We turn off gcd to avoid unnecessary gcd calculations, as suggested
  112. % by Rainer Schoepf.
  113. begin scalar !*gcd,y,z,w;
  114. if domainp x then return x . 1;
  115. y := mvar x;
  116. if eqcar(y,'int) then error1(); % assume all is hopeless.
  117. z := ldeg x;
  118. w := 1 . 1;
  119. y :=
  120. if atom y then !*k2q y
  121. else if car y eq 'tan
  122. then begin scalar yy;
  123. %% printc "Recursive tan"; printc cadr y;
  124. yy := prepsq untan simp cadr y . nil;
  125. %% princ "==> "; printc yy;
  126. if evenp z
  127. then <<z := z/2;
  128. return simp list('quotient,
  129. list('plus,
  130. list('minus,
  131. list('cos,
  132. 'times
  133. . (2 . yy))),
  134. 1),list('plus,
  135. list('cos,
  136. 'times
  137. . (2 . yy)),
  138. 1))>>
  139. else if z=1
  140. then return simp list('quotient,
  141. list('plus,
  142. list('minus,
  143. list('cos,
  144. 'times . (2 . yy))),
  145. 1),list('sin,
  146. 'times . (2 . yy)))
  147. else <<z := (z - 1)/2;
  148. w :=
  149. simp list('quotient,
  150. list('plus,
  151. list('minus,
  152. list('cos,
  153. 'times
  154. . (2 . yy))),
  155. 1),list('sin,
  156. 'times
  157. . (2 . yy)));
  158. return simp list('quotient,
  159. list('plus,
  160. list('minus,
  161. list('cos,
  162. 'times
  163. . (2 . yy))),
  164. 1),list('plus,
  165. list('cos,
  166. 'times
  167. . (2 . yy)),
  168. 1)) >>
  169. end
  170. else simp y;
  171. return addsq(multsq(multsq(exptsq(y,z),untanf lc x),w),
  172. untanf red x)
  173. end;
  174. % symbolic procedure untanlist(y);
  175. % if null y then nil
  176. % else (prepsq (untan(simp car y)) . untanlist(cdr y));
  177. symbolic procedure untan(x);
  178. % Expects x to be canonical quotient.
  179. begin scalar y;
  180. y:=cossqchk sinsqrdchk multsq(untanf(numr x),
  181. invsq untanf(denr x));
  182. return if length flatten y>length flatten x then x else y
  183. end;
  184. symbolic procedure sinsqrdchk(x);
  185. multsq(sinsqchkf(numr x), invsq sinsqchkf(denr x));
  186. symbolic procedure sinsqchkf(x);
  187. begin
  188. scalar y,z,w;
  189. if domainp x then return x . 1;
  190. y := mvar x;
  191. z := ldeg x;
  192. w := 1 . 1;
  193. y := if eqcar(y,'sin) then if evenp z
  194. then <<z := quotient(z,2);
  195. simp list('plus,1,list('minus,
  196. list('expt,('cos . cdr(y)),2)))>>
  197. else if z = 1 then !*k2q y
  198. else << z := quotient(difference(z,1),2); w := !*k2q y;
  199. simp list('plus,1,list('minus,
  200. list('expt,('cos . cdr(y)),2)))>>
  201. else !*k2q y;
  202. return addsq(multsq(multsq(exptsq(y,z),sinsqchkf(lc x)),w),
  203. sinsqchkf(red x));
  204. end;
  205. symbolic procedure cossqchkf(x);
  206. begin
  207. scalar y,z,w,x1,x2;
  208. if domainp x then return x . 1;
  209. y := mvar x;
  210. z := ldeg x;
  211. w := 1 . 1;
  212. x1 := cossqchkf(lc x);
  213. x2 := cossqchkf(red x);
  214. x := addsq(multsq(!*p2q lpow x,x1),x2);
  215. y := if eqcar(y,'cos) then if evenp z
  216. then <<z := quotient(z,2);
  217. simp list('plus,1,list('minus,
  218. list('expt,('sin . cdr(y)),2)))>>
  219. else if z = 1 then !*k2q y
  220. else << z := quotient(difference(z,1),2); w := !*k2q y;
  221. simp list('plus,1,list('minus,
  222. list('expt,('sin . cdr(y)),2)))>>
  223. else !*k2q y;
  224. y := addsq(multsq(multsq(exptsq(y,z),w),x1),x2);
  225. return if length(y) > length(x) then x else y;
  226. end;
  227. symbolic procedure cossqchk(x);
  228. begin scalar !*gcd;
  229. !*gcd := t;
  230. return multsq(cossqchkf(numr x), invsq cossqchkf(denr x))
  231. end;
  232. symbolic procedure lrootchk(l,x);
  233. % Checks each member of list l for a root.
  234. if null l then nil else krootchk(car l, x) or lrootchk(cdr l, x);
  235. symbolic procedure krootchk(f,x);
  236. % Checks a kernel to see if it is a root.
  237. if atom f then nil
  238. else if car(f) = 'sqrt and member(x, flatten cdr f) then t
  239. else if car(f) = 'expt
  240. and not atom caddr(f)
  241. and caaddr(f) = 'quotient
  242. and member(x, flatten cadr f) then t
  243. else lrootchk(cdr f, x);
  244. symbolic procedure rootchk1p(f,x);
  245. % Checks polynomial for a root.
  246. if domainp f then nil
  247. else krootchk(mvar f,x) or rootchk1p(lc f,x) or rootchk1p(red f,x);
  248. symbolic procedure rootcheckp(f,x);
  249. % Checks rational (standard quotient) for a root.
  250. rootchk1p(numr f,x) or rootchk1p(denr f,x);
  251. endmodule;
  252. end;