sfother.red 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. module sfother; % Rulesets for the Struve H and L functions, Lommel
  2. % 1 and 2 functions and Whittaker M and W functions.
  3. % Author: Chris Cannam, Nov 1992.
  4. % The aim is to re-express in terms % of other (more `standard') special
  5. % functions. No numerical approximation code.
  6. % Neither imports nor exports functions.
  7. % This module contains only rulesets.
  8. algebraic (operator struveh, struvel);
  9. algebraic (struve!*rules := {
  10. df(struveh(~n,~z),z) =>
  11. (2/pi) - struveh(1,z) when numberp n and n = 0,
  12. df(struveh(~n,~x),x) => (x*StruveH(-1 + n,x)- n*StruveH(n,x))/x,
  13. df((z**n)*struveh(~n,~z),z) => (z**n)*struveh(n-1,z),
  14. df((z**(-n))*struveh(~n,~z),z) =>
  15. (1/(sqrt(pi)*(2**n)*gamma(n+(3/2)))) - (z**(-n))*struveh(n+1,z),
  16. struveh(~n,~z) =>
  17. ((-1)**n)*besselj(-n,z)
  18. when numberp n and impart n = 0
  19. and n < 0 and (n*2)=floor(n*2) and not evenp floor(n*2),
  20. struveh(~n,~z) =>
  21. ((2/(pi*z))**(1/2))*(1-cos z) when numberp n and n=1/2,
  22. struveh(~n,~z) =>
  23. ((z/(pi*2))**(1/2)) * (1+(2/(z**2))) -
  24. ((2/(pi*z))**(1/2)) * (sin z + ((cos z)/z))
  25. when numberp n and n=3/2,
  26. struveh(~n,~x) => (x*0.5)^(n+1)*struve_compute_term(n,x,h)
  27. when numberp x and numberp n and symbolic !*rounded,
  28. struvel(~n,~x) => struve_compute_term(n,x,l)
  29. when numberp x and numberp n and symbolic !*rounded,
  30. struvel(~n,~z) =>
  31. besseli(-n,z)
  32. when numberp n and impart n = 0
  33. and n < 0 and (n*2)=floor(n*2) and not evenp floor(n*2),
  34. struvel(~n,~z) =>
  35. -i*(e**((-i*n*pi)/2))*struveh(n,i*z) when symbolic !*complex,
  36. df(struvel(~n,~x),x) => (x*StruveL(-1 + n,x)- n*StruveL(n,x))/x
  37. })$
  38. algebraic (let struve!*rules);
  39. algebraic (operator lommel1, lommel2);
  40. algebraic (lommel!*rules := {
  41. lommel1(~a,~b,~z) =>
  42. -(2**a)*besselj(a,z)*gamma(a+1)+z**a
  43. when numberp a and numberp b and a = b+1,
  44. lommel1(~a,~b,~z) =>
  45. lommel1(a,-b,z)
  46. when numberp b and b < 0 and a neq b and a neq (b+1),
  47. lommel1(~a,~b,~z) =>
  48. (sqrt(pi)*(2**a)*gamma((2*a + 1)/2)*struveh(a,z))/2 when a = b,
  49. lommel2(~a,~b,~z) => z**b when numberp a and numberp b and a = b+1,
  50. lommel2(~a,~b,~z) => lommel2(a,-b,z)
  51. when numberp b and b < 0 and a neq b and a neq (b+1),
  52. lommel2(~a,~b,~z) =>
  53. (sqrt(pi)*(2**a)*gamma((2*a + 1)/2)*(-bessely(a,z)+struveh(a,z)))/2
  54. when a = b
  55. })$
  56. algebraic (let lommel!*rules);
  57. algebraic (operator whittakerm, whittakerw);
  58. algebraic (whittaker!*rules := {
  59. whittakerm(~k,~m,~z) =>
  60. exp(-z/2)*(z**(1/2+m))*kummerm(1/2+m-k,1+2*m,z),
  61. whittakerw(~k,~m,~z) =>
  62. exp(-z/2)*(z**(1/2+m))*kummeru(1/2+m-k,1+2*m,z),
  63. df(WhittakerM(~n,~m,~z),z) => 1/(2*z)*
  64. ((1+2*m-2*n)*WhittakerM(n-1,m,z) + (2*n-z)*WhittakerM(n,m,z)),
  65. df(WhittakerW(~n,~m,~z),z) => 1/(4*z)*
  66. ((1-4*m^2-4*n+4*n^2)*WhittakerW(n-1,m,z)
  67. + (4*n-2*z)*WhittakerW(n,m,z))
  68. % AS (8.5.4)
  69. })$
  70. algebraic (let whittaker!*rules);
  71. %Handbook of Mathematical Functions - page 496
  72. algebraic procedure struve_compute_term(n,x,h_or_l);
  73. begin scalar dmode!*!*;
  74. lisp(dmode!*!* := dmode!*);
  75. return
  76. begin scalar pre,term,k,precis,result,!*complex,!*rounded,
  77. dmode!*,expo,!*msg;
  78. lisp (dmode!* := dmode!*!*);
  79. if h_or_l = l
  80. then << on complex;
  81. off rounded;
  82. expo := e^(-i*n*pi/2);
  83. on rounded;
  84. return (-i*expo*struveh(n,i*x))>>
  85. else <<
  86. pre := precision 0;
  87. precis := 10.0^(-pre-2);
  88. result := 0;
  89. << if n > -2 then <<k:=1, term := 2^(n+2)/(pi *
  90. (for i:= 1 :n+1 product(2i-1))) ;
  91. result := term >>
  92. else for kk:=0:-(n+2) do << k:=kk+1;
  93. term := (-1)^kk*(1/2*x)^(2*kk)/
  94. (Gamma(kk+3/2) * Gamma(kk+n+3/2));
  95. result := result + term>>;
  96. while abs(term) > precis do
  97. << term:= term*(-0.25)*(x^2)/((k+0.5)*(k+n+0.5));
  98. result := result + term;
  99. k := k+1>>;
  100. >>; >>;
  101. return result;
  102. end; end;
  103. symbolic operator struve_compute_term;
  104. % Lambert's W (Omega) function.
  105. % see: "On Lambert's W function" by R. Corless, G. Gonnet et. al.
  106. % only the principal branch is implemented
  107. algebraic <<
  108. % Remove autoload properties.
  109. lisp null remprop('lambert_w,'simpfn);
  110. lisp null remflag('(lambert_w),'full);
  111. operator lambert_w;
  112. let { lambert_w(0) => 0,
  113. lambert_w(-1/e) => -1,
  114. sum((- ~n)^(n-1)/factorial n *~z^n,n,1,infinity)
  115. => lambert_w(z),
  116. df(lambert_w(~z),z) => 1/((1 + lambert_w(z))*e^lambert_w z),
  117. log(lambert_w(~z)) => log(z) - lambert_w z,
  118. e^(lambert_w ~z) => ~z/lambert_w z,
  119. int(lambert_w(~z),z) => z*(lambert_w z -1 +1/lambert_w z),
  120. lambert_w(~z) => num_lambert_w(z)
  121. when numberp z and lisp !*rounded};
  122. procedure num_lambert_w(z);
  123. if z=0 then 0 else
  124. begin scalar wjnew,wj,accu,expwj,oldprec,!*complex,olddmode!*;
  125. lisp setq(olddmode!* ,dmode!*);
  126. on complex;
  127. oldprec := precision 5;
  128. accu := 10^(- lisp !:prec!:);
  129. if (abs z) <= 1 then % starting point for iteration
  130. if z >= -1/e then wj := 0 else wj := log(z)
  131. else wj := log(z) - log(log(z));
  132. wjnew := 100;
  133. while abs(wjnew) > accu do <<
  134. expwj := exp(wj);
  135. wjnew := - (wj*expwj -z)/
  136. (expwj*(wj+1)-(1/2(wj+2)*(wj*expwj -z))/(wj+1));
  137. wj := wj + wjnew >>;
  138. precision oldprec;
  139. accu := 10^(- lisp !:prec!:);
  140. while abs(wjnew) > accu do <<
  141. expwj := exp(wj);
  142. wjnew := - (wj*expwj -z)/
  143. (expwj*(wj+1)-(1/2(wj+2)*(wj*expwj -z))/(wj+1));
  144. wj := wj + wjnew >>;
  145. lisp setq(dmode!*,olddmode!*);
  146. return wj;
  147. end;
  148. >>;
  149. endmodule;
  150. end;