log2atan.red 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. module log2atan;
  2. % Author: James H. Davenport.
  3. % Modified by: Anthony C. Hearn.
  4. fluid '(!*rationalize !*tra gaussiani !*trmin intvar);
  5. exports combine!-logs;
  6. symbolic procedure combine!-logs(coef,logarg);
  7. % Attempts to produce a "simple" form for COEF*(LOGARG). COEF is
  8. % prefix, LOGARG an SQ (and already log'ged for historical reasons).
  9. begin
  10. scalar ans,dencoef,parts,logs,lparts,!*rationalize,trueimag;
  11. !*rationalize:=t; % A first attempt to use this technology.
  12. coef:=simp!* coef;
  13. if null numr logarg then return coef;
  14. parts:=split!-real!-imag numr coef;
  15. if null numr cdr parts then return multsq(coef,logarg);
  16. % Integrand was, or seemed to be, purely real.
  17. dencoef:=multf(denr coef,denr logarg);
  18. if !*tra then <<
  19. printc "attempting to find 'real' form for";
  20. mathprint list('times,list('plus,prepsq car parts,
  21. list('times,prepsq cdr parts,'i)),
  22. prepsq logarg) >>;
  23. logarg:=numr logarg;
  24. logs:= 1 ./ 1;
  25. while pairp logarg do <<
  26. if ldeg logarg neq 1 then interr "what a log";
  27. if atom mvar logarg then interr "what a log";
  28. if car mvar logarg neq 'log then interr "what a log";
  29. logs:=!*multsq(logs,
  30. !*exptsq(simp!* argof mvar logarg,lc logarg));
  31. logarg:=red logarg >>;
  32. logs:=rationalizesq logs;
  33. ans:=multsq(!*multsq(car parts,logs),1 ./ dencoef); % real part
  34. % Now to apply theory i*log(a+i*b) = atan(a/b) + (i/2 log (a^2+b^2))
  35. lparts:=split!-real!-imag numr logs;
  36. if numr difff(denr cdr lparts,intvar)
  37. then interr "unexpected denominator"
  38. else if null numr cdr lparts then return multsq(coef,logarg);
  39. % The previous test arose from
  40. % combine!-logs('(times (sqrt (plus a (minus 1))) i),
  41. % '(((((log (plus (sqrt (plus (expt x 2) 1))
  42. % (minus x))) . 1) . 1) (((log (plus (sqrt (plus
  43. % (expt x 2) 1)) x)) . 1) . -1)) . 2)
  44. % from int((-sqrt(a-1)*sqrt(x**2+1)*i-x)/(x**2+1),x).
  45. lparts:=!*multsq(denr cdr lparts ./ 1,car lparts) . cdr lparts;
  46. if not onep denr car lparts then interr "unexpected denominator";
  47. % We have discarded the logarithm of a constant: good riddance
  48. trueimag:=quotsq(addf(!*exptf(numr car lparts,2),
  49. !*exptf(numr cdr lparts,2)) ./ 1,
  50. !*exptf(denr logs,2) ./ 1);
  51. if numr diffsq(trueimag,intvar)
  52. then ans:=!*addsq(ans,
  53. !*multsq(gaussiani ./ multf(2,dencoef),
  54. !*multsq(simplogsq trueimag,cdr parts)));
  55. trueimag:=!*multsq(car lparts,!*invsq(numr cdr lparts ./ 1));
  56. if numr diffsq(trueimag,intvar)
  57. then ans:=!*addsq(ans,!*multsq(!*multsq(cdr parts,1 ./ dencoef),
  58. !*k2q list('atan,prepsq!* trueimag)));
  59. return ans;
  60. end;
  61. symbolic procedure split!-real!-imag sf;
  62. % Returns coef real.imag as SQs.
  63. if null sf then (lambda z; z . z) (nil ./ 1)
  64. else if numberp sf then (sf ./ 1) . (nil ./ 1)
  65. else if domainp sf then interr "can't handle arbitrary domains"
  66. else begin
  67. scalar cparts,rparts,mv,tmp;
  68. cparts:=split!-real!-imag lc sf;
  69. rparts:=split!-real!-imag red sf;
  70. mv:=split!-real!-imagvar mvar sf;
  71. if null numr cdr mv % main variable totally real
  72. then <<
  73. tmp:= lpow sf .* 1 .+ nil ./ 1;
  74. return !*addsq(!*multsq(car cparts,tmp),car rparts) .
  75. !*addsq(!*multsq(cdr cparts,tmp),cdr rparts) >>;
  76. if null numr car mv then <<
  77. mv:=!*exptsq(cdr mv,ldeg sf);
  78. % deal with powers of i
  79. if not evenp(ldeg sf / 2) then mv:=negsq mv;
  80. if not evenp ldeg sf
  81. then return !*addsq(!*multsq(negsq cdr cparts,mv),car rparts) .
  82. !*addsq(!*multsq(car cparts,mv),cdr rparts)
  83. else return !*addsq(!*multsq(car cparts,mv),car rparts) .
  84. !*addsq(!*multsq(cdr cparts,mv),cdr rparts) >>;
  85. % Now we have to handle the general case.
  86. cparts:=mul!-complex(cparts,exp!-complex(mv,ldeg sf));
  87. return !*addsq(car cparts,car rparts) .
  88. !*addsq(cdr cparts, cdr rparts)
  89. end;
  90. symbolic procedure mul!-complex(a,b);
  91. !*addsq(!*multsq(negsq cdr a,cdr b),!*multsq(car a,car b)) .
  92. !*addsq(!*multsq(car a,cdr b),!*multsq(cdr a,car b));
  93. symbolic procedure exp!-complex(a,n);
  94. if n=1 then a
  95. else if evenp n then exp!-complex(mul!-complex(a,a),n/2)
  96. else mul!-complex(a,exp!-complex(mul!-complex(a,a),n/2));
  97. symbolic procedure split!-real!-imagvar mv;
  98. % Returns a pair of sf.
  99. if mv eq 'i then (nil ./ 1) . (1 ./ 1)
  100. else if atom mv then (mv .** 1 .* 1 .+ nil ./ 1) . (nil ./ 1)
  101. else if car mv eq 'sqrt then begin
  102. scalar n,rp,innersqrt,c;
  103. n:=simp!* argof mv;
  104. if denr n neq 1 then interr "unexpected denominator";
  105. rp:=split!-real!-imag numr n;
  106. if null numr cdr rp and minusf numr car rp and
  107. null involvesf(numr car rp,intvar) then
  108. return (nil ./ 1) . simpsqrtsq negsq car rp;
  109. if null numr cdr rp
  110. then return (mv .** 1 .* 1 .+ nil ./ 1) . (nil ./ 1);
  111. % totally real.
  112. % OK - it's a general (ish) complex number A+iB
  113. % its square root is going to be C+iD where
  114. % C^2 = (A+sqrt(A^2+B^2))/2 (+ve sign of sqrt to make C +ve)
  115. % C is square root of this
  116. % D is C * (sqrt(A(2+B^2) -A)/B
  117. % Note that D has a non-trivial denominator. We could avoid this at
  118. % the cost of generating non-independent square roots (yuck).
  119. % Note that the above checks have ensured this den. is non-zero.
  120. if numr car rp then
  121. innersqrt:=simpsqrtsq !*addsq(!*exptsq(car rp,2),
  122. !*exptsq(cdr rp,2))
  123. else innersqrt:=cdr rp; % pure imaginary case
  124. c:=simpsqrtsq multsq(!*addsq(car rp, innersqrt), 1 ./ 2);
  125. return c . !*multsq(!*multsq(c,!*invsq cdr rp),
  126. !*addsq(innersqrt,negsq car rp));
  127. end
  128. else (mv .** 1 .* 1 .+ nil ./ 1) . (nil ./ 1);
  129. % What the heck: pretend it's real.
  130. endmodule;
  131. end;