orthogonal.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. from .functions import defun, defun_wrapped
  2. def _hermite_param(ctx, n, z, parabolic_cylinder):
  3. """
  4. Combined calculation of the Hermite polynomial H_n(z) (and its
  5. generalization to complex n) and the parabolic cylinder
  6. function D.
  7. """
  8. n, ntyp = ctx._convert_param(n)
  9. z = ctx.convert(z)
  10. q = -ctx.mpq_1_2
  11. # For re(z) > 0, 2F0 -- http://functions.wolfram.com/
  12. # HypergeometricFunctions/HermiteHGeneral/06/02/0009/
  13. # Otherwise, there is a reflection formula
  14. # 2F0 + http://functions.wolfram.com/HypergeometricFunctions/
  15. # HermiteHGeneral/16/01/01/0006/
  16. #
  17. # TODO:
  18. # An alternative would be to use
  19. # http://functions.wolfram.com/HypergeometricFunctions/
  20. # HermiteHGeneral/06/02/0006/
  21. #
  22. # Also, the 1F1 expansion
  23. # http://functions.wolfram.com/HypergeometricFunctions/
  24. # HermiteHGeneral/26/01/02/0001/
  25. # should probably be used for tiny z
  26. if not z:
  27. T1 = [2, ctx.pi], [n, 0.5], [], [q*(n-1)], [], [], 0
  28. if parabolic_cylinder:
  29. T1[1][0] += q*n
  30. return T1,
  31. can_use_2f0 = ctx.isnpint(-n) or ctx.re(z) > 0 or \
  32. (ctx.re(z) == 0 and ctx.im(z) > 0)
  33. expprec = ctx.prec*4 + 20
  34. if parabolic_cylinder:
  35. u = ctx.fmul(ctx.fmul(z,z,prec=expprec), -0.25, exact=True)
  36. w = ctx.fmul(z, ctx.sqrt(0.5,prec=expprec), prec=expprec)
  37. else:
  38. w = z
  39. w2 = ctx.fmul(w, w, prec=expprec)
  40. rw2 = ctx.fdiv(1, w2, prec=expprec)
  41. nrw2 = ctx.fneg(rw2, exact=True)
  42. nw = ctx.fneg(w, exact=True)
  43. if can_use_2f0:
  44. T1 = [2, w], [n, n], [], [], [q*n, q*(n-1)], [], nrw2
  45. terms = [T1]
  46. else:
  47. T1 = [2, nw], [n, n], [], [], [q*n, q*(n-1)], [], nrw2
  48. T2 = [2, ctx.pi, nw], [n+2, 0.5, 1], [], [q*n], [q*(n-1)], [1-q], w2
  49. terms = [T1,T2]
  50. # Multiply by prefactor for D_n
  51. if parabolic_cylinder:
  52. expu = ctx.exp(u)
  53. for i in range(len(terms)):
  54. terms[i][1][0] += q*n
  55. terms[i][0].append(expu)
  56. terms[i][1].append(1)
  57. return tuple(terms)
  58. @defun
  59. def hermite(ctx, n, z, **kwargs):
  60. return ctx.hypercomb(lambda: _hermite_param(ctx, n, z, 0), [], **kwargs)
  61. @defun
  62. def pcfd(ctx, n, z, **kwargs):
  63. r"""
  64. Gives the parabolic cylinder function in Whittaker's notation
  65. `D_n(z) = U(-n-1/2, z)` (see :func:`~mpmath.pcfu`).
  66. It solves the differential equation
  67. .. math ::
  68. y'' + \left(n + \frac{1}{2} - \frac{1}{4} z^2\right) y = 0.
  69. and can be represented in terms of Hermite polynomials
  70. (see :func:`~mpmath.hermite`) as
  71. .. math ::
  72. D_n(z) = 2^{-n/2} e^{-z^2/4} H_n\left(\frac{z}{\sqrt{2}}\right).
  73. **Plots**
  74. .. literalinclude :: /plots/pcfd.py
  75. .. image :: /plots/pcfd.png
  76. **Examples**
  77. >>> from mpmath import *
  78. >>> mp.dps = 25; mp.pretty = True
  79. >>> pcfd(0,0); pcfd(1,0); pcfd(2,0); pcfd(3,0)
  80. 1.0
  81. 0.0
  82. -1.0
  83. 0.0
  84. >>> pcfd(4,0); pcfd(-3,0)
  85. 3.0
  86. 0.6266570686577501256039413
  87. >>> pcfd('1/2', 2+3j)
  88. (-5.363331161232920734849056 - 3.858877821790010714163487j)
  89. >>> pcfd(2, -10)
  90. 1.374906442631438038871515e-9
  91. Verifying the differential equation::
  92. >>> n = mpf(2.5)
  93. >>> y = lambda z: pcfd(n,z)
  94. >>> z = 1.75
  95. >>> chop(diff(y,z,2) + (n+0.5-0.25*z**2)*y(z))
  96. 0.0
  97. Rational Taylor series expansion when `n` is an integer::
  98. >>> taylor(lambda z: pcfd(5,z), 0, 7)
  99. [0.0, 15.0, 0.0, -13.75, 0.0, 3.96875, 0.0, -0.6015625]
  100. """
  101. return ctx.hypercomb(lambda: _hermite_param(ctx, n, z, 1), [], **kwargs)
  102. @defun
  103. def pcfu(ctx, a, z, **kwargs):
  104. r"""
  105. Gives the parabolic cylinder function `U(a,z)`, which may be
  106. defined for `\Re(z) > 0` in terms of the confluent
  107. U-function (see :func:`~mpmath.hyperu`) by
  108. .. math ::
  109. U(a,z) = 2^{-\frac{1}{4}-\frac{a}{2}} e^{-\frac{1}{4} z^2}
  110. U\left(\frac{a}{2}+\frac{1}{4},
  111. \frac{1}{2}, \frac{1}{2}z^2\right)
  112. or, for arbitrary `z`,
  113. .. math ::
  114. e^{-\frac{1}{4}z^2} U(a,z) =
  115. U(a,0) \,_1F_1\left(-\tfrac{a}{2}+\tfrac{1}{4};
  116. \tfrac{1}{2}; -\tfrac{1}{2}z^2\right) +
  117. U'(a,0) z \,_1F_1\left(-\tfrac{a}{2}+\tfrac{3}{4};
  118. \tfrac{3}{2}; -\tfrac{1}{2}z^2\right).
  119. **Examples**
  120. Connection to other functions::
  121. >>> from mpmath import *
  122. >>> mp.dps = 25; mp.pretty = True
  123. >>> z = mpf(3)
  124. >>> pcfu(0.5,z)
  125. 0.03210358129311151450551963
  126. >>> sqrt(pi/2)*exp(z**2/4)*erfc(z/sqrt(2))
  127. 0.03210358129311151450551963
  128. >>> pcfu(0.5,-z)
  129. 23.75012332835297233711255
  130. >>> sqrt(pi/2)*exp(z**2/4)*erfc(-z/sqrt(2))
  131. 23.75012332835297233711255
  132. >>> pcfu(0.5,-z)
  133. 23.75012332835297233711255
  134. >>> sqrt(pi/2)*exp(z**2/4)*erfc(-z/sqrt(2))
  135. 23.75012332835297233711255
  136. """
  137. n, _ = ctx._convert_param(a)
  138. return ctx.pcfd(-n-ctx.mpq_1_2, z)
  139. @defun
  140. def pcfv(ctx, a, z, **kwargs):
  141. r"""
  142. Gives the parabolic cylinder function `V(a,z)`, which can be
  143. represented in terms of :func:`~mpmath.pcfu` as
  144. .. math ::
  145. V(a,z) = \frac{\Gamma(a+\tfrac{1}{2}) (U(a,-z)-\sin(\pi a) U(a,z)}{\pi}.
  146. **Examples**
  147. Wronskian relation between `U` and `V`::
  148. >>> from mpmath import *
  149. >>> mp.dps = 25; mp.pretty = True
  150. >>> a, z = 2, 3
  151. >>> pcfu(a,z)*diff(pcfv,(a,z),(0,1))-diff(pcfu,(a,z),(0,1))*pcfv(a,z)
  152. 0.7978845608028653558798921
  153. >>> sqrt(2/pi)
  154. 0.7978845608028653558798921
  155. >>> a, z = 2.5, 3
  156. >>> pcfu(a,z)*diff(pcfv,(a,z),(0,1))-diff(pcfu,(a,z),(0,1))*pcfv(a,z)
  157. 0.7978845608028653558798921
  158. >>> a, z = 0.25, -1
  159. >>> pcfu(a,z)*diff(pcfv,(a,z),(0,1))-diff(pcfu,(a,z),(0,1))*pcfv(a,z)
  160. 0.7978845608028653558798921
  161. >>> a, z = 2+1j, 2+3j
  162. >>> chop(pcfu(a,z)*diff(pcfv,(a,z),(0,1))-diff(pcfu,(a,z),(0,1))*pcfv(a,z))
  163. 0.7978845608028653558798921
  164. """
  165. n, ntype = ctx._convert_param(a)
  166. z = ctx.convert(z)
  167. q = ctx.mpq_1_2
  168. r = ctx.mpq_1_4
  169. if ntype == 'Q' and ctx.isint(n*2):
  170. # Faster for half-integers
  171. def h():
  172. jz = ctx.fmul(z, -1j, exact=True)
  173. T1terms = _hermite_param(ctx, -n-q, z, 1)
  174. T2terms = _hermite_param(ctx, n-q, jz, 1)
  175. for T in T1terms:
  176. T[0].append(1j)
  177. T[1].append(1)
  178. T[3].append(q-n)
  179. u = ctx.expjpi((q*n-r)) * ctx.sqrt(2/ctx.pi)
  180. for T in T2terms:
  181. T[0].append(u)
  182. T[1].append(1)
  183. return T1terms + T2terms
  184. v = ctx.hypercomb(h, [], **kwargs)
  185. if ctx._is_real_type(n) and ctx._is_real_type(z):
  186. v = ctx._re(v)
  187. return v
  188. else:
  189. def h(n):
  190. w = ctx.square_exp_arg(z, -0.25)
  191. u = ctx.square_exp_arg(z, 0.5)
  192. e = ctx.exp(w)
  193. l = [ctx.pi, q, ctx.exp(w)]
  194. Y1 = l, [-q, n*q+r, 1], [r-q*n], [], [q*n+r], [q], u
  195. Y2 = l + [z], [-q, n*q-r, 1, 1], [1-r-q*n], [], [q*n+1-r], [1+q], u
  196. c, s = ctx.cospi_sinpi(r+q*n)
  197. Y1[0].append(s)
  198. Y2[0].append(c)
  199. for Y in (Y1, Y2):
  200. Y[1].append(1)
  201. Y[3].append(q-n)
  202. return Y1, Y2
  203. return ctx.hypercomb(h, [n], **kwargs)
  204. @defun
  205. def pcfw(ctx, a, z, **kwargs):
  206. r"""
  207. Gives the parabolic cylinder function `W(a,z)` defined in (DLMF 12.14).
  208. **Examples**
  209. Value at the origin::
  210. >>> from mpmath import *
  211. >>> mp.dps = 25; mp.pretty = True
  212. >>> a = mpf(0.25)
  213. >>> pcfw(a,0)
  214. 0.9722833245718180765617104
  215. >>> power(2,-0.75)*sqrt(abs(gamma(0.25+0.5j*a)/gamma(0.75+0.5j*a)))
  216. 0.9722833245718180765617104
  217. >>> diff(pcfw,(a,0),(0,1))
  218. -0.5142533944210078966003624
  219. >>> -power(2,-0.25)*sqrt(abs(gamma(0.75+0.5j*a)/gamma(0.25+0.5j*a)))
  220. -0.5142533944210078966003624
  221. """
  222. n, _ = ctx._convert_param(a)
  223. z = ctx.convert(z)
  224. def terms():
  225. phi2 = ctx.arg(ctx.gamma(0.5 + ctx.j*n))
  226. phi2 = (ctx.loggamma(0.5+ctx.j*n) - ctx.loggamma(0.5-ctx.j*n))/2j
  227. rho = ctx.pi/8 + 0.5*phi2
  228. # XXX: cancellation computing k
  229. k = ctx.sqrt(1 + ctx.exp(2*ctx.pi*n)) - ctx.exp(ctx.pi*n)
  230. C = ctx.sqrt(k/2) * ctx.exp(0.25*ctx.pi*n)
  231. yield C * ctx.expj(rho) * ctx.pcfu(ctx.j*n, z*ctx.expjpi(-0.25))
  232. yield C * ctx.expj(-rho) * ctx.pcfu(-ctx.j*n, z*ctx.expjpi(0.25))
  233. v = ctx.sum_accurately(terms)
  234. if ctx._is_real_type(n) and ctx._is_real_type(z):
  235. v = ctx._re(v)
  236. return v
  237. """
  238. Even/odd PCFs. Useful?
  239. @defun
  240. def pcfy1(ctx, a, z, **kwargs):
  241. a, _ = ctx._convert_param(n)
  242. z = ctx.convert(z)
  243. def h():
  244. w = ctx.square_exp_arg(z)
  245. w1 = ctx.fmul(w, -0.25, exact=True)
  246. w2 = ctx.fmul(w, 0.5, exact=True)
  247. e = ctx.exp(w1)
  248. return [e], [1], [], [], [ctx.mpq_1_2*a+ctx.mpq_1_4], [ctx.mpq_1_2], w2
  249. return ctx.hypercomb(h, [], **kwargs)
  250. @defun
  251. def pcfy2(ctx, a, z, **kwargs):
  252. a, _ = ctx._convert_param(n)
  253. z = ctx.convert(z)
  254. def h():
  255. w = ctx.square_exp_arg(z)
  256. w1 = ctx.fmul(w, -0.25, exact=True)
  257. w2 = ctx.fmul(w, 0.5, exact=True)
  258. e = ctx.exp(w1)
  259. return [e, z], [1, 1], [], [], [ctx.mpq_1_2*a+ctx.mpq_3_4], \
  260. [ctx.mpq_3_2], w2
  261. return ctx.hypercomb(h, [], **kwargs)
  262. """
  263. @defun_wrapped
  264. def gegenbauer(ctx, n, a, z, **kwargs):
  265. # Special cases: a+0.5, a*2 poles
  266. if ctx.isnpint(a):
  267. return 0*(z+n)
  268. if ctx.isnpint(a+0.5):
  269. # TODO: something else is required here
  270. # E.g.: gegenbauer(-2, -0.5, 3) == -12
  271. if ctx.isnpint(n+1):
  272. raise NotImplementedError("Gegenbauer function with two limits")
  273. def h(a):
  274. a2 = 2*a
  275. T = [], [], [n+a2], [n+1, a2], [-n, n+a2], [a+0.5], 0.5*(1-z)
  276. return [T]
  277. return ctx.hypercomb(h, [a], **kwargs)
  278. def h(n):
  279. a2 = 2*a
  280. T = [], [], [n+a2], [n+1, a2], [-n, n+a2], [a+0.5], 0.5*(1-z)
  281. return [T]
  282. return ctx.hypercomb(h, [n], **kwargs)
  283. @defun_wrapped
  284. def jacobi(ctx, n, a, b, x, **kwargs):
  285. if not ctx.isnpint(a):
  286. def h(n):
  287. return (([], [], [a+n+1], [n+1, a+1], [-n, a+b+n+1], [a+1], (1-x)*0.5),)
  288. return ctx.hypercomb(h, [n], **kwargs)
  289. if not ctx.isint(b):
  290. def h(n, a):
  291. return (([], [], [-b], [n+1, -b-n], [-n, a+b+n+1], [b+1], (x+1)*0.5),)
  292. return ctx.hypercomb(h, [n, a], **kwargs)
  293. # XXX: determine appropriate limit
  294. return ctx.binomial(n+a,n) * ctx.hyp2f1(-n,1+n+a+b,a+1,(1-x)/2, **kwargs)
  295. @defun_wrapped
  296. def laguerre(ctx, n, a, z, **kwargs):
  297. # XXX: limits, poles
  298. #if ctx.isnpint(n):
  299. # return 0*(a+z)
  300. def h(a):
  301. return (([], [], [a+n+1], [a+1, n+1], [-n], [a+1], z),)
  302. return ctx.hypercomb(h, [a], **kwargs)
  303. @defun_wrapped
  304. def legendre(ctx, n, x, **kwargs):
  305. if ctx.isint(n):
  306. n = int(n)
  307. # Accuracy near zeros
  308. if (n + (n < 0)) & 1:
  309. if not x:
  310. return x
  311. mag = ctx.mag(x)
  312. if mag < -2*ctx.prec-10:
  313. return x
  314. if mag < -5:
  315. ctx.prec += -mag
  316. return ctx.hyp2f1(-n,n+1,1,(1-x)/2, **kwargs)
  317. @defun
  318. def legenp(ctx, n, m, z, type=2, **kwargs):
  319. # Legendre function, 1st kind
  320. n = ctx.convert(n)
  321. m = ctx.convert(m)
  322. # Faster
  323. if not m:
  324. return ctx.legendre(n, z, **kwargs)
  325. # TODO: correct evaluation at singularities
  326. if type == 2:
  327. def h(n,m):
  328. g = m*0.5
  329. T = [1+z, 1-z], [g, -g], [], [1-m], [-n, n+1], [1-m], 0.5*(1-z)
  330. return (T,)
  331. return ctx.hypercomb(h, [n,m], **kwargs)
  332. if type == 3:
  333. def h(n,m):
  334. g = m*0.5
  335. T = [z+1, z-1], [g, -g], [], [1-m], [-n, n+1], [1-m], 0.5*(1-z)
  336. return (T,)
  337. return ctx.hypercomb(h, [n,m], **kwargs)
  338. raise ValueError("requires type=2 or type=3")
  339. @defun
  340. def legenq(ctx, n, m, z, type=2, **kwargs):
  341. # Legendre function, 2nd kind
  342. n = ctx.convert(n)
  343. m = ctx.convert(m)
  344. z = ctx.convert(z)
  345. if z in (1, -1):
  346. #if ctx.isint(m):
  347. # return ctx.nan
  348. #return ctx.inf # unsigned
  349. return ctx.nan
  350. if type == 2:
  351. def h(n, m):
  352. cos, sin = ctx.cospi_sinpi(m)
  353. s = 2 * sin / ctx.pi
  354. c = cos
  355. a = 1+z
  356. b = 1-z
  357. u = m/2
  358. w = (1-z)/2
  359. T1 = [s, c, a, b], [-1, 1, u, -u], [], [1-m], \
  360. [-n, n+1], [1-m], w
  361. T2 = [-s, a, b], [-1, -u, u], [n+m+1], [n-m+1, m+1], \
  362. [-n, n+1], [m+1], w
  363. return T1, T2
  364. return ctx.hypercomb(h, [n, m], **kwargs)
  365. if type == 3:
  366. # The following is faster when there only is a single series
  367. # Note: not valid for -1 < z < 0 (?)
  368. if abs(z) > 1:
  369. def h(n, m):
  370. T1 = [ctx.expjpi(m), 2, ctx.pi, z, z-1, z+1], \
  371. [1, -n-1, 0.5, -n-m-1, 0.5*m, 0.5*m], \
  372. [n+m+1], [n+1.5], \
  373. [0.5*(2+n+m), 0.5*(1+n+m)], [n+1.5], z**(-2)
  374. return [T1]
  375. return ctx.hypercomb(h, [n, m], **kwargs)
  376. else:
  377. # not valid for 1 < z < inf ?
  378. def h(n, m):
  379. s = 2 * ctx.sinpi(m) / ctx.pi
  380. c = ctx.expjpi(m)
  381. a = 1+z
  382. b = z-1
  383. u = m/2
  384. w = (1-z)/2
  385. T1 = [s, c, a, b], [-1, 1, u, -u], [], [1-m], \
  386. [-n, n+1], [1-m], w
  387. T2 = [-s, c, a, b], [-1, 1, -u, u], [n+m+1], [n-m+1, m+1], \
  388. [-n, n+1], [m+1], w
  389. return T1, T2
  390. return ctx.hypercomb(h, [n, m], **kwargs)
  391. raise ValueError("requires type=2 or type=3")
  392. @defun_wrapped
  393. def chebyt(ctx, n, x, **kwargs):
  394. if (not x) and ctx.isint(n) and int(ctx._re(n)) % 2 == 1:
  395. return x * 0
  396. return ctx.hyp2f1(-n,n,(1,2),(1-x)/2, **kwargs)
  397. @defun_wrapped
  398. def chebyu(ctx, n, x, **kwargs):
  399. if (not x) and ctx.isint(n) and int(ctx._re(n)) % 2 == 1:
  400. return x * 0
  401. return (n+1) * ctx.hyp2f1(-n, n+2, (3,2), (1-x)/2, **kwargs)
  402. @defun
  403. def spherharm(ctx, l, m, theta, phi, **kwargs):
  404. l = ctx.convert(l)
  405. m = ctx.convert(m)
  406. theta = ctx.convert(theta)
  407. phi = ctx.convert(phi)
  408. l_isint = ctx.isint(l)
  409. l_natural = l_isint and l >= 0
  410. m_isint = ctx.isint(m)
  411. if l_isint and l < 0 and m_isint:
  412. return ctx.spherharm(-(l+1), m, theta, phi, **kwargs)
  413. if theta == 0 and m_isint and m < 0:
  414. return ctx.zero * 1j
  415. if l_natural and m_isint:
  416. if abs(m) > l:
  417. return ctx.zero * 1j
  418. # http://functions.wolfram.com/Polynomials/
  419. # SphericalHarmonicY/26/01/02/0004/
  420. def h(l,m):
  421. absm = abs(m)
  422. C = [-1, ctx.expj(m*phi),
  423. (2*l+1)*ctx.fac(l+absm)/ctx.pi/ctx.fac(l-absm),
  424. ctx.sin(theta)**2,
  425. ctx.fac(absm), 2]
  426. P = [0.5*m*(ctx.sign(m)+1), 1, 0.5, 0.5*absm, -1, -absm-1]
  427. return ((C, P, [], [], [absm-l, l+absm+1], [absm+1],
  428. ctx.sin(0.5*theta)**2),)
  429. else:
  430. # http://functions.wolfram.com/HypergeometricFunctions/
  431. # SphericalHarmonicYGeneral/26/01/02/0001/
  432. def h(l,m):
  433. if ctx.isnpint(l-m+1) or ctx.isnpint(l+m+1) or ctx.isnpint(1-m):
  434. return (([0], [-1], [], [], [], [], 0),)
  435. cos, sin = ctx.cos_sin(0.5*theta)
  436. C = [0.5*ctx.expj(m*phi), (2*l+1)/ctx.pi,
  437. ctx.gamma(l-m+1), ctx.gamma(l+m+1),
  438. cos**2, sin**2]
  439. P = [1, 0.5, 0.5, -0.5, 0.5*m, -0.5*m]
  440. return ((C, P, [], [1-m], [-l,l+1], [1-m], sin**2),)
  441. return ctx.hypercomb(h, [l,m], **kwargs)