1from .functions import defun, defun_wrapped 2 3@defun 4def j0(ctx, x): 5 """Computes the Bessel function `J_0(x)`. See :func:`~mpmath.besselj`.""" 6 return ctx.besselj(0, x) 7 8@defun 9def j1(ctx, x): 10 """Computes the Bessel function `J_1(x)`. See :func:`~mpmath.besselj`.""" 11 return ctx.besselj(1, x) 12 13@defun 14def besselj(ctx, n, z, derivative=0, **kwargs): 15 if type(n) is int: 16 n_isint = True 17 else: 18 n = ctx.convert(n) 19 n_isint = ctx.isint(n) 20 if n_isint: 21 n = int(ctx._re(n)) 22 if n_isint and n < 0: 23 return (-1)**n * ctx.besselj(-n, z, derivative, **kwargs) 24 z = ctx.convert(z) 25 M = ctx.mag(z) 26 if derivative: 27 d = ctx.convert(derivative) 28 # TODO: the integer special-casing shouldn't be necessary. 29 # However, the hypergeometric series gets inaccurate for large d 30 # because of inaccurate pole cancellation at a pole far from 31 # zero (needs to be fixed in hypercomb or hypsum) 32 if ctx.isint(d) and d >= 0: 33 d = int(d) 34 orig = ctx.prec 35 try: 36 ctx.prec += 15 37 v = ctx.fsum((-1)**k * ctx.binomial(d,k) * ctx.besselj(2*k+n-d,z) 38 for k in range(d+1)) 39 finally: 40 ctx.prec = orig 41 v *= ctx.mpf(2)**(-d) 42 else: 43 def h(n,d): 44 r = ctx.fmul(ctx.fmul(z, z, prec=ctx.prec+M), -0.25, exact=True) 45 B = [0.5*(n-d+1), 0.5*(n-d+2)] 46 T = [([2,ctx.pi,z],[d-2*n,0.5,n-d],[],B,[(n+1)*0.5,(n+2)*0.5],B+[n+1],r)] 47 return T 48 v = ctx.hypercomb(h, [n,d], **kwargs) 49 else: 50 # Fast case: J_n(x), n int, appropriate magnitude for fixed-point calculation 51 if (not derivative) and n_isint and abs(M) < 10 and abs(n) < 20: 52 try: 53 return ctx._besselj(n, z) 54 except NotImplementedError: 55 pass 56 if not z: 57 if not n: 58 v = ctx.one + n+z 59 elif ctx.re(n) > 0: 60 v = n*z 61 else: 62 v = ctx.inf + z + n 63 else: 64 #v = 0 65 orig = ctx.prec 66 try: 67 # XXX: workaround for accuracy in low level hypergeometric series 68 # when alternating, large arguments 69 ctx.prec += min(3*abs(M), ctx.prec) 70 w = ctx.fmul(z, 0.5, exact=True) 71 def h(n): 72 r = ctx.fneg(ctx.fmul(w, w, prec=max(0,ctx.prec+M)), exact=True) 73 return [([w], [n], [], [n+1], [], [n+1], r)] 74 v = ctx.hypercomb(h, [n], **kwargs) 75 finally: 76 ctx.prec = orig 77 v = +v 78 return v 79 80@defun 81def besseli(ctx, n, z, derivative=0, **kwargs): 82 n = ctx.convert(n) 83 z = ctx.convert(z) 84 if not z: 85 if derivative: 86 raise ValueError 87 if not n: 88 # I(0,0) = 1 89 return 1+n+z 90 if ctx.isint(n): 91 return 0*(n+z) 92 r = ctx.re(n) 93 if r == 0: 94 return ctx.nan*(n+z) 95 elif r > 0: 96 return 0*(n+z) 97 else: 98 return ctx.inf+(n+z) 99 M = ctx.mag(z) 100 if derivative: 101 d = ctx.convert(derivative) 102 def h(n,d): 103 r = ctx.fmul(ctx.fmul(z, z, prec=ctx.prec+M), 0.25, exact=True) 104 B = [0.5*(n-d+1), 0.5*(n-d+2), n+1] 105 T = [([2,ctx.pi,z],[d-2*n,0.5,n-d],[n+1],B,[(n+1)*0.5,(n+2)*0.5],B,r)] 106 return T 107 v = ctx.hypercomb(h, [n,d], **kwargs) 108 else: 109 def h(n): 110 w = ctx.fmul(z, 0.5, exact=True) 111 r = ctx.fmul(w, w, prec=max(0,ctx.prec+M)) 112 return [([w], [n], [], [n+1], [], [n+1], r)] 113 v = ctx.hypercomb(h, [n], **kwargs) 114 return v 115 116@defun_wrapped 117def bessely(ctx, n, z, derivative=0, **kwargs): 118 if not z: 119 if derivative: 120 # Not implemented 121 raise ValueError 122 if not n: 123 # ~ log(z/2) 124 return -ctx.inf + (n+z) 125 if ctx.im(n): 126 return ctx.nan * (n+z) 127 r = ctx.re(n) 128 q = n+0.5 129 if ctx.isint(q): 130 if n > 0: 131 return -ctx.inf + (n+z) 132 else: 133 return 0 * (n+z) 134 if r < 0 and int(ctx.floor(q)) % 2: 135 return ctx.inf + (n+z) 136 else: 137 return ctx.ninf + (n+z) 138 # XXX: use hypercomb 139 ctx.prec += 10 140 m, d = ctx.nint_distance(n) 141 if d < -ctx.prec: 142 h = +ctx.eps 143 ctx.prec *= 2 144 n += h 145 elif d < 0: 146 ctx.prec -= d 147 # TODO: avoid cancellation for imaginary arguments 148 cos, sin = ctx.cospi_sinpi(n) 149 return (ctx.besselj(n,z,derivative,**kwargs)*cos - \ 150 ctx.besselj(-n,z,derivative,**kwargs))/sin 151 152@defun_wrapped 153def besselk(ctx, n, z, **kwargs): 154 if not z: 155 return ctx.inf 156 M = ctx.mag(z) 157 if M < 1: 158 # Represent as limit definition 159 def h(n): 160 r = (z/2)**2 161 T1 = [z, 2], [-n, n-1], [n], [], [], [1-n], r 162 T2 = [z, 2], [n, -n-1], [-n], [], [], [1+n], r 163 return T1, T2 164 # We could use the limit definition always, but it leads 165 # to very bad cancellation (of exponentially large terms) 166 # for large real z 167 # Instead represent in terms of 2F0 168 else: 169 ctx.prec += M 170 def h(n): 171 return [([ctx.pi/2, z, ctx.exp(-z)], [0.5,-0.5,1], [], [], \ 172 [n+0.5, 0.5-n], [], -1/(2*z))] 173 return ctx.hypercomb(h, [n], **kwargs) 174 175@defun_wrapped 176def hankel1(ctx,n,x,**kwargs): 177 return ctx.besselj(n,x,**kwargs) + ctx.j*ctx.bessely(n,x,**kwargs) 178 179@defun_wrapped 180def hankel2(ctx,n,x,**kwargs): 181 return ctx.besselj(n,x,**kwargs) - ctx.j*ctx.bessely(n,x,**kwargs) 182 183@defun_wrapped 184def whitm(ctx,k,m,z,**kwargs): 185 if z == 0: 186 # M(k,m,z) = 0^(1/2+m) 187 if ctx.re(m) > -0.5: 188 return z 189 elif ctx.re(m) < -0.5: 190 return ctx.inf + z 191 else: 192 return ctx.nan * z 193 x = ctx.fmul(-0.5, z, exact=True) 194 y = 0.5+m 195 return ctx.exp(x) * z**y * ctx.hyp1f1(y-k, 1+2*m, z, **kwargs) 196 197@defun_wrapped 198def whitw(ctx,k,m,z,**kwargs): 199 if z == 0: 200 g = abs(ctx.re(m)) 201 if g < 0.5: 202 return z 203 elif g > 0.5: 204 return ctx.inf + z 205 else: 206 return ctx.nan * z 207 x = ctx.fmul(-0.5, z, exact=True) 208 y = 0.5+m 209 return ctx.exp(x) * z**y * ctx.hyperu(y-k, 1+2*m, z, **kwargs) 210 211@defun 212def hyperu(ctx, a, b, z, **kwargs): 213 a, atype = ctx._convert_param(a) 214 b, btype = ctx._convert_param(b) 215 z = ctx.convert(z) 216 if not z: 217 if ctx.re(b) <= 1: 218 return ctx.gammaprod([1-b],[a-b+1]) 219 else: 220 return ctx.inf + z 221 bb = 1+a-b 222 bb, bbtype = ctx._convert_param(bb) 223 try: 224 orig = ctx.prec 225 try: 226 ctx.prec += 10 227 v = ctx.hypsum(2, 0, (atype, bbtype), [a, bb], -1/z, maxterms=ctx.prec) 228 return v / z**a 229 finally: 230 ctx.prec = orig 231 except ctx.NoConvergence: 232 pass 233 def h(a,b): 234 w = ctx.sinpi(b) 235 T1 = ([ctx.pi,w],[1,-1],[],[a-b+1,b],[a],[b],z) 236 T2 = ([-ctx.pi,w,z],[1,-1,1-b],[],[a,2-b],[a-b+1],[2-b],z) 237 return T1, T2 238 return ctx.hypercomb(h, [a,b], **kwargs) 239 240@defun 241def struveh(ctx,n,z, **kwargs): 242 n = ctx.convert(n) 243 z = ctx.convert(z) 244 # http://functions.wolfram.com/Bessel-TypeFunctions/StruveH/26/01/02/ 245 def h(n): 246 return [([z/2, 0.5*ctx.sqrt(ctx.pi)], [n+1, -1], [], [n+1.5], [1], [1.5, n+1.5], -(z/2)**2)] 247 return ctx.hypercomb(h, [n], **kwargs) 248 249@defun 250def struvel(ctx,n,z, **kwargs): 251 n = ctx.convert(n) 252 z = ctx.convert(z) 253 # http://functions.wolfram.com/Bessel-TypeFunctions/StruveL/26/01/02/ 254 def h(n): 255 return [([z/2, 0.5*ctx.sqrt(ctx.pi)], [n+1, -1], [], [n+1.5], [1], [1.5, n+1.5], (z/2)**2)] 256 return ctx.hypercomb(h, [n], **kwargs) 257 258def _anger(ctx,which,v,z,**kwargs): 259 v = ctx._convert_param(v)[0] 260 z = ctx.convert(z) 261 def h(v): 262 b = ctx.mpq_1_2 263 u = v*b 264 m = b*3 265 a1,a2,b1,b2 = m-u, m+u, 1-u, 1+u 266 c, s = ctx.cospi_sinpi(u) 267 if which == 0: 268 A, B = [b*z, s], [c] 269 if which == 1: 270 A, B = [b*z, -c], [s] 271 w = ctx.square_exp_arg(z, mult=-0.25) 272 T1 = A, [1, 1], [], [a1,a2], [1], [a1,a2], w 273 T2 = B, [1], [], [b1,b2], [1], [b1,b2], w 274 return T1, T2 275 return ctx.hypercomb(h, [v], **kwargs) 276 277@defun 278def angerj(ctx, v, z, **kwargs): 279 return _anger(ctx, 0, v, z, **kwargs) 280 281@defun 282def webere(ctx, v, z, **kwargs): 283 return _anger(ctx, 1, v, z, **kwargs) 284 285@defun 286def lommels1(ctx, u, v, z, **kwargs): 287 u = ctx._convert_param(u)[0] 288 v = ctx._convert_param(v)[0] 289 z = ctx.convert(z) 290 def h(u,v): 291 b = ctx.mpq_1_2 292 w = ctx.square_exp_arg(z, mult=-0.25) 293 return ([u-v+1, u+v+1, z], [-1, -1, u+1], [], [], [1], \ 294 [b*(u-v+3),b*(u+v+3)], w), 295 return ctx.hypercomb(h, [u,v], **kwargs) 296 297@defun 298def lommels2(ctx, u, v, z, **kwargs): 299 u = ctx._convert_param(u)[0] 300 v = ctx._convert_param(v)[0] 301 z = ctx.convert(z) 302 # Asymptotic expansion (GR p. 947) -- need to be careful 303 # not to use for small arguments 304 # def h(u,v): 305 # b = ctx.mpq_1_2 306 # w = -(z/2)**(-2) 307 # return ([z], [u-1], [], [], [b*(1-u+v)], [b*(1-u-v)], w), 308 def h(u,v): 309 b = ctx.mpq_1_2 310 w = ctx.square_exp_arg(z, mult=-0.25) 311 T1 = [u-v+1, u+v+1, z], [-1, -1, u+1], [], [], [1], [b*(u-v+3),b*(u+v+3)], w 312 T2 = [2, z], [u+v-1, -v], [v, b*(u+v+1)], [b*(v-u+1)], [], [1-v], w 313 T3 = [2, z], [u-v-1, v], [-v, b*(u-v+1)], [b*(1-u-v)], [], [1+v], w 314 #c1 = ctx.cospi((u-v)*b) 315 #c2 = ctx.cospi((u+v)*b) 316 #s = ctx.sinpi(v) 317 #r1 = (u-v+1)*b 318 #r2 = (u+v+1)*b 319 #T2 = [c1, s, z, 2], [1, -1, -v, v], [], [-v+1], [], [-v+1], w 320 #T3 = [-c2, s, z, 2], [1, -1, v, -v], [], [v+1], [], [v+1], w 321 #T2 = [c1, s, z, 2], [1, -1, -v, v+u-1], [r1, r2], [-v+1], [], [-v+1], w 322 #T3 = [-c2, s, z, 2], [1, -1, v, -v+u-1], [r1, r2], [v+1], [], [v+1], w 323 return T1, T2, T3 324 return ctx.hypercomb(h, [u,v], **kwargs) 325 326@defun 327def ber(ctx, n, z, **kwargs): 328 n = ctx.convert(n) 329 z = ctx.convert(z) 330 # http://functions.wolfram.com/Bessel-TypeFunctions/KelvinBer2/26/01/02/0001/ 331 def h(n): 332 r = -(z/4)**4 333 cos, sin = ctx.cospi_sinpi(-0.75*n) 334 T1 = [cos, z/2], [1, n], [], [n+1], [], [0.5, 0.5*(n+1), 0.5*n+1], r 335 T2 = [sin, z/2], [1, n+2], [], [n+2], [], [1.5, 0.5*(n+3), 0.5*n+1], r 336 return T1, T2 337 return ctx.hypercomb(h, [n], **kwargs) 338 339@defun 340def bei(ctx, n, z, **kwargs): 341 n = ctx.convert(n) 342 z = ctx.convert(z) 343 # http://functions.wolfram.com/Bessel-TypeFunctions/KelvinBei2/26/01/02/0001/ 344 def h(n): 345 r = -(z/4)**4 346 cos, sin = ctx.cospi_sinpi(0.75*n) 347 T1 = [cos, z/2], [1, n+2], [], [n+2], [], [1.5, 0.5*(n+3), 0.5*n+1], r 348 T2 = [sin, z/2], [1, n], [], [n+1], [], [0.5, 0.5*(n+1), 0.5*n+1], r 349 return T1, T2 350 return ctx.hypercomb(h, [n], **kwargs) 351 352@defun 353def ker(ctx, n, z, **kwargs): 354 n = ctx.convert(n) 355 z = ctx.convert(z) 356 # http://functions.wolfram.com/Bessel-TypeFunctions/KelvinKer2/26/01/02/0001/ 357 def h(n): 358 r = -(z/4)**4 359 cos1, sin1 = ctx.cospi_sinpi(0.25*n) 360 cos2, sin2 = ctx.cospi_sinpi(0.75*n) 361 T1 = [2, z, 4*cos1], [-n-3, n, 1], [-n], [], [], [0.5, 0.5*(1+n), 0.5*(n+2)], r 362 T2 = [2, z, -sin1], [-n-3, 2+n, 1], [-n-1], [], [], [1.5, 0.5*(3+n), 0.5*(n+2)], r 363 T3 = [2, z, 4*cos2], [n-3, -n, 1], [n], [], [], [0.5, 0.5*(1-n), 1-0.5*n], r 364 T4 = [2, z, -sin2], [n-3, 2-n, 1], [n-1], [], [], [1.5, 0.5*(3-n), 1-0.5*n], r 365 return T1, T2, T3, T4 366 return ctx.hypercomb(h, [n], **kwargs) 367 368@defun 369def kei(ctx, n, z, **kwargs): 370 n = ctx.convert(n) 371 z = ctx.convert(z) 372 # http://functions.wolfram.com/Bessel-TypeFunctions/KelvinKei2/26/01/02/0001/ 373 def h(n): 374 r = -(z/4)**4 375 cos1, sin1 = ctx.cospi_sinpi(0.75*n) 376 cos2, sin2 = ctx.cospi_sinpi(0.25*n) 377 T1 = [-cos1, 2, z], [1, n-3, 2-n], [n-1], [], [], [1.5, 0.5*(3-n), 1-0.5*n], r 378 T2 = [-sin1, 2, z], [1, n-1, -n], [n], [], [], [0.5, 0.5*(1-n), 1-0.5*n], r 379 T3 = [-sin2, 2, z], [1, -n-1, n], [-n], [], [], [0.5, 0.5*(n+1), 0.5*(n+2)], r 380 T4 = [-cos2, 2, z], [1, -n-3, n+2], [-n-1], [], [], [1.5, 0.5*(n+3), 0.5*(n+2)], r 381 return T1, T2, T3, T4 382 return ctx.hypercomb(h, [n], **kwargs) 383 384# TODO: do this more generically? 385def c_memo(f): 386 name = f.__name__ 387 def f_wrapped(ctx): 388 cache = ctx._misc_const_cache 389 prec = ctx.prec 390 p,v = cache.get(name, (-1,0)) 391 if p >= prec: 392 return +v 393 else: 394 cache[name] = (prec, f(ctx)) 395 return cache[name][1] 396 return f_wrapped 397 398@c_memo 399def _airyai_C1(ctx): 400 return 1 / (ctx.cbrt(9) * ctx.gamma(ctx.mpf(2)/3)) 401 402@c_memo 403def _airyai_C2(ctx): 404 return -1 / (ctx.cbrt(3) * ctx.gamma(ctx.mpf(1)/3)) 405 406@c_memo 407def _airybi_C1(ctx): 408 return 1 / (ctx.nthroot(3,6) * ctx.gamma(ctx.mpf(2)/3)) 409 410@c_memo 411def _airybi_C2(ctx): 412 return ctx.nthroot(3,6) / ctx.gamma(ctx.mpf(1)/3) 413 414def _airybi_n2_inf(ctx): 415 prec = ctx.prec 416 try: 417 v = ctx.power(3,'2/3')*ctx.gamma('2/3')/(2*ctx.pi) 418 finally: 419 ctx.prec = prec 420 return +v 421 422# Derivatives at z = 0 423# TODO: could be expressed more elegantly using triple factorials 424def _airyderiv_0(ctx, z, n, ntype, which): 425 if ntype == 'Z': 426 if n < 0: 427 return z 428 r = ctx.mpq_1_3 429 prec = ctx.prec 430 try: 431 ctx.prec += 10 432 v = ctx.gamma((n+1)*r) * ctx.power(3,n*r) / ctx.pi 433 if which == 0: 434 v *= ctx.sinpi(2*(n+1)*r) 435 v /= ctx.power(3,'2/3') 436 else: 437 v *= abs(ctx.sinpi(2*(n+1)*r)) 438 v /= ctx.power(3,'1/6') 439 finally: 440 ctx.prec = prec 441 return +v + z 442 else: 443 # singular (does the limit exist?) 444 raise NotImplementedError 445 446@defun 447def airyai(ctx, z, derivative=0, **kwargs): 448 z = ctx.convert(z) 449 if derivative: 450 n, ntype = ctx._convert_param(derivative) 451 else: 452 n = 0 453 # Values at infinities 454 if not ctx.isnormal(z) and z: 455 if n and ntype == 'Z': 456 if n == -1: 457 if z == ctx.inf: 458 return ctx.mpf(1)/3 + 1/z 459 if z == ctx.ninf: 460 return ctx.mpf(-2)/3 + 1/z 461 if n < -1: 462 if z == ctx.inf: 463 return z 464 if z == ctx.ninf: 465 return (-1)**n * (-z) 466 if (not n) and z == ctx.inf or z == ctx.ninf: 467 return 1/z 468 # TODO: limits 469 raise ValueError("essential singularity of Ai(z)") 470 # Account for exponential scaling 471 if z: 472 extraprec = max(0, int(1.5*ctx.mag(z))) 473 else: 474 extraprec = 0 475 if n: 476 if n == 1: 477 def h(): 478 # http://functions.wolfram.com/03.07.06.0005.01 479 if ctx._re(z) > 4: 480 ctx.prec += extraprec 481 w = z**1.5; r = -0.75/w; u = -2*w/3 482 ctx.prec -= extraprec 483 C = -ctx.exp(u)/(2*ctx.sqrt(ctx.pi))*ctx.nthroot(z,4) 484 return ([C],[1],[],[],[(-1,6),(7,6)],[],r), 485 # http://functions.wolfram.com/03.07.26.0001.01 486 else: 487 ctx.prec += extraprec 488 w = z**3 / 9 489 ctx.prec -= extraprec 490 C1 = _airyai_C1(ctx) * 0.5 491 C2 = _airyai_C2(ctx) 492 T1 = [C1,z],[1,2],[],[],[],[ctx.mpq_5_3],w 493 T2 = [C2],[1],[],[],[],[ctx.mpq_1_3],w 494 return T1, T2 495 return ctx.hypercomb(h, [], **kwargs) 496 else: 497 if z == 0: 498 return _airyderiv_0(ctx, z, n, ntype, 0) 499 # http://functions.wolfram.com/03.05.20.0004.01 500 def h(n): 501 ctx.prec += extraprec 502 w = z**3/9 503 ctx.prec -= extraprec 504 q13,q23,q43 = ctx.mpq_1_3, ctx.mpq_2_3, ctx.mpq_4_3 505 a1=q13; a2=1; b1=(1-n)*q13; b2=(2-n)*q13; b3=1-n*q13 506 T1 = [3, z], [n-q23, -n], [a1], [b1,b2,b3], \ 507 [a1,a2], [b1,b2,b3], w 508 a1=q23; b1=(2-n)*q13; b2=1-n*q13; b3=(4-n)*q13 509 T2 = [3, z, -z], [n-q43, -n, 1], [a1], [b1,b2,b3], \ 510 [a1,a2], [b1,b2,b3], w 511 return T1, T2 512 v = ctx.hypercomb(h, [n], **kwargs) 513 if ctx._is_real_type(z) and ctx.isint(n): 514 v = ctx._re(v) 515 return v 516 else: 517 def h(): 518 if ctx._re(z) > 4: 519 # We could use 1F1, but it results in huge cancellation; 520 # the following expansion is better. 521 # TODO: asymptotic series for derivatives 522 ctx.prec += extraprec 523 w = z**1.5; r = -0.75/w; u = -2*w/3 524 ctx.prec -= extraprec 525 C = ctx.exp(u)/(2*ctx.sqrt(ctx.pi)*ctx.nthroot(z,4)) 526 return ([C],[1],[],[],[(1,6),(5,6)],[],r), 527 else: 528 ctx.prec += extraprec 529 w = z**3 / 9 530 ctx.prec -= extraprec 531 C1 = _airyai_C1(ctx) 532 C2 = _airyai_C2(ctx) 533 T1 = [C1],[1],[],[],[],[ctx.mpq_2_3],w 534 T2 = [z*C2],[1],[],[],[],[ctx.mpq_4_3],w 535 return T1, T2 536 return ctx.hypercomb(h, [], **kwargs) 537 538@defun 539def airybi(ctx, z, derivative=0, **kwargs): 540 z = ctx.convert(z) 541 if derivative: 542 n, ntype = ctx._convert_param(derivative) 543 else: 544 n = 0 545 # Values at infinities 546 if not ctx.isnormal(z) and z: 547 if n and ntype == 'Z': 548 if z == ctx.inf: 549 return z 550 if z == ctx.ninf: 551 if n == -1: 552 return 1/z 553 if n == -2: 554 return _airybi_n2_inf(ctx) 555 if n < -2: 556 return (-1)**n * (-z) 557 if not n: 558 if z == ctx.inf: 559 return z 560 if z == ctx.ninf: 561 return 1/z 562 # TODO: limits 563 raise ValueError("essential singularity of Bi(z)") 564 if z: 565 extraprec = max(0, int(1.5*ctx.mag(z))) 566 else: 567 extraprec = 0 568 if n: 569 if n == 1: 570 # http://functions.wolfram.com/03.08.26.0001.01 571 def h(): 572 ctx.prec += extraprec 573 w = z**3 / 9 574 ctx.prec -= extraprec 575 C1 = _airybi_C1(ctx)*0.5 576 C2 = _airybi_C2(ctx) 577 T1 = [C1,z],[1,2],[],[],[],[ctx.mpq_5_3],w 578 T2 = [C2],[1],[],[],[],[ctx.mpq_1_3],w 579 return T1, T2 580 return ctx.hypercomb(h, [], **kwargs) 581 else: 582 if z == 0: 583 return _airyderiv_0(ctx, z, n, ntype, 1) 584 def h(n): 585 ctx.prec += extraprec 586 w = z**3/9 587 ctx.prec -= extraprec 588 q13,q23,q43 = ctx.mpq_1_3, ctx.mpq_2_3, ctx.mpq_4_3 589 q16 = ctx.mpq_1_6 590 q56 = ctx.mpq_5_6 591 a1=q13; a2=1; b1=(1-n)*q13; b2=(2-n)*q13; b3=1-n*q13 592 T1 = [3, z], [n-q16, -n], [a1], [b1,b2,b3], \ 593 [a1,a2], [b1,b2,b3], w 594 a1=q23; b1=(2-n)*q13; b2=1-n*q13; b3=(4-n)*q13 595 T2 = [3, z], [n-q56, 1-n], [a1], [b1,b2,b3], \ 596 [a1,a2], [b1,b2,b3], w 597 return T1, T2 598 v = ctx.hypercomb(h, [n], **kwargs) 599 if ctx._is_real_type(z) and ctx.isint(n): 600 v = ctx._re(v) 601 return v 602 else: 603 def h(): 604 ctx.prec += extraprec 605 w = z**3 / 9 606 ctx.prec -= extraprec 607 C1 = _airybi_C1(ctx) 608 C2 = _airybi_C2(ctx) 609 T1 = [C1],[1],[],[],[],[ctx.mpq_2_3],w 610 T2 = [z*C2],[1],[],[],[],[ctx.mpq_4_3],w 611 return T1, T2 612 return ctx.hypercomb(h, [], **kwargs) 613 614def _airy_zero(ctx, which, k, derivative, complex=False): 615 # Asymptotic formulas are given in DLMF section 9.9 616 def U(t): return t**(2/3.)*(1-7/(t**2*48)) 617 def T(t): return t**(2/3.)*(1+5/(t**2*48)) 618 k = int(k) 619 if k < 1: 620 raise ValueError("k cannot be less than 1") 621 if not derivative in (0,1): 622 raise ValueError("Derivative should lie between 0 and 1") 623 if which == 0: 624 if derivative: 625 return ctx.findroot(lambda z: ctx.airyai(z,1), 626 -U(3*ctx.pi*(4*k-3)/8)) 627 return ctx.findroot(ctx.airyai, -T(3*ctx.pi*(4*k-1)/8)) 628 if which == 1 and complex == False: 629 if derivative: 630 return ctx.findroot(lambda z: ctx.airybi(z,1), 631 -U(3*ctx.pi*(4*k-1)/8)) 632 return ctx.findroot(ctx.airybi, -T(3*ctx.pi*(4*k-3)/8)) 633 if which == 1 and complex == True: 634 if derivative: 635 t = 3*ctx.pi*(4*k-3)/8 + 0.75j*ctx.ln2 636 s = ctx.expjpi(ctx.mpf(1)/3) * T(t) 637 return ctx.findroot(lambda z: ctx.airybi(z,1), s) 638 t = 3*ctx.pi*(4*k-1)/8 + 0.75j*ctx.ln2 639 s = ctx.expjpi(ctx.mpf(1)/3) * U(t) 640 return ctx.findroot(ctx.airybi, s) 641 642@defun 643def airyaizero(ctx, k, derivative=0): 644 return _airy_zero(ctx, 0, k, derivative, False) 645 646@defun 647def airybizero(ctx, k, derivative=0, complex=False): 648 return _airy_zero(ctx, 1, k, derivative, complex) 649 650def _scorer(ctx, z, which, kwargs): 651 z = ctx.convert(z) 652 if ctx.isinf(z): 653 if z == ctx.inf: 654 if which == 0: return 1/z 655 if which == 1: return z 656 if z == ctx.ninf: 657 return 1/z 658 raise ValueError("essential singularity") 659 if z: 660 extraprec = max(0, int(1.5*ctx.mag(z))) 661 else: 662 extraprec = 0 663 if kwargs.get('derivative'): 664 raise NotImplementedError 665 # Direct asymptotic expansions, to avoid 666 # exponentially large cancellation 667 try: 668 if ctx.mag(z) > 3: 669 if which == 0 and abs(ctx.arg(z)) < ctx.pi/3 * 0.999: 670 def h(): 671 return (([ctx.pi,z],[-1,-1],[],[],[(1,3),(2,3),1],[],9/z**3),) 672 return ctx.hypercomb(h, [], maxterms=ctx.prec, force_series=True) 673 if which == 1 and abs(ctx.arg(-z)) < 2*ctx.pi/3 * 0.999: 674 def h(): 675 return (([-ctx.pi,z],[-1,-1],[],[],[(1,3),(2,3),1],[],9/z**3),) 676 return ctx.hypercomb(h, [], maxterms=ctx.prec, force_series=True) 677 except ctx.NoConvergence: 678 pass 679 def h(): 680 A = ctx.airybi(z, **kwargs)/3 681 B = -2*ctx.pi 682 if which == 1: 683 A *= 2 684 B *= -1 685 ctx.prec += extraprec 686 w = z**3/9 687 ctx.prec -= extraprec 688 T1 = [A], [1], [], [], [], [], 0 689 T2 = [B,z], [-1,2], [], [], [1], [ctx.mpq_4_3,ctx.mpq_5_3], w 690 return T1, T2 691 return ctx.hypercomb(h, [], **kwargs) 692 693@defun 694def scorergi(ctx, z, **kwargs): 695 return _scorer(ctx, z, 0, kwargs) 696 697@defun 698def scorerhi(ctx, z, **kwargs): 699 return _scorer(ctx, z, 1, kwargs) 700 701@defun_wrapped 702def coulombc(ctx, l, eta, _cache={}): 703 if (l, eta) in _cache and _cache[l,eta][0] >= ctx.prec: 704 return +_cache[l,eta][1] 705 G3 = ctx.loggamma(2*l+2) 706 G1 = ctx.loggamma(1+l+ctx.j*eta) 707 G2 = ctx.loggamma(1+l-ctx.j*eta) 708 v = 2**l * ctx.exp((-ctx.pi*eta+G1+G2)/2 - G3) 709 if not (ctx.im(l) or ctx.im(eta)): 710 v = ctx.re(v) 711 _cache[l,eta] = (ctx.prec, v) 712 return v 713 714@defun_wrapped 715def coulombf(ctx, l, eta, z, w=1, chop=True, **kwargs): 716 # Regular Coulomb wave function 717 # Note: w can be either 1 or -1; the other may be better in some cases 718 # TODO: check that chop=True chops when and only when it should 719 #ctx.prec += 10 720 def h(l, eta): 721 try: 722 jw = ctx.j*w 723 jwz = ctx.fmul(jw, z, exact=True) 724 jwz2 = ctx.fmul(jwz, -2, exact=True) 725 C = ctx.coulombc(l, eta) 726 T1 = [C, z, ctx.exp(jwz)], [1, l+1, 1], [], [], [1+l+jw*eta], \ 727 [2*l+2], jwz2 728 except ValueError: 729 T1 = [0], [-1], [], [], [], [], 0 730 return (T1,) 731 v = ctx.hypercomb(h, [l,eta], **kwargs) 732 if chop and (not ctx.im(l)) and (not ctx.im(eta)) and (not ctx.im(z)) and \ 733 (ctx.re(z) >= 0): 734 v = ctx.re(v) 735 return v 736 737@defun_wrapped 738def _coulomb_chi(ctx, l, eta, _cache={}): 739 if (l, eta) in _cache and _cache[l,eta][0] >= ctx.prec: 740 return _cache[l,eta][1] 741 def terms(): 742 l2 = -l-1 743 jeta = ctx.j*eta 744 return [ctx.loggamma(1+l+jeta) * (-0.5j), 745 ctx.loggamma(1+l-jeta) * (0.5j), 746 ctx.loggamma(1+l2+jeta) * (0.5j), 747 ctx.loggamma(1+l2-jeta) * (-0.5j), 748 -(l+0.5)*ctx.pi] 749 v = ctx.sum_accurately(terms, 1) 750 _cache[l,eta] = (ctx.prec, v) 751 return v 752 753@defun_wrapped 754def coulombg(ctx, l, eta, z, w=1, chop=True, **kwargs): 755 # Irregular Coulomb wave function 756 # Note: w can be either 1 or -1; the other may be better in some cases 757 # TODO: check that chop=True chops when and only when it should 758 if not ctx._im(l): 759 l = ctx._re(l) # XXX: for isint 760 def h(l, eta): 761 # Force perturbation for integers and half-integers 762 if ctx.isint(l*2): 763 T1 = [0], [-1], [], [], [], [], 0 764 return (T1,) 765 l2 = -l-1 766 try: 767 chi = ctx._coulomb_chi(l, eta) 768 jw = ctx.j*w 769 s = ctx.sin(chi); c = ctx.cos(chi) 770 C1 = ctx.coulombc(l,eta) 771 C2 = ctx.coulombc(l2,eta) 772 u = ctx.exp(jw*z) 773 x = -2*jw*z 774 T1 = [s, C1, z, u, c], [-1, 1, l+1, 1, 1], [], [], \ 775 [1+l+jw*eta], [2*l+2], x 776 T2 = [-s, C2, z, u], [-1, 1, l2+1, 1], [], [], \ 777 [1+l2+jw*eta], [2*l2+2], x 778 return T1, T2 779 except ValueError: 780 T1 = [0], [-1], [], [], [], [], 0 781 return (T1,) 782 v = ctx.hypercomb(h, [l,eta], **kwargs) 783 if chop and (not ctx._im(l)) and (not ctx._im(eta)) and (not ctx._im(z)) and \ 784 (ctx._re(z) >= 0): 785 v = ctx._re(v) 786 return v 787 788def mcmahon(ctx,kind,prime,v,m): 789 """ 790 Computes an estimate for the location of the Bessel function zero 791 j_{v,m}, y_{v,m}, j'_{v,m} or y'_{v,m} using McMahon's asymptotic 792 expansion (Abramowitz & Stegun 9.5.12-13, DLMF 20.21(vi)). 793 794 Returns (r,err) where r is the estimated location of the root 795 and err is a positive number estimating the error of the 796 asymptotic expansion. 797 """ 798 u = 4*v**2 799 if kind == 1 and not prime: b = (4*m+2*v-1)*ctx.pi/4 800 if kind == 2 and not prime: b = (4*m+2*v-3)*ctx.pi/4 801 if kind == 1 and prime: b = (4*m+2*v-3)*ctx.pi/4 802 if kind == 2 and prime: b = (4*m+2*v-1)*ctx.pi/4 803 if not prime: 804 s1 = b 805 s2 = -(u-1)/(8*b) 806 s3 = -4*(u-1)*(7*u-31)/(3*(8*b)**3) 807 s4 = -32*(u-1)*(83*u**2-982*u+3779)/(15*(8*b)**5) 808 s5 = -64*(u-1)*(6949*u**3-153855*u**2+1585743*u-6277237)/(105*(8*b)**7) 809 if prime: 810 s1 = b 811 s2 = -(u+3)/(8*b) 812 s3 = -4*(7*u**2+82*u-9)/(3*(8*b)**3) 813 s4 = -32*(83*u**3+2075*u**2-3039*u+3537)/(15*(8*b)**5) 814 s5 = -64*(6949*u**4+296492*u**3-1248002*u**2+7414380*u-5853627)/(105*(8*b)**7) 815 terms = [s1,s2,s3,s4,s5] 816 s = s1 817 err = 0.0 818 for i in range(1,len(terms)): 819 if abs(terms[i]) < abs(terms[i-1]): 820 s += terms[i] 821 else: 822 err = abs(terms[i]) 823 if i == len(terms)-1: 824 err = abs(terms[-1]) 825 return s, err 826 827def generalized_bisection(ctx,f,a,b,n): 828 """ 829 Given f known to have exactly n simple roots within [a,b], 830 return a list of n intervals isolating the roots 831 and having opposite signs at the endpoints. 832 833 TODO: this can be optimized, e.g. by reusing evaluation points. 834 """ 835 if n < 1: 836 raise ValueError("n cannot be less than 1") 837 N = n+1 838 points = [] 839 signs = [] 840 while 1: 841 points = ctx.linspace(a,b,N) 842 signs = [ctx.sign(f(x)) for x in points] 843 ok_intervals = [(points[i],points[i+1]) for i in range(N-1) \ 844 if signs[i]*signs[i+1] == -1] 845 if len(ok_intervals) == n: 846 return ok_intervals 847 N = N*2 848 849def find_in_interval(ctx, f, ab): 850 return ctx.findroot(f, ab, solver='illinois', verify=False) 851 852def bessel_zero(ctx, kind, prime, v, m, isoltol=0.01, _interval_cache={}): 853 prec = ctx.prec 854 workprec = max(prec, ctx.mag(v), ctx.mag(m))+10 855 try: 856 ctx.prec = workprec 857 v = ctx.mpf(v) 858 m = int(m) 859 prime = int(prime) 860 if v < 0: 861 raise ValueError("v cannot be negative") 862 if m < 1: 863 raise ValueError("m cannot be less than 1") 864 if not prime in (0,1): 865 raise ValueError("prime should lie between 0 and 1") 866 if kind == 1: 867 if prime: f = lambda x: ctx.besselj(v,x,derivative=1) 868 else: f = lambda x: ctx.besselj(v,x) 869 if kind == 2: 870 if prime: f = lambda x: ctx.bessely(v,x,derivative=1) 871 else: f = lambda x: ctx.bessely(v,x) 872 # The first root of J' is very close to 0 for small 873 # orders, and this needs to be special-cased 874 if kind == 1 and prime and m == 1: 875 if v == 0: 876 return ctx.zero 877 if v <= 1: 878 # TODO: use v <= j'_{v,1} < y_{v,1}? 879 r = 2*ctx.sqrt(v*(1+v)/(v+2)) 880 return find_in_interval(ctx, f, (r/10, 2*r)) 881 if (kind,prime,v,m) in _interval_cache: 882 return find_in_interval(ctx, f, _interval_cache[kind,prime,v,m]) 883 r, err = mcmahon(ctx, kind, prime, v, m) 884 if err < isoltol: 885 return find_in_interval(ctx, f, (r-isoltol, r+isoltol)) 886 # An x such that 0 < x < r_{v,1} 887 if kind == 1 and not prime: low = 2.4 888 if kind == 1 and prime: low = 1.8 889 if kind == 2 and not prime: low = 0.8 890 if kind == 2 and prime: low = 2.0 891 n = m+1 892 while 1: 893 r1, err = mcmahon(ctx, kind, prime, v, n) 894 if err < isoltol: 895 r2, err2 = mcmahon(ctx, kind, prime, v, n+1) 896 intervals = generalized_bisection(ctx, f, low, 0.5*(r1+r2), n) 897 for k, ab in enumerate(intervals): 898 _interval_cache[kind,prime,v,k+1] = ab 899 return find_in_interval(ctx, f, intervals[m-1]) 900 else: 901 n = n*2 902 finally: 903 ctx.prec = prec 904 905@defun 906def besseljzero(ctx, v, m, derivative=0): 907 r""" 908 For a real order `\nu \ge 0` and a positive integer `m`, returns 909 `j_{\nu,m}`, the `m`-th positive zero of the Bessel function of the 910 first kind `J_{\nu}(z)` (see :func:`~mpmath.besselj`). Alternatively, 911 with *derivative=1*, gives the first nonnegative simple zero 912 `j'_{\nu,m}` of `J'_{\nu}(z)`. 913 914 The indexing convention is that used by Abramowitz & Stegun 915 and the DLMF. Note the special case `j'_{0,1} = 0`, while all other 916 zeros are positive. In effect, only simple zeros are counted 917 (all zeros of Bessel functions are simple except possibly `z = 0`) 918 and `j_{\nu,m}` becomes a monotonic function of both `\nu` 919 and `m`. 920 921 The zeros are interlaced according to the inequalities 922 923 .. math :: 924 925 j'_{\nu,k} < j_{\nu,k} < j'_{\nu,k+1} 926 927 j_{\nu,1} < j_{\nu+1,2} < j_{\nu,2} < j_{\nu+1,2} < j_{\nu,3} < \cdots 928 929 **Examples** 930 931 Initial zeros of the Bessel functions `J_0(z), J_1(z), J_2(z)`:: 932 933 >>> from mpmath import * 934 >>> mp.dps = 25; mp.pretty = True 935 >>> besseljzero(0,1); besseljzero(0,2); besseljzero(0,3) 936 2.404825557695772768621632 937 5.520078110286310649596604 938 8.653727912911012216954199 939 >>> besseljzero(1,1); besseljzero(1,2); besseljzero(1,3) 940 3.831705970207512315614436 941 7.01558666981561875353705 942 10.17346813506272207718571 943 >>> besseljzero(2,1); besseljzero(2,2); besseljzero(2,3) 944 5.135622301840682556301402 945 8.417244140399864857783614 946 11.61984117214905942709415 947 948 Initial zeros of `J'_0(z), J'_1(z), J'_2(z)`:: 949 950 0.0 951 3.831705970207512315614436 952 7.01558666981561875353705 953 >>> besseljzero(1,1,1); besseljzero(1,2,1); besseljzero(1,3,1) 954 1.84118378134065930264363 955 5.331442773525032636884016 956 8.536316366346285834358961 957 >>> besseljzero(2,1,1); besseljzero(2,2,1); besseljzero(2,3,1) 958 3.054236928227140322755932 959 6.706133194158459146634394 960 9.969467823087595793179143 961 962 Zeros with large index:: 963 964 >>> besseljzero(0,100); besseljzero(0,1000); besseljzero(0,10000) 965 313.3742660775278447196902 966 3140.807295225078628895545 967 31415.14114171350798533666 968 >>> besseljzero(5,100); besseljzero(5,1000); besseljzero(5,10000) 969 321.1893195676003157339222 970 3148.657306813047523500494 971 31422.9947255486291798943 972 >>> besseljzero(0,100,1); besseljzero(0,1000,1); besseljzero(0,10000,1) 973 311.8018681873704508125112 974 3139.236339643802482833973 975 31413.57032947022399485808 976 977 Zeros of functions with large order:: 978 979 >>> besseljzero(50,1) 980 57.11689916011917411936228 981 >>> besseljzero(50,2) 982 62.80769876483536093435393 983 >>> besseljzero(50,100) 984 388.6936600656058834640981 985 >>> besseljzero(50,1,1) 986 52.99764038731665010944037 987 >>> besseljzero(50,2,1) 988 60.02631933279942589882363 989 >>> besseljzero(50,100,1) 990 387.1083151608726181086283 991 992 Zeros of functions with fractional order:: 993 994 >>> besseljzero(0.5,1); besseljzero(1.5,1); besseljzero(2.25,4) 995 3.141592653589793238462643 996 4.493409457909064175307881 997 15.15657692957458622921634 998 999 Both `J_{\nu}(z)` and `J'_{\nu}(z)` can be expressed as infinite 1000 products over their zeros:: 1001 1002 >>> v,z = 2, mpf(1) 1003 >>> (z/2)**v/gamma(v+1) * \ 1004 ... nprod(lambda k: 1-(z/besseljzero(v,k))**2, [1,inf]) 1005 ... 1006 0.1149034849319004804696469 1007 >>> besselj(v,z) 1008 0.1149034849319004804696469 1009 >>> (z/2)**(v-1)/2/gamma(v) * \ 1010 ... nprod(lambda k: 1-(z/besseljzero(v,k,1))**2, [1,inf]) 1011 ... 1012 0.2102436158811325550203884 1013 >>> besselj(v,z,1) 1014 0.2102436158811325550203884 1015 1016 """ 1017 return +bessel_zero(ctx, 1, derivative, v, m) 1018 1019@defun 1020def besselyzero(ctx, v, m, derivative=0): 1021 r""" 1022 For a real order `\nu \ge 0` and a positive integer `m`, returns 1023 `y_{\nu,m}`, the `m`-th positive zero of the Bessel function of the 1024 second kind `Y_{\nu}(z)` (see :func:`~mpmath.bessely`). Alternatively, 1025 with *derivative=1*, gives the first positive zero `y'_{\nu,m}` of 1026 `Y'_{\nu}(z)`. 1027 1028 The zeros are interlaced according to the inequalities 1029 1030 .. math :: 1031 1032 y_{\nu,k} < y'_{\nu,k} < y_{\nu,k+1} 1033 1034 y_{\nu,1} < y_{\nu+1,2} < y_{\nu,2} < y_{\nu+1,2} < y_{\nu,3} < \cdots 1035 1036 **Examples** 1037 1038 Initial zeros of the Bessel functions `Y_0(z), Y_1(z), Y_2(z)`:: 1039 1040 >>> from mpmath import * 1041 >>> mp.dps = 25; mp.pretty = True 1042 >>> besselyzero(0,1); besselyzero(0,2); besselyzero(0,3) 1043 0.8935769662791675215848871 1044 3.957678419314857868375677 1045 7.086051060301772697623625 1046 >>> besselyzero(1,1); besselyzero(1,2); besselyzero(1,3) 1047 2.197141326031017035149034 1048 5.429681040794135132772005 1049 8.596005868331168926429606 1050 >>> besselyzero(2,1); besselyzero(2,2); besselyzero(2,3) 1051 3.384241767149593472701426 1052 6.793807513268267538291167 1053 10.02347797936003797850539 1054 1055 Initial zeros of `Y'_0(z), Y'_1(z), Y'_2(z)`:: 1056 1057 >>> besselyzero(0,1,1); besselyzero(0,2,1); besselyzero(0,3,1) 1058 2.197141326031017035149034 1059 5.429681040794135132772005 1060 8.596005868331168926429606 1061 >>> besselyzero(1,1,1); besselyzero(1,2,1); besselyzero(1,3,1) 1062 3.683022856585177699898967 1063 6.941499953654175655751944 1064 10.12340465543661307978775 1065 >>> besselyzero(2,1,1); besselyzero(2,2,1); besselyzero(2,3,1) 1066 5.002582931446063945200176 1067 8.350724701413079526349714 1068 11.57419546521764654624265 1069 1070 Zeros with large index:: 1071 1072 >>> besselyzero(0,100); besselyzero(0,1000); besselyzero(0,10000) 1073 311.8034717601871549333419 1074 3139.236498918198006794026 1075 31413.57034538691205229188 1076 >>> besselyzero(5,100); besselyzero(5,1000); besselyzero(5,10000) 1077 319.6183338562782156235062 1078 3147.086508524556404473186 1079 31421.42392920214673402828 1080 >>> besselyzero(0,100,1); besselyzero(0,1000,1); besselyzero(0,10000,1) 1081 313.3726705426359345050449 1082 3140.807136030340213610065 1083 31415.14112579761578220175 1084 1085 Zeros of functions with large order:: 1086 1087 >>> besselyzero(50,1) 1088 53.50285882040036394680237 1089 >>> besselyzero(50,2) 1090 60.11244442774058114686022 1091 >>> besselyzero(50,100) 1092 387.1096509824943957706835 1093 >>> besselyzero(50,1,1) 1094 56.96290427516751320063605 1095 >>> besselyzero(50,2,1) 1096 62.74888166945933944036623 1097 >>> besselyzero(50,100,1) 1098 388.6923300548309258355475 1099 1100 Zeros of functions with fractional order:: 1101 1102 >>> besselyzero(0.5,1); besselyzero(1.5,1); besselyzero(2.25,4) 1103 1.570796326794896619231322 1104 2.798386045783887136720249 1105 13.56721208770735123376018 1106 1107 """ 1108 return +bessel_zero(ctx, 2, derivative, v, m) 1109