Coverage for /usr/lib/python3/dist-packages/sympy/functions/special/elliptic_integrals.py: 19%
219 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1""" Elliptic Integrals. """
3from sympy.core import S, pi, I, Rational
4from sympy.core.function import Function, ArgumentIndexError
5from sympy.core.symbol import Dummy
6from sympy.functions.elementary.complexes import sign
7from sympy.functions.elementary.hyperbolic import atanh
8from sympy.functions.elementary.miscellaneous import sqrt
9from sympy.functions.elementary.trigonometric import sin, tan
10from sympy.functions.special.gamma_functions import gamma
11from sympy.functions.special.hyper import hyper, meijerg
13class elliptic_k(Function):
14 r"""
15 The complete elliptic integral of the first kind, defined by
17 .. math:: K(m) = F\left(\tfrac{\pi}{2}\middle| m\right)
19 where $F\left(z\middle| m\right)$ is the Legendre incomplete
20 elliptic integral of the first kind.
22 Explanation
23 ===========
25 The function $K(m)$ is a single-valued function on the complex
26 plane with branch cut along the interval $(1, \infty)$.
28 Note that our notation defines the incomplete elliptic integral
29 in terms of the parameter $m$ instead of the elliptic modulus
30 (eccentricity) $k$.
31 In this case, the parameter $m$ is defined as $m=k^2$.
33 Examples
34 ========
36 >>> from sympy import elliptic_k, I
37 >>> from sympy.abc import m
38 >>> elliptic_k(0)
39 pi/2
40 >>> elliptic_k(1.0 + I)
41 1.50923695405127 + 0.625146415202697*I
42 >>> elliptic_k(m).series(n=3)
43 pi/2 + pi*m/8 + 9*pi*m**2/128 + O(m**3)
45 See Also
46 ========
48 elliptic_f
50 References
51 ==========
53 .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
54 .. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticK
56 """
58 @classmethod
59 def eval(cls, m):
60 if m.is_zero:
61 return pi*S.Half
62 elif m is S.Half:
63 return 8*pi**Rational(3, 2)/gamma(Rational(-1, 4))**2
64 elif m is S.One:
65 return S.ComplexInfinity
66 elif m is S.NegativeOne:
67 return gamma(Rational(1, 4))**2/(4*sqrt(2*pi))
68 elif m in (S.Infinity, S.NegativeInfinity, I*S.Infinity,
69 I*S.NegativeInfinity, S.ComplexInfinity):
70 return S.Zero
72 def fdiff(self, argindex=1):
73 m = self.args[0]
74 return (elliptic_e(m) - (1 - m)*elliptic_k(m))/(2*m*(1 - m))
76 def _eval_conjugate(self):
77 m = self.args[0]
78 if (m.is_real and (m - 1).is_positive) is False:
79 return self.func(m.conjugate())
81 def _eval_nseries(self, x, n, logx, cdir=0):
82 from sympy.simplify import hyperexpand
83 return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx))
85 def _eval_rewrite_as_hyper(self, m, **kwargs):
86 return pi*S.Half*hyper((S.Half, S.Half), (S.One,), m)
88 def _eval_rewrite_as_meijerg(self, m, **kwargs):
89 return meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -m)/2
91 def _eval_is_zero(self):
92 m = self.args[0]
93 if m.is_infinite:
94 return True
96 def _eval_rewrite_as_Integral(self, *args):
97 from sympy.integrals.integrals import Integral
98 t = Dummy('t')
99 m = self.args[0]
100 return Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, pi/2))
103class elliptic_f(Function):
104 r"""
105 The Legendre incomplete elliptic integral of the first
106 kind, defined by
108 .. math:: F\left(z\middle| m\right) =
109 \int_0^z \frac{dt}{\sqrt{1 - m \sin^2 t}}
111 Explanation
112 ===========
114 This function reduces to a complete elliptic integral of
115 the first kind, $K(m)$, when $z = \pi/2$.
117 Note that our notation defines the incomplete elliptic integral
118 in terms of the parameter $m$ instead of the elliptic modulus
119 (eccentricity) $k$.
120 In this case, the parameter $m$ is defined as $m=k^2$.
122 Examples
123 ========
125 >>> from sympy import elliptic_f, I
126 >>> from sympy.abc import z, m
127 >>> elliptic_f(z, m).series(z)
128 z + z**5*(3*m**2/40 - m/30) + m*z**3/6 + O(z**6)
129 >>> elliptic_f(3.0 + I/2, 1.0 + I)
130 2.909449841483 + 1.74720545502474*I
132 See Also
133 ========
135 elliptic_k
137 References
138 ==========
140 .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
141 .. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticF
143 """
145 @classmethod
146 def eval(cls, z, m):
147 if z.is_zero:
148 return S.Zero
149 if m.is_zero:
150 return z
151 k = 2*z/pi
152 if k.is_integer:
153 return k*elliptic_k(m)
154 elif m in (S.Infinity, S.NegativeInfinity):
155 return S.Zero
156 elif z.could_extract_minus_sign():
157 return -elliptic_f(-z, m)
159 def fdiff(self, argindex=1):
160 z, m = self.args
161 fm = sqrt(1 - m*sin(z)**2)
162 if argindex == 1:
163 return 1/fm
164 elif argindex == 2:
165 return (elliptic_e(z, m)/(2*m*(1 - m)) - elliptic_f(z, m)/(2*m) -
166 sin(2*z)/(4*(1 - m)*fm))
167 raise ArgumentIndexError(self, argindex)
169 def _eval_conjugate(self):
170 z, m = self.args
171 if (m.is_real and (m - 1).is_positive) is False:
172 return self.func(z.conjugate(), m.conjugate())
174 def _eval_rewrite_as_Integral(self, *args):
175 from sympy.integrals.integrals import Integral
176 t = Dummy('t')
177 z, m = self.args[0], self.args[1]
178 return Integral(1/(sqrt(1 - m*sin(t)**2)), (t, 0, z))
180 def _eval_is_zero(self):
181 z, m = self.args
182 if z.is_zero:
183 return True
184 if m.is_extended_real and m.is_infinite:
185 return True
188class elliptic_e(Function):
189 r"""
190 Called with two arguments $z$ and $m$, evaluates the
191 incomplete elliptic integral of the second kind, defined by
193 .. math:: E\left(z\middle| m\right) = \int_0^z \sqrt{1 - m \sin^2 t} dt
195 Called with a single argument $m$, evaluates the Legendre complete
196 elliptic integral of the second kind
198 .. math:: E(m) = E\left(\tfrac{\pi}{2}\middle| m\right)
200 Explanation
201 ===========
203 The function $E(m)$ is a single-valued function on the complex
204 plane with branch cut along the interval $(1, \infty)$.
206 Note that our notation defines the incomplete elliptic integral
207 in terms of the parameter $m$ instead of the elliptic modulus
208 (eccentricity) $k$.
209 In this case, the parameter $m$ is defined as $m=k^2$.
211 Examples
212 ========
214 >>> from sympy import elliptic_e, I
215 >>> from sympy.abc import z, m
216 >>> elliptic_e(z, m).series(z)
217 z + z**5*(-m**2/40 + m/30) - m*z**3/6 + O(z**6)
218 >>> elliptic_e(m).series(n=4)
219 pi/2 - pi*m/8 - 3*pi*m**2/128 - 5*pi*m**3/512 + O(m**4)
220 >>> elliptic_e(1 + I, 2 - I/2).n()
221 1.55203744279187 + 0.290764986058437*I
222 >>> elliptic_e(0)
223 pi/2
224 >>> elliptic_e(2.0 - I)
225 0.991052601328069 + 0.81879421395609*I
227 References
228 ==========
230 .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
231 .. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticE2
232 .. [3] https://functions.wolfram.com/EllipticIntegrals/EllipticE
234 """
236 @classmethod
237 def eval(cls, m, z=None):
238 if z is not None:
239 z, m = m, z
240 k = 2*z/pi
241 if m.is_zero:
242 return z
243 if z.is_zero:
244 return S.Zero
245 elif k.is_integer:
246 return k*elliptic_e(m)
247 elif m in (S.Infinity, S.NegativeInfinity):
248 return S.ComplexInfinity
249 elif z.could_extract_minus_sign():
250 return -elliptic_e(-z, m)
251 else:
252 if m.is_zero:
253 return pi/2
254 elif m is S.One:
255 return S.One
256 elif m is S.Infinity:
257 return I*S.Infinity
258 elif m is S.NegativeInfinity:
259 return S.Infinity
260 elif m is S.ComplexInfinity:
261 return S.ComplexInfinity
263 def fdiff(self, argindex=1):
264 if len(self.args) == 2:
265 z, m = self.args
266 if argindex == 1:
267 return sqrt(1 - m*sin(z)**2)
268 elif argindex == 2:
269 return (elliptic_e(z, m) - elliptic_f(z, m))/(2*m)
270 else:
271 m = self.args[0]
272 if argindex == 1:
273 return (elliptic_e(m) - elliptic_k(m))/(2*m)
274 raise ArgumentIndexError(self, argindex)
276 def _eval_conjugate(self):
277 if len(self.args) == 2:
278 z, m = self.args
279 if (m.is_real and (m - 1).is_positive) is False:
280 return self.func(z.conjugate(), m.conjugate())
281 else:
282 m = self.args[0]
283 if (m.is_real and (m - 1).is_positive) is False:
284 return self.func(m.conjugate())
286 def _eval_nseries(self, x, n, logx, cdir=0):
287 from sympy.simplify import hyperexpand
288 if len(self.args) == 1:
289 return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx))
290 return super()._eval_nseries(x, n=n, logx=logx)
292 def _eval_rewrite_as_hyper(self, *args, **kwargs):
293 if len(args) == 1:
294 m = args[0]
295 return (pi/2)*hyper((Rational(-1, 2), S.Half), (S.One,), m)
297 def _eval_rewrite_as_meijerg(self, *args, **kwargs):
298 if len(args) == 1:
299 m = args[0]
300 return -meijerg(((S.Half, Rational(3, 2)), []), \
301 ((S.Zero,), (S.Zero,)), -m)/4
303 def _eval_rewrite_as_Integral(self, *args):
304 from sympy.integrals.integrals import Integral
305 z, m = (pi/2, self.args[0]) if len(self.args) == 1 else self.args
306 t = Dummy('t')
307 return Integral(sqrt(1 - m*sin(t)**2), (t, 0, z))
310class elliptic_pi(Function):
311 r"""
312 Called with three arguments $n$, $z$ and $m$, evaluates the
313 Legendre incomplete elliptic integral of the third kind, defined by
315 .. math:: \Pi\left(n; z\middle| m\right) = \int_0^z \frac{dt}
316 {\left(1 - n \sin^2 t\right) \sqrt{1 - m \sin^2 t}}
318 Called with two arguments $n$ and $m$, evaluates the complete
319 elliptic integral of the third kind:
321 .. math:: \Pi\left(n\middle| m\right) =
322 \Pi\left(n; \tfrac{\pi}{2}\middle| m\right)
324 Explanation
325 ===========
327 Note that our notation defines the incomplete elliptic integral
328 in terms of the parameter $m$ instead of the elliptic modulus
329 (eccentricity) $k$.
330 In this case, the parameter $m$ is defined as $m=k^2$.
332 Examples
333 ========
335 >>> from sympy import elliptic_pi, I
336 >>> from sympy.abc import z, n, m
337 >>> elliptic_pi(n, z, m).series(z, n=4)
338 z + z**3*(m/6 + n/3) + O(z**4)
339 >>> elliptic_pi(0.5 + I, 1.0 - I, 1.2)
340 2.50232379629182 - 0.760939574180767*I
341 >>> elliptic_pi(0, 0)
342 pi/2
343 >>> elliptic_pi(1.0 - I/3, 2.0 + I)
344 3.29136443417283 + 0.32555634906645*I
346 References
347 ==========
349 .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
350 .. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticPi3
351 .. [3] https://functions.wolfram.com/EllipticIntegrals/EllipticPi
353 """
355 @classmethod
356 def eval(cls, n, m, z=None):
357 if z is not None:
358 n, z, m = n, m, z
359 if n.is_zero:
360 return elliptic_f(z, m)
361 elif n is S.One:
362 return (elliptic_f(z, m) +
363 (sqrt(1 - m*sin(z)**2)*tan(z) -
364 elliptic_e(z, m))/(1 - m))
365 k = 2*z/pi
366 if k.is_integer:
367 return k*elliptic_pi(n, m)
368 elif m.is_zero:
369 return atanh(sqrt(n - 1)*tan(z))/sqrt(n - 1)
370 elif n == m:
371 return (elliptic_f(z, n) - elliptic_pi(1, z, n) +
372 tan(z)/sqrt(1 - n*sin(z)**2))
373 elif n in (S.Infinity, S.NegativeInfinity):
374 return S.Zero
375 elif m in (S.Infinity, S.NegativeInfinity):
376 return S.Zero
377 elif z.could_extract_minus_sign():
378 return -elliptic_pi(n, -z, m)
379 if n.is_zero:
380 return elliptic_f(z, m)
381 if m.is_extended_real and m.is_infinite or \
382 n.is_extended_real and n.is_infinite:
383 return S.Zero
384 else:
385 if n.is_zero:
386 return elliptic_k(m)
387 elif n is S.One:
388 return S.ComplexInfinity
389 elif m.is_zero:
390 return pi/(2*sqrt(1 - n))
391 elif m == S.One:
392 return S.NegativeInfinity/sign(n - 1)
393 elif n == m:
394 return elliptic_e(n)/(1 - n)
395 elif n in (S.Infinity, S.NegativeInfinity):
396 return S.Zero
397 elif m in (S.Infinity, S.NegativeInfinity):
398 return S.Zero
399 if n.is_zero:
400 return elliptic_k(m)
401 if m.is_extended_real and m.is_infinite or \
402 n.is_extended_real and n.is_infinite:
403 return S.Zero
405 def _eval_conjugate(self):
406 if len(self.args) == 3:
407 n, z, m = self.args
408 if (n.is_real and (n - 1).is_positive) is False and \
409 (m.is_real and (m - 1).is_positive) is False:
410 return self.func(n.conjugate(), z.conjugate(), m.conjugate())
411 else:
412 n, m = self.args
413 return self.func(n.conjugate(), m.conjugate())
415 def fdiff(self, argindex=1):
416 if len(self.args) == 3:
417 n, z, m = self.args
418 fm, fn = sqrt(1 - m*sin(z)**2), 1 - n*sin(z)**2
419 if argindex == 1:
420 return (elliptic_e(z, m) + (m - n)*elliptic_f(z, m)/n +
421 (n**2 - m)*elliptic_pi(n, z, m)/n -
422 n*fm*sin(2*z)/(2*fn))/(2*(m - n)*(n - 1))
423 elif argindex == 2:
424 return 1/(fm*fn)
425 elif argindex == 3:
426 return (elliptic_e(z, m)/(m - 1) +
427 elliptic_pi(n, z, m) -
428 m*sin(2*z)/(2*(m - 1)*fm))/(2*(n - m))
429 else:
430 n, m = self.args
431 if argindex == 1:
432 return (elliptic_e(m) + (m - n)*elliptic_k(m)/n +
433 (n**2 - m)*elliptic_pi(n, m)/n)/(2*(m - n)*(n - 1))
434 elif argindex == 2:
435 return (elliptic_e(m)/(m - 1) + elliptic_pi(n, m))/(2*(n - m))
436 raise ArgumentIndexError(self, argindex)
438 def _eval_rewrite_as_Integral(self, *args):
439 from sympy.integrals.integrals import Integral
440 if len(self.args) == 2:
441 n, m, z = self.args[0], self.args[1], pi/2
442 else:
443 n, z, m = self.args
444 t = Dummy('t')
445 return Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, z))