Coverage for /usr/lib/python3/dist-packages/mpmath/functions/elliptic.py: 8%

455 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1r""" 

2Elliptic functions historically comprise the elliptic integrals 

3and their inverses, and originate from the problem of computing the 

4arc length of an ellipse. From a more modern point of view, 

5an elliptic function is defined as a doubly periodic function, i.e. 

6a function which satisfies 

7 

8.. math :: 

9 

10 f(z + 2 \omega_1) = f(z + 2 \omega_2) = f(z) 

11 

12for some half-periods `\omega_1, \omega_2` with 

13`\mathrm{Im}[\omega_1 / \omega_2] > 0`. The canonical elliptic 

14functions are the Jacobi elliptic functions. More broadly, this section 

15includes quasi-doubly periodic functions (such as the Jacobi theta 

16functions) and other functions useful in the study of elliptic functions. 

17 

18Many different conventions for the arguments of 

19elliptic functions are in use. It is even standard to use 

20different parameterizations for different functions in the same 

21text or software (and mpmath is no exception). 

22The usual parameters are the elliptic nome `q`, which usually 

23must satisfy `|q| < 1`; the elliptic parameter `m` (an arbitrary 

24complex number); the elliptic modulus `k` (an arbitrary complex 

25number); and the half-period ratio `\tau`, which usually must 

26satisfy `\mathrm{Im}[\tau] > 0`. 

27These quantities can be expressed in terms of each other 

28using the following relations: 

29 

30.. math :: 

31 

32 m = k^2 

33 

34.. math :: 

35 

36 \tau = i \frac{K(1-m)}{K(m)} 

37 

38.. math :: 

39 

40 q = e^{i \pi \tau} 

41 

42.. math :: 

43 

44 k = \frac{\vartheta_2^2(q)}{\vartheta_3^2(q)} 

45 

46In addition, an alternative definition is used for the nome in 

47number theory, which we here denote by q-bar: 

48 

49.. math :: 

50 

51 \bar{q} = q^2 = e^{2 i \pi \tau} 

52 

53For convenience, mpmath provides functions to convert 

54between the various parameters (:func:`~mpmath.qfrom`, :func:`~mpmath.mfrom`, 

55:func:`~mpmath.kfrom`, :func:`~mpmath.taufrom`, :func:`~mpmath.qbarfrom`). 

56 

57**References** 

58 

591. [AbramowitzStegun]_ 

60 

612. [WhittakerWatson]_ 

62 

63""" 

64 

65from .functions import defun, defun_wrapped 

66 

67@defun_wrapped 

68def eta(ctx, tau): 

69 r""" 

70 Returns the Dedekind eta function of tau in the upper half-plane. 

71 

72 >>> from mpmath import * 

73 >>> mp.dps = 25; mp.pretty = True 

74 >>> eta(1j); gamma(0.25) / (2*pi**0.75) 

75 (0.7682254223260566590025942 + 0.0j) 

76 0.7682254223260566590025942 

77 >>> tau = sqrt(2) + sqrt(5)*1j 

78 >>> eta(-1/tau); sqrt(-1j*tau) * eta(tau) 

79 (0.9022859908439376463573294 + 0.07985093673948098408048575j) 

80 (0.9022859908439376463573295 + 0.07985093673948098408048575j) 

81 >>> eta(tau+1); exp(pi*1j/12) * eta(tau) 

82 (0.4493066139717553786223114 + 0.3290014793877986663915939j) 

83 (0.4493066139717553786223114 + 0.3290014793877986663915939j) 

84 >>> f = lambda z: diff(eta, z) / eta(z) 

85 >>> chop(36*diff(f,tau)**2 - 24*diff(f,tau,2)*f(tau) + diff(f,tau,3)) 

86 0.0 

87 

88 """ 

89 if ctx.im(tau) <= 0.0: 

90 raise ValueError("eta is only defined in the upper half-plane") 

91 q = ctx.expjpi(tau/12) 

92 return q * ctx.qp(q**24) 

93 

94def nome(ctx, m): 

95 m = ctx.convert(m) 

96 if not m: 

97 return m 

98 if m == ctx.one: 

99 return m 

100 if ctx.isnan(m): 

101 return m 

102 if ctx.isinf(m): 

103 if m == ctx.ninf: 

104 return type(m)(-1) 

105 else: 

106 return ctx.mpc(-1) 

107 a = ctx.ellipk(ctx.one-m) 

108 b = ctx.ellipk(m) 

109 v = ctx.exp(-ctx.pi*a/b) 

110 if not ctx._im(m) and ctx._re(m) < 1: 

111 if ctx._is_real_type(m): 

112 return v.real 

113 else: 

114 return v.real + 0j 

115 elif m == 2: 

116 v = ctx.mpc(0, v.imag) 

117 return v 

118 

119@defun_wrapped 

120def qfrom(ctx, q=None, m=None, k=None, tau=None, qbar=None): 

121 r""" 

122 Returns the elliptic nome `q`, given any of `q, m, k, \tau, \bar{q}`:: 

123 

124 >>> from mpmath import * 

125 >>> mp.dps = 25; mp.pretty = True 

126 >>> qfrom(q=0.25) 

127 0.25 

128 >>> qfrom(m=mfrom(q=0.25)) 

129 0.25 

130 >>> qfrom(k=kfrom(q=0.25)) 

131 0.25 

132 >>> qfrom(tau=taufrom(q=0.25)) 

133 (0.25 + 0.0j) 

134 >>> qfrom(qbar=qbarfrom(q=0.25)) 

135 0.25 

136 

137 """ 

138 if q is not None: 

139 return ctx.convert(q) 

140 if m is not None: 

141 return nome(ctx, m) 

142 if k is not None: 

143 return nome(ctx, ctx.convert(k)**2) 

144 if tau is not None: 

145 return ctx.expjpi(tau) 

146 if qbar is not None: 

147 return ctx.sqrt(qbar) 

148 

149@defun_wrapped 

150def qbarfrom(ctx, q=None, m=None, k=None, tau=None, qbar=None): 

151 r""" 

152 Returns the number-theoretic nome `\bar q`, given any of 

153 `q, m, k, \tau, \bar{q}`:: 

154 

155 >>> from mpmath import * 

156 >>> mp.dps = 25; mp.pretty = True 

157 >>> qbarfrom(qbar=0.25) 

158 0.25 

159 >>> qbarfrom(q=qfrom(qbar=0.25)) 

160 0.25 

161 >>> qbarfrom(m=extraprec(20)(mfrom)(qbar=0.25)) # ill-conditioned 

162 0.25 

163 >>> qbarfrom(k=extraprec(20)(kfrom)(qbar=0.25)) # ill-conditioned 

164 0.25 

165 >>> qbarfrom(tau=taufrom(qbar=0.25)) 

166 (0.25 + 0.0j) 

167 

168 """ 

169 if qbar is not None: 

170 return ctx.convert(qbar) 

171 if q is not None: 

172 return ctx.convert(q) ** 2 

173 if m is not None: 

174 return nome(ctx, m) ** 2 

175 if k is not None: 

176 return nome(ctx, ctx.convert(k)**2) ** 2 

177 if tau is not None: 

178 return ctx.expjpi(2*tau) 

179 

180@defun_wrapped 

181def taufrom(ctx, q=None, m=None, k=None, tau=None, qbar=None): 

182 r""" 

183 Returns the elliptic half-period ratio `\tau`, given any of 

184 `q, m, k, \tau, \bar{q}`:: 

185 

186 >>> from mpmath import * 

187 >>> mp.dps = 25; mp.pretty = True 

188 >>> taufrom(tau=0.5j) 

189 (0.0 + 0.5j) 

190 >>> taufrom(q=qfrom(tau=0.5j)) 

191 (0.0 + 0.5j) 

192 >>> taufrom(m=mfrom(tau=0.5j)) 

193 (0.0 + 0.5j) 

194 >>> taufrom(k=kfrom(tau=0.5j)) 

195 (0.0 + 0.5j) 

196 >>> taufrom(qbar=qbarfrom(tau=0.5j)) 

197 (0.0 + 0.5j) 

198 

199 """ 

200 if tau is not None: 

201 return ctx.convert(tau) 

202 if m is not None: 

203 m = ctx.convert(m) 

204 return ctx.j*ctx.ellipk(1-m)/ctx.ellipk(m) 

205 if k is not None: 

206 k = ctx.convert(k) 

207 return ctx.j*ctx.ellipk(1-k**2)/ctx.ellipk(k**2) 

208 if q is not None: 

209 return ctx.log(q) / (ctx.pi*ctx.j) 

210 if qbar is not None: 

211 qbar = ctx.convert(qbar) 

212 return ctx.log(qbar) / (2*ctx.pi*ctx.j) 

213 

214@defun_wrapped 

215def kfrom(ctx, q=None, m=None, k=None, tau=None, qbar=None): 

216 r""" 

217 Returns the elliptic modulus `k`, given any of 

218 `q, m, k, \tau, \bar{q}`:: 

219 

220 >>> from mpmath import * 

221 >>> mp.dps = 25; mp.pretty = True 

222 >>> kfrom(k=0.25) 

223 0.25 

224 >>> kfrom(m=mfrom(k=0.25)) 

225 0.25 

226 >>> kfrom(q=qfrom(k=0.25)) 

227 0.25 

228 >>> kfrom(tau=taufrom(k=0.25)) 

229 (0.25 + 0.0j) 

230 >>> kfrom(qbar=qbarfrom(k=0.25)) 

231 0.25 

232 

233 As `q \to 1` and `q \to -1`, `k` rapidly approaches 

234 `1` and `i \infty` respectively:: 

235 

236 >>> kfrom(q=0.75) 

237 0.9999999999999899166471767 

238 >>> kfrom(q=-0.75) 

239 (0.0 + 7041781.096692038332790615j) 

240 >>> kfrom(q=1) 

241 1 

242 >>> kfrom(q=-1) 

243 (0.0 + +infj) 

244 """ 

245 if k is not None: 

246 return ctx.convert(k) 

247 if m is not None: 

248 return ctx.sqrt(m) 

249 if tau is not None: 

250 q = ctx.expjpi(tau) 

251 if qbar is not None: 

252 q = ctx.sqrt(qbar) 

253 if q == 1: 

254 return q 

255 if q == -1: 

256 return ctx.mpc(0,'inf') 

257 return (ctx.jtheta(2,0,q)/ctx.jtheta(3,0,q))**2 

258 

259@defun_wrapped 

260def mfrom(ctx, q=None, m=None, k=None, tau=None, qbar=None): 

261 r""" 

262 Returns the elliptic parameter `m`, given any of 

263 `q, m, k, \tau, \bar{q}`:: 

264 

265 >>> from mpmath import * 

266 >>> mp.dps = 25; mp.pretty = True 

267 >>> mfrom(m=0.25) 

268 0.25 

269 >>> mfrom(q=qfrom(m=0.25)) 

270 0.25 

271 >>> mfrom(k=kfrom(m=0.25)) 

272 0.25 

273 >>> mfrom(tau=taufrom(m=0.25)) 

274 (0.25 + 0.0j) 

275 >>> mfrom(qbar=qbarfrom(m=0.25)) 

276 0.25 

277 

278 As `q \to 1` and `q \to -1`, `m` rapidly approaches 

279 `1` and `-\infty` respectively:: 

280 

281 >>> mfrom(q=0.75) 

282 0.9999999999999798332943533 

283 >>> mfrom(q=-0.75) 

284 -49586681013729.32611558353 

285 >>> mfrom(q=1) 

286 1.0 

287 >>> mfrom(q=-1) 

288 -inf 

289 

290 The inverse nome as a function of `q` has an integer 

291 Taylor series expansion:: 

292 

293 >>> taylor(lambda q: mfrom(q), 0, 7) 

294 [0.0, 16.0, -128.0, 704.0, -3072.0, 11488.0, -38400.0, 117632.0] 

295 

296 """ 

297 if m is not None: 

298 return m 

299 if k is not None: 

300 return k**2 

301 if tau is not None: 

302 q = ctx.expjpi(tau) 

303 if qbar is not None: 

304 q = ctx.sqrt(qbar) 

305 if q == 1: 

306 return ctx.convert(q) 

307 if q == -1: 

308 return q*ctx.inf 

309 v = (ctx.jtheta(2,0,q)/ctx.jtheta(3,0,q))**4 

310 if ctx._is_real_type(q) and q < 0: 

311 v = v.real 

312 return v 

313 

314jacobi_spec = { 

315 'sn' : ([3],[2],[1],[4], 'sin', 'tanh'), 

316 'cn' : ([4],[2],[2],[4], 'cos', 'sech'), 

317 'dn' : ([4],[3],[3],[4], '1', 'sech'), 

318 'ns' : ([2],[3],[4],[1], 'csc', 'coth'), 

319 'nc' : ([2],[4],[4],[2], 'sec', 'cosh'), 

320 'nd' : ([3],[4],[4],[3], '1', 'cosh'), 

321 'sc' : ([3],[4],[1],[2], 'tan', 'sinh'), 

322 'sd' : ([3,3],[2,4],[1],[3], 'sin', 'sinh'), 

323 'cd' : ([3],[2],[2],[3], 'cos', '1'), 

324 'cs' : ([4],[3],[2],[1], 'cot', 'csch'), 

325 'dc' : ([2],[3],[3],[2], 'sec', '1'), 

326 'ds' : ([2,4],[3,3],[3],[1], 'csc', 'csch'), 

327 'cc' : None, 

328 'ss' : None, 

329 'nn' : None, 

330 'dd' : None 

331} 

332 

333@defun 

334def ellipfun(ctx, kind, u=None, m=None, q=None, k=None, tau=None): 

335 try: 

336 S = jacobi_spec[kind] 

337 except KeyError: 

338 raise ValueError("First argument must be a two-character string " 

339 "containing 's', 'c', 'd' or 'n', e.g.: 'sn'") 

340 if u is None: 

341 def f(*args, **kwargs): 

342 return ctx.ellipfun(kind, *args, **kwargs) 

343 f.__name__ = kind 

344 return f 

345 prec = ctx.prec 

346 try: 

347 ctx.prec += 10 

348 u = ctx.convert(u) 

349 q = ctx.qfrom(m=m, q=q, k=k, tau=tau) 

350 if S is None: 

351 v = ctx.one + 0*q*u 

352 elif q == ctx.zero: 

353 if S[4] == '1': v = ctx.one 

354 else: v = getattr(ctx, S[4])(u) 

355 v += 0*q*u 

356 elif q == ctx.one: 

357 if S[5] == '1': v = ctx.one 

358 else: v = getattr(ctx, S[5])(u) 

359 v += 0*q*u 

360 else: 

361 t = u / ctx.jtheta(3, 0, q)**2 

362 v = ctx.one 

363 for a in S[0]: v *= ctx.jtheta(a, 0, q) 

364 for b in S[1]: v /= ctx.jtheta(b, 0, q) 

365 for c in S[2]: v *= ctx.jtheta(c, t, q) 

366 for d in S[3]: v /= ctx.jtheta(d, t, q) 

367 finally: 

368 ctx.prec = prec 

369 return +v 

370 

371@defun_wrapped 

372def kleinj(ctx, tau=None, **kwargs): 

373 r""" 

374 Evaluates the Klein j-invariant, which is a modular function defined for 

375 `\tau` in the upper half-plane as 

376 

377 .. math :: 

378 

379 J(\tau) = \frac{g_2^3(\tau)}{g_2^3(\tau) - 27 g_3^2(\tau)} 

380 

381 where `g_2` and `g_3` are the modular invariants of the Weierstrass 

382 elliptic function, 

383 

384 .. math :: 

385 

386 g_2(\tau) = 60 \sum_{(m,n) \in \mathbb{Z}^2 \setminus (0,0)} (m \tau+n)^{-4} 

387 

388 g_3(\tau) = 140 \sum_{(m,n) \in \mathbb{Z}^2 \setminus (0,0)} (m \tau+n)^{-6}. 

389 

390 An alternative, common notation is that of the j-function 

391 `j(\tau) = 1728 J(\tau)`. 

392 

393 **Plots** 

394 

395 .. literalinclude :: /plots/kleinj.py 

396 .. image :: /plots/kleinj.png 

397 .. literalinclude :: /plots/kleinj2.py 

398 .. image :: /plots/kleinj2.png 

399 

400 **Examples** 

401 

402 Verifying the functional equation `J(\tau) = J(\tau+1) = J(-\tau^{-1})`:: 

403 

404 >>> from mpmath import * 

405 >>> mp.dps = 25; mp.pretty = True 

406 >>> tau = 0.625+0.75*j 

407 >>> tau = 0.625+0.75*j 

408 >>> kleinj(tau) 

409 (-0.1507492166511182267125242 + 0.07595948379084571927228948j) 

410 >>> kleinj(tau+1) 

411 (-0.1507492166511182267125242 + 0.07595948379084571927228948j) 

412 >>> kleinj(-1/tau) 

413 (-0.1507492166511182267125242 + 0.07595948379084571927228946j) 

414 

415 The j-function has a famous Laurent series expansion in terms of the nome 

416 `\bar{q}`, `j(\tau) = \bar{q}^{-1} + 744 + 196884\bar{q} + \ldots`:: 

417 

418 >>> mp.dps = 15 

419 >>> taylor(lambda q: 1728*q*kleinj(qbar=q), 0, 5, singular=True) 

420 [1.0, 744.0, 196884.0, 21493760.0, 864299970.0, 20245856256.0] 

421 

422 The j-function admits exact evaluation at special algebraic points 

423 related to the Heegner numbers 1, 2, 3, 7, 11, 19, 43, 67, 163:: 

424 

425 >>> @extraprec(10) 

426 ... def h(n): 

427 ... v = (1+sqrt(n)*j) 

428 ... if n > 2: 

429 ... v *= 0.5 

430 ... return v 

431 ... 

432 >>> mp.dps = 25 

433 >>> for n in [1,2,3,7,11,19,43,67,163]: 

434 ... n, chop(1728*kleinj(h(n))) 

435 ... 

436 (1, 1728.0) 

437 (2, 8000.0) 

438 (3, 0.0) 

439 (7, -3375.0) 

440 (11, -32768.0) 

441 (19, -884736.0) 

442 (43, -884736000.0) 

443 (67, -147197952000.0) 

444 (163, -262537412640768000.0) 

445 

446 Also at other special points, the j-function assumes explicit 

447 algebraic values, e.g.:: 

448 

449 >>> chop(1728*kleinj(j*sqrt(5))) 

450 1264538.909475140509320227 

451 >>> identify(cbrt(_)) # note: not simplified 

452 '((100+sqrt(13520))/2)' 

453 >>> (50+26*sqrt(5))**3 

454 1264538.909475140509320227 

455 

456 """ 

457 q = ctx.qfrom(tau=tau, **kwargs) 

458 t2 = ctx.jtheta(2,0,q) 

459 t3 = ctx.jtheta(3,0,q) 

460 t4 = ctx.jtheta(4,0,q) 

461 P = (t2**8 + t3**8 + t4**8)**3 

462 Q = 54*(t2*t3*t4)**8 

463 return P/Q 

464 

465 

466def RF_calc(ctx, x, y, z, r): 

467 if y == z: return RC_calc(ctx, x, y, r) 

468 if x == z: return RC_calc(ctx, y, x, r) 

469 if x == y: return RC_calc(ctx, z, x, r) 

470 if not (ctx.isnormal(x) and ctx.isnormal(y) and ctx.isnormal(z)): 

471 if ctx.isnan(x) or ctx.isnan(y) or ctx.isnan(z): 

472 return x*y*z 

473 if ctx.isinf(x) or ctx.isinf(y) or ctx.isinf(z): 

474 return ctx.zero 

475 xm,ym,zm = x,y,z 

476 A0 = Am = (x+y+z)/3 

477 Q = ctx.root(3*r, -6) * max(abs(A0-x),abs(A0-y),abs(A0-z)) 

478 g = ctx.mpf(0.25) 

479 pow4 = ctx.one 

480 m = 0 

481 while 1: 

482 xs = ctx.sqrt(xm) 

483 ys = ctx.sqrt(ym) 

484 zs = ctx.sqrt(zm) 

485 lm = xs*ys + xs*zs + ys*zs 

486 Am1 = (Am+lm)*g 

487 xm, ym, zm = (xm+lm)*g, (ym+lm)*g, (zm+lm)*g 

488 if pow4 * Q < abs(Am): 

489 break 

490 Am = Am1 

491 m += 1 

492 pow4 *= g 

493 t = pow4/Am 

494 X = (A0-x)*t 

495 Y = (A0-y)*t 

496 Z = -X-Y 

497 E2 = X*Y-Z**2 

498 E3 = X*Y*Z 

499 return ctx.power(Am,-0.5) * (9240-924*E2+385*E2**2+660*E3-630*E2*E3)/9240 

500 

501def RC_calc(ctx, x, y, r, pv=True): 

502 if not (ctx.isnormal(x) and ctx.isnormal(y)): 

503 if ctx.isinf(x) or ctx.isinf(y): 

504 return 1/(x*y) 

505 if y == 0: 

506 return ctx.inf 

507 if x == 0: 

508 return ctx.pi / ctx.sqrt(y) / 2 

509 raise ValueError 

510 # Cauchy principal value 

511 if pv and ctx._im(y) == 0 and ctx._re(y) < 0: 

512 return ctx.sqrt(x/(x-y)) * RC_calc(ctx, x-y, -y, r) 

513 if x == y: 

514 return 1/ctx.sqrt(x) 

515 extraprec = 2*max(0,-ctx.mag(x-y)+ctx.mag(x)) 

516 ctx.prec += extraprec 

517 if ctx._is_real_type(x) and ctx._is_real_type(y): 

518 x = ctx._re(x) 

519 y = ctx._re(y) 

520 a = ctx.sqrt(x/y) 

521 if x < y: 

522 b = ctx.sqrt(y-x) 

523 v = ctx.acos(a)/b 

524 else: 

525 b = ctx.sqrt(x-y) 

526 v = ctx.acosh(a)/b 

527 else: 

528 sx = ctx.sqrt(x) 

529 sy = ctx.sqrt(y) 

530 v = ctx.acos(sx/sy)/(ctx.sqrt((1-x/y))*sy) 

531 ctx.prec -= extraprec 

532 return v 

533 

534def RJ_calc(ctx, x, y, z, p, r, integration): 

535 """ 

536 With integration == 0, computes RJ only using Carlson's algorithm 

537 (may be wrong for some values). 

538 With integration == 1, uses an initial integration to make sure 

539 Carlson's algorithm is correct. 

540 With integration == 2, uses only integration. 

541 """ 

542 if not (ctx.isnormal(x) and ctx.isnormal(y) and \ 

543 ctx.isnormal(z) and ctx.isnormal(p)): 

544 if ctx.isnan(x) or ctx.isnan(y) or ctx.isnan(z) or ctx.isnan(p): 

545 return x*y*z 

546 if ctx.isinf(x) or ctx.isinf(y) or ctx.isinf(z) or ctx.isinf(p): 

547 return ctx.zero 

548 if not p: 

549 return ctx.inf 

550 if (not x) + (not y) + (not z) > 1: 

551 return ctx.inf 

552 # Check conditions and fall back on integration for argument 

553 # reduction if needed. The following conditions might be needlessly 

554 # restrictive. 

555 initial_integral = ctx.zero 

556 if integration >= 1: 

557 ok = (x.real >= 0 and y.real >= 0 and z.real >= 0 and p.real > 0) 

558 if not ok: 

559 if x == p or y == p or z == p: 

560 ok = True 

561 if not ok: 

562 if p.imag != 0 or p.real >= 0: 

563 if (x.imag == 0 and x.real >= 0 and ctx.conj(y) == z): 

564 ok = True 

565 if (y.imag == 0 and y.real >= 0 and ctx.conj(x) == z): 

566 ok = True 

567 if (z.imag == 0 and z.real >= 0 and ctx.conj(x) == y): 

568 ok = True 

569 if not ok or (integration == 2): 

570 N = ctx.ceil(-min(x.real, y.real, z.real, p.real)) + 1 

571 # Integrate around any singularities 

572 if all((t.imag >= 0 or t.real > 0) for t in [x, y, z, p]): 

573 margin = ctx.j 

574 elif all((t.imag < 0 or t.real > 0) for t in [x, y, z, p]): 

575 margin = -ctx.j 

576 else: 

577 margin = 1 

578 # Go through the upper half-plane, but low enough that any 

579 # parameter starting in the lower plane doesn't cross the 

580 # branch cut 

581 for t in [x, y, z, p]: 

582 if t.imag >= 0 or t.real > 0: 

583 continue 

584 margin = min(margin, abs(t.imag) * 0.5) 

585 margin *= ctx.j 

586 N += margin 

587 F = lambda t: 1/(ctx.sqrt(t+x)*ctx.sqrt(t+y)*ctx.sqrt(t+z)*(t+p)) 

588 if integration == 2: 

589 return 1.5 * ctx.quad(F, [0, N, ctx.inf]) 

590 initial_integral = 1.5 * ctx.quad(F, [0, N]) 

591 x += N; y += N; z += N; p += N 

592 xm,ym,zm,pm = x,y,z,p 

593 A0 = Am = (x + y + z + 2*p)/5 

594 delta = (p-x)*(p-y)*(p-z) 

595 Q = ctx.root(0.25*r, -6) * max(abs(A0-x),abs(A0-y),abs(A0-z),abs(A0-p)) 

596 m = 0 

597 g = ctx.mpf(0.25) 

598 pow4 = ctx.one 

599 S = 0 

600 while 1: 

601 sx = ctx.sqrt(xm) 

602 sy = ctx.sqrt(ym) 

603 sz = ctx.sqrt(zm) 

604 sp = ctx.sqrt(pm) 

605 lm = sx*sy + sx*sz + sy*sz 

606 Am1 = (Am+lm)*g 

607 xm = (xm+lm)*g; ym = (ym+lm)*g; zm = (zm+lm)*g; pm = (pm+lm)*g 

608 dm = (sp+sx) * (sp+sy) * (sp+sz) 

609 em = delta * ctx.power(4, -3*m) / dm**2 

610 if pow4 * Q < abs(Am): 

611 break 

612 T = RC_calc(ctx, ctx.one, ctx.one+em, r) * pow4 / dm 

613 S += T 

614 pow4 *= g 

615 m += 1 

616 Am = Am1 

617 t = ctx.ldexp(1,-2*m) / Am 

618 X = (A0-x)*t 

619 Y = (A0-y)*t 

620 Z = (A0-z)*t 

621 P = (-X-Y-Z)/2 

622 E2 = X*Y + X*Z + Y*Z - 3*P**2 

623 E3 = X*Y*Z + 2*E2*P + 4*P**3 

624 E4 = (2*X*Y*Z + E2*P + 3*P**3)*P 

625 E5 = X*Y*Z*P**2 

626 P = 24024 - 5148*E2 + 2457*E2**2 + 4004*E3 - 4158*E2*E3 - 3276*E4 + 2772*E5 

627 Q = 24024 

628 v1 = g**m * ctx.power(Am, -1.5) * P/Q 

629 v2 = 6*S 

630 return initial_integral + v1 + v2 

631 

632@defun 

633def elliprf(ctx, x, y, z): 

634 r""" 

635 Evaluates the Carlson symmetric elliptic integral of the first kind 

636 

637 .. math :: 

638 

639 R_F(x,y,z) = \frac{1}{2} 

640 \int_0^{\infty} \frac{dt}{\sqrt{(t+x)(t+y)(t+z)}} 

641 

642 which is defined for `x,y,z \notin (-\infty,0)`, and with 

643 at most one of `x,y,z` being zero. 

644 

645 For real `x,y,z \ge 0`, the principal square root is taken in the integrand. 

646 For complex `x,y,z`, the principal square root is taken as `t \to \infty` 

647 and as `t \to 0` non-principal branches are chosen as necessary so as to 

648 make the integrand continuous. 

649 

650 **Examples** 

651 

652 Some basic values and limits:: 

653 

654 >>> from mpmath import * 

655 >>> mp.dps = 25; mp.pretty = True 

656 >>> elliprf(0,1,1); pi/2 

657 1.570796326794896619231322 

658 1.570796326794896619231322 

659 >>> elliprf(0,1,inf) 

660 0.0 

661 >>> elliprf(1,1,1) 

662 1.0 

663 >>> elliprf(2,2,2)**2 

664 0.5 

665 >>> elliprf(1,0,0); elliprf(0,0,1); elliprf(0,1,0); elliprf(0,0,0) 

666 +inf 

667 +inf 

668 +inf 

669 +inf 

670 

671 Representing complete elliptic integrals in terms of `R_F`:: 

672 

673 >>> m = mpf(0.75) 

674 >>> ellipk(m); elliprf(0,1-m,1) 

675 2.156515647499643235438675 

676 2.156515647499643235438675 

677 >>> ellipe(m); elliprf(0,1-m,1)-m*elliprd(0,1-m,1)/3 

678 1.211056027568459524803563 

679 1.211056027568459524803563 

680 

681 Some symmetries and argument transformations:: 

682 

683 >>> x,y,z = 2,3,4 

684 >>> elliprf(x,y,z); elliprf(y,x,z); elliprf(z,y,x) 

685 0.5840828416771517066928492 

686 0.5840828416771517066928492 

687 0.5840828416771517066928492 

688 >>> k = mpf(100000) 

689 >>> elliprf(k*x,k*y,k*z); k**(-0.5) * elliprf(x,y,z) 

690 0.001847032121923321253219284 

691 0.001847032121923321253219284 

692 >>> l = sqrt(x*y) + sqrt(y*z) + sqrt(z*x) 

693 >>> elliprf(x,y,z); 2*elliprf(x+l,y+l,z+l) 

694 0.5840828416771517066928492 

695 0.5840828416771517066928492 

696 >>> elliprf((x+l)/4,(y+l)/4,(z+l)/4) 

697 0.5840828416771517066928492 

698 

699 Comparing with numerical integration:: 

700 

701 >>> x,y,z = 2,3,4 

702 >>> elliprf(x,y,z) 

703 0.5840828416771517066928492 

704 >>> f = lambda t: 0.5*((t+x)*(t+y)*(t+z))**(-0.5) 

705 >>> q = extradps(25)(quad) 

706 >>> q(f, [0,inf]) 

707 0.5840828416771517066928492 

708 

709 With the following arguments, the square root in the integrand becomes 

710 discontinuous at `t = 1/2` if the principal branch is used. To obtain 

711 the right value, `-\sqrt{r}` must be taken instead of `\sqrt{r}` 

712 on `t \in (0, 1/2)`:: 

713 

714 >>> x,y,z = j-1,j,0 

715 >>> elliprf(x,y,z) 

716 (0.7961258658423391329305694 - 1.213856669836495986430094j) 

717 >>> -q(f, [0,0.5]) + q(f, [0.5,inf]) 

718 (0.7961258658423391329305694 - 1.213856669836495986430094j) 

719 

720 The so-called *first lemniscate constant*, a transcendental number:: 

721 

722 >>> elliprf(0,1,2) 

723 1.31102877714605990523242 

724 >>> extradps(25)(quad)(lambda t: 1/sqrt(1-t**4), [0,1]) 

725 1.31102877714605990523242 

726 >>> gamma('1/4')**2/(4*sqrt(2*pi)) 

727 1.31102877714605990523242 

728 

729 **References** 

730 

731 1. [Carlson]_ 

732 2. [DLMF]_ Chapter 19. Elliptic Integrals 

733 

734 """ 

735 x = ctx.convert(x) 

736 y = ctx.convert(y) 

737 z = ctx.convert(z) 

738 prec = ctx.prec 

739 try: 

740 ctx.prec += 20 

741 tol = ctx.eps * 2**10 

742 v = RF_calc(ctx, x, y, z, tol) 

743 finally: 

744 ctx.prec = prec 

745 return +v 

746 

747@defun 

748def elliprc(ctx, x, y, pv=True): 

749 r""" 

750 Evaluates the degenerate Carlson symmetric elliptic integral 

751 of the first kind 

752 

753 .. math :: 

754 

755 R_C(x,y) = R_F(x,y,y) = 

756 \frac{1}{2} \int_0^{\infty} \frac{dt}{(t+y) \sqrt{(t+x)}}. 

757 

758 If `y \in (-\infty,0)`, either a value defined by continuity, 

759 or with *pv=True* the Cauchy principal value, can be computed. 

760 

761 If `x \ge 0, y > 0`, the value can be expressed in terms of 

762 elementary functions as 

763 

764 .. math :: 

765 

766 R_C(x,y) = 

767 \begin{cases} 

768 \dfrac{1}{\sqrt{y-x}} 

769 \cos^{-1}\left(\sqrt{\dfrac{x}{y}}\right), & x < y \\ 

770 \dfrac{1}{\sqrt{y}}, & x = y \\ 

771 \dfrac{1}{\sqrt{x-y}} 

772 \cosh^{-1}\left(\sqrt{\dfrac{x}{y}}\right), & x > y \\ 

773 \end{cases}. 

774 

775 **Examples** 

776 

777 Some special values and limits:: 

778 

779 >>> from mpmath import * 

780 >>> mp.dps = 25; mp.pretty = True 

781 >>> elliprc(1,2)*4; elliprc(0,1)*2; +pi 

782 3.141592653589793238462643 

783 3.141592653589793238462643 

784 3.141592653589793238462643 

785 >>> elliprc(1,0) 

786 +inf 

787 >>> elliprc(5,5)**2 

788 0.2 

789 >>> elliprc(1,inf); elliprc(inf,1); elliprc(inf,inf) 

790 0.0 

791 0.0 

792 0.0 

793 

794 Comparing with the elementary closed-form solution:: 

795 

796 >>> elliprc('1/3', '1/5'); sqrt(7.5)*acosh(sqrt('5/3')) 

797 2.041630778983498390751238 

798 2.041630778983498390751238 

799 >>> elliprc('1/5', '1/3'); sqrt(7.5)*acos(sqrt('3/5')) 

800 1.875180765206547065111085 

801 1.875180765206547065111085 

802 

803 Comparing with numerical integration:: 

804 

805 >>> q = extradps(25)(quad) 

806 >>> elliprc(2, -3, pv=True) 

807 0.3333969101113672670749334 

808 >>> elliprc(2, -3, pv=False) 

809 (0.3333969101113672670749334 + 0.7024814731040726393156375j) 

810 >>> 0.5*q(lambda t: 1/(sqrt(t+2)*(t-3)), [0,3-j,6,inf]) 

811 (0.3333969101113672670749334 + 0.7024814731040726393156375j) 

812 

813 """ 

814 x = ctx.convert(x) 

815 y = ctx.convert(y) 

816 prec = ctx.prec 

817 try: 

818 ctx.prec += 20 

819 tol = ctx.eps * 2**10 

820 v = RC_calc(ctx, x, y, tol, pv) 

821 finally: 

822 ctx.prec = prec 

823 return +v 

824 

825@defun 

826def elliprj(ctx, x, y, z, p, integration=1): 

827 r""" 

828 Evaluates the Carlson symmetric elliptic integral of the third kind 

829 

830 .. math :: 

831 

832 R_J(x,y,z,p) = \frac{3}{2} 

833 \int_0^{\infty} \frac{dt}{(t+p)\sqrt{(t+x)(t+y)(t+z)}}. 

834 

835 Like :func:`~mpmath.elliprf`, the branch of the square root in the integrand 

836 is defined so as to be continuous along the path of integration for 

837 complex values of the arguments. 

838 

839 **Examples** 

840 

841 Some values and limits:: 

842 

843 >>> from mpmath import * 

844 >>> mp.dps = 25; mp.pretty = True 

845 >>> elliprj(1,1,1,1) 

846 1.0 

847 >>> elliprj(2,2,2,2); 1/(2*sqrt(2)) 

848 0.3535533905932737622004222 

849 0.3535533905932737622004222 

850 >>> elliprj(0,1,2,2) 

851 1.067937989667395702268688 

852 >>> 3*(2*gamma('5/4')**2-pi**2/gamma('1/4')**2)/(sqrt(2*pi)) 

853 1.067937989667395702268688 

854 >>> elliprj(0,1,1,2); 3*pi*(2-sqrt(2))/4 

855 1.380226776765915172432054 

856 1.380226776765915172432054 

857 >>> elliprj(1,3,2,0); elliprj(0,1,1,0); elliprj(0,0,0,0) 

858 +inf 

859 +inf 

860 +inf 

861 >>> elliprj(1,inf,1,0); elliprj(1,1,1,inf) 

862 0.0 

863 0.0 

864 >>> chop(elliprj(1+j, 1-j, 1, 1)) 

865 0.8505007163686739432927844 

866 

867 Scale transformation:: 

868 

869 >>> x,y,z,p = 2,3,4,5 

870 >>> k = mpf(100000) 

871 >>> elliprj(k*x,k*y,k*z,k*p); k**(-1.5)*elliprj(x,y,z,p) 

872 4.521291677592745527851168e-9 

873 4.521291677592745527851168e-9 

874 

875 Comparing with numerical integration:: 

876 

877 >>> elliprj(1,2,3,4) 

878 0.2398480997495677621758617 

879 >>> f = lambda t: 1/((t+4)*sqrt((t+1)*(t+2)*(t+3))) 

880 >>> 1.5*quad(f, [0,inf]) 

881 0.2398480997495677621758617 

882 >>> elliprj(1,2+1j,3,4-2j) 

883 (0.216888906014633498739952 + 0.04081912627366673332369512j) 

884 >>> f = lambda t: 1/((t+4-2j)*sqrt((t+1)*(t+2+1j)*(t+3))) 

885 >>> 1.5*quad(f, [0,inf]) 

886 (0.216888906014633498739952 + 0.04081912627366673332369511j) 

887 

888 """ 

889 x = ctx.convert(x) 

890 y = ctx.convert(y) 

891 z = ctx.convert(z) 

892 p = ctx.convert(p) 

893 prec = ctx.prec 

894 try: 

895 ctx.prec += 20 

896 tol = ctx.eps * 2**10 

897 v = RJ_calc(ctx, x, y, z, p, tol, integration) 

898 finally: 

899 ctx.prec = prec 

900 return +v 

901 

902@defun 

903def elliprd(ctx, x, y, z): 

904 r""" 

905 Evaluates the degenerate Carlson symmetric elliptic integral 

906 of the third kind or Carlson elliptic integral of the 

907 second kind `R_D(x,y,z) = R_J(x,y,z,z)`. 

908 

909 See :func:`~mpmath.elliprj` for additional information. 

910 

911 **Examples** 

912 

913 >>> from mpmath import * 

914 >>> mp.dps = 25; mp.pretty = True 

915 >>> elliprd(1,2,3) 

916 0.2904602810289906442326534 

917 >>> elliprj(1,2,3,3) 

918 0.2904602810289906442326534 

919 

920 The so-called *second lemniscate constant*, a transcendental number:: 

921 

922 >>> elliprd(0,2,1)/3 

923 0.5990701173677961037199612 

924 >>> extradps(25)(quad)(lambda t: t**2/sqrt(1-t**4), [0,1]) 

925 0.5990701173677961037199612 

926 >>> gamma('3/4')**2/sqrt(2*pi) 

927 0.5990701173677961037199612 

928 

929 """ 

930 return ctx.elliprj(x,y,z,z) 

931 

932@defun 

933def elliprg(ctx, x, y, z): 

934 r""" 

935 Evaluates the Carlson completely symmetric elliptic integral 

936 of the second kind 

937 

938 .. math :: 

939 

940 R_G(x,y,z) = \frac{1}{4} \int_0^{\infty} 

941 \frac{t}{\sqrt{(t+x)(t+y)(t+z)}} 

942 \left( \frac{x}{t+x} + \frac{y}{t+y} + \frac{z}{t+z}\right) dt. 

943 

944 **Examples** 

945 

946 Evaluation for real and complex arguments:: 

947 

948 >>> from mpmath import * 

949 >>> mp.dps = 25; mp.pretty = True 

950 >>> elliprg(0,1,1)*4; +pi 

951 3.141592653589793238462643 

952 3.141592653589793238462643 

953 >>> elliprg(0,0.5,1) 

954 0.6753219405238377512600874 

955 >>> chop(elliprg(1+j, 1-j, 2)) 

956 1.172431327676416604532822 

957 

958 A double integral that can be evaluated in terms of `R_G`:: 

959 

960 >>> x,y,z = 2,3,4 

961 >>> def f(t,u): 

962 ... st = fp.sin(t); ct = fp.cos(t) 

963 ... su = fp.sin(u); cu = fp.cos(u) 

964 ... return (x*(st*cu)**2 + y*(st*su)**2 + z*ct**2)**0.5 * st 

965 ... 

966 >>> nprint(mpf(fp.quad(f, [0,fp.pi], [0,2*fp.pi])/(4*fp.pi)), 13) 

967 1.725503028069 

968 >>> nprint(elliprg(x,y,z), 13) 

969 1.725503028069 

970 

971 """ 

972 x = ctx.convert(x) 

973 y = ctx.convert(y) 

974 z = ctx.convert(z) 

975 zeros = (not x) + (not y) + (not z) 

976 if zeros == 3: 

977 return (x+y+z)*0 

978 if zeros == 2: 

979 if x: return 0.5*ctx.sqrt(x) 

980 if y: return 0.5*ctx.sqrt(y) 

981 return 0.5*ctx.sqrt(z) 

982 if zeros == 1: 

983 if not z: 

984 x, z = z, x 

985 def terms(): 

986 T1 = 0.5*z*ctx.elliprf(x,y,z) 

987 T2 = -0.5*(x-z)*(y-z)*ctx.elliprd(x,y,z)/3 

988 T3 = 0.5*ctx.sqrt(x)*ctx.sqrt(y)/ctx.sqrt(z) 

989 return T1,T2,T3 

990 return ctx.sum_accurately(terms) 

991 

992 

993@defun_wrapped 

994def ellipf(ctx, phi, m): 

995 r""" 

996 Evaluates the Legendre incomplete elliptic integral of the first kind 

997 

998 .. math :: 

999 

1000 F(\phi,m) = \int_0^{\phi} \frac{dt}{\sqrt{1-m \sin^2 t}} 

1001 

1002 or equivalently 

1003 

1004 .. math :: 

1005 

1006 F(\phi,m) = \int_0^{\sin \phi} 

1007 \frac{dt}{\left(\sqrt{1-t^2}\right)\left(\sqrt{1-mt^2}\right)}. 

1008 

1009 The function reduces to a complete elliptic integral of the first kind 

1010 (see :func:`~mpmath.ellipk`) when `\phi = \frac{\pi}{2}`; that is, 

1011 

1012 .. math :: 

1013 

1014 F\left(\frac{\pi}{2}, m\right) = K(m). 

1015 

1016 In the defining integral, it is assumed that the principal branch 

1017 of the square root is taken and that the path of integration avoids 

1018 crossing any branch cuts. Outside `-\pi/2 \le \Re(\phi) \le \pi/2`, 

1019 the function extends quasi-periodically as 

1020 

1021 .. math :: 

1022 

1023 F(\phi + n \pi, m) = 2 n K(m) + F(\phi,m), n \in \mathbb{Z}. 

1024 

1025 **Plots** 

1026 

1027 .. literalinclude :: /plots/ellipf.py 

1028 .. image :: /plots/ellipf.png 

1029 

1030 **Examples** 

1031 

1032 Basic values and limits:: 

1033 

1034 >>> from mpmath import * 

1035 >>> mp.dps = 25; mp.pretty = True 

1036 >>> ellipf(0,1) 

1037 0.0 

1038 >>> ellipf(0,0) 

1039 0.0 

1040 >>> ellipf(1,0); ellipf(2+3j,0) 

1041 1.0 

1042 (2.0 + 3.0j) 

1043 >>> ellipf(1,1); log(sec(1)+tan(1)) 

1044 1.226191170883517070813061 

1045 1.226191170883517070813061 

1046 >>> ellipf(pi/2, -0.5); ellipk(-0.5) 

1047 1.415737208425956198892166 

1048 1.415737208425956198892166 

1049 >>> ellipf(pi/2+eps, 1); ellipf(-pi/2-eps, 1) 

1050 +inf 

1051 +inf 

1052 >>> ellipf(1.5, 1) 

1053 3.340677542798311003320813 

1054 

1055 Comparing with numerical integration:: 

1056 

1057 >>> z,m = 0.5, 1.25 

1058 >>> ellipf(z,m) 

1059 0.5287219202206327872978255 

1060 >>> quad(lambda t: (1-m*sin(t)**2)**(-0.5), [0,z]) 

1061 0.5287219202206327872978255 

1062 

1063 The arguments may be complex numbers:: 

1064 

1065 >>> ellipf(3j, 0.5) 

1066 (0.0 + 1.713602407841590234804143j) 

1067 >>> ellipf(3+4j, 5-6j) 

1068 (1.269131241950351323305741 - 0.3561052815014558335412538j) 

1069 >>> z,m = 2+3j, 1.25 

1070 >>> k = 1011 

1071 >>> ellipf(z+pi*k,m); ellipf(z,m) + 2*k*ellipk(m) 

1072 (4086.184383622179764082821 - 3003.003538923749396546871j) 

1073 (4086.184383622179764082821 - 3003.003538923749396546871j) 

1074 

1075 For `|\Re(z)| < \pi/2`, the function can be expressed as a 

1076 hypergeometric series of two variables 

1077 (see :func:`~mpmath.appellf1`):: 

1078 

1079 >>> z,m = 0.5, 0.25 

1080 >>> ellipf(z,m) 

1081 0.5050887275786480788831083 

1082 >>> sin(z)*appellf1(0.5,0.5,0.5,1.5,sin(z)**2,m*sin(z)**2) 

1083 0.5050887275786480788831083 

1084 

1085 """ 

1086 z = phi 

1087 if not (ctx.isnormal(z) and ctx.isnormal(m)): 

1088 if m == 0: 

1089 return z + m 

1090 if z == 0: 

1091 return z * m 

1092 if m == ctx.inf or m == ctx.ninf: return z/m 

1093 raise ValueError 

1094 x = z.real 

1095 ctx.prec += max(0, ctx.mag(x)) 

1096 pi = +ctx.pi 

1097 away = abs(x) > pi/2 

1098 if m == 1: 

1099 if away: 

1100 return ctx.inf 

1101 if away: 

1102 d = ctx.nint(x/pi) 

1103 z = z-pi*d 

1104 P = 2*d*ctx.ellipk(m) 

1105 else: 

1106 P = 0 

1107 c, s = ctx.cos_sin(z) 

1108 return s * ctx.elliprf(c**2, 1-m*s**2, 1) + P 

1109 

1110@defun_wrapped 

1111def ellipe(ctx, *args): 

1112 r""" 

1113 Called with a single argument `m`, evaluates the Legendre complete 

1114 elliptic integral of the second kind, `E(m)`, defined by 

1115 

1116 .. math :: E(m) = \int_0^{\pi/2} \sqrt{1-m \sin^2 t} \, dt \,=\, 

1117 \frac{\pi}{2} 

1118 \,_2F_1\left(\frac{1}{2}, -\frac{1}{2}, 1, m\right). 

1119 

1120 Called with two arguments `\phi, m`, evaluates the incomplete elliptic 

1121 integral of the second kind 

1122 

1123 .. math :: 

1124 

1125 E(\phi,m) = \int_0^{\phi} \sqrt{1-m \sin^2 t} \, dt = 

1126 \int_0^{\sin z} 

1127 \frac{\sqrt{1-mt^2}}{\sqrt{1-t^2}} \, dt. 

1128 

1129 The incomplete integral reduces to a complete integral when 

1130 `\phi = \frac{\pi}{2}`; that is, 

1131 

1132 .. math :: 

1133 

1134 E\left(\frac{\pi}{2}, m\right) = E(m). 

1135 

1136 In the defining integral, it is assumed that the principal branch 

1137 of the square root is taken and that the path of integration avoids 

1138 crossing any branch cuts. Outside `-\pi/2 \le \Re(z) \le \pi/2`, 

1139 the function extends quasi-periodically as 

1140 

1141 .. math :: 

1142 

1143 E(\phi + n \pi, m) = 2 n E(m) + E(\phi,m), n \in \mathbb{Z}. 

1144 

1145 **Plots** 

1146 

1147 .. literalinclude :: /plots/ellipe.py 

1148 .. image :: /plots/ellipe.png 

1149 

1150 **Examples for the complete integral** 

1151 

1152 Basic values and limits:: 

1153 

1154 >>> from mpmath import * 

1155 >>> mp.dps = 25; mp.pretty = True 

1156 >>> ellipe(0) 

1157 1.570796326794896619231322 

1158 >>> ellipe(1) 

1159 1.0 

1160 >>> ellipe(-1) 

1161 1.910098894513856008952381 

1162 >>> ellipe(2) 

1163 (0.5990701173677961037199612 + 0.5990701173677961037199612j) 

1164 >>> ellipe(inf) 

1165 (0.0 + +infj) 

1166 >>> ellipe(-inf) 

1167 +inf 

1168 

1169 Verifying the defining integral and hypergeometric 

1170 representation:: 

1171 

1172 >>> ellipe(0.5) 

1173 1.350643881047675502520175 

1174 >>> quad(lambda t: sqrt(1-0.5*sin(t)**2), [0, pi/2]) 

1175 1.350643881047675502520175 

1176 >>> pi/2*hyp2f1(0.5,-0.5,1,0.5) 

1177 1.350643881047675502520175 

1178 

1179 Evaluation is supported for arbitrary complex `m`:: 

1180 

1181 >>> ellipe(0.5+0.25j) 

1182 (1.360868682163129682716687 - 0.1238733442561786843557315j) 

1183 >>> ellipe(3+4j) 

1184 (1.499553520933346954333612 - 1.577879007912758274533309j) 

1185 

1186 A definite integral:: 

1187 

1188 >>> quad(ellipe, [0,1]) 

1189 1.333333333333333333333333 

1190 

1191 **Examples for the incomplete integral** 

1192 

1193 Basic values and limits:: 

1194 

1195 >>> ellipe(0,1) 

1196 0.0 

1197 >>> ellipe(0,0) 

1198 0.0 

1199 >>> ellipe(1,0) 

1200 1.0 

1201 >>> ellipe(2+3j,0) 

1202 (2.0 + 3.0j) 

1203 >>> ellipe(1,1); sin(1) 

1204 0.8414709848078965066525023 

1205 0.8414709848078965066525023 

1206 >>> ellipe(pi/2, -0.5); ellipe(-0.5) 

1207 1.751771275694817862026502 

1208 1.751771275694817862026502 

1209 >>> ellipe(pi/2, 1); ellipe(-pi/2, 1) 

1210 1.0 

1211 -1.0 

1212 >>> ellipe(1.5, 1) 

1213 0.9974949866040544309417234 

1214 

1215 Comparing with numerical integration:: 

1216 

1217 >>> z,m = 0.5, 1.25 

1218 >>> ellipe(z,m) 

1219 0.4740152182652628394264449 

1220 >>> quad(lambda t: sqrt(1-m*sin(t)**2), [0,z]) 

1221 0.4740152182652628394264449 

1222 

1223 The arguments may be complex numbers:: 

1224 

1225 >>> ellipe(3j, 0.5) 

1226 (0.0 + 7.551991234890371873502105j) 

1227 >>> ellipe(3+4j, 5-6j) 

1228 (24.15299022574220502424466 + 75.2503670480325997418156j) 

1229 >>> k = 35 

1230 >>> z,m = 2+3j, 1.25 

1231 >>> ellipe(z+pi*k,m); ellipe(z,m) + 2*k*ellipe(m) 

1232 (48.30138799412005235090766 + 17.47255216721987688224357j) 

1233 (48.30138799412005235090766 + 17.47255216721987688224357j) 

1234 

1235 For `|\Re(z)| < \pi/2`, the function can be expressed as a 

1236 hypergeometric series of two variables 

1237 (see :func:`~mpmath.appellf1`):: 

1238 

1239 >>> z,m = 0.5, 0.25 

1240 >>> ellipe(z,m) 

1241 0.4950017030164151928870375 

1242 >>> sin(z)*appellf1(0.5,0.5,-0.5,1.5,sin(z)**2,m*sin(z)**2) 

1243 0.4950017030164151928870376 

1244 

1245 """ 

1246 if len(args) == 1: 

1247 return ctx._ellipe(args[0]) 

1248 else: 

1249 phi, m = args 

1250 z = phi 

1251 if not (ctx.isnormal(z) and ctx.isnormal(m)): 

1252 if m == 0: 

1253 return z + m 

1254 if z == 0: 

1255 return z * m 

1256 if m == ctx.inf or m == ctx.ninf: 

1257 return ctx.inf 

1258 raise ValueError 

1259 x = z.real 

1260 ctx.prec += max(0, ctx.mag(x)) 

1261 pi = +ctx.pi 

1262 away = abs(x) > pi/2 

1263 if away: 

1264 d = ctx.nint(x/pi) 

1265 z = z-pi*d 

1266 P = 2*d*ctx.ellipe(m) 

1267 else: 

1268 P = 0 

1269 def terms(): 

1270 c, s = ctx.cos_sin(z) 

1271 x = c**2 

1272 y = 1-m*s**2 

1273 RF = ctx.elliprf(x, y, 1) 

1274 RD = ctx.elliprd(x, y, 1) 

1275 return s*RF, -m*s**3*RD/3 

1276 return ctx.sum_accurately(terms) + P 

1277 

1278@defun_wrapped 

1279def ellippi(ctx, *args): 

1280 r""" 

1281 Called with three arguments `n, \phi, m`, evaluates the Legendre 

1282 incomplete elliptic integral of the third kind 

1283 

1284 .. math :: 

1285 

1286 \Pi(n; \phi, m) = \int_0^{\phi} 

1287 \frac{dt}{(1-n \sin^2 t) \sqrt{1-m \sin^2 t}} = 

1288 \int_0^{\sin \phi} 

1289 \frac{dt}{(1-nt^2) \sqrt{1-t^2} \sqrt{1-mt^2}}. 

1290 

1291 Called with two arguments `n, m`, evaluates the complete 

1292 elliptic integral of the third kind 

1293 `\Pi(n,m) = \Pi(n; \frac{\pi}{2},m)`. 

1294 

1295 In the defining integral, it is assumed that the principal branch 

1296 of the square root is taken and that the path of integration avoids 

1297 crossing any branch cuts. Outside `-\pi/2 \le \Re(\phi) \le \pi/2`, 

1298 the function extends quasi-periodically as 

1299 

1300 .. math :: 

1301 

1302 \Pi(n,\phi+k\pi,m) = 2k\Pi(n,m) + \Pi(n,\phi,m), k \in \mathbb{Z}. 

1303 

1304 **Plots** 

1305 

1306 .. literalinclude :: /plots/ellippi.py 

1307 .. image :: /plots/ellippi.png 

1308 

1309 **Examples for the complete integral** 

1310 

1311 Some basic values and limits:: 

1312 

1313 >>> from mpmath import * 

1314 >>> mp.dps = 25; mp.pretty = True 

1315 >>> ellippi(0,-5); ellipk(-5) 

1316 0.9555039270640439337379334 

1317 0.9555039270640439337379334 

1318 >>> ellippi(inf,2) 

1319 0.0 

1320 >>> ellippi(2,inf) 

1321 0.0 

1322 >>> abs(ellippi(1,5)) 

1323 +inf 

1324 >>> abs(ellippi(0.25,1)) 

1325 +inf 

1326 

1327 Evaluation in terms of simpler functions:: 

1328 

1329 >>> ellippi(0.25,0.25); ellipe(0.25)/(1-0.25) 

1330 1.956616279119236207279727 

1331 1.956616279119236207279727 

1332 >>> ellippi(3,0); pi/(2*sqrt(-2)) 

1333 (0.0 - 1.11072073453959156175397j) 

1334 (0.0 - 1.11072073453959156175397j) 

1335 >>> ellippi(-3,0); pi/(2*sqrt(4)) 

1336 0.7853981633974483096156609 

1337 0.7853981633974483096156609 

1338 

1339 **Examples for the incomplete integral** 

1340 

1341 Basic values and limits:: 

1342 

1343 >>> ellippi(0.25,-0.5); ellippi(0.25,pi/2,-0.5) 

1344 1.622944760954741603710555 

1345 1.622944760954741603710555 

1346 >>> ellippi(1,0,1) 

1347 0.0 

1348 >>> ellippi(inf,0,1) 

1349 0.0 

1350 >>> ellippi(0,0.25,0.5); ellipf(0.25,0.5) 

1351 0.2513040086544925794134591 

1352 0.2513040086544925794134591 

1353 >>> ellippi(1,1,1); (log(sec(1)+tan(1))+sec(1)*tan(1))/2 

1354 2.054332933256248668692452 

1355 2.054332933256248668692452 

1356 >>> ellippi(0.25, 53*pi/2, 0.75); 53*ellippi(0.25,0.75) 

1357 135.240868757890840755058 

1358 135.240868757890840755058 

1359 >>> ellippi(0.5,pi/4,0.5); 2*ellipe(pi/4,0.5)-1/sqrt(3) 

1360 0.9190227391656969903987269 

1361 0.9190227391656969903987269 

1362 

1363 Complex arguments are supported:: 

1364 

1365 >>> ellippi(0.5, 5+6j-2*pi, -7-8j) 

1366 (-0.3612856620076747660410167 + 0.5217735339984807829755815j) 

1367 

1368 Some degenerate cases:: 

1369 

1370 >>> ellippi(1,1) 

1371 +inf 

1372 >>> ellippi(1,0) 

1373 +inf 

1374 >>> ellippi(1,2,0) 

1375 +inf 

1376 >>> ellippi(1,2,1) 

1377 +inf 

1378 >>> ellippi(1,0,1) 

1379 0.0 

1380 

1381 """ 

1382 if len(args) == 2: 

1383 n, m = args 

1384 complete = True 

1385 z = phi = ctx.pi/2 

1386 else: 

1387 n, phi, m = args 

1388 complete = False 

1389 z = phi 

1390 if not (ctx.isnormal(n) and ctx.isnormal(z) and ctx.isnormal(m)): 

1391 if ctx.isnan(n) or ctx.isnan(z) or ctx.isnan(m): 

1392 raise ValueError 

1393 if complete: 

1394 if m == 0: 

1395 if n == 1: 

1396 return ctx.inf 

1397 return ctx.pi/(2*ctx.sqrt(1-n)) 

1398 if n == 0: return ctx.ellipk(m) 

1399 if ctx.isinf(n) or ctx.isinf(m): return ctx.zero 

1400 else: 

1401 if z == 0: return z 

1402 if ctx.isinf(n): return ctx.zero 

1403 if ctx.isinf(m): return ctx.zero 

1404 if ctx.isinf(n) or ctx.isinf(z) or ctx.isinf(m): 

1405 raise ValueError 

1406 if complete: 

1407 if m == 1: 

1408 if n == 1: 

1409 return ctx.inf 

1410 return -ctx.inf/ctx.sign(n-1) 

1411 away = False 

1412 else: 

1413 x = z.real 

1414 ctx.prec += max(0, ctx.mag(x)) 

1415 pi = +ctx.pi 

1416 away = abs(x) > pi/2 

1417 if away: 

1418 d = ctx.nint(x/pi) 

1419 z = z-pi*d 

1420 P = 2*d*ctx.ellippi(n,m) 

1421 if ctx.isinf(P): 

1422 return ctx.inf 

1423 else: 

1424 P = 0 

1425 def terms(): 

1426 if complete: 

1427 c, s = ctx.zero, ctx.one 

1428 else: 

1429 c, s = ctx.cos_sin(z) 

1430 x = c**2 

1431 y = 1-m*s**2 

1432 RF = ctx.elliprf(x, y, 1) 

1433 RJ = ctx.elliprj(x, y, 1, 1-n*s**2) 

1434 return s*RF, n*s**3*RJ/3 

1435 return ctx.sum_accurately(terms) + P