BryanW commited on
Commit
20889fd
·
verified ·
1 Parent(s): 0875f57

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/__pycache__/__init__.cpython-312.pyc +0 -0
  2. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/__pycache__/delta.cpython-312.pyc +0 -0
  3. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/__pycache__/expr_with_limits.cpython-312.pyc +0 -0
  4. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/__pycache__/guess.cpython-312.pyc +0 -0
  5. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  6. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/test_delta.cpython-312.pyc +0 -0
  7. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/test_gosper.cpython-312.pyc +0 -0
  8. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/test_guess.cpython-312.pyc +0 -0
  9. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/test_products.cpython-312.pyc +0 -0
  10. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/__pycache__/__init__.cpython-312.pyc +0 -0
  11. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/combinatorial/__init__.py +1 -0
  12. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/combinatorial/factorials.py +1133 -0
  13. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/combinatorial/numbers.py +0 -0
  14. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/__init__.py +1 -0
  15. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/_trigonometric_special.py +261 -0
  16. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/complexes.py +1492 -0
  17. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/exponential.py +1286 -0
  18. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/hyperbolic.py +2285 -0
  19. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/integers.py +710 -0
  20. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/miscellaneous.py +915 -0
  21. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/piecewise.py +1517 -0
  22. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/tests/test_complexes.py +1030 -0
  23. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/tests/test_miscellaneous.py +504 -0
  24. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/trigonometric.py +0 -0
  25. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/__init__.py +1 -0
  26. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/bessel.py +2208 -0
  27. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/beta_functions.py +389 -0
  28. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/bsplines.py +348 -0
  29. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/delta_functions.py +664 -0
  30. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/elliptic_integrals.py +445 -0
  31. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/error_functions.py +2801 -0
  32. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/gamma_functions.py +1344 -0
  33. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/hyper.py +1185 -0
  34. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/mathieu_functions.py +269 -0
  35. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/polynomials.py +1447 -0
  36. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/singularity_functions.py +235 -0
  37. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/spherical_harmonics.py +334 -0
  38. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/tensor_functions.py +474 -0
  39. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/zeta_functions.py +786 -0
  40. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/__init__.cpython-312.pyc +0 -0
  41. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/experimental_lambdify.cpython-312.pyc +0 -0
  42. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/plot.cpython-312.pyc +0 -0
  43. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/plot_implicit.cpython-312.pyc +0 -0
  44. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/plotgrid.cpython-312.pyc +0 -0
  45. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/textplot.cpython-312.pyc +0 -0
  46. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/utils.cpython-312.pyc +0 -0
  47. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/backends/textbackend/__init__.py +3 -0
  48. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/backends/textbackend/text.py +24 -0
  49. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/intervalmath/__init__.py +12 -0
  50. URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/intervalmath/interval_arithmetic.py +413 -0
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (372 Bytes). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/__pycache__/delta.cpython-312.pyc ADDED
Binary file (13.6 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/__pycache__/expr_with_limits.cpython-312.pyc ADDED
Binary file (26.9 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/__pycache__/guess.cpython-312.pyc ADDED
Binary file (23.6 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (212 Bytes). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/test_delta.cpython-312.pyc ADDED
Binary file (75.8 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/test_gosper.cpython-312.pyc ADDED
Binary file (20.1 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/test_guess.cpython-312.pyc ADDED
Binary file (6.58 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/concrete/tests/__pycache__/test_products.cpython-312.pyc ADDED
Binary file (30.8 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (6.17 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/combinatorial/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ # Stub __init__.py for sympy.functions.combinatorial
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/combinatorial/factorials.py ADDED
@@ -0,0 +1,1133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ from functools import reduce
3
+
4
+ from sympy.core import S, sympify, Dummy, Mod
5
+ from sympy.core.cache import cacheit
6
+ from sympy.core.function import DefinedFunction, ArgumentIndexError, PoleError
7
+ from sympy.core.logic import fuzzy_and
8
+ from sympy.core.numbers import Integer, pi, I
9
+ from sympy.core.relational import Eq
10
+ from sympy.external.gmpy import gmpy as _gmpy
11
+ from sympy.ntheory import sieve
12
+ from sympy.ntheory.residue_ntheory import binomial_mod
13
+ from sympy.polys.polytools import Poly
14
+
15
+ from math import factorial as _factorial, prod, sqrt as _sqrt
16
+
17
+ class CombinatorialFunction(DefinedFunction):
18
+ """Base class for combinatorial functions. """
19
+
20
+ def _eval_simplify(self, **kwargs):
21
+ from sympy.simplify.combsimp import combsimp
22
+ # combinatorial function with non-integer arguments is
23
+ # automatically passed to gammasimp
24
+ expr = combsimp(self)
25
+ measure = kwargs['measure']
26
+ if measure(expr) <= kwargs['ratio']*measure(self):
27
+ return expr
28
+ return self
29
+
30
+
31
+ ###############################################################################
32
+ ######################## FACTORIAL and MULTI-FACTORIAL ########################
33
+ ###############################################################################
34
+
35
+
36
+ class factorial(CombinatorialFunction):
37
+ r"""Implementation of factorial function over nonnegative integers.
38
+ By convention (consistent with the gamma function and the binomial
39
+ coefficients), factorial of a negative integer is complex infinity.
40
+
41
+ The factorial is very important in combinatorics where it gives
42
+ the number of ways in which `n` objects can be permuted. It also
43
+ arises in calculus, probability, number theory, etc.
44
+
45
+ There is strict relation of factorial with gamma function. In
46
+ fact `n! = gamma(n+1)` for nonnegative integers. Rewrite of this
47
+ kind is very useful in case of combinatorial simplification.
48
+
49
+ Computation of the factorial is done using two algorithms. For
50
+ small arguments a precomputed look up table is used. However for bigger
51
+ input algorithm Prime-Swing is used. It is the fastest algorithm
52
+ known and computes `n!` via prime factorization of special class
53
+ of numbers, called here the 'Swing Numbers'.
54
+
55
+ Examples
56
+ ========
57
+
58
+ >>> from sympy import Symbol, factorial, S
59
+ >>> n = Symbol('n', integer=True)
60
+
61
+ >>> factorial(0)
62
+ 1
63
+
64
+ >>> factorial(7)
65
+ 5040
66
+
67
+ >>> factorial(-2)
68
+ zoo
69
+
70
+ >>> factorial(n)
71
+ factorial(n)
72
+
73
+ >>> factorial(2*n)
74
+ factorial(2*n)
75
+
76
+ >>> factorial(S(1)/2)
77
+ factorial(1/2)
78
+
79
+ See Also
80
+ ========
81
+
82
+ factorial2, RisingFactorial, FallingFactorial
83
+ """
84
+
85
+ def fdiff(self, argindex=1):
86
+ from sympy.functions.special.gamma_functions import (gamma, polygamma)
87
+ if argindex == 1:
88
+ return gamma(self.args[0] + 1)*polygamma(0, self.args[0] + 1)
89
+ else:
90
+ raise ArgumentIndexError(self, argindex)
91
+
92
+ _small_swing = [
93
+ 1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003, 429, 6435, 6435, 109395,
94
+ 12155, 230945, 46189, 969969, 88179, 2028117, 676039, 16900975, 1300075,
95
+ 35102025, 5014575, 145422675, 9694845, 300540195, 300540195
96
+ ]
97
+
98
+ _small_factorials: list[int] = []
99
+
100
+ @classmethod
101
+ def _swing(cls, n):
102
+ if n < 33:
103
+ return cls._small_swing[n]
104
+ else:
105
+ N, primes = int(_sqrt(n)), []
106
+
107
+ for prime in sieve.primerange(3, N + 1):
108
+ p, q = 1, n
109
+
110
+ while True:
111
+ q //= prime
112
+
113
+ if q > 0:
114
+ if q & 1 == 1:
115
+ p *= prime
116
+ else:
117
+ break
118
+
119
+ if p > 1:
120
+ primes.append(p)
121
+
122
+ for prime in sieve.primerange(N + 1, n//3 + 1):
123
+ if (n // prime) & 1 == 1:
124
+ primes.append(prime)
125
+
126
+ L_product = prod(sieve.primerange(n//2 + 1, n + 1))
127
+ R_product = prod(primes)
128
+
129
+ return L_product*R_product
130
+
131
+ @classmethod
132
+ def _recursive(cls, n):
133
+ if n < 2:
134
+ return 1
135
+ else:
136
+ return (cls._recursive(n//2)**2)*cls._swing(n)
137
+
138
+ @classmethod
139
+ def eval(cls, n):
140
+ n = sympify(n)
141
+
142
+ if n.is_Number:
143
+ if n.is_zero:
144
+ return S.One
145
+ elif n is S.Infinity:
146
+ return S.Infinity
147
+ elif n.is_Integer:
148
+ if n.is_negative:
149
+ return S.ComplexInfinity
150
+ else:
151
+ n = n.p
152
+
153
+ if n < 20:
154
+ if not cls._small_factorials:
155
+ result = 1
156
+ for i in range(1, 20):
157
+ result *= i
158
+ cls._small_factorials.append(result)
159
+ result = cls._small_factorials[n-1]
160
+
161
+ # GMPY factorial is faster, use it when available
162
+ #
163
+ # XXX: There is a sympy.external.gmpy.factorial function
164
+ # which provides gmpy.fac if available or the flint version
165
+ # if flint is used. It could be used here to avoid the
166
+ # conditional logic but it needs to be checked whether the
167
+ # pure Python fallback used there is as fast as the
168
+ # fallback used here (perhaps the fallback here should be
169
+ # moved to sympy.external.ntheory).
170
+ elif _gmpy is not None:
171
+ result = _gmpy.fac(n)
172
+
173
+ else:
174
+ bits = bin(n).count('1')
175
+ result = cls._recursive(n)*2**(n - bits)
176
+
177
+ return Integer(result)
178
+
179
+ def _facmod(self, n, q):
180
+ res, N = 1, int(_sqrt(n))
181
+
182
+ # Exponent of prime p in n! is e_p(n) = [n/p] + [n/p**2] + ...
183
+ # for p > sqrt(n), e_p(n) < sqrt(n), the primes with [n/p] = m,
184
+ # occur consecutively and are grouped together in pw[m] for
185
+ # simultaneous exponentiation at a later stage
186
+ pw = [1]*N
187
+
188
+ m = 2 # to initialize the if condition below
189
+ for prime in sieve.primerange(2, n + 1):
190
+ if m > 1:
191
+ m, y = 0, n // prime
192
+ while y:
193
+ m += y
194
+ y //= prime
195
+ if m < N:
196
+ pw[m] = pw[m]*prime % q
197
+ else:
198
+ res = res*pow(prime, m, q) % q
199
+
200
+ for ex, bs in enumerate(pw):
201
+ if ex == 0 or bs == 1:
202
+ continue
203
+ if bs == 0:
204
+ return 0
205
+ res = res*pow(bs, ex, q) % q
206
+
207
+ return res
208
+
209
+ def _eval_Mod(self, q):
210
+ n = self.args[0]
211
+ if n.is_integer and n.is_nonnegative and q.is_integer:
212
+ aq = abs(q)
213
+ d = aq - n
214
+ if d.is_nonpositive:
215
+ return S.Zero
216
+ else:
217
+ isprime = aq.is_prime
218
+ if d == 1:
219
+ # Apply Wilson's theorem (if a natural number n > 1
220
+ # is a prime number, then (n-1)! = -1 mod n) and
221
+ # its inverse (if n > 4 is a composite number, then
222
+ # (n-1)! = 0 mod n)
223
+ if isprime:
224
+ return -1 % q
225
+ elif isprime is False and (aq - 6).is_nonnegative:
226
+ return S.Zero
227
+ elif n.is_Integer and q.is_Integer:
228
+ n, d, aq = map(int, (n, d, aq))
229
+ if isprime and (d - 1 < n):
230
+ fc = self._facmod(d - 1, aq)
231
+ fc = pow(fc, aq - 2, aq)
232
+ if d%2:
233
+ fc = -fc
234
+ else:
235
+ fc = self._facmod(n, aq)
236
+
237
+ return fc % q
238
+
239
+ def _eval_rewrite_as_gamma(self, n, piecewise=True, **kwargs):
240
+ from sympy.functions.special.gamma_functions import gamma
241
+ return gamma(n + 1)
242
+
243
+ def _eval_rewrite_as_Product(self, n, **kwargs):
244
+ from sympy.concrete.products import Product
245
+ if n.is_nonnegative and n.is_integer:
246
+ i = Dummy('i', integer=True)
247
+ return Product(i, (i, 1, n))
248
+
249
+ def _eval_is_integer(self):
250
+ if self.args[0].is_integer and self.args[0].is_nonnegative:
251
+ return True
252
+
253
+ def _eval_is_positive(self):
254
+ if self.args[0].is_integer and self.args[0].is_nonnegative:
255
+ return True
256
+
257
+ def _eval_is_even(self):
258
+ x = self.args[0]
259
+ if x.is_integer and x.is_nonnegative:
260
+ return (x - 2).is_nonnegative
261
+
262
+ def _eval_is_composite(self):
263
+ x = self.args[0]
264
+ if x.is_integer and x.is_nonnegative:
265
+ return (x - 3).is_nonnegative
266
+
267
+ def _eval_is_real(self):
268
+ x = self.args[0]
269
+ if x.is_nonnegative or x.is_noninteger:
270
+ return True
271
+
272
+ def _eval_as_leading_term(self, x, logx, cdir):
273
+ arg = self.args[0].as_leading_term(x)
274
+ arg0 = arg.subs(x, 0)
275
+ if arg0.is_zero:
276
+ return S.One
277
+ elif not arg0.is_infinite:
278
+ return self.func(arg)
279
+ raise PoleError("Cannot expand %s around 0" % (self))
280
+
281
+ class MultiFactorial(CombinatorialFunction):
282
+ pass
283
+
284
+
285
+ class subfactorial(CombinatorialFunction):
286
+ r"""The subfactorial counts the derangements of $n$ items and is
287
+ defined for non-negative integers as:
288
+
289
+ .. math:: !n = \begin{cases} 1 & n = 0 \\ 0 & n = 1 \\
290
+ (n-1)(!(n-1) + !(n-2)) & n > 1 \end{cases}
291
+
292
+ It can also be written as ``int(round(n!/exp(1)))`` but the
293
+ recursive definition with caching is implemented for this function.
294
+
295
+ An interesting analytic expression is the following [2]_
296
+
297
+ .. math:: !x = \Gamma(x + 1, -1)/e
298
+
299
+ which is valid for non-negative integers `x`. The above formula
300
+ is not very useful in case of non-integers. `\Gamma(x + 1, -1)` is
301
+ single-valued only for integral arguments `x`, elsewhere on the positive
302
+ real axis it has an infinite number of branches none of which are real.
303
+
304
+ References
305
+ ==========
306
+
307
+ .. [1] https://en.wikipedia.org/wiki/Subfactorial
308
+ .. [2] https://mathworld.wolfram.com/Subfactorial.html
309
+
310
+ Examples
311
+ ========
312
+
313
+ >>> from sympy import subfactorial
314
+ >>> from sympy.abc import n
315
+ >>> subfactorial(n + 1)
316
+ subfactorial(n + 1)
317
+ >>> subfactorial(5)
318
+ 44
319
+
320
+ See Also
321
+ ========
322
+
323
+ factorial, uppergamma,
324
+ sympy.utilities.iterables.generate_derangements
325
+ """
326
+
327
+ @classmethod
328
+ @cacheit
329
+ def _eval(self, n):
330
+ if not n:
331
+ return S.One
332
+ elif n == 1:
333
+ return S.Zero
334
+ else:
335
+ z1, z2 = 1, 0
336
+ for i in range(2, n + 1):
337
+ z1, z2 = z2, (i - 1)*(z2 + z1)
338
+ return z2
339
+
340
+ @classmethod
341
+ def eval(cls, arg):
342
+ if arg.is_Number:
343
+ if arg.is_Integer and arg.is_nonnegative:
344
+ return cls._eval(arg)
345
+ elif arg is S.NaN:
346
+ return S.NaN
347
+ elif arg is S.Infinity:
348
+ return S.Infinity
349
+
350
+ def _eval_is_even(self):
351
+ if self.args[0].is_odd and self.args[0].is_nonnegative:
352
+ return True
353
+
354
+ def _eval_is_integer(self):
355
+ if self.args[0].is_integer and self.args[0].is_nonnegative:
356
+ return True
357
+
358
+ def _eval_rewrite_as_factorial(self, arg, **kwargs):
359
+ from sympy.concrete.summations import summation
360
+ i = Dummy('i')
361
+ f = S.NegativeOne**i / factorial(i)
362
+ return factorial(arg) * summation(f, (i, 0, arg))
363
+
364
+ def _eval_rewrite_as_gamma(self, arg, piecewise=True, **kwargs):
365
+ from sympy.functions.elementary.exponential import exp
366
+ from sympy.functions.special.gamma_functions import (gamma, lowergamma)
367
+ return (S.NegativeOne**(arg + 1)*exp(-I*pi*arg)*lowergamma(arg + 1, -1)
368
+ + gamma(arg + 1))*exp(-1)
369
+
370
+ def _eval_rewrite_as_uppergamma(self, arg, **kwargs):
371
+ from sympy.functions.special.gamma_functions import uppergamma
372
+ return uppergamma(arg + 1, -1)/S.Exp1
373
+
374
+ def _eval_is_nonnegative(self):
375
+ if self.args[0].is_integer and self.args[0].is_nonnegative:
376
+ return True
377
+
378
+ def _eval_is_odd(self):
379
+ if self.args[0].is_even and self.args[0].is_nonnegative:
380
+ return True
381
+
382
+
383
+ class factorial2(CombinatorialFunction):
384
+ r"""The double factorial `n!!`, not to be confused with `(n!)!`
385
+
386
+ The double factorial is defined for nonnegative integers and for odd
387
+ negative integers as:
388
+
389
+ .. math:: n!! = \begin{cases} 1 & n = 0 \\
390
+ n(n-2)(n-4) \cdots 1 & n\ \text{positive odd} \\
391
+ n(n-2)(n-4) \cdots 2 & n\ \text{positive even} \\
392
+ (n+2)!!/(n+2) & n\ \text{negative odd} \end{cases}
393
+
394
+ References
395
+ ==========
396
+
397
+ .. [1] https://en.wikipedia.org/wiki/Double_factorial
398
+
399
+ Examples
400
+ ========
401
+
402
+ >>> from sympy import factorial2, var
403
+ >>> n = var('n')
404
+ >>> n
405
+ n
406
+ >>> factorial2(n + 1)
407
+ factorial2(n + 1)
408
+ >>> factorial2(5)
409
+ 15
410
+ >>> factorial2(-1)
411
+ 1
412
+ >>> factorial2(-5)
413
+ 1/3
414
+
415
+ See Also
416
+ ========
417
+
418
+ factorial, RisingFactorial, FallingFactorial
419
+ """
420
+
421
+ @classmethod
422
+ def eval(cls, arg):
423
+ # TODO: extend this to complex numbers?
424
+
425
+ if arg.is_Number:
426
+ if not arg.is_Integer:
427
+ raise ValueError("argument must be nonnegative integer "
428
+ "or negative odd integer")
429
+
430
+ # This implementation is faster than the recursive one
431
+ # It also avoids "maximum recursion depth exceeded" runtime error
432
+ if arg.is_nonnegative:
433
+ if arg.is_even:
434
+ k = arg / 2
435
+ return 2**k * factorial(k)
436
+ return factorial(arg) / factorial2(arg - 1)
437
+
438
+
439
+ if arg.is_odd:
440
+ return arg*(S.NegativeOne)**((1 - arg)/2) / factorial2(-arg)
441
+ raise ValueError("argument must be nonnegative integer "
442
+ "or negative odd integer")
443
+
444
+
445
+ def _eval_is_even(self):
446
+ # Double factorial is even for every positive even input
447
+ n = self.args[0]
448
+ if n.is_integer:
449
+ if n.is_odd:
450
+ return False
451
+ if n.is_even:
452
+ if n.is_positive:
453
+ return True
454
+ if n.is_zero:
455
+ return False
456
+
457
+ def _eval_is_integer(self):
458
+ # Double factorial is an integer for every nonnegative input, and for
459
+ # -1 and -3
460
+ n = self.args[0]
461
+ if n.is_integer:
462
+ if (n + 1).is_nonnegative:
463
+ return True
464
+ if n.is_odd:
465
+ return (n + 3).is_nonnegative
466
+
467
+ def _eval_is_odd(self):
468
+ # Double factorial is odd for every odd input not smaller than -3, and
469
+ # for 0
470
+ n = self.args[0]
471
+ if n.is_odd:
472
+ return (n + 3).is_nonnegative
473
+ if n.is_even:
474
+ if n.is_positive:
475
+ return False
476
+ if n.is_zero:
477
+ return True
478
+
479
+ def _eval_is_positive(self):
480
+ # Double factorial is positive for every nonnegative input, and for
481
+ # every odd negative input which is of the form -1-4k for an
482
+ # nonnegative integer k
483
+ n = self.args[0]
484
+ if n.is_integer:
485
+ if (n + 1).is_nonnegative:
486
+ return True
487
+ if n.is_odd:
488
+ return ((n + 1) / 2).is_even
489
+
490
+ def _eval_rewrite_as_gamma(self, n, piecewise=True, **kwargs):
491
+ from sympy.functions.elementary.miscellaneous import sqrt
492
+ from sympy.functions.elementary.piecewise import Piecewise
493
+ from sympy.functions.special.gamma_functions import gamma
494
+ return 2**(n/2)*gamma(n/2 + 1) * Piecewise((1, Eq(Mod(n, 2), 0)),
495
+ (sqrt(2/pi), Eq(Mod(n, 2), 1)))
496
+
497
+
498
+ ###############################################################################
499
+ ######################## RISING and FALLING FACTORIALS ########################
500
+ ###############################################################################
501
+
502
+
503
+ class RisingFactorial(CombinatorialFunction):
504
+ r"""
505
+ Rising factorial (also called Pochhammer symbol [1]_) is a double valued
506
+ function arising in concrete mathematics, hypergeometric functions
507
+ and series expansions. It is defined by:
508
+
509
+ .. math:: \texttt{rf(y, k)} = (x)^k = x \cdot (x+1) \cdots (x+k-1)
510
+
511
+ where `x` can be arbitrary expression and `k` is an integer. For
512
+ more information check "Concrete mathematics" by Graham, pp. 66
513
+ or visit https://mathworld.wolfram.com/RisingFactorial.html page.
514
+
515
+ When `x` is a `~.Poly` instance of degree $\ge 1$ with a single variable,
516
+ `(x)^k = x(y) \cdot x(y+1) \cdots x(y+k-1)`, where `y` is the
517
+ variable of `x`. This is as described in [2]_.
518
+
519
+ Examples
520
+ ========
521
+
522
+ >>> from sympy import rf, Poly
523
+ >>> from sympy.abc import x
524
+ >>> rf(x, 0)
525
+ 1
526
+ >>> rf(1, 5)
527
+ 120
528
+ >>> rf(x, 5) == x*(1 + x)*(2 + x)*(3 + x)*(4 + x)
529
+ True
530
+ >>> rf(Poly(x**3, x), 2)
531
+ Poly(x**6 + 3*x**5 + 3*x**4 + x**3, x, domain='ZZ')
532
+
533
+ Rewriting is complicated unless the relationship between
534
+ the arguments is known, but rising factorial can
535
+ be rewritten in terms of gamma, factorial, binomial,
536
+ and falling factorial.
537
+
538
+ >>> from sympy import Symbol, factorial, ff, binomial, gamma
539
+ >>> n = Symbol('n', integer=True, positive=True)
540
+ >>> R = rf(n, n + 2)
541
+ >>> for i in (rf, ff, factorial, binomial, gamma):
542
+ ... R.rewrite(i)
543
+ ...
544
+ RisingFactorial(n, n + 2)
545
+ FallingFactorial(2*n + 1, n + 2)
546
+ factorial(2*n + 1)/factorial(n - 1)
547
+ binomial(2*n + 1, n + 2)*factorial(n + 2)
548
+ gamma(2*n + 2)/gamma(n)
549
+
550
+ See Also
551
+ ========
552
+
553
+ factorial, factorial2, FallingFactorial
554
+
555
+ References
556
+ ==========
557
+
558
+ .. [1] https://en.wikipedia.org/wiki/Pochhammer_symbol
559
+ .. [2] Peter Paule, "Greatest Factorial Factorization and Symbolic
560
+ Summation", Journal of Symbolic Computation, vol. 20, pp. 235-268,
561
+ 1995.
562
+
563
+ """
564
+
565
+ @classmethod
566
+ def eval(cls, x, k):
567
+ x = sympify(x)
568
+ k = sympify(k)
569
+
570
+ if x is S.NaN or k is S.NaN:
571
+ return S.NaN
572
+ elif x is S.One:
573
+ return factorial(k)
574
+ elif k.is_Integer:
575
+ if k.is_zero:
576
+ return S.One
577
+ else:
578
+ if k.is_positive:
579
+ if x is S.Infinity:
580
+ return S.Infinity
581
+ elif x is S.NegativeInfinity:
582
+ if k.is_odd:
583
+ return S.NegativeInfinity
584
+ else:
585
+ return S.Infinity
586
+ else:
587
+ if isinstance(x, Poly):
588
+ gens = x.gens
589
+ if len(gens)!= 1:
590
+ raise ValueError("rf only defined for "
591
+ "polynomials on one generator")
592
+ else:
593
+ return reduce(lambda r, i:
594
+ r*(x.shift(i)),
595
+ range(int(k)), 1)
596
+ else:
597
+ return reduce(lambda r, i: r*(x + i),
598
+ range(int(k)), 1)
599
+
600
+ else:
601
+ if x is S.Infinity:
602
+ return S.Infinity
603
+ elif x is S.NegativeInfinity:
604
+ return S.Infinity
605
+ else:
606
+ if isinstance(x, Poly):
607
+ gens = x.gens
608
+ if len(gens)!= 1:
609
+ raise ValueError("rf only defined for "
610
+ "polynomials on one generator")
611
+ else:
612
+ return 1/reduce(lambda r, i:
613
+ r*(x.shift(-i)),
614
+ range(1, abs(int(k)) + 1), 1)
615
+ else:
616
+ return 1/reduce(lambda r, i:
617
+ r*(x - i),
618
+ range(1, abs(int(k)) + 1), 1)
619
+
620
+ if k.is_integer == False:
621
+ if x.is_integer and x.is_negative:
622
+ return S.Zero
623
+
624
+ def _eval_rewrite_as_gamma(self, x, k, piecewise=True, **kwargs):
625
+ from sympy.functions.elementary.piecewise import Piecewise
626
+ from sympy.functions.special.gamma_functions import gamma
627
+ if not piecewise:
628
+ if (x <= 0) == True:
629
+ return S.NegativeOne**k*gamma(1 - x) / gamma(-k - x + 1)
630
+ return gamma(x + k) / gamma(x)
631
+ return Piecewise(
632
+ (gamma(x + k) / gamma(x), x > 0),
633
+ (S.NegativeOne**k*gamma(1 - x) / gamma(-k - x + 1), True))
634
+
635
+ def _eval_rewrite_as_FallingFactorial(self, x, k, **kwargs):
636
+ return FallingFactorial(x + k - 1, k)
637
+
638
+ def _eval_rewrite_as_factorial(self, x, k, **kwargs):
639
+ from sympy.functions.elementary.piecewise import Piecewise
640
+ if x.is_integer and k.is_integer:
641
+ return Piecewise(
642
+ (factorial(k + x - 1)/factorial(x - 1), x > 0),
643
+ (S.NegativeOne**k*factorial(-x)/factorial(-k - x), True))
644
+
645
+ def _eval_rewrite_as_binomial(self, x, k, **kwargs):
646
+ if k.is_integer:
647
+ return factorial(k) * binomial(x + k - 1, k)
648
+
649
+ def _eval_rewrite_as_tractable(self, x, k, limitvar=None, **kwargs):
650
+ from sympy.functions.special.gamma_functions import gamma
651
+ if limitvar:
652
+ k_lim = k.subs(limitvar, S.Infinity)
653
+ if k_lim is S.Infinity:
654
+ return (gamma(x + k).rewrite('tractable', deep=True) / gamma(x))
655
+ elif k_lim is S.NegativeInfinity:
656
+ return (S.NegativeOne**k*gamma(1 - x) / gamma(-k - x + 1).rewrite('tractable', deep=True))
657
+ return self.rewrite(gamma).rewrite('tractable', deep=True)
658
+
659
+ def _eval_is_integer(self):
660
+ return fuzzy_and((self.args[0].is_integer, self.args[1].is_integer,
661
+ self.args[1].is_nonnegative))
662
+
663
+
664
+ class FallingFactorial(CombinatorialFunction):
665
+ r"""
666
+ Falling factorial (related to rising factorial) is a double valued
667
+ function arising in concrete mathematics, hypergeometric functions
668
+ and series expansions. It is defined by
669
+
670
+ .. math:: \texttt{ff(x, k)} = (x)_k = x \cdot (x-1) \cdots (x-k+1)
671
+
672
+ where `x` can be arbitrary expression and `k` is an integer. For
673
+ more information check "Concrete mathematics" by Graham, pp. 66
674
+ or [1]_.
675
+
676
+ When `x` is a `~.Poly` instance of degree $\ge 1$ with single variable,
677
+ `(x)_k = x(y) \cdot x(y-1) \cdots x(y-k+1)`, where `y` is the
678
+ variable of `x`. This is as described in
679
+
680
+ >>> from sympy import ff, Poly, Symbol
681
+ >>> from sympy.abc import x
682
+ >>> n = Symbol('n', integer=True)
683
+
684
+ >>> ff(x, 0)
685
+ 1
686
+ >>> ff(5, 5)
687
+ 120
688
+ >>> ff(x, 5) == x*(x - 1)*(x - 2)*(x - 3)*(x - 4)
689
+ True
690
+ >>> ff(Poly(x**2, x), 2)
691
+ Poly(x**4 - 2*x**3 + x**2, x, domain='ZZ')
692
+ >>> ff(n, n)
693
+ factorial(n)
694
+
695
+ Rewriting is complicated unless the relationship between
696
+ the arguments is known, but falling factorial can
697
+ be rewritten in terms of gamma, factorial and binomial
698
+ and rising factorial.
699
+
700
+ >>> from sympy import factorial, rf, gamma, binomial, Symbol
701
+ >>> n = Symbol('n', integer=True, positive=True)
702
+ >>> F = ff(n, n - 2)
703
+ >>> for i in (rf, ff, factorial, binomial, gamma):
704
+ ... F.rewrite(i)
705
+ ...
706
+ RisingFactorial(3, n - 2)
707
+ FallingFactorial(n, n - 2)
708
+ factorial(n)/2
709
+ binomial(n, n - 2)*factorial(n - 2)
710
+ gamma(n + 1)/2
711
+
712
+ See Also
713
+ ========
714
+
715
+ factorial, factorial2, RisingFactorial
716
+
717
+ References
718
+ ==========
719
+
720
+ .. [1] https://mathworld.wolfram.com/FallingFactorial.html
721
+ .. [2] Peter Paule, "Greatest Factorial Factorization and Symbolic
722
+ Summation", Journal of Symbolic Computation, vol. 20, pp. 235-268,
723
+ 1995.
724
+
725
+ """
726
+
727
+ @classmethod
728
+ def eval(cls, x, k):
729
+ x = sympify(x)
730
+ k = sympify(k)
731
+
732
+ if x is S.NaN or k is S.NaN:
733
+ return S.NaN
734
+ elif k.is_integer and x == k:
735
+ return factorial(x)
736
+ elif k.is_Integer:
737
+ if k.is_zero:
738
+ return S.One
739
+ else:
740
+ if k.is_positive:
741
+ if x is S.Infinity:
742
+ return S.Infinity
743
+ elif x is S.NegativeInfinity:
744
+ if k.is_odd:
745
+ return S.NegativeInfinity
746
+ else:
747
+ return S.Infinity
748
+ else:
749
+ if isinstance(x, Poly):
750
+ gens = x.gens
751
+ if len(gens)!= 1:
752
+ raise ValueError("ff only defined for "
753
+ "polynomials on one generator")
754
+ else:
755
+ return reduce(lambda r, i:
756
+ r*(x.shift(-i)),
757
+ range(int(k)), 1)
758
+ else:
759
+ return reduce(lambda r, i: r*(x - i),
760
+ range(int(k)), 1)
761
+ else:
762
+ if x is S.Infinity:
763
+ return S.Infinity
764
+ elif x is S.NegativeInfinity:
765
+ return S.Infinity
766
+ else:
767
+ if isinstance(x, Poly):
768
+ gens = x.gens
769
+ if len(gens)!= 1:
770
+ raise ValueError("rf only defined for "
771
+ "polynomials on one generator")
772
+ else:
773
+ return 1/reduce(lambda r, i:
774
+ r*(x.shift(i)),
775
+ range(1, abs(int(k)) + 1), 1)
776
+ else:
777
+ return 1/reduce(lambda r, i: r*(x + i),
778
+ range(1, abs(int(k)) + 1), 1)
779
+
780
+ def _eval_rewrite_as_gamma(self, x, k, piecewise=True, **kwargs):
781
+ from sympy.functions.elementary.piecewise import Piecewise
782
+ from sympy.functions.special.gamma_functions import gamma
783
+ if not piecewise:
784
+ if (x < 0) == True:
785
+ return S.NegativeOne**k*gamma(k - x) / gamma(-x)
786
+ return gamma(x + 1) / gamma(x - k + 1)
787
+ return Piecewise(
788
+ (gamma(x + 1) / gamma(x - k + 1), x >= 0),
789
+ (S.NegativeOne**k*gamma(k - x) / gamma(-x), True))
790
+
791
+ def _eval_rewrite_as_RisingFactorial(self, x, k, **kwargs):
792
+ return rf(x - k + 1, k)
793
+
794
+ def _eval_rewrite_as_binomial(self, x, k, **kwargs):
795
+ if k.is_integer:
796
+ return factorial(k) * binomial(x, k)
797
+
798
+ def _eval_rewrite_as_factorial(self, x, k, **kwargs):
799
+ from sympy.functions.elementary.piecewise import Piecewise
800
+ if x.is_integer and k.is_integer:
801
+ return Piecewise(
802
+ (factorial(x)/factorial(-k + x), x >= 0),
803
+ (S.NegativeOne**k*factorial(k - x - 1)/factorial(-x - 1), True))
804
+
805
+ def _eval_rewrite_as_tractable(self, x, k, limitvar=None, **kwargs):
806
+ from sympy.functions.special.gamma_functions import gamma
807
+ if limitvar:
808
+ k_lim = k.subs(limitvar, S.Infinity)
809
+ if k_lim is S.Infinity:
810
+ return (S.NegativeOne**k*gamma(k - x).rewrite('tractable', deep=True) / gamma(-x))
811
+ elif k_lim is S.NegativeInfinity:
812
+ return (gamma(x + 1) / gamma(x - k + 1).rewrite('tractable', deep=True))
813
+ return self.rewrite(gamma).rewrite('tractable', deep=True)
814
+
815
+ def _eval_is_integer(self):
816
+ return fuzzy_and((self.args[0].is_integer, self.args[1].is_integer,
817
+ self.args[1].is_nonnegative))
818
+
819
+
820
+ rf = RisingFactorial
821
+ ff = FallingFactorial
822
+
823
+ ###############################################################################
824
+ ########################### BINOMIAL COEFFICIENTS #############################
825
+ ###############################################################################
826
+
827
+
828
+ class binomial(CombinatorialFunction):
829
+ r"""Implementation of the binomial coefficient. It can be defined
830
+ in two ways depending on its desired interpretation:
831
+
832
+ .. math:: \binom{n}{k} = \frac{n!}{k!(n-k)!}\ \text{or}\
833
+ \binom{n}{k} = \frac{(n)_k}{k!}
834
+
835
+ First, in a strict combinatorial sense it defines the
836
+ number of ways we can choose `k` elements from a set of
837
+ `n` elements. In this case both arguments are nonnegative
838
+ integers and binomial is computed using an efficient
839
+ algorithm based on prime factorization.
840
+
841
+ The other definition is generalization for arbitrary `n`,
842
+ however `k` must also be nonnegative. This case is very
843
+ useful when evaluating summations.
844
+
845
+ For the sake of convenience, for negative integer `k` this function
846
+ will return zero no matter the other argument.
847
+
848
+ To expand the binomial when `n` is a symbol, use either
849
+ ``expand_func()`` or ``expand(func=True)``. The former will keep
850
+ the polynomial in factored form while the latter will expand the
851
+ polynomial itself. See examples for details.
852
+
853
+ Examples
854
+ ========
855
+
856
+ >>> from sympy import Symbol, Rational, binomial, expand_func
857
+ >>> n = Symbol('n', integer=True, positive=True)
858
+
859
+ >>> binomial(15, 8)
860
+ 6435
861
+
862
+ >>> binomial(n, -1)
863
+ 0
864
+
865
+ Rows of Pascal's triangle can be generated with the binomial function:
866
+
867
+ >>> for N in range(8):
868
+ ... print([binomial(N, i) for i in range(N + 1)])
869
+ ...
870
+ [1]
871
+ [1, 1]
872
+ [1, 2, 1]
873
+ [1, 3, 3, 1]
874
+ [1, 4, 6, 4, 1]
875
+ [1, 5, 10, 10, 5, 1]
876
+ [1, 6, 15, 20, 15, 6, 1]
877
+ [1, 7, 21, 35, 35, 21, 7, 1]
878
+
879
+ As can a given diagonal, e.g. the 4th diagonal:
880
+
881
+ >>> N = -4
882
+ >>> [binomial(N, i) for i in range(1 - N)]
883
+ [1, -4, 10, -20, 35]
884
+
885
+ >>> binomial(Rational(5, 4), 3)
886
+ -5/128
887
+ >>> binomial(Rational(-5, 4), 3)
888
+ -195/128
889
+
890
+ >>> binomial(n, 3)
891
+ binomial(n, 3)
892
+
893
+ >>> binomial(n, 3).expand(func=True)
894
+ n**3/6 - n**2/2 + n/3
895
+
896
+ >>> expand_func(binomial(n, 3))
897
+ n*(n - 2)*(n - 1)/6
898
+
899
+ In many cases, we can also compute binomial coefficients modulo a
900
+ prime p quickly using Lucas' Theorem [2]_, though we need to include
901
+ `evaluate=False` to postpone evaluation:
902
+
903
+ >>> from sympy import Mod
904
+ >>> Mod(binomial(156675, 4433, evaluate=False), 10**5 + 3)
905
+ 28625
906
+
907
+ Using a generalisation of Lucas's Theorem given by Granville [3]_,
908
+ we can extend this to arbitrary n:
909
+
910
+ >>> Mod(binomial(10**18, 10**12, evaluate=False), (10**5 + 3)**2)
911
+ 3744312326
912
+
913
+ References
914
+ ==========
915
+
916
+ .. [1] https://www.johndcook.com/blog/binomial_coefficients/
917
+ .. [2] https://en.wikipedia.org/wiki/Lucas%27s_theorem
918
+ .. [3] Binomial coefficients modulo prime powers, Andrew Granville,
919
+ Available: https://web.archive.org/web/20170202003812/http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf
920
+ """
921
+
922
+ def fdiff(self, argindex=1):
923
+ from sympy.functions.special.gamma_functions import polygamma
924
+ if argindex == 1:
925
+ # https://functions.wolfram.com/GammaBetaErf/Binomial/20/01/01/
926
+ n, k = self.args
927
+ return binomial(n, k)*(polygamma(0, n + 1) - \
928
+ polygamma(0, n - k + 1))
929
+ elif argindex == 2:
930
+ # https://functions.wolfram.com/GammaBetaErf/Binomial/20/01/02/
931
+ n, k = self.args
932
+ return binomial(n, k)*(polygamma(0, n - k + 1) - \
933
+ polygamma(0, k + 1))
934
+ else:
935
+ raise ArgumentIndexError(self, argindex)
936
+
937
+ @classmethod
938
+ def _eval(self, n, k):
939
+ # n.is_Number and k.is_Integer and k != 1 and n != k
940
+
941
+ if k.is_Integer:
942
+ if n.is_Integer and n >= 0:
943
+ n, k = int(n), int(k)
944
+
945
+ if k > n:
946
+ return S.Zero
947
+ elif k > n // 2:
948
+ k = n - k
949
+
950
+ # XXX: This conditional logic should be moved to
951
+ # sympy.external.gmpy and the pure Python version of bincoef
952
+ # should be moved to sympy.external.ntheory.
953
+ if _gmpy is not None:
954
+ return Integer(_gmpy.bincoef(n, k))
955
+
956
+ d, result = n - k, 1
957
+ for i in range(1, k + 1):
958
+ d += 1
959
+ result = result * d // i
960
+ return Integer(result)
961
+ else:
962
+ d, result = n - k, 1
963
+ for i in range(1, k + 1):
964
+ d += 1
965
+ result *= d
966
+ return result / _factorial(k)
967
+
968
+ @classmethod
969
+ def eval(cls, n, k):
970
+ n, k = map(sympify, (n, k))
971
+ d = n - k
972
+ n_nonneg, n_isint = n.is_nonnegative, n.is_integer
973
+ if k.is_zero or ((n_nonneg or n_isint is False)
974
+ and d.is_zero):
975
+ return S.One
976
+ if (k - 1).is_zero or ((n_nonneg or n_isint is False)
977
+ and (d - 1).is_zero):
978
+ return n
979
+ if k.is_integer:
980
+ if k.is_negative or (n_nonneg and n_isint and d.is_negative):
981
+ return S.Zero
982
+ elif n.is_number:
983
+ res = cls._eval(n, k)
984
+ return res.expand(basic=True) if res else res
985
+ elif n_nonneg is False and n_isint:
986
+ # a special case when binomial evaluates to complex infinity
987
+ return S.ComplexInfinity
988
+ elif k.is_number:
989
+ from sympy.functions.special.gamma_functions import gamma
990
+ return gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1))
991
+
992
+ def _eval_Mod(self, q):
993
+ n, k = self.args
994
+
995
+ if any(x.is_integer is False for x in (n, k, q)):
996
+ raise ValueError("Integers expected for binomial Mod")
997
+
998
+ if all(x.is_Integer for x in (n, k, q)):
999
+ n, k = map(int, (n, k))
1000
+ aq, res = abs(q), 1
1001
+
1002
+ # handle negative integers k or n
1003
+ if k < 0:
1004
+ return S.Zero
1005
+ if n < 0:
1006
+ n = -n + k - 1
1007
+ res = -1 if k%2 else 1
1008
+
1009
+ # non negative integers k and n
1010
+ if k > n:
1011
+ return S.Zero
1012
+
1013
+ isprime = aq.is_prime
1014
+ aq = int(aq)
1015
+ if isprime:
1016
+ if aq < n:
1017
+ # use Lucas Theorem
1018
+ N, K = n, k
1019
+ while N or K:
1020
+ res = res*binomial(N % aq, K % aq) % aq
1021
+ N, K = N // aq, K // aq
1022
+
1023
+ else:
1024
+ # use Factorial Modulo
1025
+ d = n - k
1026
+ if k > d:
1027
+ k, d = d, k
1028
+ kf = 1
1029
+ for i in range(2, k + 1):
1030
+ kf = kf*i % aq
1031
+ df = kf
1032
+ for i in range(k + 1, d + 1):
1033
+ df = df*i % aq
1034
+ res *= df
1035
+ for i in range(d + 1, n + 1):
1036
+ res = res*i % aq
1037
+
1038
+ res *= pow(kf*df % aq, aq - 2, aq)
1039
+ res %= aq
1040
+
1041
+ elif _sqrt(q) < k and q != 1:
1042
+ res = binomial_mod(n, k, q)
1043
+
1044
+ else:
1045
+ # Binomial Factorization is performed by calculating the
1046
+ # exponents of primes <= n in `n! /(k! (n - k)!)`,
1047
+ # for non-negative integers n and k. As the exponent of
1048
+ # prime in n! is e_p(n) = [n/p] + [n/p**2] + ...
1049
+ # the exponent of prime in binomial(n, k) would be
1050
+ # e_p(n) - e_p(k) - e_p(n - k)
1051
+ M = int(_sqrt(n))
1052
+ for prime in sieve.primerange(2, n + 1):
1053
+ if prime > n - k:
1054
+ res = res*prime % aq
1055
+ elif prime > n // 2:
1056
+ continue
1057
+ elif prime > M:
1058
+ if n % prime < k % prime:
1059
+ res = res*prime % aq
1060
+ else:
1061
+ N, K = n, k
1062
+ exp = a = 0
1063
+
1064
+ while N > 0:
1065
+ a = int((N % prime) < (K % prime + a))
1066
+ N, K = N // prime, K // prime
1067
+ exp += a
1068
+
1069
+ if exp > 0:
1070
+ res *= pow(prime, exp, aq)
1071
+ res %= aq
1072
+
1073
+ return S(res % q)
1074
+
1075
+ def _eval_expand_func(self, **hints):
1076
+ """
1077
+ Function to expand binomial(n, k) when m is positive integer
1078
+ Also,
1079
+ n is self.args[0] and k is self.args[1] while using binomial(n, k)
1080
+ """
1081
+ n = self.args[0]
1082
+ if n.is_Number:
1083
+ return binomial(*self.args)
1084
+
1085
+ k = self.args[1]
1086
+ if (n-k).is_Integer:
1087
+ k = n - k
1088
+
1089
+ if k.is_Integer:
1090
+ if k.is_zero:
1091
+ return S.One
1092
+ elif k.is_negative:
1093
+ return S.Zero
1094
+ else:
1095
+ n, result = self.args[0], 1
1096
+ for i in range(1, k + 1):
1097
+ result *= n - k + i
1098
+ return result / _factorial(k)
1099
+ else:
1100
+ return binomial(*self.args)
1101
+
1102
+ def _eval_rewrite_as_factorial(self, n, k, **kwargs):
1103
+ return factorial(n)/(factorial(k)*factorial(n - k))
1104
+
1105
+ def _eval_rewrite_as_gamma(self, n, k, piecewise=True, **kwargs):
1106
+ from sympy.functions.special.gamma_functions import gamma
1107
+ return gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1))
1108
+
1109
+ def _eval_rewrite_as_tractable(self, n, k, limitvar=None, **kwargs):
1110
+ return self._eval_rewrite_as_gamma(n, k).rewrite('tractable')
1111
+
1112
+ def _eval_rewrite_as_FallingFactorial(self, n, k, **kwargs):
1113
+ if k.is_integer:
1114
+ return ff(n, k) / factorial(k)
1115
+
1116
+ def _eval_is_integer(self):
1117
+ n, k = self.args
1118
+ if n.is_integer and k.is_integer:
1119
+ return True
1120
+ elif k.is_integer is False:
1121
+ return False
1122
+
1123
+ def _eval_is_nonnegative(self):
1124
+ n, k = self.args
1125
+ if n.is_integer and k.is_integer:
1126
+ if n.is_nonnegative or k.is_negative or k.is_even:
1127
+ return True
1128
+ elif k.is_even is False:
1129
+ return False
1130
+
1131
+ def _eval_as_leading_term(self, x, logx, cdir):
1132
+ from sympy.functions.special.gamma_functions import gamma
1133
+ return self.rewrite(gamma)._eval_as_leading_term(x, logx=logx, cdir=cdir)
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/combinatorial/numbers.py ADDED
The diff for this file is too large to render. See raw diff
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ # Stub __init__.py for sympy.functions.elementary
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/_trigonometric_special.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ r"""A module for special angle formulas for trigonometric functions
2
+
3
+ TODO
4
+ ====
5
+
6
+ This module should be developed in the future to contain direct square root
7
+ representation of
8
+
9
+ .. math
10
+ F(\frac{n}{m} \pi)
11
+
12
+ for every
13
+
14
+ - $m \in \{ 3, 5, 17, 257, 65537 \}$
15
+ - $n \in \mathbb{N}$, $0 \le n < m$
16
+ - $F \in \{\sin, \cos, \tan, \csc, \sec, \cot\}$
17
+
18
+ Without multi-step rewrites
19
+ (e.g. $\tan \to \cos/\sin \to \cos/\sqrt \to \ sqrt$)
20
+ or using chebyshev identities
21
+ (e.g. $\cos \to \cos + \cos^2 + \cdots \to \sqrt{} + \sqrt{}^2 + \cdots $),
22
+ which are trivial to implement in sympy,
23
+ and had used to give overly complicated expressions.
24
+
25
+ The reference can be found below, if anyone may need help implementing them.
26
+
27
+ References
28
+ ==========
29
+
30
+ .. [*] Gottlieb, Christian. (1999). The Simple and straightforward construction
31
+ of the regular 257-gon. The Mathematical Intelligencer. 21. 31-37.
32
+ 10.1007/BF03024829.
33
+ .. [*] https://resources.wolframcloud.com/FunctionRepository/resources/Cos2PiOverFermatPrime
34
+ """
35
+ from __future__ import annotations
36
+ from typing import Callable
37
+ from functools import reduce
38
+ from sympy.core.expr import Expr
39
+ from sympy.core.singleton import S
40
+ from sympy.core.intfunc import igcdex
41
+ from sympy.core.numbers import Integer
42
+ from sympy.functions.elementary.miscellaneous import sqrt
43
+ from sympy.core.cache import cacheit
44
+
45
+
46
+ def migcdex(*x: int) -> tuple[tuple[int, ...], int]:
47
+ r"""Compute extended gcd for multiple integers.
48
+
49
+ Explanation
50
+ ===========
51
+
52
+ Given the integers $x_1, \cdots, x_n$ and
53
+ an extended gcd for multiple arguments are defined as a solution
54
+ $(y_1, \cdots, y_n), g$ for the diophantine equation
55
+ $x_1 y_1 + \cdots + x_n y_n = g$ such that
56
+ $g = \gcd(x_1, \cdots, x_n)$.
57
+
58
+ Examples
59
+ ========
60
+
61
+ >>> from sympy.functions.elementary._trigonometric_special import migcdex
62
+ >>> migcdex()
63
+ ((), 0)
64
+ >>> migcdex(4)
65
+ ((1,), 4)
66
+ >>> migcdex(4, 6)
67
+ ((-1, 1), 2)
68
+ >>> migcdex(6, 10, 15)
69
+ ((1, 1, -1), 1)
70
+ """
71
+ if not x:
72
+ return (), 0
73
+
74
+ if len(x) == 1:
75
+ return (1,), x[0]
76
+
77
+ if len(x) == 2:
78
+ u, v, h = igcdex(x[0], x[1])
79
+ return (u, v), h
80
+
81
+ y, g = migcdex(*x[1:])
82
+ u, v, h = igcdex(x[0], g)
83
+ return (u, *(v * i for i in y)), h
84
+
85
+
86
+ def ipartfrac(*denoms: int) -> tuple[int, ...]:
87
+ r"""Compute the partial fraction decomposition.
88
+
89
+ Explanation
90
+ ===========
91
+
92
+ Given a rational number $\frac{1}{q_1 \cdots q_n}$ where all
93
+ $q_1, \cdots, q_n$ are pairwise coprime,
94
+
95
+ A partial fraction decomposition is defined as
96
+
97
+ .. math::
98
+ \frac{1}{q_1 \cdots q_n} = \frac{p_1}{q_1} + \cdots + \frac{p_n}{q_n}
99
+
100
+ And it can be derived from solving the following diophantine equation for
101
+ the $p_1, \cdots, p_n$
102
+
103
+ .. math::
104
+ 1 = p_1 \prod_{i \ne 1}q_i + \cdots + p_n \prod_{i \ne n}q_i
105
+
106
+ Where $q_1, \cdots, q_n$ being pairwise coprime implies
107
+ $\gcd(\prod_{i \ne 1}q_i, \cdots, \prod_{i \ne n}q_i) = 1$,
108
+ which guarantees the existence of the solution.
109
+
110
+ It is sufficient to compute partial fraction decomposition only
111
+ for numerator $1$ because partial fraction decomposition for any
112
+ $\frac{n}{q_1 \cdots q_n}$ can be easily computed by multiplying
113
+ the result by $n$ afterwards.
114
+
115
+ Parameters
116
+ ==========
117
+
118
+ denoms : int
119
+ The pairwise coprime integer denominators $q_i$ which defines the
120
+ rational number $\frac{1}{q_1 \cdots q_n}$
121
+
122
+ Returns
123
+ =======
124
+
125
+ tuple[int, ...]
126
+ The list of numerators which semantically corresponds to $p_i$ of the
127
+ partial fraction decomposition
128
+ $\frac{1}{q_1 \cdots q_n} = \frac{p_1}{q_1} + \cdots + \frac{p_n}{q_n}$
129
+
130
+ Examples
131
+ ========
132
+
133
+ >>> from sympy import Rational, Mul
134
+ >>> from sympy.functions.elementary._trigonometric_special import ipartfrac
135
+
136
+ >>> denoms = 2, 3, 5
137
+ >>> numers = ipartfrac(2, 3, 5)
138
+ >>> numers
139
+ (1, 7, -14)
140
+
141
+ >>> Rational(1, Mul(*denoms))
142
+ 1/30
143
+ >>> out = 0
144
+ >>> for n, d in zip(numers, denoms):
145
+ ... out += Rational(n, d)
146
+ >>> out
147
+ 1/30
148
+ """
149
+ if not denoms:
150
+ return ()
151
+
152
+ def mul(x: int, y: int) -> int:
153
+ return x * y
154
+
155
+ denom = reduce(mul, denoms)
156
+ a = [denom // x for x in denoms]
157
+ h, _ = migcdex(*a)
158
+ return h
159
+
160
+
161
+ def fermat_coords(n: int) -> list[int] | None:
162
+ """If n can be factored in terms of Fermat primes with
163
+ multiplicity of each being 1, return those primes, else
164
+ None
165
+ """
166
+ primes = []
167
+ for p in [3, 5, 17, 257, 65537]:
168
+ quotient, remainder = divmod(n, p)
169
+ if remainder == 0:
170
+ n = quotient
171
+ primes.append(p)
172
+ if n == 1:
173
+ return primes
174
+ return None
175
+
176
+
177
+ @cacheit
178
+ def cos_3() -> Expr:
179
+ r"""Computes $\cos \frac{\pi}{3}$ in square roots"""
180
+ return S.Half
181
+
182
+
183
+ @cacheit
184
+ def cos_5() -> Expr:
185
+ r"""Computes $\cos \frac{\pi}{5}$ in square roots"""
186
+ return (sqrt(5) + 1) / 4
187
+
188
+
189
+ @cacheit
190
+ def cos_17() -> Expr:
191
+ r"""Computes $\cos \frac{\pi}{17}$ in square roots"""
192
+ return sqrt(
193
+ (15 + sqrt(17)) / 32 + sqrt(2) * (sqrt(17 - sqrt(17)) +
194
+ sqrt(sqrt(2) * (-8 * sqrt(17 + sqrt(17)) - (1 - sqrt(17))
195
+ * sqrt(17 - sqrt(17))) + 6 * sqrt(17) + 34)) / 32)
196
+
197
+
198
+ @cacheit
199
+ def cos_257() -> Expr:
200
+ r"""Computes $\cos \frac{\pi}{257}$ in square roots
201
+
202
+ References
203
+ ==========
204
+
205
+ .. [*] https://math.stackexchange.com/questions/516142/how-does-cos2-pi-257-look-like-in-real-radicals
206
+ .. [*] https://r-knott.surrey.ac.uk/Fibonacci/simpleTrig.html
207
+ """
208
+ def f1(a: Expr, b: Expr) -> tuple[Expr, Expr]:
209
+ return (a + sqrt(a**2 + b)) / 2, (a - sqrt(a**2 + b)) / 2
210
+
211
+ def f2(a: Expr, b: Expr) -> Expr:
212
+ return (a - sqrt(a**2 + b))/2
213
+
214
+ t1, t2 = f1(S.NegativeOne, Integer(256))
215
+ z1, z3 = f1(t1, Integer(64))
216
+ z2, z4 = f1(t2, Integer(64))
217
+ y1, y5 = f1(z1, 4*(5 + t1 + 2*z1))
218
+ y6, y2 = f1(z2, 4*(5 + t2 + 2*z2))
219
+ y3, y7 = f1(z3, 4*(5 + t1 + 2*z3))
220
+ y8, y4 = f1(z4, 4*(5 + t2 + 2*z4))
221
+ x1, x9 = f1(y1, -4*(t1 + y1 + y3 + 2*y6))
222
+ x2, x10 = f1(y2, -4*(t2 + y2 + y4 + 2*y7))
223
+ x3, x11 = f1(y3, -4*(t1 + y3 + y5 + 2*y8))
224
+ x4, x12 = f1(y4, -4*(t2 + y4 + y6 + 2*y1))
225
+ x5, x13 = f1(y5, -4*(t1 + y5 + y7 + 2*y2))
226
+ x6, x14 = f1(y6, -4*(t2 + y6 + y8 + 2*y3))
227
+ x15, x7 = f1(y7, -4*(t1 + y7 + y1 + 2*y4))
228
+ x8, x16 = f1(y8, -4*(t2 + y8 + y2 + 2*y5))
229
+ v1 = f2(x1, -4*(x1 + x2 + x3 + x6))
230
+ v2 = f2(x2, -4*(x2 + x3 + x4 + x7))
231
+ v3 = f2(x8, -4*(x8 + x9 + x10 + x13))
232
+ v4 = f2(x9, -4*(x9 + x10 + x11 + x14))
233
+ v5 = f2(x10, -4*(x10 + x11 + x12 + x15))
234
+ v6 = f2(x16, -4*(x16 + x1 + x2 + x5))
235
+ u1 = -f2(-v1, -4*(v2 + v3))
236
+ u2 = -f2(-v4, -4*(v5 + v6))
237
+ w1 = -2*f2(-u1, -4*u2)
238
+ return sqrt(sqrt(2)*sqrt(w1 + 4)/8 + S.Half)
239
+
240
+
241
+ def cos_table() -> dict[int, Callable[[], Expr]]:
242
+ r"""Lazily evaluated table for $\cos \frac{\pi}{n}$ in square roots for
243
+ $n \in \{3, 5, 17, 257, 65537\}$.
244
+
245
+ Notes
246
+ =====
247
+
248
+ 65537 is the only other known Fermat prime and it is nearly impossible to
249
+ build in the current SymPy due to performance issues.
250
+
251
+ References
252
+ ==========
253
+
254
+ https://r-knott.surrey.ac.uk/Fibonacci/simpleTrig.html
255
+ """
256
+ return {
257
+ 3: cos_3,
258
+ 5: cos_5,
259
+ 17: cos_17,
260
+ 257: cos_257
261
+ }
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/complexes.py ADDED
@@ -0,0 +1,1492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from sympy.core import S, Add, Mul, sympify, Symbol, Dummy, Basic
4
+ from sympy.core.expr import Expr
5
+ from sympy.core.exprtools import factor_terms
6
+ from sympy.core.function import (DefinedFunction, Derivative, ArgumentIndexError,
7
+ AppliedUndef, expand_mul, PoleError)
8
+ from sympy.core.logic import fuzzy_not, fuzzy_or
9
+ from sympy.core.numbers import pi, I, oo
10
+ from sympy.core.power import Pow
11
+ from sympy.core.relational import Eq
12
+ from sympy.functions.elementary.miscellaneous import sqrt
13
+ from sympy.functions.elementary.piecewise import Piecewise
14
+
15
+ ###############################################################################
16
+ ######################### REAL and IMAGINARY PARTS ############################
17
+ ###############################################################################
18
+
19
+
20
+ class re(DefinedFunction):
21
+ """
22
+ Returns real part of expression. This function performs only
23
+ elementary analysis and so it will fail to decompose properly
24
+ more complicated expressions. If completely simplified result
25
+ is needed then use ``Basic.as_real_imag()`` or perform complex
26
+ expansion on instance of this function.
27
+
28
+ Examples
29
+ ========
30
+
31
+ >>> from sympy import re, im, I, E, symbols
32
+ >>> x, y = symbols('x y', real=True)
33
+ >>> re(2*E)
34
+ 2*E
35
+ >>> re(2*I + 17)
36
+ 17
37
+ >>> re(2*I)
38
+ 0
39
+ >>> re(im(x) + x*I + 2)
40
+ 2
41
+ >>> re(5 + I + 2)
42
+ 7
43
+
44
+ Parameters
45
+ ==========
46
+
47
+ arg : Expr
48
+ Real or complex expression.
49
+
50
+ Returns
51
+ =======
52
+
53
+ expr : Expr
54
+ Real part of expression.
55
+
56
+ See Also
57
+ ========
58
+
59
+ im
60
+ """
61
+
62
+ args: tuple[Expr]
63
+
64
+ is_extended_real = True
65
+ unbranched = True # implicitly works on the projection to C
66
+ _singularities = True # non-holomorphic
67
+
68
+ @classmethod
69
+ def eval(cls, arg):
70
+ if arg is S.NaN:
71
+ return S.NaN
72
+ elif arg is S.ComplexInfinity:
73
+ return S.NaN
74
+ elif arg.is_extended_real:
75
+ return arg
76
+ elif arg.is_imaginary or (I*arg).is_extended_real:
77
+ return S.Zero
78
+ elif arg.is_Matrix:
79
+ return arg.as_real_imag()[0]
80
+ elif arg.is_Function and isinstance(arg, conjugate):
81
+ return re(arg.args[0])
82
+ else:
83
+
84
+ included, reverted, excluded = [], [], []
85
+ args = Add.make_args(arg)
86
+ for term in args:
87
+ coeff = term.as_coefficient(I)
88
+
89
+ if coeff is not None:
90
+ if not coeff.is_extended_real:
91
+ reverted.append(coeff)
92
+ elif not term.has(I) and term.is_extended_real:
93
+ excluded.append(term)
94
+ else:
95
+ # Try to do some advanced expansion. If
96
+ # impossible, don't try to do re(arg) again
97
+ # (because this is what we are trying to do now).
98
+ real_imag = term.as_real_imag(ignore=arg)
99
+ if real_imag:
100
+ excluded.append(real_imag[0])
101
+ else:
102
+ included.append(term)
103
+
104
+ if len(args) != len(included):
105
+ a, b, c = (Add(*xs) for xs in [included, reverted, excluded])
106
+
107
+ return cls(a) - im(b) + c
108
+
109
+ def as_real_imag(self, deep=True, **hints):
110
+ """
111
+ Returns the real number with a zero imaginary part.
112
+
113
+ """
114
+ return (self, S.Zero)
115
+
116
+ def _eval_derivative(self, x):
117
+ if x.is_extended_real or self.args[0].is_extended_real:
118
+ return re(Derivative(self.args[0], x, evaluate=True))
119
+ if x.is_imaginary or self.args[0].is_imaginary:
120
+ return -I \
121
+ * im(Derivative(self.args[0], x, evaluate=True))
122
+
123
+ def _eval_rewrite_as_im(self, arg, **kwargs):
124
+ return self.args[0] - I*im(self.args[0])
125
+
126
+ def _eval_is_algebraic(self):
127
+ return self.args[0].is_algebraic
128
+
129
+ def _eval_is_zero(self):
130
+ # is_imaginary implies nonzero
131
+ return fuzzy_or([self.args[0].is_imaginary, self.args[0].is_zero])
132
+
133
+ def _eval_is_finite(self):
134
+ if self.args[0].is_finite:
135
+ return True
136
+
137
+ def _eval_is_complex(self):
138
+ if self.args[0].is_finite:
139
+ return True
140
+
141
+
142
+ class im(DefinedFunction):
143
+ """
144
+ Returns imaginary part of expression. This function performs only
145
+ elementary analysis and so it will fail to decompose properly more
146
+ complicated expressions. If completely simplified result is needed then
147
+ use ``Basic.as_real_imag()`` or perform complex expansion on instance of
148
+ this function.
149
+
150
+ Examples
151
+ ========
152
+
153
+ >>> from sympy import re, im, E, I
154
+ >>> from sympy.abc import x, y
155
+ >>> im(2*E)
156
+ 0
157
+ >>> im(2*I + 17)
158
+ 2
159
+ >>> im(x*I)
160
+ re(x)
161
+ >>> im(re(x) + y)
162
+ im(y)
163
+ >>> im(2 + 3*I)
164
+ 3
165
+
166
+ Parameters
167
+ ==========
168
+
169
+ arg : Expr
170
+ Real or complex expression.
171
+
172
+ Returns
173
+ =======
174
+
175
+ expr : Expr
176
+ Imaginary part of expression.
177
+
178
+ See Also
179
+ ========
180
+
181
+ re
182
+ """
183
+
184
+ args: tuple[Expr]
185
+
186
+ is_extended_real = True
187
+ unbranched = True # implicitly works on the projection to C
188
+ _singularities = True # non-holomorphic
189
+
190
+ @classmethod
191
+ def eval(cls, arg):
192
+ if arg is S.NaN:
193
+ return S.NaN
194
+ elif arg is S.ComplexInfinity:
195
+ return S.NaN
196
+ elif arg.is_extended_real:
197
+ return S.Zero
198
+ elif arg.is_imaginary or (I*arg).is_extended_real:
199
+ return -I * arg
200
+ elif arg.is_Matrix:
201
+ return arg.as_real_imag()[1]
202
+ elif arg.is_Function and isinstance(arg, conjugate):
203
+ return -im(arg.args[0])
204
+ else:
205
+ included, reverted, excluded = [], [], []
206
+ args = Add.make_args(arg)
207
+ for term in args:
208
+ coeff = term.as_coefficient(I)
209
+
210
+ if coeff is not None:
211
+ if not coeff.is_extended_real:
212
+ reverted.append(coeff)
213
+ else:
214
+ excluded.append(coeff)
215
+ elif term.has(I) or not term.is_extended_real:
216
+ # Try to do some advanced expansion. If
217
+ # impossible, don't try to do im(arg) again
218
+ # (because this is what we are trying to do now).
219
+ real_imag = term.as_real_imag(ignore=arg)
220
+ if real_imag:
221
+ excluded.append(real_imag[1])
222
+ else:
223
+ included.append(term)
224
+
225
+ if len(args) != len(included):
226
+ a, b, c = (Add(*xs) for xs in [included, reverted, excluded])
227
+
228
+ return cls(a) + re(b) + c
229
+
230
+ def as_real_imag(self, deep=True, **hints):
231
+ """
232
+ Return the imaginary part with a zero real part.
233
+
234
+ """
235
+ return (self, S.Zero)
236
+
237
+ def _eval_derivative(self, x):
238
+ if x.is_extended_real or self.args[0].is_extended_real:
239
+ return im(Derivative(self.args[0], x, evaluate=True))
240
+ if x.is_imaginary or self.args[0].is_imaginary:
241
+ return -I \
242
+ * re(Derivative(self.args[0], x, evaluate=True))
243
+
244
+ def _eval_rewrite_as_re(self, arg, **kwargs):
245
+ return -I*(self.args[0] - re(self.args[0]))
246
+
247
+ def _eval_is_algebraic(self):
248
+ return self.args[0].is_algebraic
249
+
250
+ def _eval_is_zero(self):
251
+ return self.args[0].is_extended_real
252
+
253
+ def _eval_is_finite(self):
254
+ if self.args[0].is_finite:
255
+ return True
256
+
257
+ def _eval_is_complex(self):
258
+ if self.args[0].is_finite:
259
+ return True
260
+
261
+ ###############################################################################
262
+ ############### SIGN, ABSOLUTE VALUE, ARGUMENT and CONJUGATION ################
263
+ ###############################################################################
264
+
265
+ class sign(DefinedFunction):
266
+ """
267
+ Returns the complex sign of an expression:
268
+
269
+ Explanation
270
+ ===========
271
+
272
+ If the expression is real the sign will be:
273
+
274
+ * $1$ if expression is positive
275
+ * $0$ if expression is equal to zero
276
+ * $-1$ if expression is negative
277
+
278
+ If the expression is imaginary the sign will be:
279
+
280
+ * $I$ if im(expression) is positive
281
+ * $-I$ if im(expression) is negative
282
+
283
+ Otherwise an unevaluated expression will be returned. When evaluated, the
284
+ result (in general) will be ``cos(arg(expr)) + I*sin(arg(expr))``.
285
+
286
+ Examples
287
+ ========
288
+
289
+ >>> from sympy import sign, I
290
+
291
+ >>> sign(-1)
292
+ -1
293
+ >>> sign(0)
294
+ 0
295
+ >>> sign(-3*I)
296
+ -I
297
+ >>> sign(1 + I)
298
+ sign(1 + I)
299
+ >>> _.evalf()
300
+ 0.707106781186548 + 0.707106781186548*I
301
+
302
+ Parameters
303
+ ==========
304
+
305
+ arg : Expr
306
+ Real or imaginary expression.
307
+
308
+ Returns
309
+ =======
310
+
311
+ expr : Expr
312
+ Complex sign of expression.
313
+
314
+ See Also
315
+ ========
316
+
317
+ Abs, conjugate
318
+ """
319
+
320
+ is_complex = True
321
+ _singularities = True
322
+
323
+ def doit(self, **hints):
324
+ s = super().doit()
325
+ if s == self and self.args[0].is_zero is False:
326
+ return self.args[0] / Abs(self.args[0])
327
+ return s
328
+
329
+ @classmethod
330
+ def eval(cls, arg):
331
+ # handle what we can
332
+ if arg.is_Mul:
333
+ c, args = arg.as_coeff_mul()
334
+ unk = []
335
+ s = sign(c)
336
+ for a in args:
337
+ if a.is_extended_negative:
338
+ s = -s
339
+ elif a.is_extended_positive:
340
+ pass
341
+ else:
342
+ if a.is_imaginary:
343
+ ai = im(a)
344
+ if ai.is_comparable: # i.e. a = I*real
345
+ s *= I
346
+ if ai.is_extended_negative:
347
+ # can't use sign(ai) here since ai might not be
348
+ # a Number
349
+ s = -s
350
+ else:
351
+ unk.append(a)
352
+ else:
353
+ unk.append(a)
354
+ if c is S.One and len(unk) == len(args):
355
+ return None
356
+ return s * cls(arg._new_rawargs(*unk))
357
+ if arg is S.NaN:
358
+ return S.NaN
359
+ if arg.is_zero: # it may be an Expr that is zero
360
+ return S.Zero
361
+ if arg.is_extended_positive:
362
+ return S.One
363
+ if arg.is_extended_negative:
364
+ return S.NegativeOne
365
+ if arg.is_Function:
366
+ if isinstance(arg, sign):
367
+ return arg
368
+ if arg.is_imaginary:
369
+ if arg.is_Pow and arg.exp is S.Half:
370
+ # we catch this because non-trivial sqrt args are not expanded
371
+ # e.g. sqrt(1-sqrt(2)) --x--> to I*sqrt(sqrt(2) - 1)
372
+ return I
373
+ arg2 = -I * arg
374
+ if arg2.is_extended_positive:
375
+ return I
376
+ if arg2.is_extended_negative:
377
+ return -I
378
+
379
+ def _eval_Abs(self):
380
+ if fuzzy_not(self.args[0].is_zero):
381
+ return S.One
382
+
383
+ def _eval_conjugate(self):
384
+ return sign(conjugate(self.args[0]))
385
+
386
+ def _eval_derivative(self, x):
387
+ if self.args[0].is_extended_real:
388
+ from sympy.functions.special.delta_functions import DiracDelta
389
+ return 2 * Derivative(self.args[0], x, evaluate=True) \
390
+ * DiracDelta(self.args[0])
391
+ elif self.args[0].is_imaginary:
392
+ from sympy.functions.special.delta_functions import DiracDelta
393
+ return 2 * Derivative(self.args[0], x, evaluate=True) \
394
+ * DiracDelta(-I * self.args[0])
395
+
396
+ def _eval_is_nonnegative(self):
397
+ if self.args[0].is_nonnegative:
398
+ return True
399
+
400
+ def _eval_is_nonpositive(self):
401
+ if self.args[0].is_nonpositive:
402
+ return True
403
+
404
+ def _eval_is_imaginary(self):
405
+ return self.args[0].is_imaginary
406
+
407
+ def _eval_is_integer(self):
408
+ return self.args[0].is_extended_real
409
+
410
+ def _eval_is_zero(self):
411
+ return self.args[0].is_zero
412
+
413
+ def _eval_power(self, other):
414
+ if (
415
+ fuzzy_not(self.args[0].is_zero) and
416
+ other.is_integer and
417
+ other.is_even
418
+ ):
419
+ return S.One
420
+
421
+ def _eval_nseries(self, x, n, logx, cdir=0):
422
+ arg0 = self.args[0]
423
+ x0 = arg0.subs(x, 0)
424
+ if x0 != 0:
425
+ return self.func(x0)
426
+ if cdir != 0:
427
+ cdir = arg0.dir(x, cdir)
428
+ return -S.One if re(cdir) < 0 else S.One
429
+
430
+ def _eval_rewrite_as_Piecewise(self, arg, **kwargs):
431
+ if arg.is_extended_real:
432
+ return Piecewise((1, arg > 0), (-1, arg < 0), (0, True))
433
+
434
+ def _eval_rewrite_as_Heaviside(self, arg, **kwargs):
435
+ from sympy.functions.special.delta_functions import Heaviside
436
+ if arg.is_extended_real:
437
+ return Heaviside(arg) * 2 - 1
438
+
439
+ def _eval_rewrite_as_Abs(self, arg, **kwargs):
440
+ return Piecewise((0, Eq(arg, 0)), (arg / Abs(arg), True))
441
+
442
+ def _eval_simplify(self, **kwargs):
443
+ return self.func(factor_terms(self.args[0])) # XXX include doit?
444
+
445
+
446
+ class Abs(DefinedFunction):
447
+ """
448
+ Return the absolute value of the argument.
449
+
450
+ Explanation
451
+ ===========
452
+
453
+ This is an extension of the built-in function ``abs()`` to accept symbolic
454
+ values. If you pass a SymPy expression to the built-in ``abs()``, it will
455
+ pass it automatically to ``Abs()``.
456
+
457
+ Examples
458
+ ========
459
+
460
+ >>> from sympy import Abs, Symbol, S, I
461
+ >>> Abs(-1)
462
+ 1
463
+ >>> x = Symbol('x', real=True)
464
+ >>> Abs(-x)
465
+ Abs(x)
466
+ >>> Abs(x**2)
467
+ x**2
468
+ >>> abs(-x) # The Python built-in
469
+ Abs(x)
470
+ >>> Abs(3*x + 2*I)
471
+ sqrt(9*x**2 + 4)
472
+ >>> Abs(8*I)
473
+ 8
474
+
475
+ Note that the Python built-in will return either an Expr or int depending on
476
+ the argument::
477
+
478
+ >>> type(abs(-1))
479
+ <... 'int'>
480
+ >>> type(abs(S.NegativeOne))
481
+ <class 'sympy.core.numbers.One'>
482
+
483
+ Abs will always return a SymPy object.
484
+
485
+ Parameters
486
+ ==========
487
+
488
+ arg : Expr
489
+ Real or complex expression.
490
+
491
+ Returns
492
+ =======
493
+
494
+ expr : Expr
495
+ Absolute value returned can be an expression or integer depending on
496
+ input arg.
497
+
498
+ See Also
499
+ ========
500
+
501
+ sign, conjugate
502
+ """
503
+
504
+ args: tuple[Expr]
505
+
506
+ is_extended_real = True
507
+ is_extended_negative = False
508
+ is_extended_nonnegative = True
509
+ unbranched = True
510
+ _singularities = True # non-holomorphic
511
+
512
+ def fdiff(self, argindex=1):
513
+ """
514
+ Get the first derivative of the argument to Abs().
515
+
516
+ """
517
+ if argindex == 1:
518
+ return sign(self.args[0])
519
+ else:
520
+ raise ArgumentIndexError(self, argindex)
521
+
522
+ @classmethod
523
+ def eval(cls, arg):
524
+ from sympy.simplify.simplify import signsimp
525
+
526
+ if hasattr(arg, '_eval_Abs'):
527
+ obj = arg._eval_Abs()
528
+ if obj is not None:
529
+ return obj
530
+ if not isinstance(arg, Expr):
531
+ raise TypeError("Bad argument type for Abs(): %s" % type(arg))
532
+
533
+ # handle what we can
534
+ arg = signsimp(arg, evaluate=False)
535
+ n, d = arg.as_numer_denom()
536
+ if d.free_symbols and not n.free_symbols:
537
+ return cls(n)/cls(d)
538
+
539
+ if arg.is_Mul:
540
+ known = []
541
+ unk = []
542
+ for t in arg.args:
543
+ if t.is_Pow and t.exp.is_integer and t.exp.is_negative:
544
+ bnew = cls(t.base)
545
+ if isinstance(bnew, cls):
546
+ unk.append(t)
547
+ else:
548
+ known.append(Pow(bnew, t.exp))
549
+ else:
550
+ tnew = cls(t)
551
+ if isinstance(tnew, cls):
552
+ unk.append(t)
553
+ else:
554
+ known.append(tnew)
555
+ known = Mul(*known)
556
+ unk = cls(Mul(*unk), evaluate=False) if unk else S.One
557
+ return known*unk
558
+ if arg is S.NaN:
559
+ return S.NaN
560
+ if arg is S.ComplexInfinity:
561
+ return oo
562
+ from sympy.functions.elementary.exponential import exp, log
563
+
564
+ if arg.is_Pow:
565
+ base, exponent = arg.as_base_exp()
566
+ if base.is_extended_real:
567
+ if exponent.is_integer:
568
+ if exponent.is_even:
569
+ return arg
570
+ if base is S.NegativeOne:
571
+ return S.One
572
+ return Abs(base)**exponent
573
+ if base.is_extended_nonnegative:
574
+ return base**re(exponent)
575
+ if base.is_extended_negative:
576
+ return (-base)**re(exponent)*exp(-pi*im(exponent))
577
+ return
578
+ elif not base.has(Symbol): # complex base
579
+ # express base**exponent as exp(exponent*log(base))
580
+ a, b = log(base).as_real_imag()
581
+ z = a + I*b
582
+ return exp(re(exponent*z))
583
+ if isinstance(arg, exp):
584
+ return exp(re(arg.args[0]))
585
+ if isinstance(arg, AppliedUndef):
586
+ if arg.is_positive:
587
+ return arg
588
+ elif arg.is_negative:
589
+ return -arg
590
+ return
591
+ if arg.is_Add and arg.has(oo, S.NegativeInfinity):
592
+ if any(a.is_infinite for a in arg.as_real_imag()):
593
+ return oo
594
+ if arg.is_zero:
595
+ return S.Zero
596
+ if arg.is_extended_nonnegative:
597
+ return arg
598
+ if arg.is_extended_nonpositive:
599
+ return -arg
600
+ if arg.is_imaginary:
601
+ arg2 = -I * arg
602
+ if arg2.is_extended_nonnegative:
603
+ return arg2
604
+ if arg.is_extended_real:
605
+ return
606
+ # reject result if all new conjugates are just wrappers around
607
+ # an expression that was already in the arg
608
+ conj = signsimp(arg.conjugate(), evaluate=False)
609
+ new_conj = conj.atoms(conjugate) - arg.atoms(conjugate)
610
+ if new_conj and all(arg.has(i.args[0]) for i in new_conj):
611
+ return
612
+ if arg != conj and arg != -conj:
613
+ ignore = arg.atoms(Abs)
614
+ abs_free_arg = arg.xreplace({i: Dummy(real=True) for i in ignore})
615
+ unk = [a for a in abs_free_arg.free_symbols if a.is_extended_real is None]
616
+ if not unk or not all(conj.has(conjugate(u)) for u in unk):
617
+ return sqrt(expand_mul(arg*conj))
618
+
619
+ def _eval_is_real(self):
620
+ if self.args[0].is_finite:
621
+ return True
622
+
623
+ def _eval_is_integer(self):
624
+ if self.args[0].is_extended_real:
625
+ return self.args[0].is_integer
626
+
627
+ def _eval_is_extended_nonzero(self):
628
+ return fuzzy_not(self._args[0].is_zero)
629
+
630
+ def _eval_is_zero(self):
631
+ return self._args[0].is_zero
632
+
633
+ def _eval_is_extended_positive(self):
634
+ return fuzzy_not(self._args[0].is_zero)
635
+
636
+ def _eval_is_rational(self):
637
+ if self.args[0].is_extended_real:
638
+ return self.args[0].is_rational
639
+
640
+ def _eval_is_even(self):
641
+ if self.args[0].is_extended_real:
642
+ return self.args[0].is_even
643
+
644
+ def _eval_is_odd(self):
645
+ if self.args[0].is_extended_real:
646
+ return self.args[0].is_odd
647
+
648
+ def _eval_is_algebraic(self):
649
+ return self.args[0].is_algebraic
650
+
651
+ def _eval_power(self, exponent):
652
+ if self.args[0].is_extended_real and exponent.is_integer:
653
+ if exponent.is_even:
654
+ return self.args[0]**exponent
655
+ elif exponent is not S.NegativeOne and exponent.is_Integer:
656
+ return self.args[0]**(exponent - 1)*self
657
+ return
658
+
659
+ def _eval_nseries(self, x, n, logx, cdir=0):
660
+ from sympy.functions.elementary.exponential import log
661
+ direction = self.args[0].leadterm(x)[0]
662
+ if direction.has(log(x)):
663
+ direction = direction.subs(log(x), logx)
664
+ s = self.args[0]._eval_nseries(x, n=n, logx=logx)
665
+ return (sign(direction)*s).expand()
666
+
667
+ def _eval_derivative(self, x):
668
+ if self.args[0].is_extended_real or self.args[0].is_imaginary:
669
+ return Derivative(self.args[0], x, evaluate=True) \
670
+ * sign(conjugate(self.args[0]))
671
+ rv = (re(self.args[0]) * Derivative(re(self.args[0]), x,
672
+ evaluate=True) + im(self.args[0]) * Derivative(im(self.args[0]),
673
+ x, evaluate=True)) / Abs(self.args[0])
674
+ return rv.rewrite(sign)
675
+
676
+ def _eval_rewrite_as_Heaviside(self, arg, **kwargs):
677
+ # Note this only holds for real arg (since Heaviside is not defined
678
+ # for complex arguments).
679
+ from sympy.functions.special.delta_functions import Heaviside
680
+ if arg.is_extended_real:
681
+ return arg*(Heaviside(arg) - Heaviside(-arg))
682
+
683
+ def _eval_rewrite_as_Piecewise(self, arg, **kwargs):
684
+ if arg.is_extended_real:
685
+ return Piecewise((arg, arg >= 0), (-arg, True))
686
+ elif arg.is_imaginary:
687
+ return Piecewise((I*arg, I*arg >= 0), (-I*arg, True))
688
+
689
+ def _eval_rewrite_as_sign(self, arg, **kwargs):
690
+ return arg/sign(arg)
691
+
692
+ def _eval_rewrite_as_conjugate(self, arg, **kwargs):
693
+ return sqrt(arg*conjugate(arg))
694
+
695
+
696
+ class arg(DefinedFunction):
697
+ r"""
698
+ Returns the argument (in radians) of a complex number. The argument is
699
+ evaluated in consistent convention with ``atan2`` where the branch-cut is
700
+ taken along the negative real axis and ``arg(z)`` is in the interval
701
+ $(-\pi,\pi]$. For a positive number, the argument is always 0; the
702
+ argument of a negative number is $\pi$; and the argument of 0
703
+ is undefined and returns ``nan``. So the ``arg`` function will never nest
704
+ greater than 3 levels since at the 4th application, the result must be
705
+ nan; for a real number, nan is returned on the 3rd application.
706
+
707
+ Examples
708
+ ========
709
+
710
+ >>> from sympy import arg, I, sqrt, Dummy
711
+ >>> from sympy.abc import x
712
+ >>> arg(2.0)
713
+ 0
714
+ >>> arg(I)
715
+ pi/2
716
+ >>> arg(sqrt(2) + I*sqrt(2))
717
+ pi/4
718
+ >>> arg(sqrt(3)/2 + I/2)
719
+ pi/6
720
+ >>> arg(4 + 3*I)
721
+ atan(3/4)
722
+ >>> arg(0.8 + 0.6*I)
723
+ 0.643501108793284
724
+ >>> arg(arg(arg(arg(x))))
725
+ nan
726
+ >>> real = Dummy(real=True)
727
+ >>> arg(arg(arg(real)))
728
+ nan
729
+
730
+ Parameters
731
+ ==========
732
+
733
+ arg : Expr
734
+ Real or complex expression.
735
+
736
+ Returns
737
+ =======
738
+
739
+ value : Expr
740
+ Returns arc tangent of arg measured in radians.
741
+
742
+ """
743
+
744
+ is_extended_real = True
745
+ is_real = True
746
+ is_finite = True
747
+ _singularities = True # non-holomorphic
748
+
749
+ @classmethod
750
+ def eval(cls, arg):
751
+ a = arg
752
+ for i in range(3):
753
+ if isinstance(a, cls):
754
+ a = a.args[0]
755
+ else:
756
+ if i == 2 and a.is_extended_real:
757
+ return S.NaN
758
+ break
759
+ else:
760
+ return S.NaN
761
+ from sympy.functions.elementary.exponential import exp, exp_polar
762
+ if isinstance(arg, exp_polar):
763
+ return periodic_argument(arg, oo)
764
+ elif isinstance(arg, exp):
765
+ i_ = im(arg.args[0])
766
+ if i_.is_comparable:
767
+ i_ %= 2*S.Pi
768
+ if i_ > S.Pi:
769
+ i_ -= 2*S.Pi
770
+ return i_
771
+
772
+ if not arg.is_Atom:
773
+ c, arg_ = factor_terms(arg).as_coeff_Mul()
774
+ if arg_.is_Mul:
775
+ arg_ = Mul(*[a if (sign(a) not in (-1, 1)) else
776
+ sign(a) for a in arg_.args])
777
+ arg_ = sign(c)*arg_
778
+ else:
779
+ arg_ = arg
780
+ if any(i.is_extended_positive is None for i in arg_.atoms(AppliedUndef)):
781
+ return
782
+ from sympy.functions.elementary.trigonometric import atan2
783
+ x, y = arg_.as_real_imag()
784
+ rv = atan2(y, x)
785
+ if rv.is_number:
786
+ return rv
787
+ if arg_ != arg:
788
+ return cls(arg_, evaluate=False)
789
+
790
+ def _eval_derivative(self, t):
791
+ x, y = self.args[0].as_real_imag()
792
+ return (x * Derivative(y, t, evaluate=True) - y *
793
+ Derivative(x, t, evaluate=True)) / (x**2 + y**2)
794
+
795
+ def _eval_rewrite_as_atan2(self, arg, **kwargs):
796
+ from sympy.functions.elementary.trigonometric import atan2
797
+ x, y = self.args[0].as_real_imag()
798
+ return atan2(y, x)
799
+
800
+ def _eval_as_leading_term(self, x, logx, cdir):
801
+ arg0 = self.args[0]
802
+ t = Dummy('t', positive=True)
803
+ if cdir == 0:
804
+ cdir = 1
805
+ z = arg0.subs(x, cdir*t)
806
+ if z.is_positive:
807
+ return S.Zero
808
+ elif z.is_negative:
809
+ return S.Pi
810
+ else:
811
+ raise PoleError("Cannot expand %s around 0" % (self))
812
+
813
+ def _eval_nseries(self, x, n, logx, cdir=0):
814
+ from sympy.series.order import Order
815
+ if n <= 0:
816
+ return Order(1)
817
+ return self._eval_as_leading_term(x, logx=logx, cdir=cdir)
818
+
819
+
820
+ class conjugate(DefinedFunction):
821
+ """
822
+ Returns the *complex conjugate* [1]_ of an argument.
823
+ In mathematics, the complex conjugate of a complex number
824
+ is given by changing the sign of the imaginary part.
825
+
826
+ Thus, the conjugate of the complex number
827
+ :math:`a + ib` (where $a$ and $b$ are real numbers) is :math:`a - ib`
828
+
829
+ Examples
830
+ ========
831
+
832
+ >>> from sympy import conjugate, I
833
+ >>> conjugate(2)
834
+ 2
835
+ >>> conjugate(I)
836
+ -I
837
+ >>> conjugate(3 + 2*I)
838
+ 3 - 2*I
839
+ >>> conjugate(5 - I)
840
+ 5 + I
841
+
842
+ Parameters
843
+ ==========
844
+
845
+ arg : Expr
846
+ Real or complex expression.
847
+
848
+ Returns
849
+ =======
850
+
851
+ arg : Expr
852
+ Complex conjugate of arg as real, imaginary or mixed expression.
853
+
854
+ See Also
855
+ ========
856
+
857
+ sign, Abs
858
+
859
+ References
860
+ ==========
861
+
862
+ .. [1] https://en.wikipedia.org/wiki/Complex_conjugation
863
+ """
864
+ _singularities = True # non-holomorphic
865
+
866
+ @classmethod
867
+ def eval(cls, arg):
868
+ obj = arg._eval_conjugate()
869
+ if obj is not None:
870
+ return obj
871
+
872
+ def inverse(self):
873
+ return conjugate
874
+
875
+ def _eval_Abs(self):
876
+ return Abs(self.args[0], evaluate=True)
877
+
878
+ def _eval_adjoint(self):
879
+ return transpose(self.args[0])
880
+
881
+ def _eval_conjugate(self):
882
+ return self.args[0]
883
+
884
+ def _eval_derivative(self, x):
885
+ if x.is_real:
886
+ return conjugate(Derivative(self.args[0], x, evaluate=True))
887
+ elif x.is_imaginary:
888
+ return -conjugate(Derivative(self.args[0], x, evaluate=True))
889
+
890
+ def _eval_transpose(self):
891
+ return adjoint(self.args[0])
892
+
893
+ def _eval_is_algebraic(self):
894
+ return self.args[0].is_algebraic
895
+
896
+
897
+ class transpose(DefinedFunction):
898
+ """
899
+ Linear map transposition.
900
+
901
+ Examples
902
+ ========
903
+
904
+ >>> from sympy import transpose, Matrix, MatrixSymbol
905
+ >>> A = MatrixSymbol('A', 25, 9)
906
+ >>> transpose(A)
907
+ A.T
908
+ >>> B = MatrixSymbol('B', 9, 22)
909
+ >>> transpose(B)
910
+ B.T
911
+ >>> transpose(A*B)
912
+ B.T*A.T
913
+ >>> M = Matrix([[4, 5], [2, 1], [90, 12]])
914
+ >>> M
915
+ Matrix([
916
+ [ 4, 5],
917
+ [ 2, 1],
918
+ [90, 12]])
919
+ >>> transpose(M)
920
+ Matrix([
921
+ [4, 2, 90],
922
+ [5, 1, 12]])
923
+
924
+ Parameters
925
+ ==========
926
+
927
+ arg : Matrix
928
+ Matrix or matrix expression to take the transpose of.
929
+
930
+ Returns
931
+ =======
932
+
933
+ value : Matrix
934
+ Transpose of arg.
935
+
936
+ """
937
+
938
+ @classmethod
939
+ def eval(cls, arg):
940
+ obj = arg._eval_transpose()
941
+ if obj is not None:
942
+ return obj
943
+
944
+ def _eval_adjoint(self):
945
+ return conjugate(self.args[0])
946
+
947
+ def _eval_conjugate(self):
948
+ return adjoint(self.args[0])
949
+
950
+ def _eval_transpose(self):
951
+ return self.args[0]
952
+
953
+
954
+ class adjoint(DefinedFunction):
955
+ """
956
+ Conjugate transpose or Hermite conjugation.
957
+
958
+ Examples
959
+ ========
960
+
961
+ >>> from sympy import adjoint, MatrixSymbol
962
+ >>> A = MatrixSymbol('A', 10, 5)
963
+ >>> adjoint(A)
964
+ Adjoint(A)
965
+
966
+ Parameters
967
+ ==========
968
+
969
+ arg : Matrix
970
+ Matrix or matrix expression to take the adjoint of.
971
+
972
+ Returns
973
+ =======
974
+
975
+ value : Matrix
976
+ Represents the conjugate transpose or Hermite
977
+ conjugation of arg.
978
+
979
+ """
980
+
981
+ @classmethod
982
+ def eval(cls, arg):
983
+ obj = arg._eval_adjoint()
984
+ if obj is not None:
985
+ return obj
986
+ obj = arg._eval_transpose()
987
+ if obj is not None:
988
+ return conjugate(obj)
989
+
990
+ def _eval_adjoint(self):
991
+ return self.args[0]
992
+
993
+ def _eval_conjugate(self):
994
+ return transpose(self.args[0])
995
+
996
+ def _eval_transpose(self):
997
+ return conjugate(self.args[0])
998
+
999
+ def _latex(self, printer, exp=None, *args):
1000
+ arg = printer._print(self.args[0])
1001
+ tex = r'%s^{\dagger}' % arg
1002
+ if exp:
1003
+ tex = r'\left(%s\right)^{%s}' % (tex, exp)
1004
+ return tex
1005
+
1006
+ def _pretty(self, printer, *args):
1007
+ from sympy.printing.pretty.stringpict import prettyForm
1008
+ pform = printer._print(self.args[0], *args)
1009
+ if printer._use_unicode:
1010
+ pform = pform**prettyForm('\N{DAGGER}')
1011
+ else:
1012
+ pform = pform**prettyForm('+')
1013
+ return pform
1014
+
1015
+ ###############################################################################
1016
+ ############### HANDLING OF POLAR NUMBERS #####################################
1017
+ ###############################################################################
1018
+
1019
+
1020
+ class polar_lift(DefinedFunction):
1021
+ """
1022
+ Lift argument to the Riemann surface of the logarithm, using the
1023
+ standard branch.
1024
+
1025
+ Examples
1026
+ ========
1027
+
1028
+ >>> from sympy import Symbol, polar_lift, I
1029
+ >>> p = Symbol('p', polar=True)
1030
+ >>> x = Symbol('x')
1031
+ >>> polar_lift(4)
1032
+ 4*exp_polar(0)
1033
+ >>> polar_lift(-4)
1034
+ 4*exp_polar(I*pi)
1035
+ >>> polar_lift(-I)
1036
+ exp_polar(-I*pi/2)
1037
+ >>> polar_lift(I + 2)
1038
+ polar_lift(2 + I)
1039
+
1040
+ >>> polar_lift(4*x)
1041
+ 4*polar_lift(x)
1042
+ >>> polar_lift(4*p)
1043
+ 4*p
1044
+
1045
+ Parameters
1046
+ ==========
1047
+
1048
+ arg : Expr
1049
+ Real or complex expression.
1050
+
1051
+ See Also
1052
+ ========
1053
+
1054
+ sympy.functions.elementary.exponential.exp_polar
1055
+ periodic_argument
1056
+ """
1057
+
1058
+ is_polar = True
1059
+ is_comparable = False # Cannot be evalf'd.
1060
+
1061
+ @classmethod
1062
+ def eval(cls, arg):
1063
+ from sympy.functions.elementary.complexes import arg as argument
1064
+ if arg.is_number:
1065
+ ar = argument(arg)
1066
+ # In general we want to affirm that something is known,
1067
+ # e.g. `not ar.has(argument) and not ar.has(atan)`
1068
+ # but for now we will just be more restrictive and
1069
+ # see that it has evaluated to one of the known values.
1070
+ if ar in (0, pi/2, -pi/2, pi):
1071
+ from sympy.functions.elementary.exponential import exp_polar
1072
+ return exp_polar(I*ar)*abs(arg)
1073
+
1074
+ if arg.is_Mul:
1075
+ args = arg.args
1076
+ else:
1077
+ args = [arg]
1078
+ included = []
1079
+ excluded = []
1080
+ positive = []
1081
+ for arg in args:
1082
+ if arg.is_polar:
1083
+ included += [arg]
1084
+ elif arg.is_positive:
1085
+ positive += [arg]
1086
+ else:
1087
+ excluded += [arg]
1088
+ if len(excluded) < len(args):
1089
+ if excluded:
1090
+ return Mul(*(included + positive))*polar_lift(Mul(*excluded))
1091
+ elif included:
1092
+ return Mul(*(included + positive))
1093
+ else:
1094
+ from sympy.functions.elementary.exponential import exp_polar
1095
+ return Mul(*positive)*exp_polar(0)
1096
+
1097
+ def _eval_evalf(self, prec):
1098
+ """ Careful! any evalf of polar numbers is flaky """
1099
+ return self.args[0]._eval_evalf(prec)
1100
+
1101
+ def _eval_Abs(self):
1102
+ return Abs(self.args[0], evaluate=True)
1103
+
1104
+
1105
+ class periodic_argument(DefinedFunction):
1106
+ r"""
1107
+ Represent the argument on a quotient of the Riemann surface of the
1108
+ logarithm. That is, given a period $P$, always return a value in
1109
+ $(-P/2, P/2]$, by using $\exp(PI) = 1$.
1110
+
1111
+ Examples
1112
+ ========
1113
+
1114
+ >>> from sympy import exp_polar, periodic_argument
1115
+ >>> from sympy import I, pi
1116
+ >>> periodic_argument(exp_polar(10*I*pi), 2*pi)
1117
+ 0
1118
+ >>> periodic_argument(exp_polar(5*I*pi), 4*pi)
1119
+ pi
1120
+ >>> from sympy import exp_polar, periodic_argument
1121
+ >>> from sympy import I, pi
1122
+ >>> periodic_argument(exp_polar(5*I*pi), 2*pi)
1123
+ pi
1124
+ >>> periodic_argument(exp_polar(5*I*pi), 3*pi)
1125
+ -pi
1126
+ >>> periodic_argument(exp_polar(5*I*pi), pi)
1127
+ 0
1128
+
1129
+ Parameters
1130
+ ==========
1131
+
1132
+ ar : Expr
1133
+ A polar number.
1134
+
1135
+ period : Expr
1136
+ The period $P$.
1137
+
1138
+ See Also
1139
+ ========
1140
+
1141
+ sympy.functions.elementary.exponential.exp_polar
1142
+ polar_lift : Lift argument to the Riemann surface of the logarithm
1143
+ principal_branch
1144
+ """
1145
+
1146
+ @classmethod
1147
+ def _getunbranched(cls, ar):
1148
+ from sympy.functions.elementary.exponential import exp_polar, log
1149
+ if ar.is_Mul:
1150
+ args = ar.args
1151
+ else:
1152
+ args = [ar]
1153
+ unbranched = 0
1154
+ for a in args:
1155
+ if not a.is_polar:
1156
+ unbranched += arg(a)
1157
+ elif isinstance(a, exp_polar):
1158
+ unbranched += a.exp.as_real_imag()[1]
1159
+ elif a.is_Pow:
1160
+ re, im = a.exp.as_real_imag()
1161
+ unbranched += re*unbranched_argument(
1162
+ a.base) + im*log(abs(a.base))
1163
+ elif isinstance(a, polar_lift):
1164
+ unbranched += arg(a.args[0])
1165
+ else:
1166
+ return None
1167
+ return unbranched
1168
+
1169
+ @classmethod
1170
+ def eval(cls, ar, period):
1171
+ # Our strategy is to evaluate the argument on the Riemann surface of the
1172
+ # logarithm, and then reduce.
1173
+ # NOTE evidently this means it is a rather bad idea to use this with
1174
+ # period != 2*pi and non-polar numbers.
1175
+ if not period.is_extended_positive:
1176
+ return None
1177
+ if period == oo and isinstance(ar, principal_branch):
1178
+ return periodic_argument(*ar.args)
1179
+ if isinstance(ar, polar_lift) and period >= 2*pi:
1180
+ return periodic_argument(ar.args[0], period)
1181
+ if ar.is_Mul:
1182
+ newargs = [x for x in ar.args if not x.is_positive]
1183
+ if len(newargs) != len(ar.args):
1184
+ return periodic_argument(Mul(*newargs), period)
1185
+ unbranched = cls._getunbranched(ar)
1186
+ if unbranched is None:
1187
+ return None
1188
+ from sympy.functions.elementary.trigonometric import atan, atan2
1189
+ if unbranched.has(periodic_argument, atan2, atan):
1190
+ return None
1191
+ if period == oo:
1192
+ return unbranched
1193
+ if period != oo:
1194
+ from sympy.functions.elementary.integers import ceiling
1195
+ n = ceiling(unbranched/period - S.Half)*period
1196
+ if not n.has(ceiling):
1197
+ return unbranched - n
1198
+
1199
+ def _eval_evalf(self, prec):
1200
+ z, period = self.args
1201
+ if period == oo:
1202
+ unbranched = periodic_argument._getunbranched(z)
1203
+ if unbranched is None:
1204
+ return self
1205
+ return unbranched._eval_evalf(prec)
1206
+ ub = periodic_argument(z, oo)._eval_evalf(prec)
1207
+ from sympy.functions.elementary.integers import ceiling
1208
+ return (ub - ceiling(ub/period - S.Half)*period)._eval_evalf(prec)
1209
+
1210
+
1211
+ def unbranched_argument(arg):
1212
+ '''
1213
+ Returns periodic argument of arg with period as infinity.
1214
+
1215
+ Examples
1216
+ ========
1217
+
1218
+ >>> from sympy import exp_polar, unbranched_argument
1219
+ >>> from sympy import I, pi
1220
+ >>> unbranched_argument(exp_polar(15*I*pi))
1221
+ 15*pi
1222
+ >>> unbranched_argument(exp_polar(7*I*pi))
1223
+ 7*pi
1224
+
1225
+ See also
1226
+ ========
1227
+
1228
+ periodic_argument
1229
+ '''
1230
+ return periodic_argument(arg, oo)
1231
+
1232
+
1233
+ class principal_branch(DefinedFunction):
1234
+ """
1235
+ Represent a polar number reduced to its principal branch on a quotient
1236
+ of the Riemann surface of the logarithm.
1237
+
1238
+ Explanation
1239
+ ===========
1240
+
1241
+ This is a function of two arguments. The first argument is a polar
1242
+ number `z`, and the second one a positive real number or infinity, `p`.
1243
+ The result is ``z mod exp_polar(I*p)``.
1244
+
1245
+ Examples
1246
+ ========
1247
+
1248
+ >>> from sympy import exp_polar, principal_branch, oo, I, pi
1249
+ >>> from sympy.abc import z
1250
+ >>> principal_branch(z, oo)
1251
+ z
1252
+ >>> principal_branch(exp_polar(2*pi*I)*3, 2*pi)
1253
+ 3*exp_polar(0)
1254
+ >>> principal_branch(exp_polar(2*pi*I)*3*z, 2*pi)
1255
+ 3*principal_branch(z, 2*pi)
1256
+
1257
+ Parameters
1258
+ ==========
1259
+
1260
+ x : Expr
1261
+ A polar number.
1262
+
1263
+ period : Expr
1264
+ Positive real number or infinity.
1265
+
1266
+ See Also
1267
+ ========
1268
+
1269
+ sympy.functions.elementary.exponential.exp_polar
1270
+ polar_lift : Lift argument to the Riemann surface of the logarithm
1271
+ periodic_argument
1272
+ """
1273
+
1274
+ is_polar = True
1275
+ is_comparable = False # cannot always be evalf'd
1276
+
1277
+ @classmethod
1278
+ def eval(self, x, period):
1279
+ from sympy.functions.elementary.exponential import exp_polar
1280
+ if isinstance(x, polar_lift):
1281
+ return principal_branch(x.args[0], period)
1282
+ if period == oo:
1283
+ return x
1284
+ ub = periodic_argument(x, oo)
1285
+ barg = periodic_argument(x, period)
1286
+ if ub != barg and not ub.has(periodic_argument) \
1287
+ and not barg.has(periodic_argument):
1288
+ pl = polar_lift(x)
1289
+
1290
+ def mr(expr):
1291
+ if not isinstance(expr, Symbol):
1292
+ return polar_lift(expr)
1293
+ return expr
1294
+ pl = pl.replace(polar_lift, mr)
1295
+ # Recompute unbranched argument
1296
+ ub = periodic_argument(pl, oo)
1297
+ if not pl.has(polar_lift):
1298
+ if ub != barg:
1299
+ res = exp_polar(I*(barg - ub))*pl
1300
+ else:
1301
+ res = pl
1302
+ if not res.is_polar and not res.has(exp_polar):
1303
+ res *= exp_polar(0)
1304
+ return res
1305
+
1306
+ if not x.free_symbols:
1307
+ c, m = x, ()
1308
+ else:
1309
+ c, m = x.as_coeff_mul(*x.free_symbols)
1310
+ others = []
1311
+ for y in m:
1312
+ if y.is_positive:
1313
+ c *= y
1314
+ else:
1315
+ others += [y]
1316
+ m = tuple(others)
1317
+ arg = periodic_argument(c, period)
1318
+ if arg.has(periodic_argument):
1319
+ return None
1320
+ if arg.is_number and (unbranched_argument(c) != arg or
1321
+ (arg == 0 and m != () and c != 1)):
1322
+ if arg == 0:
1323
+ return abs(c)*principal_branch(Mul(*m), period)
1324
+ return principal_branch(exp_polar(I*arg)*Mul(*m), period)*abs(c)
1325
+ if arg.is_number and ((abs(arg) < period/2) == True or arg == period/2) \
1326
+ and m == ():
1327
+ return exp_polar(arg*I)*abs(c)
1328
+
1329
+ def _eval_evalf(self, prec):
1330
+ z, period = self.args
1331
+ p = periodic_argument(z, period)._eval_evalf(prec)
1332
+ if abs(p) > pi or p == -pi:
1333
+ return self # Cannot evalf for this argument.
1334
+ from sympy.functions.elementary.exponential import exp
1335
+ return (abs(z)*exp(I*p))._eval_evalf(prec)
1336
+
1337
+
1338
+ def _polarify(eq, lift, pause=False):
1339
+ from sympy.integrals.integrals import Integral
1340
+ if eq.is_polar:
1341
+ return eq
1342
+ if eq.is_number and not pause:
1343
+ return polar_lift(eq)
1344
+ if isinstance(eq, Symbol) and not pause and lift:
1345
+ return polar_lift(eq)
1346
+ elif eq.is_Atom:
1347
+ return eq
1348
+ elif eq.is_Add:
1349
+ r = eq.func(*[_polarify(arg, lift, pause=True) for arg in eq.args])
1350
+ if lift:
1351
+ return polar_lift(r)
1352
+ return r
1353
+ elif eq.is_Pow and eq.base == S.Exp1:
1354
+ return eq.func(S.Exp1, _polarify(eq.exp, lift, pause=False))
1355
+ elif eq.is_Function:
1356
+ return eq.func(*[_polarify(arg, lift, pause=False) for arg in eq.args])
1357
+ elif isinstance(eq, Integral):
1358
+ # Don't lift the integration variable
1359
+ func = _polarify(eq.function, lift, pause=pause)
1360
+ limits = []
1361
+ for limit in eq.args[1:]:
1362
+ var = _polarify(limit[0], lift=False, pause=pause)
1363
+ rest = _polarify(limit[1:], lift=lift, pause=pause)
1364
+ limits.append((var,) + rest)
1365
+ return Integral(*((func,) + tuple(limits)))
1366
+ else:
1367
+ return eq.func(*[_polarify(arg, lift, pause=pause)
1368
+ if isinstance(arg, Expr) else arg for arg in eq.args])
1369
+
1370
+
1371
+ def polarify(eq, subs=True, lift=False):
1372
+ """
1373
+ Turn all numbers in eq into their polar equivalents (under the standard
1374
+ choice of argument).
1375
+
1376
+ Note that no attempt is made to guess a formal convention of adding
1377
+ polar numbers, expressions like $1 + x$ will generally not be altered.
1378
+
1379
+ Note also that this function does not promote ``exp(x)`` to ``exp_polar(x)``.
1380
+
1381
+ If ``subs`` is ``True``, all symbols which are not already polar will be
1382
+ substituted for polar dummies; in this case the function behaves much
1383
+ like :func:`~.posify`.
1384
+
1385
+ If ``lift`` is ``True``, both addition statements and non-polar symbols are
1386
+ changed to their ``polar_lift()``ed versions.
1387
+ Note that ``lift=True`` implies ``subs=False``.
1388
+
1389
+ Examples
1390
+ ========
1391
+
1392
+ >>> from sympy import polarify, sin, I
1393
+ >>> from sympy.abc import x, y
1394
+ >>> expr = (-x)**y
1395
+ >>> expr.expand()
1396
+ (-x)**y
1397
+ >>> polarify(expr)
1398
+ ((_x*exp_polar(I*pi))**_y, {_x: x, _y: y})
1399
+ >>> polarify(expr)[0].expand()
1400
+ _x**_y*exp_polar(_y*I*pi)
1401
+ >>> polarify(x, lift=True)
1402
+ polar_lift(x)
1403
+ >>> polarify(x*(1+y), lift=True)
1404
+ polar_lift(x)*polar_lift(y + 1)
1405
+
1406
+ Adds are treated carefully:
1407
+
1408
+ >>> polarify(1 + sin((1 + I)*x))
1409
+ (sin(_x*polar_lift(1 + I)) + 1, {_x: x})
1410
+ """
1411
+ if lift:
1412
+ subs = False
1413
+ eq = _polarify(sympify(eq), lift)
1414
+ if not subs:
1415
+ return eq
1416
+ reps = {s: Dummy(s.name, polar=True) for s in eq.free_symbols}
1417
+ eq = eq.subs(reps)
1418
+ return eq, {r: s for s, r in reps.items()}
1419
+
1420
+
1421
+ def _unpolarify(eq, exponents_only, pause=False):
1422
+ if not isinstance(eq, Basic) or eq.is_Atom:
1423
+ return eq
1424
+
1425
+ if not pause:
1426
+ from sympy.functions.elementary.exponential import exp, exp_polar
1427
+ if isinstance(eq, exp_polar):
1428
+ return exp(_unpolarify(eq.exp, exponents_only))
1429
+ if isinstance(eq, principal_branch) and eq.args[1] == 2*pi:
1430
+ return _unpolarify(eq.args[0], exponents_only)
1431
+ if (
1432
+ eq.is_Add or eq.is_Mul or eq.is_Boolean or
1433
+ eq.is_Relational and (
1434
+ eq.rel_op in ('==', '!=') and 0 in eq.args or
1435
+ eq.rel_op not in ('==', '!='))
1436
+ ):
1437
+ return eq.func(*[_unpolarify(x, exponents_only) for x in eq.args])
1438
+ if isinstance(eq, polar_lift):
1439
+ return _unpolarify(eq.args[0], exponents_only)
1440
+
1441
+ if eq.is_Pow:
1442
+ expo = _unpolarify(eq.exp, exponents_only)
1443
+ base = _unpolarify(eq.base, exponents_only,
1444
+ not (expo.is_integer and not pause))
1445
+ return base**expo
1446
+
1447
+ if eq.is_Function and getattr(eq.func, 'unbranched', False):
1448
+ return eq.func(*[_unpolarify(x, exponents_only, exponents_only)
1449
+ for x in eq.args])
1450
+
1451
+ return eq.func(*[_unpolarify(x, exponents_only, True) for x in eq.args])
1452
+
1453
+
1454
+ def unpolarify(eq, subs=None, exponents_only=False):
1455
+ """
1456
+ If `p` denotes the projection from the Riemann surface of the logarithm to
1457
+ the complex line, return a simplified version `eq'` of `eq` such that
1458
+ `p(eq') = p(eq)`.
1459
+ Also apply the substitution subs in the end. (This is a convenience, since
1460
+ ``unpolarify``, in a certain sense, undoes :func:`polarify`.)
1461
+
1462
+ Examples
1463
+ ========
1464
+
1465
+ >>> from sympy import unpolarify, polar_lift, sin, I
1466
+ >>> unpolarify(polar_lift(I + 2))
1467
+ 2 + I
1468
+ >>> unpolarify(sin(polar_lift(I + 7)))
1469
+ sin(7 + I)
1470
+ """
1471
+ if isinstance(eq, bool):
1472
+ return eq
1473
+
1474
+ eq = sympify(eq)
1475
+ if subs is not None:
1476
+ return unpolarify(eq.subs(subs))
1477
+ changed = True
1478
+ pause = False
1479
+ if exponents_only:
1480
+ pause = True
1481
+ while changed:
1482
+ changed = False
1483
+ res = _unpolarify(eq, exponents_only, pause)
1484
+ if res != eq:
1485
+ changed = True
1486
+ eq = res
1487
+ if isinstance(res, bool):
1488
+ return res
1489
+ # Finally, replacing Exp(0) by 1 is always correct.
1490
+ # So is polar_lift(0) -> 0.
1491
+ from sympy.functions.elementary.exponential import exp_polar
1492
+ return res.subs({exp_polar(0): 1, polar_lift(0): 0})
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/exponential.py ADDED
@@ -0,0 +1,1286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ from itertools import product
3
+
4
+ from sympy.core.add import Add
5
+ from sympy.core.cache import cacheit
6
+ from sympy.core.expr import Expr
7
+ from sympy.core.function import (DefinedFunction, ArgumentIndexError, expand_log,
8
+ expand_mul, FunctionClass, PoleError, expand_multinomial, expand_complex)
9
+ from sympy.core.logic import fuzzy_and, fuzzy_not, fuzzy_or
10
+ from sympy.core.mul import Mul
11
+ from sympy.core.numbers import Integer, Rational, pi, I
12
+ from sympy.core.parameters import global_parameters
13
+ from sympy.core.power import Pow
14
+ from sympy.core.singleton import S
15
+ from sympy.core.symbol import Wild, Dummy
16
+ from sympy.core.sympify import sympify
17
+ from sympy.functions.combinatorial.factorials import factorial
18
+ from sympy.functions.elementary.complexes import arg, unpolarify, im, re, Abs
19
+ from sympy.functions.elementary.miscellaneous import sqrt
20
+ from sympy.ntheory import multiplicity, perfect_power
21
+ from sympy.ntheory.factor_ import factorint
22
+
23
+ # NOTE IMPORTANT
24
+ # The series expansion code in this file is an important part of the gruntz
25
+ # algorithm for determining limits. _eval_nseries has to return a generalized
26
+ # power series with coefficients in C(log(x), log).
27
+ # In more detail, the result of _eval_nseries(self, x, n) must be
28
+ # c_0*x**e_0 + ... (finitely many terms)
29
+ # where e_i are numbers (not necessarily integers) and c_i involve only
30
+ # numbers, the function log, and log(x). [This also means it must not contain
31
+ # log(x(1+p)), this *has* to be expanded to log(x)+log(1+p) if x.is_positive and
32
+ # p.is_positive.]
33
+
34
+
35
+ class ExpBase(DefinedFunction):
36
+
37
+ unbranched = True
38
+ _singularities = (S.ComplexInfinity,)
39
+
40
+ @property
41
+ def kind(self):
42
+ return self.exp.kind
43
+
44
+ def inverse(self, argindex=1):
45
+ """
46
+ Returns the inverse function of ``exp(x)``.
47
+ """
48
+ return log
49
+
50
+ def as_numer_denom(self):
51
+ """
52
+ Returns this with a positive exponent as a 2-tuple (a fraction).
53
+
54
+ Examples
55
+ ========
56
+
57
+ >>> from sympy import exp
58
+ >>> from sympy.abc import x
59
+ >>> exp(-x).as_numer_denom()
60
+ (1, exp(x))
61
+ >>> exp(x).as_numer_denom()
62
+ (exp(x), 1)
63
+ """
64
+ # this should be the same as Pow.as_numer_denom wrt
65
+ # exponent handling
66
+ if not self.is_commutative:
67
+ return self, S.One
68
+ exp = self.exp
69
+ neg_exp = exp.is_negative
70
+ if not neg_exp and not (-exp).is_negative:
71
+ neg_exp = exp.could_extract_minus_sign()
72
+ if neg_exp:
73
+ return S.One, self.func(-exp)
74
+ return self, S.One
75
+
76
+ @property
77
+ def exp(self):
78
+ """
79
+ Returns the exponent of the function.
80
+ """
81
+ return self.args[0]
82
+
83
+ def as_base_exp(self):
84
+ """
85
+ Returns the 2-tuple (base, exponent).
86
+ """
87
+ return self.func(1), Mul(*self.args)
88
+
89
+ def _eval_adjoint(self):
90
+ return self.func(self.exp.adjoint())
91
+
92
+ def _eval_conjugate(self):
93
+ return self.func(self.exp.conjugate())
94
+
95
+ def _eval_transpose(self):
96
+ return self.func(self.exp.transpose())
97
+
98
+ def _eval_is_finite(self):
99
+ arg = self.exp
100
+ if arg.is_infinite:
101
+ if arg.is_extended_negative:
102
+ return True
103
+ if arg.is_extended_positive:
104
+ return False
105
+ if arg.is_finite:
106
+ return True
107
+
108
+ def _eval_is_rational(self):
109
+ s = self.func(*self.args)
110
+ if s.func == self.func:
111
+ z = s.exp.is_zero
112
+ if z:
113
+ return True
114
+ elif s.exp.is_rational and fuzzy_not(z):
115
+ return False
116
+ else:
117
+ return s.is_rational
118
+
119
+ def _eval_is_zero(self):
120
+ return self.exp is S.NegativeInfinity
121
+
122
+ def _eval_power(self, other):
123
+ """exp(arg)**e -> exp(arg*e) if assumptions allow it.
124
+ """
125
+ b, e = self.as_base_exp()
126
+ return Pow._eval_power(Pow(b, e, evaluate=False), other)
127
+
128
+ def _eval_expand_power_exp(self, **hints):
129
+ from sympy.concrete.products import Product
130
+ from sympy.concrete.summations import Sum
131
+ arg = self.args[0]
132
+ if arg.is_Add and arg.is_commutative:
133
+ return Mul.fromiter(self.func(x) for x in arg.args)
134
+ elif isinstance(arg, Sum) and arg.is_commutative:
135
+ return Product(self.func(arg.function), *arg.limits)
136
+ return self.func(arg)
137
+
138
+
139
+ class exp_polar(ExpBase):
140
+ r"""
141
+ Represent a *polar number* (see g-function Sphinx documentation).
142
+
143
+ Explanation
144
+ ===========
145
+
146
+ ``exp_polar`` represents the function
147
+ `Exp: \mathbb{C} \rightarrow \mathcal{S}`, sending the complex number
148
+ `z = a + bi` to the polar number `r = exp(a), \theta = b`. It is one of
149
+ the main functions to construct polar numbers.
150
+
151
+ Examples
152
+ ========
153
+
154
+ >>> from sympy import exp_polar, pi, I, exp
155
+
156
+ The main difference is that polar numbers do not "wrap around" at `2 \pi`:
157
+
158
+ >>> exp(2*pi*I)
159
+ 1
160
+ >>> exp_polar(2*pi*I)
161
+ exp_polar(2*I*pi)
162
+
163
+ apart from that they behave mostly like classical complex numbers:
164
+
165
+ >>> exp_polar(2)*exp_polar(3)
166
+ exp_polar(5)
167
+
168
+ See Also
169
+ ========
170
+
171
+ sympy.simplify.powsimp.powsimp
172
+ polar_lift
173
+ periodic_argument
174
+ principal_branch
175
+ """
176
+
177
+ is_polar = True
178
+ is_comparable = False # cannot be evalf'd
179
+
180
+ def _eval_Abs(self): # Abs is never a polar number
181
+ return exp(re(self.args[0]))
182
+
183
+ def _eval_evalf(self, prec):
184
+ """ Careful! any evalf of polar numbers is flaky """
185
+ i = im(self.args[0])
186
+ try:
187
+ bad = (i <= -pi or i > pi)
188
+ except TypeError:
189
+ bad = True
190
+ if bad:
191
+ return self # cannot evalf for this argument
192
+ res = exp(self.args[0])._eval_evalf(prec)
193
+ if i > 0 and im(res) < 0:
194
+ # i ~ pi, but exp(I*i) evaluated to argument slightly bigger than pi
195
+ return re(res)
196
+ return res
197
+
198
+ def _eval_power(self, other):
199
+ return self.func(self.args[0]*other)
200
+
201
+ def _eval_is_extended_real(self):
202
+ if self.args[0].is_extended_real:
203
+ return True
204
+
205
+ def as_base_exp(self):
206
+ # XXX exp_polar(0) is special!
207
+ if self.args[0] == 0:
208
+ return self, S.One
209
+ return ExpBase.as_base_exp(self)
210
+
211
+
212
+ class ExpMeta(FunctionClass):
213
+ def __instancecheck__(cls, instance):
214
+ if exp in instance.__class__.__mro__:
215
+ return True
216
+ return isinstance(instance, Pow) and instance.base is S.Exp1
217
+
218
+
219
+ class exp(ExpBase, metaclass=ExpMeta):
220
+ """
221
+ The exponential function, :math:`e^x`.
222
+
223
+ Examples
224
+ ========
225
+
226
+ >>> from sympy import exp, I, pi
227
+ >>> from sympy.abc import x
228
+ >>> exp(x)
229
+ exp(x)
230
+ >>> exp(x).diff(x)
231
+ exp(x)
232
+ >>> exp(I*pi)
233
+ -1
234
+
235
+ Parameters
236
+ ==========
237
+
238
+ arg : Expr
239
+
240
+ See Also
241
+ ========
242
+
243
+ log
244
+ """
245
+
246
+ def fdiff(self, argindex=1):
247
+ """
248
+ Returns the first derivative of this function.
249
+ """
250
+ if argindex == 1:
251
+ return self
252
+ else:
253
+ raise ArgumentIndexError(self, argindex)
254
+
255
+ def _eval_refine(self, assumptions):
256
+ from sympy.assumptions import ask, Q
257
+ arg = self.args[0]
258
+ if arg.is_Mul:
259
+ Ioo = I*S.Infinity
260
+ if arg in [Ioo, -Ioo]:
261
+ return S.NaN
262
+
263
+ coeff = arg.as_coefficient(pi*I)
264
+ if coeff:
265
+ if ask(Q.integer(2*coeff)):
266
+ if ask(Q.even(coeff)):
267
+ return S.One
268
+ elif ask(Q.odd(coeff)):
269
+ return S.NegativeOne
270
+ elif ask(Q.even(coeff + S.Half)):
271
+ return -I
272
+ elif ask(Q.odd(coeff + S.Half)):
273
+ return I
274
+
275
+ @classmethod
276
+ def eval(cls, arg):
277
+ from sympy.calculus import AccumBounds
278
+ from sympy.matrices.matrixbase import MatrixBase
279
+ from sympy.sets.setexpr import SetExpr
280
+ from sympy.simplify.simplify import logcombine
281
+ if isinstance(arg, MatrixBase):
282
+ return arg.exp()
283
+ elif global_parameters.exp_is_pow:
284
+ return Pow(S.Exp1, arg)
285
+ elif arg.is_Number:
286
+ if arg is S.NaN:
287
+ return S.NaN
288
+ elif arg.is_zero:
289
+ return S.One
290
+ elif arg is S.One:
291
+ return S.Exp1
292
+ elif arg is S.Infinity:
293
+ return S.Infinity
294
+ elif arg is S.NegativeInfinity:
295
+ return S.Zero
296
+ elif arg is S.ComplexInfinity:
297
+ return S.NaN
298
+ elif isinstance(arg, log):
299
+ return arg.args[0]
300
+ elif isinstance(arg, AccumBounds):
301
+ return AccumBounds(exp(arg.min), exp(arg.max))
302
+ elif isinstance(arg, SetExpr):
303
+ return arg._eval_func(cls)
304
+ elif arg.is_Mul:
305
+ coeff = arg.as_coefficient(pi*I)
306
+ if coeff:
307
+ if (2*coeff).is_integer:
308
+ if coeff.is_even:
309
+ return S.One
310
+ elif coeff.is_odd:
311
+ return S.NegativeOne
312
+ elif (coeff + S.Half).is_even:
313
+ return -I
314
+ elif (coeff + S.Half).is_odd:
315
+ return I
316
+ elif coeff.is_Rational:
317
+ ncoeff = coeff % 2 # restrict to [0, 2pi)
318
+ if ncoeff > 1: # restrict to (-pi, pi]
319
+ ncoeff -= 2
320
+ if ncoeff != coeff:
321
+ return cls(ncoeff*pi*I)
322
+
323
+ # Warning: code in risch.py will be very sensitive to changes
324
+ # in this (see DifferentialExtension).
325
+
326
+ # look for a single log factor
327
+
328
+ coeff, terms = arg.as_coeff_Mul()
329
+
330
+ # but it can't be multiplied by oo
331
+ if coeff in [S.NegativeInfinity, S.Infinity]:
332
+ if terms.is_number:
333
+ if coeff is S.NegativeInfinity:
334
+ terms = -terms
335
+ if re(terms).is_zero and terms is not S.Zero:
336
+ return S.NaN
337
+ if re(terms).is_positive and im(terms) is not S.Zero:
338
+ return S.ComplexInfinity
339
+ if re(terms).is_negative:
340
+ return S.Zero
341
+ return None
342
+
343
+ coeffs, log_term = [coeff], None
344
+ for term in Mul.make_args(terms):
345
+ term_ = logcombine(term)
346
+ if isinstance(term_, log):
347
+ if log_term is None:
348
+ log_term = term_.args[0]
349
+ else:
350
+ return None
351
+ elif term.is_comparable:
352
+ coeffs.append(term)
353
+ else:
354
+ return None
355
+
356
+ return log_term**Mul(*coeffs) if log_term else None
357
+
358
+ elif arg.is_Add:
359
+ out = []
360
+ add = []
361
+ argchanged = False
362
+ for a in arg.args:
363
+ if a is S.One:
364
+ add.append(a)
365
+ continue
366
+ newa = cls(a)
367
+ if isinstance(newa, cls):
368
+ if newa.args[0] != a:
369
+ add.append(newa.args[0])
370
+ argchanged = True
371
+ else:
372
+ add.append(a)
373
+ else:
374
+ out.append(newa)
375
+ if out or argchanged:
376
+ return Mul(*out)*cls(Add(*add), evaluate=False)
377
+
378
+ if arg.is_zero:
379
+ return S.One
380
+
381
+ @property
382
+ def base(self):
383
+ """
384
+ Returns the base of the exponential function.
385
+ """
386
+ return S.Exp1
387
+
388
+ @staticmethod
389
+ @cacheit
390
+ def taylor_term(n, x, *previous_terms):
391
+ """
392
+ Calculates the next term in the Taylor series expansion.
393
+ """
394
+ if n < 0:
395
+ return S.Zero
396
+ if n == 0:
397
+ return S.One
398
+ x = sympify(x)
399
+ if previous_terms:
400
+ p = previous_terms[-1]
401
+ if p is not None:
402
+ return p * x / n
403
+ return x**n/factorial(n)
404
+
405
+ def as_real_imag(self, deep=True, **hints):
406
+ """
407
+ Returns this function as a 2-tuple representing a complex number.
408
+
409
+ Examples
410
+ ========
411
+
412
+ >>> from sympy import exp, I
413
+ >>> from sympy.abc import x
414
+ >>> exp(x).as_real_imag()
415
+ (exp(re(x))*cos(im(x)), exp(re(x))*sin(im(x)))
416
+ >>> exp(1).as_real_imag()
417
+ (E, 0)
418
+ >>> exp(I).as_real_imag()
419
+ (cos(1), sin(1))
420
+ >>> exp(1+I).as_real_imag()
421
+ (E*cos(1), E*sin(1))
422
+
423
+ See Also
424
+ ========
425
+
426
+ sympy.functions.elementary.complexes.re
427
+ sympy.functions.elementary.complexes.im
428
+ """
429
+ from sympy.functions.elementary.trigonometric import cos, sin
430
+ re, im = self.args[0].as_real_imag()
431
+ if deep:
432
+ re = re.expand(deep, **hints)
433
+ im = im.expand(deep, **hints)
434
+ cos, sin = cos(im), sin(im)
435
+ return (exp(re)*cos, exp(re)*sin)
436
+
437
+ def _eval_subs(self, old, new):
438
+ # keep processing of power-like args centralized in Pow
439
+ if old.is_Pow: # handle (exp(3*log(x))).subs(x**2, z) -> z**(3/2)
440
+ old = exp(old.exp*log(old.base))
441
+ elif old is S.Exp1 and new.is_Function:
442
+ old = exp
443
+ if isinstance(old, exp) or old is S.Exp1:
444
+ f = lambda a: Pow(*a.as_base_exp(), evaluate=False) if (
445
+ a.is_Pow or isinstance(a, exp)) else a
446
+ return Pow._eval_subs(f(self), f(old), new)
447
+
448
+ if old is exp and not new.is_Function:
449
+ return new**self.exp._subs(old, new)
450
+ return super()._eval_subs(old, new)
451
+
452
+ def _eval_is_extended_real(self):
453
+ if self.args[0].is_extended_real:
454
+ return True
455
+ elif self.args[0].is_imaginary:
456
+ arg2 = -S(2) * I * self.args[0] / pi
457
+ return arg2.is_even
458
+
459
+ def _eval_is_complex(self):
460
+ def complex_extended_negative(arg):
461
+ yield arg.is_complex
462
+ yield arg.is_extended_negative
463
+ return fuzzy_or(complex_extended_negative(self.args[0]))
464
+
465
+ def _eval_is_algebraic(self):
466
+ if (self.exp / pi / I).is_rational:
467
+ return True
468
+ if fuzzy_not(self.exp.is_zero):
469
+ if self.exp.is_algebraic:
470
+ return False
471
+ elif (self.exp / pi).is_rational:
472
+ return False
473
+
474
+ def _eval_is_extended_positive(self):
475
+ if self.exp.is_extended_real:
476
+ return self.args[0] is not S.NegativeInfinity
477
+ elif self.exp.is_imaginary:
478
+ arg2 = -I * self.args[0] / pi
479
+ return arg2.is_even
480
+
481
+ def _eval_nseries(self, x, n, logx, cdir=0):
482
+ # NOTE Please see the comment at the beginning of this file, labelled
483
+ # IMPORTANT.
484
+ from sympy.functions.elementary.complexes import sign
485
+ from sympy.functions.elementary.integers import ceiling
486
+ from sympy.series.limits import limit
487
+ from sympy.series.order import Order
488
+ from sympy.simplify.powsimp import powsimp
489
+ arg = self.exp
490
+ arg_series = arg._eval_nseries(x, n=n, logx=logx)
491
+ if arg_series.is_Order:
492
+ return 1 + arg_series
493
+ arg0 = limit(arg_series.removeO(), x, 0)
494
+ if arg0 is S.NegativeInfinity:
495
+ return Order(x**n, x)
496
+ if arg0 is S.Infinity:
497
+ return self
498
+ if arg0.is_infinite:
499
+ raise PoleError("Cannot expand %s around 0" % (self))
500
+ # checking for indecisiveness/ sign terms in arg0
501
+ if any(isinstance(arg, sign) for arg in arg0.args):
502
+ return self
503
+ t = Dummy("t")
504
+ nterms = n
505
+ try:
506
+ cf = Order(arg.as_leading_term(x, logx=logx), x).getn()
507
+ except (NotImplementedError, PoleError):
508
+ cf = 0
509
+ if cf and cf > 0:
510
+ nterms = ceiling(n/cf)
511
+ exp_series = exp(t)._taylor(t, nterms)
512
+ r = exp(arg0)*exp_series.subs(t, arg_series - arg0)
513
+ rep = {logx: log(x)} if logx is not None else {}
514
+ if r.subs(rep) == self:
515
+ return r
516
+ if cf and cf > 1:
517
+ r += Order((arg_series - arg0)**n, x)/x**((cf-1)*n)
518
+ else:
519
+ r += Order((arg_series - arg0)**n, x)
520
+ r = r.expand()
521
+ r = powsimp(r, deep=True, combine='exp')
522
+ # powsimp may introduce unexpanded (-1)**Rational; see PR #17201
523
+ simplerat = lambda x: x.is_Rational and x.q in [3, 4, 6]
524
+ w = Wild('w', properties=[simplerat])
525
+ r = r.replace(S.NegativeOne**w, expand_complex(S.NegativeOne**w))
526
+ return r
527
+
528
+ def _taylor(self, x, n):
529
+ l = []
530
+ g = None
531
+ for i in range(n):
532
+ g = self.taylor_term(i, self.args[0], g)
533
+ g = g.nseries(x, n=n)
534
+ l.append(g.removeO())
535
+ return Add(*l)
536
+
537
+ def _eval_as_leading_term(self, x, logx, cdir):
538
+ from sympy.calculus.util import AccumBounds
539
+ arg = self.args[0].cancel().as_leading_term(x, logx=logx)
540
+ arg0 = arg.subs(x, 0)
541
+ if arg is S.NaN:
542
+ return S.NaN
543
+ if isinstance(arg0, AccumBounds):
544
+ # This check addresses a corner case involving AccumBounds.
545
+ # if isinstance(arg, AccumBounds) is True, then arg0 can either be 0,
546
+ # AccumBounds(-oo, 0) or AccumBounds(-oo, oo).
547
+ # Check out function: test_issue_18473() in test_exponential.py and
548
+ # test_limits.py for more information.
549
+ if re(cdir) < S.Zero:
550
+ return exp(-arg0)
551
+ return exp(arg0)
552
+ if arg0 is S.NaN:
553
+ arg0 = arg.limit(x, 0)
554
+ if arg0.is_infinite is False:
555
+ return exp(arg0)
556
+ raise PoleError("Cannot expand %s around 0" % (self))
557
+
558
+ def _eval_rewrite_as_sin(self, arg, **kwargs):
559
+ from sympy.functions.elementary.trigonometric import sin
560
+ return sin(I*arg + pi/2) - I*sin(I*arg)
561
+
562
+ def _eval_rewrite_as_cos(self, arg, **kwargs):
563
+ from sympy.functions.elementary.trigonometric import cos
564
+ return cos(I*arg) + I*cos(I*arg + pi/2)
565
+
566
+ def _eval_rewrite_as_tanh(self, arg, **kwargs):
567
+ from sympy.functions.elementary.hyperbolic import tanh
568
+ return (1 + tanh(arg/2))/(1 - tanh(arg/2))
569
+
570
+ def _eval_rewrite_as_sqrt(self, arg, **kwargs):
571
+ from sympy.functions.elementary.trigonometric import sin, cos
572
+ if arg.is_Mul:
573
+ coeff = arg.coeff(pi*I)
574
+ if coeff and coeff.is_number:
575
+ cosine, sine = cos(pi*coeff), sin(pi*coeff)
576
+ if not isinstance(cosine, cos) and not isinstance (sine, sin):
577
+ return cosine + I*sine
578
+
579
+ def _eval_rewrite_as_Pow(self, arg, **kwargs):
580
+ if arg.is_Mul:
581
+ logs = [a for a in arg.args if isinstance(a, log) and len(a.args) == 1]
582
+ if logs:
583
+ return Pow(logs[0].args[0], arg.coeff(logs[0]))
584
+
585
+
586
+ def match_real_imag(expr):
587
+ r"""
588
+ Try to match expr with $a + Ib$ for real $a$ and $b$.
589
+
590
+ ``match_real_imag`` returns a tuple containing the real and imaginary
591
+ parts of expr or ``(None, None)`` if direct matching is not possible. Contrary
592
+ to :func:`~.re`, :func:`~.im``, and ``as_real_imag()``, this helper will not force things
593
+ by returning expressions themselves containing ``re()`` or ``im()`` and it
594
+ does not expand its argument either.
595
+
596
+ """
597
+ r_, i_ = expr.as_independent(I, as_Add=True)
598
+ if i_ == 0 and r_.is_real:
599
+ return (r_, i_)
600
+ i_ = i_.as_coefficient(I)
601
+ if i_ and i_.is_real and r_.is_real:
602
+ return (r_, i_)
603
+ else:
604
+ return (None, None) # simpler to check for than None
605
+
606
+
607
+ class log(DefinedFunction):
608
+ r"""
609
+ The natural logarithm function `\ln(x)` or `\log(x)`.
610
+
611
+ Explanation
612
+ ===========
613
+
614
+ Logarithms are taken with the natural base, `e`. To get
615
+ a logarithm of a different base ``b``, use ``log(x, b)``,
616
+ which is essentially short-hand for ``log(x)/log(b)``.
617
+
618
+ ``log`` represents the principal branch of the natural
619
+ logarithm. As such it has a branch cut along the negative
620
+ real axis and returns values having a complex argument in
621
+ `(-\pi, \pi]`.
622
+
623
+ Examples
624
+ ========
625
+
626
+ >>> from sympy import log, sqrt, S, I
627
+ >>> log(8, 2)
628
+ 3
629
+ >>> log(S(8)/3, 2)
630
+ -log(3)/log(2) + 3
631
+ >>> log(-1 + I*sqrt(3))
632
+ log(2) + 2*I*pi/3
633
+
634
+ See Also
635
+ ========
636
+
637
+ exp
638
+
639
+ """
640
+
641
+ args: tuple[Expr]
642
+
643
+ _singularities = (S.Zero, S.ComplexInfinity)
644
+
645
+ def fdiff(self, argindex=1):
646
+ """
647
+ Returns the first derivative of the function.
648
+ """
649
+ if argindex == 1:
650
+ return 1/self.args[0]
651
+ else:
652
+ raise ArgumentIndexError(self, argindex)
653
+
654
+ def inverse(self, argindex=1):
655
+ r"""
656
+ Returns `e^x`, the inverse function of `\log(x)`.
657
+ """
658
+ return exp
659
+
660
+ @classmethod
661
+ def eval(cls, arg, base=None):
662
+ from sympy.calculus import AccumBounds
663
+ from sympy.sets.setexpr import SetExpr
664
+
665
+ arg = sympify(arg)
666
+
667
+ if base is not None:
668
+ base = sympify(base)
669
+ if base == 1:
670
+ if arg == 1:
671
+ return S.NaN
672
+ else:
673
+ return S.ComplexInfinity
674
+ try:
675
+ # handle extraction of powers of the base now
676
+ # or else expand_log in Mul would have to handle this
677
+ n = multiplicity(base, arg)
678
+ if n:
679
+ return n + log(arg / base**n) / log(base)
680
+ else:
681
+ return log(arg)/log(base)
682
+ except ValueError:
683
+ pass
684
+ if base is not S.Exp1:
685
+ return cls(arg)/cls(base)
686
+ else:
687
+ return cls(arg)
688
+
689
+ if arg.is_Number:
690
+ if arg.is_zero:
691
+ return S.ComplexInfinity
692
+ elif arg is S.One:
693
+ return S.Zero
694
+ elif arg is S.Infinity:
695
+ return S.Infinity
696
+ elif arg is S.NegativeInfinity:
697
+ return S.Infinity
698
+ elif arg is S.NaN:
699
+ return S.NaN
700
+ elif arg.is_Rational and arg.p == 1:
701
+ return -cls(arg.q)
702
+
703
+ if arg.is_Pow and arg.base is S.Exp1 and arg.exp.is_extended_real:
704
+ return arg.exp
705
+ if isinstance(arg, exp) and arg.exp.is_extended_real:
706
+ return arg.exp
707
+ elif isinstance(arg, exp) and arg.exp.is_number:
708
+ r_, i_ = match_real_imag(arg.exp)
709
+ if i_ and i_.is_comparable:
710
+ i_ %= 2*pi
711
+ if i_ > pi:
712
+ i_ -= 2*pi
713
+ return r_ + expand_mul(i_ * I, deep=False)
714
+ elif isinstance(arg, exp_polar):
715
+ return unpolarify(arg.exp)
716
+ elif isinstance(arg, AccumBounds):
717
+ if arg.min.is_positive:
718
+ return AccumBounds(log(arg.min), log(arg.max))
719
+ elif arg.min.is_zero:
720
+ return AccumBounds(S.NegativeInfinity, log(arg.max))
721
+ else:
722
+ return S.NaN
723
+ elif isinstance(arg, SetExpr):
724
+ return arg._eval_func(cls)
725
+
726
+ if arg.is_number:
727
+ if arg.is_negative:
728
+ return pi * I + cls(-arg)
729
+ elif arg is S.ComplexInfinity:
730
+ return S.ComplexInfinity
731
+ elif arg is S.Exp1:
732
+ return S.One
733
+
734
+ if arg.is_zero:
735
+ return S.ComplexInfinity
736
+
737
+ # don't autoexpand Pow or Mul (see the issue 3351):
738
+ if not arg.is_Add:
739
+ coeff = arg.as_coefficient(I)
740
+
741
+ if coeff is not None:
742
+ if coeff is S.Infinity:
743
+ return S.Infinity
744
+ elif coeff is S.NegativeInfinity:
745
+ return S.Infinity
746
+ elif coeff.is_Rational:
747
+ if coeff.is_nonnegative:
748
+ return pi * I * S.Half + cls(coeff)
749
+ else:
750
+ return -pi * I * S.Half + cls(-coeff)
751
+
752
+ if arg.is_number and arg.is_algebraic:
753
+ # Match arg = coeff*(r_ + i_*I) with coeff>0, r_ and i_ real.
754
+ coeff, arg_ = arg.as_independent(I, as_Add=False)
755
+ if coeff.is_negative:
756
+ coeff *= -1
757
+ arg_ *= -1
758
+ arg_ = expand_mul(arg_, deep=False)
759
+ r_, i_ = arg_.as_independent(I, as_Add=True)
760
+ i_ = i_.as_coefficient(I)
761
+ if coeff.is_real and i_ and i_.is_real and r_.is_real:
762
+ if r_.is_zero:
763
+ if i_.is_positive:
764
+ return pi * I * S.Half + cls(coeff * i_)
765
+ elif i_.is_negative:
766
+ return -pi * I * S.Half + cls(coeff * -i_)
767
+ else:
768
+ from sympy.simplify import ratsimp
769
+ # Check for arguments involving rational multiples of pi
770
+ t = (i_/r_).cancel()
771
+ t1 = (-t).cancel()
772
+ atan_table = _log_atan_table()
773
+ if t in atan_table:
774
+ modulus = ratsimp(coeff * Abs(arg_))
775
+ if r_.is_positive:
776
+ return cls(modulus) + I * atan_table[t]
777
+ else:
778
+ return cls(modulus) + I * (atan_table[t] - pi)
779
+ elif t1 in atan_table:
780
+ modulus = ratsimp(coeff * Abs(arg_))
781
+ if r_.is_positive:
782
+ return cls(modulus) + I * (-atan_table[t1])
783
+ else:
784
+ return cls(modulus) + I * (pi - atan_table[t1])
785
+
786
+ @staticmethod
787
+ @cacheit
788
+ def taylor_term(n, x, *previous_terms): # of log(1+x)
789
+ r"""
790
+ Returns the next term in the Taylor series expansion of `\log(1+x)`.
791
+ """
792
+ from sympy.simplify.powsimp import powsimp
793
+ if n < 0:
794
+ return S.Zero
795
+ x = sympify(x)
796
+ if n == 0:
797
+ return x
798
+ if previous_terms:
799
+ p = previous_terms[-1]
800
+ if p is not None:
801
+ return powsimp((-n) * p * x / (n + 1), deep=True, combine='exp')
802
+ return (1 - 2*(n % 2)) * x**(n + 1)/(n + 1)
803
+
804
+ def _eval_expand_log(self, deep=True, **hints):
805
+ from sympy.concrete import Sum, Product
806
+ force = hints.get('force', False)
807
+ factor = hints.get('factor', False)
808
+ if (len(self.args) == 2):
809
+ return expand_log(self.func(*self.args), deep=deep, force=force)
810
+ arg = self.args[0]
811
+ if arg.is_Integer:
812
+ # remove perfect powers
813
+ p = perfect_power(arg)
814
+ logarg = None
815
+ coeff = 1
816
+ if p is not False:
817
+ arg, coeff = p
818
+ logarg = self.func(arg)
819
+ # expand as product of its prime factors if factor=True
820
+ if factor:
821
+ p = factorint(arg)
822
+ if arg not in p.keys():
823
+ logarg = sum(n*log(val) for val, n in p.items())
824
+ if logarg is not None:
825
+ return coeff*logarg
826
+ elif arg.is_Rational:
827
+ return log(arg.p) - log(arg.q)
828
+ elif arg.is_Mul:
829
+ expr = []
830
+ nonpos = []
831
+ for x in arg.args:
832
+ if force or x.is_positive or x.is_polar:
833
+ a = self.func(x)
834
+ if isinstance(a, log):
835
+ expr.append(self.func(x)._eval_expand_log(**hints))
836
+ else:
837
+ expr.append(a)
838
+ elif x.is_negative:
839
+ a = self.func(-x)
840
+ expr.append(a)
841
+ nonpos.append(S.NegativeOne)
842
+ else:
843
+ nonpos.append(x)
844
+ return Add(*expr) + log(Mul(*nonpos))
845
+ elif arg.is_Pow or isinstance(arg, exp):
846
+ if force or (arg.exp.is_extended_real and (arg.base.is_positive or ((arg.exp+1)
847
+ .is_positive and (arg.exp-1).is_nonpositive))) or arg.base.is_polar:
848
+ b = arg.base
849
+ e = arg.exp
850
+ a = self.func(b)
851
+ if isinstance(a, log):
852
+ return unpolarify(e) * a._eval_expand_log(**hints)
853
+ else:
854
+ return unpolarify(e) * a
855
+ elif isinstance(arg, Product):
856
+ if force or arg.function.is_positive:
857
+ return Sum(log(arg.function), *arg.limits)
858
+
859
+ return self.func(arg)
860
+
861
+ def _eval_simplify(self, **kwargs):
862
+ from sympy.simplify.simplify import expand_log, simplify, inversecombine
863
+ if len(self.args) == 2: # it's unevaluated
864
+ return simplify(self.func(*self.args), **kwargs)
865
+
866
+ expr = self.func(simplify(self.args[0], **kwargs))
867
+ if kwargs['inverse']:
868
+ expr = inversecombine(expr)
869
+ expr = expand_log(expr, deep=True)
870
+ return min([expr, self], key=kwargs['measure'])
871
+
872
+ def as_real_imag(self, deep=True, **hints):
873
+ """
874
+ Returns this function as a complex coordinate.
875
+
876
+ Examples
877
+ ========
878
+
879
+ >>> from sympy import I, log
880
+ >>> from sympy.abc import x
881
+ >>> log(x).as_real_imag()
882
+ (log(Abs(x)), arg(x))
883
+ >>> log(I).as_real_imag()
884
+ (0, pi/2)
885
+ >>> log(1 + I).as_real_imag()
886
+ (log(sqrt(2)), pi/4)
887
+ >>> log(I*x).as_real_imag()
888
+ (log(Abs(x)), arg(I*x))
889
+
890
+ """
891
+ sarg = self.args[0]
892
+ if deep:
893
+ sarg = self.args[0].expand(deep, **hints)
894
+ sarg_abs = Abs(sarg)
895
+ if sarg_abs == sarg:
896
+ return self, S.Zero
897
+ sarg_arg = arg(sarg)
898
+ if hints.get('log', False): # Expand the log
899
+ hints['complex'] = False
900
+ return (log(sarg_abs).expand(deep, **hints), sarg_arg)
901
+ else:
902
+ return log(sarg_abs), sarg_arg
903
+
904
+ def _eval_is_rational(self):
905
+ s = self.func(*self.args)
906
+ if s.func == self.func:
907
+ if (self.args[0] - 1).is_zero:
908
+ return True
909
+ if s.args[0].is_rational and fuzzy_not((self.args[0] - 1).is_zero):
910
+ return False
911
+ else:
912
+ return s.is_rational
913
+
914
+ def _eval_is_algebraic(self):
915
+ s = self.func(*self.args)
916
+ if s.func == self.func:
917
+ if (self.args[0] - 1).is_zero:
918
+ return True
919
+ elif fuzzy_not((self.args[0] - 1).is_zero):
920
+ if self.args[0].is_algebraic:
921
+ return False
922
+ else:
923
+ return s.is_algebraic
924
+
925
+ def _eval_is_extended_real(self):
926
+ return self.args[0].is_extended_positive
927
+
928
+ def _eval_is_complex(self):
929
+ z = self.args[0]
930
+ return fuzzy_and([z.is_complex, fuzzy_not(z.is_zero)])
931
+
932
+ def _eval_is_finite(self):
933
+ arg = self.args[0]
934
+ if arg.is_zero:
935
+ return False
936
+ return arg.is_finite
937
+
938
+ def _eval_is_extended_positive(self):
939
+ return (self.args[0] - 1).is_extended_positive
940
+
941
+ def _eval_is_zero(self):
942
+ return (self.args[0] - 1).is_zero
943
+
944
+ def _eval_is_extended_nonnegative(self):
945
+ return (self.args[0] - 1).is_extended_nonnegative
946
+
947
+ def _eval_nseries(self, x, n, logx, cdir=0):
948
+ # NOTE Please see the comment at the beginning of this file, labelled
949
+ # IMPORTANT.
950
+ from sympy.series.order import Order
951
+ from sympy.simplify.simplify import logcombine
952
+ from sympy.core.symbol import Dummy
953
+
954
+ if self.args[0] == x:
955
+ return log(x) if logx is None else logx
956
+ arg = self.args[0]
957
+ t = Dummy('t', positive=True)
958
+ if cdir == 0:
959
+ cdir = 1
960
+ z = arg.subs(x, cdir*t)
961
+
962
+ k, l = Wild("k"), Wild("l")
963
+ r = z.match(k*t**l)
964
+ if r is not None:
965
+ k, l = r[k], r[l]
966
+ if l != 0 and not l.has(t) and not k.has(t):
967
+ r = l*log(x) if logx is None else l*logx
968
+ r += log(k) - l*log(cdir) # XXX true regardless of assumptions?
969
+ return r
970
+
971
+ def coeff_exp(term, x):
972
+ coeff, exp = S.One, S.Zero
973
+ for factor in Mul.make_args(term):
974
+ if factor.has(x):
975
+ base, exp = factor.as_base_exp()
976
+ if base != x:
977
+ try:
978
+ return term.leadterm(x)
979
+ except ValueError:
980
+ return term, S.Zero
981
+ else:
982
+ coeff *= factor
983
+ return coeff, exp
984
+
985
+ # TODO new and probably slow
986
+ try:
987
+ a, b = z.leadterm(t, logx=logx, cdir=1)
988
+ except (ValueError, NotImplementedError, PoleError):
989
+ s = z._eval_nseries(t, n=n, logx=logx, cdir=1)
990
+ while s.is_Order:
991
+ n += 1
992
+ s = z._eval_nseries(t, n=n, logx=logx, cdir=1)
993
+ try:
994
+ a, b = s.removeO().leadterm(t, cdir=1)
995
+ except ValueError:
996
+ a, b = s.removeO().as_leading_term(t, cdir=1), S.Zero
997
+
998
+ p = (z/(a*t**b) - 1).cancel()._eval_nseries(t, n=n, logx=logx, cdir=1)
999
+ if p.has(exp):
1000
+ p = logcombine(p)
1001
+ if isinstance(p, Order):
1002
+ n = p.getn()
1003
+ _, d = coeff_exp(p, t)
1004
+ logx = log(x) if logx is None else logx
1005
+
1006
+ if not d.is_positive:
1007
+ res = log(a) - b*log(cdir) + b*logx
1008
+ _res = res
1009
+ logflags = {"deep": True, "log": True, "mul": False, "power_exp": False,
1010
+ "power_base": False, "multinomial": False, "basic": False, "force": True,
1011
+ "factor": False}
1012
+ expr = self.expand(**logflags)
1013
+ if (not a.could_extract_minus_sign() and
1014
+ logx.could_extract_minus_sign()):
1015
+ _res = _res.subs(-logx, -log(x)).expand(**logflags)
1016
+ else:
1017
+ _res = _res.subs(logx, log(x)).expand(**logflags)
1018
+ if _res == expr:
1019
+ return res
1020
+ return res + Order(x**n, x)
1021
+
1022
+ def mul(d1, d2):
1023
+ res = {}
1024
+ for e1, e2 in product(d1, d2):
1025
+ ex = e1 + e2
1026
+ if ex < n:
1027
+ res[ex] = res.get(ex, S.Zero) + d1[e1]*d2[e2]
1028
+ return res
1029
+
1030
+ pterms = {}
1031
+
1032
+ for term in Add.make_args(p.removeO()):
1033
+ co1, e1 = coeff_exp(term, t)
1034
+ pterms[e1] = pterms.get(e1, S.Zero) + co1
1035
+
1036
+ k = S.One
1037
+ terms = {}
1038
+ pk = pterms
1039
+
1040
+ while k*d < n:
1041
+ coeff = -S.NegativeOne**k/k
1042
+ for ex in pk:
1043
+ terms[ex] = terms.get(ex, S.Zero) + coeff*pk[ex]
1044
+ pk = mul(pk, pterms)
1045
+ k += S.One
1046
+
1047
+ res = log(a) - b*log(cdir) + b*logx
1048
+ for ex in terms:
1049
+ res += terms[ex].cancel()*t**(ex)
1050
+
1051
+ if a.is_negative and im(z) != 0:
1052
+ from sympy.functions.special.delta_functions import Heaviside
1053
+ for i, term in enumerate(z.lseries(t)):
1054
+ if not term.is_real or i == 5:
1055
+ break
1056
+ if i < 5:
1057
+ coeff, _ = term.as_coeff_exponent(t)
1058
+ res += -2*I*pi*Heaviside(-im(coeff), 0)
1059
+
1060
+ res = res.subs(t, x/cdir)
1061
+ return res + Order(x**n, x)
1062
+
1063
+ def _eval_as_leading_term(self, x, logx, cdir):
1064
+ # NOTE
1065
+ # Refer https://github.com/sympy/sympy/pull/23592 for more information
1066
+ # on each of the following steps involved in this method.
1067
+ arg0 = self.args[0].together()
1068
+
1069
+ # STEP 1
1070
+ t = Dummy('t', positive=True)
1071
+ if cdir == 0:
1072
+ cdir = 1
1073
+ z = arg0.subs(x, cdir*t)
1074
+
1075
+ # STEP 2
1076
+ try:
1077
+ c, e = z.leadterm(t, logx=logx, cdir=1)
1078
+ except ValueError:
1079
+ arg = arg0.as_leading_term(x, logx=logx, cdir=cdir)
1080
+ return log(arg)
1081
+ if c.has(t):
1082
+ c = c.subs(t, x/cdir)
1083
+ if e != 0:
1084
+ raise PoleError("Cannot expand %s around 0" % (self))
1085
+ return log(c)
1086
+
1087
+ # STEP 3
1088
+ if c == S.One and e == S.Zero:
1089
+ return (arg0 - S.One).as_leading_term(x, logx=logx)
1090
+
1091
+ # STEP 4
1092
+ res = log(c) - e*log(cdir)
1093
+ logx = log(x) if logx is None else logx
1094
+ res += e*logx
1095
+
1096
+ # STEP 5
1097
+ if c.is_negative and im(z) != 0:
1098
+ from sympy.functions.special.delta_functions import Heaviside
1099
+ for i, term in enumerate(z.lseries(t)):
1100
+ if not term.is_real or i == 5:
1101
+ break
1102
+ if i < 5:
1103
+ coeff, _ = term.as_coeff_exponent(t)
1104
+ res += -2*I*pi*Heaviside(-im(coeff), 0)
1105
+ return res
1106
+
1107
+
1108
+ class LambertW(DefinedFunction):
1109
+ r"""
1110
+ The Lambert W function $W(z)$ is defined as the inverse
1111
+ function of $w \exp(w)$ [1]_.
1112
+
1113
+ Explanation
1114
+ ===========
1115
+
1116
+ In other words, the value of $W(z)$ is such that $z = W(z) \exp(W(z))$
1117
+ for any complex number $z$. The Lambert W function is a multivalued
1118
+ function with infinitely many branches $W_k(z)$, indexed by
1119
+ $k \in \mathbb{Z}$. Each branch gives a different solution $w$
1120
+ of the equation $z = w \exp(w)$.
1121
+
1122
+ The Lambert W function has two partially real branches: the
1123
+ principal branch ($k = 0$) is real for real $z > -1/e$, and the
1124
+ $k = -1$ branch is real for $-1/e < z < 0$. All branches except
1125
+ $k = 0$ have a logarithmic singularity at $z = 0$.
1126
+
1127
+ Examples
1128
+ ========
1129
+
1130
+ >>> from sympy import LambertW
1131
+ >>> LambertW(1.2)
1132
+ 0.635564016364870
1133
+ >>> LambertW(1.2, -1).n()
1134
+ -1.34747534407696 - 4.41624341514535*I
1135
+ >>> LambertW(-1).is_real
1136
+ False
1137
+
1138
+ References
1139
+ ==========
1140
+
1141
+ .. [1] https://en.wikipedia.org/wiki/Lambert_W_function
1142
+ """
1143
+ _singularities = (-Pow(S.Exp1, -1, evaluate=False), S.ComplexInfinity)
1144
+
1145
+ @classmethod
1146
+ def eval(cls, x, k=None):
1147
+ if k == S.Zero:
1148
+ return cls(x)
1149
+ elif k is None:
1150
+ k = S.Zero
1151
+
1152
+ if k.is_zero:
1153
+ if x.is_zero:
1154
+ return S.Zero
1155
+ if x is S.Exp1:
1156
+ return S.One
1157
+ if x == -1/S.Exp1:
1158
+ return S.NegativeOne
1159
+ if x == -log(2)/2:
1160
+ return -log(2)
1161
+ if x == 2*log(2):
1162
+ return log(2)
1163
+ if x == -pi/2:
1164
+ return I*pi/2
1165
+ if x == exp(1 + S.Exp1):
1166
+ return S.Exp1
1167
+ if x is S.Infinity:
1168
+ return S.Infinity
1169
+
1170
+ if fuzzy_not(k.is_zero):
1171
+ if x.is_zero:
1172
+ return S.NegativeInfinity
1173
+ if k is S.NegativeOne:
1174
+ if x == -pi/2:
1175
+ return -I*pi/2
1176
+ elif x == -1/S.Exp1:
1177
+ return S.NegativeOne
1178
+ elif x == -2*exp(-2):
1179
+ return -Integer(2)
1180
+
1181
+ def fdiff(self, argindex=1):
1182
+ """
1183
+ Return the first derivative of this function.
1184
+ """
1185
+ x = self.args[0]
1186
+
1187
+ if len(self.args) == 1:
1188
+ if argindex == 1:
1189
+ return LambertW(x)/(x*(1 + LambertW(x)))
1190
+ else:
1191
+ k = self.args[1]
1192
+ if argindex == 1:
1193
+ return LambertW(x, k)/(x*(1 + LambertW(x, k)))
1194
+
1195
+ raise ArgumentIndexError(self, argindex)
1196
+
1197
+ def _eval_is_extended_real(self):
1198
+ x = self.args[0]
1199
+ if len(self.args) == 1:
1200
+ k = S.Zero
1201
+ else:
1202
+ k = self.args[1]
1203
+ if k.is_zero:
1204
+ if (x + 1/S.Exp1).is_positive:
1205
+ return True
1206
+ elif (x + 1/S.Exp1).is_nonpositive:
1207
+ return False
1208
+ elif (k + 1).is_zero:
1209
+ if x.is_negative and (x + 1/S.Exp1).is_positive:
1210
+ return True
1211
+ elif x.is_nonpositive or (x + 1/S.Exp1).is_nonnegative:
1212
+ return False
1213
+ elif fuzzy_not(k.is_zero) and fuzzy_not((k + 1).is_zero):
1214
+ if x.is_extended_real:
1215
+ return False
1216
+
1217
+ def _eval_is_finite(self):
1218
+ return self.args[0].is_finite
1219
+
1220
+ def _eval_is_algebraic(self):
1221
+ s = self.func(*self.args)
1222
+ if s.func == self.func:
1223
+ if fuzzy_not(self.args[0].is_zero) and self.args[0].is_algebraic:
1224
+ return False
1225
+ else:
1226
+ return s.is_algebraic
1227
+
1228
+ def _eval_as_leading_term(self, x, logx, cdir):
1229
+ if len(self.args) == 1:
1230
+ arg = self.args[0]
1231
+ arg0 = arg.subs(x, 0).cancel()
1232
+ if not arg0.is_zero:
1233
+ return self.func(arg0)
1234
+ return arg.as_leading_term(x)
1235
+
1236
+ def _eval_nseries(self, x, n, logx, cdir=0):
1237
+ if len(self.args) == 1:
1238
+ from sympy.functions.elementary.integers import ceiling
1239
+ from sympy.series.order import Order
1240
+ arg = self.args[0].nseries(x, n=n, logx=logx)
1241
+ lt = arg.as_leading_term(x, logx=logx)
1242
+ lte = 1
1243
+ if lt.is_Pow:
1244
+ lte = lt.exp
1245
+ if ceiling(n/lte) >= 1:
1246
+ s = Add(*[(-S.One)**(k - 1)*Integer(k)**(k - 2)/
1247
+ factorial(k - 1)*arg**k for k in range(1, ceiling(n/lte))])
1248
+ s = expand_multinomial(s)
1249
+ else:
1250
+ s = S.Zero
1251
+
1252
+ return s + Order(x**n, x)
1253
+ return super()._eval_nseries(x, n, logx)
1254
+
1255
+ def _eval_is_zero(self):
1256
+ x = self.args[0]
1257
+ if len(self.args) == 1:
1258
+ return x.is_zero
1259
+ else:
1260
+ return fuzzy_and([x.is_zero, self.args[1].is_zero])
1261
+
1262
+
1263
+ @cacheit
1264
+ def _log_atan_table():
1265
+ return {
1266
+ # first quadrant only
1267
+ sqrt(3): pi / 3,
1268
+ 1: pi / 4,
1269
+ sqrt(5 - 2 * sqrt(5)): pi / 5,
1270
+ sqrt(2) * sqrt(5 - sqrt(5)) / (1 + sqrt(5)): pi / 5,
1271
+ sqrt(5 + 2 * sqrt(5)): pi * Rational(2, 5),
1272
+ sqrt(2) * sqrt(sqrt(5) + 5) / (-1 + sqrt(5)): pi * Rational(2, 5),
1273
+ sqrt(3) / 3: pi / 6,
1274
+ sqrt(2) - 1: pi / 8,
1275
+ sqrt(2 - sqrt(2)) / sqrt(sqrt(2) + 2): pi / 8,
1276
+ sqrt(2) + 1: pi * Rational(3, 8),
1277
+ sqrt(sqrt(2) + 2) / sqrt(2 - sqrt(2)): pi * Rational(3, 8),
1278
+ sqrt(1 - 2 * sqrt(5) / 5): pi / 10,
1279
+ (-sqrt(2) + sqrt(10)) / (2 * sqrt(sqrt(5) + 5)): pi / 10,
1280
+ sqrt(1 + 2 * sqrt(5) / 5): pi * Rational(3, 10),
1281
+ (sqrt(2) + sqrt(10)) / (2 * sqrt(5 - sqrt(5))): pi * Rational(3, 10),
1282
+ 2 - sqrt(3): pi / 12,
1283
+ (-1 + sqrt(3)) / (1 + sqrt(3)): pi / 12,
1284
+ 2 + sqrt(3): pi * Rational(5, 12),
1285
+ (1 + sqrt(3)) / (-1 + sqrt(3)): pi * Rational(5, 12)
1286
+ }
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/hyperbolic.py ADDED
@@ -0,0 +1,2285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import S, sympify, cacheit
2
+ from sympy.core.add import Add
3
+ from sympy.core.function import DefinedFunction, ArgumentIndexError
4
+ from sympy.core.logic import fuzzy_or, fuzzy_and, fuzzy_not, FuzzyBool
5
+ from sympy.core.numbers import I, pi, Rational
6
+ from sympy.core.symbol import Dummy
7
+ from sympy.functions.combinatorial.factorials import (binomial, factorial,
8
+ RisingFactorial)
9
+ from sympy.functions.combinatorial.numbers import bernoulli, euler, nC
10
+ from sympy.functions.elementary.complexes import Abs, im, re
11
+ from sympy.functions.elementary.exponential import exp, log, match_real_imag
12
+ from sympy.functions.elementary.integers import floor
13
+ from sympy.functions.elementary.miscellaneous import sqrt
14
+ from sympy.functions.elementary.trigonometric import (
15
+ acos, acot, asin, atan, cos, cot, csc, sec, sin, tan,
16
+ _imaginary_unit_as_coefficient)
17
+ from sympy.polys.specialpolys import symmetric_poly
18
+
19
+
20
+ def _rewrite_hyperbolics_as_exp(expr):
21
+ return expr.xreplace({h: h.rewrite(exp)
22
+ for h in expr.atoms(HyperbolicFunction)})
23
+
24
+
25
+ @cacheit
26
+ def _acosh_table():
27
+ return {
28
+ I: log(I*(1 + sqrt(2))),
29
+ -I: log(-I*(1 + sqrt(2))),
30
+ S.Half: pi/3,
31
+ Rational(-1, 2): pi*Rational(2, 3),
32
+ sqrt(2)/2: pi/4,
33
+ -sqrt(2)/2: pi*Rational(3, 4),
34
+ 1/sqrt(2): pi/4,
35
+ -1/sqrt(2): pi*Rational(3, 4),
36
+ sqrt(3)/2: pi/6,
37
+ -sqrt(3)/2: pi*Rational(5, 6),
38
+ (sqrt(3) - 1)/sqrt(2**3): pi*Rational(5, 12),
39
+ -(sqrt(3) - 1)/sqrt(2**3): pi*Rational(7, 12),
40
+ sqrt(2 + sqrt(2))/2: pi/8,
41
+ -sqrt(2 + sqrt(2))/2: pi*Rational(7, 8),
42
+ sqrt(2 - sqrt(2))/2: pi*Rational(3, 8),
43
+ -sqrt(2 - sqrt(2))/2: pi*Rational(5, 8),
44
+ (1 + sqrt(3))/(2*sqrt(2)): pi/12,
45
+ -(1 + sqrt(3))/(2*sqrt(2)): pi*Rational(11, 12),
46
+ (sqrt(5) + 1)/4: pi/5,
47
+ -(sqrt(5) + 1)/4: pi*Rational(4, 5)
48
+ }
49
+
50
+
51
+ @cacheit
52
+ def _acsch_table():
53
+ return {
54
+ I: -pi / 2,
55
+ I*(sqrt(2) + sqrt(6)): -pi / 12,
56
+ I*(1 + sqrt(5)): -pi / 10,
57
+ I*2 / sqrt(2 - sqrt(2)): -pi / 8,
58
+ I*2: -pi / 6,
59
+ I*sqrt(2 + 2/sqrt(5)): -pi / 5,
60
+ I*sqrt(2): -pi / 4,
61
+ I*(sqrt(5)-1): -3*pi / 10,
62
+ I*2 / sqrt(3): -pi / 3,
63
+ I*2 / sqrt(2 + sqrt(2)): -3*pi / 8,
64
+ I*sqrt(2 - 2/sqrt(5)): -2*pi / 5,
65
+ I*(sqrt(6) - sqrt(2)): -5*pi / 12,
66
+ S(2): -I*log((1+sqrt(5))/2),
67
+ }
68
+
69
+
70
+ @cacheit
71
+ def _asech_table():
72
+ return {
73
+ I: - (pi*I / 2) + log(1 + sqrt(2)),
74
+ -I: (pi*I / 2) + log(1 + sqrt(2)),
75
+ (sqrt(6) - sqrt(2)): pi / 12,
76
+ (sqrt(2) - sqrt(6)): 11*pi / 12,
77
+ sqrt(2 - 2/sqrt(5)): pi / 10,
78
+ -sqrt(2 - 2/sqrt(5)): 9*pi / 10,
79
+ 2 / sqrt(2 + sqrt(2)): pi / 8,
80
+ -2 / sqrt(2 + sqrt(2)): 7*pi / 8,
81
+ 2 / sqrt(3): pi / 6,
82
+ -2 / sqrt(3): 5*pi / 6,
83
+ (sqrt(5) - 1): pi / 5,
84
+ (1 - sqrt(5)): 4*pi / 5,
85
+ sqrt(2): pi / 4,
86
+ -sqrt(2): 3*pi / 4,
87
+ sqrt(2 + 2/sqrt(5)): 3*pi / 10,
88
+ -sqrt(2 + 2/sqrt(5)): 7*pi / 10,
89
+ S(2): pi / 3,
90
+ -S(2): 2*pi / 3,
91
+ sqrt(2*(2 + sqrt(2))): 3*pi / 8,
92
+ -sqrt(2*(2 + sqrt(2))): 5*pi / 8,
93
+ (1 + sqrt(5)): 2*pi / 5,
94
+ (-1 - sqrt(5)): 3*pi / 5,
95
+ (sqrt(6) + sqrt(2)): 5*pi / 12,
96
+ (-sqrt(6) - sqrt(2)): 7*pi / 12,
97
+ I*S.Infinity: -pi*I / 2,
98
+ I*S.NegativeInfinity: pi*I / 2,
99
+ }
100
+
101
+ ###############################################################################
102
+ ########################### HYPERBOLIC FUNCTIONS ##############################
103
+ ###############################################################################
104
+
105
+
106
+ class HyperbolicFunction(DefinedFunction):
107
+ """
108
+ Base class for hyperbolic functions.
109
+
110
+ See Also
111
+ ========
112
+
113
+ sinh, cosh, tanh, coth
114
+ """
115
+
116
+ unbranched = True
117
+
118
+
119
+ def _peeloff_ipi(arg):
120
+ r"""
121
+ Split ARG into two parts, a "rest" and a multiple of $I\pi$.
122
+ This assumes ARG to be an ``Add``.
123
+ The multiple of $I\pi$ returned in the second position is always a ``Rational``.
124
+
125
+ Examples
126
+ ========
127
+
128
+ >>> from sympy.functions.elementary.hyperbolic import _peeloff_ipi as peel
129
+ >>> from sympy import pi, I
130
+ >>> from sympy.abc import x, y
131
+ >>> peel(x + I*pi/2)
132
+ (x, 1/2)
133
+ >>> peel(x + I*2*pi/3 + I*pi*y)
134
+ (x + I*pi*y + I*pi/6, 1/2)
135
+ """
136
+ ipi = pi*I
137
+ for a in Add.make_args(arg):
138
+ if a == ipi:
139
+ K = S.One
140
+ break
141
+ elif a.is_Mul:
142
+ K, p = a.as_two_terms()
143
+ if p == ipi and K.is_Rational:
144
+ break
145
+ else:
146
+ return arg, S.Zero
147
+
148
+ m1 = (K % S.Half)
149
+ m2 = K - m1
150
+ return arg - m2*ipi, m2
151
+
152
+
153
+ class sinh(HyperbolicFunction):
154
+ r"""
155
+ ``sinh(x)`` is the hyperbolic sine of ``x``.
156
+
157
+ The hyperbolic sine function is $\frac{e^x - e^{-x}}{2}$.
158
+
159
+ Examples
160
+ ========
161
+
162
+ >>> from sympy import sinh
163
+ >>> from sympy.abc import x
164
+ >>> sinh(x)
165
+ sinh(x)
166
+
167
+ See Also
168
+ ========
169
+
170
+ cosh, tanh, asinh
171
+ """
172
+
173
+ def fdiff(self, argindex=1):
174
+ """
175
+ Returns the first derivative of this function.
176
+ """
177
+ if argindex == 1:
178
+ return cosh(self.args[0])
179
+ else:
180
+ raise ArgumentIndexError(self, argindex)
181
+
182
+ def inverse(self, argindex=1):
183
+ """
184
+ Returns the inverse of this function.
185
+ """
186
+ return asinh
187
+
188
+ @classmethod
189
+ def eval(cls, arg):
190
+ if arg.is_Number:
191
+ if arg is S.NaN:
192
+ return S.NaN
193
+ elif arg is S.Infinity:
194
+ return S.Infinity
195
+ elif arg is S.NegativeInfinity:
196
+ return S.NegativeInfinity
197
+ elif arg.is_zero:
198
+ return S.Zero
199
+ elif arg.is_negative:
200
+ return -cls(-arg)
201
+ else:
202
+ if arg is S.ComplexInfinity:
203
+ return S.NaN
204
+
205
+ i_coeff = _imaginary_unit_as_coefficient(arg)
206
+
207
+ if i_coeff is not None:
208
+ return I * sin(i_coeff)
209
+ else:
210
+ if arg.could_extract_minus_sign():
211
+ return -cls(-arg)
212
+
213
+ if arg.is_Add:
214
+ x, m = _peeloff_ipi(arg)
215
+ if m:
216
+ m = m*pi*I
217
+ return sinh(m)*cosh(x) + cosh(m)*sinh(x)
218
+
219
+ if arg.is_zero:
220
+ return S.Zero
221
+
222
+ if arg.func == asinh:
223
+ return arg.args[0]
224
+
225
+ if arg.func == acosh:
226
+ x = arg.args[0]
227
+ return sqrt(x - 1) * sqrt(x + 1)
228
+
229
+ if arg.func == atanh:
230
+ x = arg.args[0]
231
+ return x/sqrt(1 - x**2)
232
+
233
+ if arg.func == acoth:
234
+ x = arg.args[0]
235
+ return 1/(sqrt(x - 1) * sqrt(x + 1))
236
+
237
+ @staticmethod
238
+ @cacheit
239
+ def taylor_term(n, x, *previous_terms):
240
+ """
241
+ Returns the next term in the Taylor series expansion.
242
+ """
243
+ if n < 0 or n % 2 == 0:
244
+ return S.Zero
245
+ else:
246
+ x = sympify(x)
247
+
248
+ if len(previous_terms) > 2:
249
+ p = previous_terms[-2]
250
+ return p * x**2 / (n*(n - 1))
251
+ else:
252
+ return x**(n) / factorial(n)
253
+
254
+ def _eval_conjugate(self):
255
+ return self.func(self.args[0].conjugate())
256
+
257
+ def as_real_imag(self, deep=True, **hints):
258
+ """
259
+ Returns this function as a complex coordinate.
260
+ """
261
+ if self.args[0].is_extended_real:
262
+ if deep:
263
+ hints['complex'] = False
264
+ return (self.expand(deep, **hints), S.Zero)
265
+ else:
266
+ return (self, S.Zero)
267
+ if deep:
268
+ re, im = self.args[0].expand(deep, **hints).as_real_imag()
269
+ else:
270
+ re, im = self.args[0].as_real_imag()
271
+ return (sinh(re)*cos(im), cosh(re)*sin(im))
272
+
273
+ def _eval_expand_complex(self, deep=True, **hints):
274
+ re_part, im_part = self.as_real_imag(deep=deep, **hints)
275
+ return re_part + im_part*I
276
+
277
+ def _eval_expand_trig(self, deep=True, **hints):
278
+ if deep:
279
+ arg = self.args[0].expand(deep, **hints)
280
+ else:
281
+ arg = self.args[0]
282
+ x = None
283
+ if arg.is_Add: # TODO, implement more if deep stuff here
284
+ x, y = arg.as_two_terms()
285
+ else:
286
+ coeff, terms = arg.as_coeff_Mul(rational=True)
287
+ if coeff is not S.One and coeff.is_Integer and terms is not S.One:
288
+ x = terms
289
+ y = (coeff - 1)*x
290
+ if x is not None:
291
+ return (sinh(x)*cosh(y) + sinh(y)*cosh(x)).expand(trig=True)
292
+ return sinh(arg)
293
+
294
+ def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs):
295
+ return (exp(arg) - exp(-arg)) / 2
296
+
297
+ def _eval_rewrite_as_exp(self, arg, **kwargs):
298
+ return (exp(arg) - exp(-arg)) / 2
299
+
300
+ def _eval_rewrite_as_sin(self, arg, **kwargs):
301
+ return -I * sin(I * arg)
302
+
303
+ def _eval_rewrite_as_csc(self, arg, **kwargs):
304
+ return -I / csc(I * arg)
305
+
306
+ def _eval_rewrite_as_cosh(self, arg, **kwargs):
307
+ return -I*cosh(arg + pi*I/2)
308
+
309
+ def _eval_rewrite_as_tanh(self, arg, **kwargs):
310
+ tanh_half = tanh(S.Half*arg)
311
+ return 2*tanh_half/(1 - tanh_half**2)
312
+
313
+ def _eval_rewrite_as_coth(self, arg, **kwargs):
314
+ coth_half = coth(S.Half*arg)
315
+ return 2*coth_half/(coth_half**2 - 1)
316
+
317
+ def _eval_rewrite_as_csch(self, arg, **kwargs):
318
+ return 1 / csch(arg)
319
+
320
+ def _eval_as_leading_term(self, x, logx, cdir):
321
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
322
+ arg0 = arg.subs(x, 0)
323
+
324
+ if arg0 is S.NaN:
325
+ arg0 = arg.limit(x, 0, dir='-' if cdir.is_negative else '+')
326
+ if arg0.is_zero:
327
+ return arg
328
+ elif arg0.is_finite:
329
+ return self.func(arg0)
330
+ else:
331
+ return self
332
+
333
+ def _eval_is_real(self):
334
+ arg = self.args[0]
335
+ if arg.is_real:
336
+ return True
337
+
338
+ # if `im` is of the form n*pi
339
+ # else, check if it is a number
340
+ re, im = arg.as_real_imag()
341
+ return (im%pi).is_zero
342
+
343
+ def _eval_is_extended_real(self):
344
+ if self.args[0].is_extended_real:
345
+ return True
346
+
347
+ def _eval_is_positive(self):
348
+ if self.args[0].is_extended_real:
349
+ return self.args[0].is_positive
350
+
351
+ def _eval_is_negative(self):
352
+ if self.args[0].is_extended_real:
353
+ return self.args[0].is_negative
354
+
355
+ def _eval_is_finite(self):
356
+ arg = self.args[0]
357
+ return arg.is_finite
358
+
359
+ def _eval_is_zero(self):
360
+ rest, ipi_mult = _peeloff_ipi(self.args[0])
361
+ if rest.is_zero:
362
+ return ipi_mult.is_integer
363
+
364
+
365
+ class cosh(HyperbolicFunction):
366
+ r"""
367
+ ``cosh(x)`` is the hyperbolic cosine of ``x``.
368
+
369
+ The hyperbolic cosine function is $\frac{e^x + e^{-x}}{2}$.
370
+
371
+ Examples
372
+ ========
373
+
374
+ >>> from sympy import cosh
375
+ >>> from sympy.abc import x
376
+ >>> cosh(x)
377
+ cosh(x)
378
+
379
+ See Also
380
+ ========
381
+
382
+ sinh, tanh, acosh
383
+ """
384
+
385
+ def fdiff(self, argindex=1):
386
+ if argindex == 1:
387
+ return sinh(self.args[0])
388
+ else:
389
+ raise ArgumentIndexError(self, argindex)
390
+
391
+ @classmethod
392
+ def eval(cls, arg):
393
+ from sympy.functions.elementary.trigonometric import cos
394
+ if arg.is_Number:
395
+ if arg is S.NaN:
396
+ return S.NaN
397
+ elif arg is S.Infinity:
398
+ return S.Infinity
399
+ elif arg is S.NegativeInfinity:
400
+ return S.Infinity
401
+ elif arg.is_zero:
402
+ return S.One
403
+ elif arg.is_negative:
404
+ return cls(-arg)
405
+ else:
406
+ if arg is S.ComplexInfinity:
407
+ return S.NaN
408
+
409
+ i_coeff = _imaginary_unit_as_coefficient(arg)
410
+
411
+ if i_coeff is not None:
412
+ return cos(i_coeff)
413
+ else:
414
+ if arg.could_extract_minus_sign():
415
+ return cls(-arg)
416
+
417
+ if arg.is_Add:
418
+ x, m = _peeloff_ipi(arg)
419
+ if m:
420
+ m = m*pi*I
421
+ return cosh(m)*cosh(x) + sinh(m)*sinh(x)
422
+
423
+ if arg.is_zero:
424
+ return S.One
425
+
426
+ if arg.func == asinh:
427
+ return sqrt(1 + arg.args[0]**2)
428
+
429
+ if arg.func == acosh:
430
+ return arg.args[0]
431
+
432
+ if arg.func == atanh:
433
+ return 1/sqrt(1 - arg.args[0]**2)
434
+
435
+ if arg.func == acoth:
436
+ x = arg.args[0]
437
+ return x/(sqrt(x - 1) * sqrt(x + 1))
438
+
439
+ @staticmethod
440
+ @cacheit
441
+ def taylor_term(n, x, *previous_terms):
442
+ if n < 0 or n % 2 == 1:
443
+ return S.Zero
444
+ else:
445
+ x = sympify(x)
446
+
447
+ if len(previous_terms) > 2:
448
+ p = previous_terms[-2]
449
+ return p * x**2 / (n*(n - 1))
450
+ else:
451
+ return x**(n)/factorial(n)
452
+
453
+ def _eval_conjugate(self):
454
+ return self.func(self.args[0].conjugate())
455
+
456
+ def as_real_imag(self, deep=True, **hints):
457
+ if self.args[0].is_extended_real:
458
+ if deep:
459
+ hints['complex'] = False
460
+ return (self.expand(deep, **hints), S.Zero)
461
+ else:
462
+ return (self, S.Zero)
463
+ if deep:
464
+ re, im = self.args[0].expand(deep, **hints).as_real_imag()
465
+ else:
466
+ re, im = self.args[0].as_real_imag()
467
+
468
+ return (cosh(re)*cos(im), sinh(re)*sin(im))
469
+
470
+ def _eval_expand_complex(self, deep=True, **hints):
471
+ re_part, im_part = self.as_real_imag(deep=deep, **hints)
472
+ return re_part + im_part*I
473
+
474
+ def _eval_expand_trig(self, deep=True, **hints):
475
+ if deep:
476
+ arg = self.args[0].expand(deep, **hints)
477
+ else:
478
+ arg = self.args[0]
479
+ x = None
480
+ if arg.is_Add: # TODO, implement more if deep stuff here
481
+ x, y = arg.as_two_terms()
482
+ else:
483
+ coeff, terms = arg.as_coeff_Mul(rational=True)
484
+ if coeff is not S.One and coeff.is_Integer and terms is not S.One:
485
+ x = terms
486
+ y = (coeff - 1)*x
487
+ if x is not None:
488
+ return (cosh(x)*cosh(y) + sinh(x)*sinh(y)).expand(trig=True)
489
+ return cosh(arg)
490
+
491
+ def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs):
492
+ return (exp(arg) + exp(-arg)) / 2
493
+
494
+ def _eval_rewrite_as_exp(self, arg, **kwargs):
495
+ return (exp(arg) + exp(-arg)) / 2
496
+
497
+ def _eval_rewrite_as_cos(self, arg, **kwargs):
498
+ return cos(I * arg, evaluate=False)
499
+
500
+ def _eval_rewrite_as_sec(self, arg, **kwargs):
501
+ return 1 / sec(I * arg, evaluate=False)
502
+
503
+ def _eval_rewrite_as_sinh(self, arg, **kwargs):
504
+ return -I*sinh(arg + pi*I/2, evaluate=False)
505
+
506
+ def _eval_rewrite_as_tanh(self, arg, **kwargs):
507
+ tanh_half = tanh(S.Half*arg)**2
508
+ return (1 + tanh_half)/(1 - tanh_half)
509
+
510
+ def _eval_rewrite_as_coth(self, arg, **kwargs):
511
+ coth_half = coth(S.Half*arg)**2
512
+ return (coth_half + 1)/(coth_half - 1)
513
+
514
+ def _eval_rewrite_as_sech(self, arg, **kwargs):
515
+ return 1 / sech(arg)
516
+
517
+ def _eval_as_leading_term(self, x, logx, cdir):
518
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
519
+ arg0 = arg.subs(x, 0)
520
+
521
+ if arg0 is S.NaN:
522
+ arg0 = arg.limit(x, 0, dir='-' if cdir.is_negative else '+')
523
+ if arg0.is_zero:
524
+ return S.One
525
+ elif arg0.is_finite:
526
+ return self.func(arg0)
527
+ else:
528
+ return self
529
+
530
+ def _eval_is_real(self):
531
+ arg = self.args[0]
532
+
533
+ # `cosh(x)` is real for real OR purely imaginary `x`
534
+ if arg.is_real or arg.is_imaginary:
535
+ return True
536
+
537
+ # cosh(a+ib) = cos(b)*cosh(a) + i*sin(b)*sinh(a)
538
+ # the imaginary part can be an expression like n*pi
539
+ # if not, check if the imaginary part is a number
540
+ re, im = arg.as_real_imag()
541
+ return (im%pi).is_zero
542
+
543
+ def _eval_is_positive(self):
544
+ # cosh(x+I*y) = cos(y)*cosh(x) + I*sin(y)*sinh(x)
545
+ # cosh(z) is positive iff it is real and the real part is positive.
546
+ # So we need sin(y)*sinh(x) = 0 which gives x=0 or y=n*pi
547
+ # Case 1 (y=n*pi): cosh(z) = (-1)**n * cosh(x) -> positive for n even
548
+ # Case 2 (x=0): cosh(z) = cos(y) -> positive when cos(y) is positive
549
+ z = self.args[0]
550
+
551
+ x, y = z.as_real_imag()
552
+ ymod = y % (2*pi)
553
+
554
+ yzero = ymod.is_zero
555
+ # shortcut if ymod is zero
556
+ if yzero:
557
+ return True
558
+
559
+ xzero = x.is_zero
560
+ # shortcut x is not zero
561
+ if xzero is False:
562
+ return yzero
563
+
564
+ return fuzzy_or([
565
+ # Case 1:
566
+ yzero,
567
+ # Case 2:
568
+ fuzzy_and([
569
+ xzero,
570
+ fuzzy_or([ymod < pi/2, ymod > 3*pi/2])
571
+ ])
572
+ ])
573
+
574
+
575
+ def _eval_is_nonnegative(self):
576
+ z = self.args[0]
577
+
578
+ x, y = z.as_real_imag()
579
+ ymod = y % (2*pi)
580
+
581
+ yzero = ymod.is_zero
582
+ # shortcut if ymod is zero
583
+ if yzero:
584
+ return True
585
+
586
+ xzero = x.is_zero
587
+ # shortcut x is not zero
588
+ if xzero is False:
589
+ return yzero
590
+
591
+ return fuzzy_or([
592
+ # Case 1:
593
+ yzero,
594
+ # Case 2:
595
+ fuzzy_and([
596
+ xzero,
597
+ fuzzy_or([ymod <= pi/2, ymod >= 3*pi/2])
598
+ ])
599
+ ])
600
+
601
+ def _eval_is_finite(self):
602
+ arg = self.args[0]
603
+ return arg.is_finite
604
+
605
+ def _eval_is_zero(self):
606
+ rest, ipi_mult = _peeloff_ipi(self.args[0])
607
+ if ipi_mult and rest.is_zero:
608
+ return (ipi_mult - S.Half).is_integer
609
+
610
+
611
+ class tanh(HyperbolicFunction):
612
+ r"""
613
+ ``tanh(x)`` is the hyperbolic tangent of ``x``.
614
+
615
+ The hyperbolic tangent function is $\frac{\sinh(x)}{\cosh(x)}$.
616
+
617
+ Examples
618
+ ========
619
+
620
+ >>> from sympy import tanh
621
+ >>> from sympy.abc import x
622
+ >>> tanh(x)
623
+ tanh(x)
624
+
625
+ See Also
626
+ ========
627
+
628
+ sinh, cosh, atanh
629
+ """
630
+
631
+ def fdiff(self, argindex=1):
632
+ if argindex == 1:
633
+ return S.One - tanh(self.args[0])**2
634
+ else:
635
+ raise ArgumentIndexError(self, argindex)
636
+
637
+ def inverse(self, argindex=1):
638
+ """
639
+ Returns the inverse of this function.
640
+ """
641
+ return atanh
642
+
643
+ @classmethod
644
+ def eval(cls, arg):
645
+ if arg.is_Number:
646
+ if arg is S.NaN:
647
+ return S.NaN
648
+ elif arg is S.Infinity:
649
+ return S.One
650
+ elif arg is S.NegativeInfinity:
651
+ return S.NegativeOne
652
+ elif arg.is_zero:
653
+ return S.Zero
654
+ elif arg.is_negative:
655
+ return -cls(-arg)
656
+ else:
657
+ if arg is S.ComplexInfinity:
658
+ return S.NaN
659
+
660
+ i_coeff = _imaginary_unit_as_coefficient(arg)
661
+
662
+ if i_coeff is not None:
663
+ if i_coeff.could_extract_minus_sign():
664
+ return -I * tan(-i_coeff)
665
+ return I * tan(i_coeff)
666
+ else:
667
+ if arg.could_extract_minus_sign():
668
+ return -cls(-arg)
669
+
670
+ if arg.is_Add:
671
+ x, m = _peeloff_ipi(arg)
672
+ if m:
673
+ tanhm = tanh(m*pi*I)
674
+ if tanhm is S.ComplexInfinity:
675
+ return coth(x)
676
+ else: # tanhm == 0
677
+ return tanh(x)
678
+
679
+ if arg.is_zero:
680
+ return S.Zero
681
+
682
+ if arg.func == asinh:
683
+ x = arg.args[0]
684
+ return x/sqrt(1 + x**2)
685
+
686
+ if arg.func == acosh:
687
+ x = arg.args[0]
688
+ return sqrt(x - 1) * sqrt(x + 1) / x
689
+
690
+ if arg.func == atanh:
691
+ return arg.args[0]
692
+
693
+ if arg.func == acoth:
694
+ return 1/arg.args[0]
695
+
696
+ @staticmethod
697
+ @cacheit
698
+ def taylor_term(n, x, *previous_terms):
699
+ if n < 0 or n % 2 == 0:
700
+ return S.Zero
701
+ else:
702
+ x = sympify(x)
703
+
704
+ a = 2**(n + 1)
705
+
706
+ B = bernoulli(n + 1)
707
+ F = factorial(n + 1)
708
+
709
+ return a*(a - 1) * B/F * x**n
710
+
711
+ def _eval_conjugate(self):
712
+ return self.func(self.args[0].conjugate())
713
+
714
+ def as_real_imag(self, deep=True, **hints):
715
+ if self.args[0].is_extended_real:
716
+ if deep:
717
+ hints['complex'] = False
718
+ return (self.expand(deep, **hints), S.Zero)
719
+ else:
720
+ return (self, S.Zero)
721
+ if deep:
722
+ re, im = self.args[0].expand(deep, **hints).as_real_imag()
723
+ else:
724
+ re, im = self.args[0].as_real_imag()
725
+ denom = sinh(re)**2 + cos(im)**2
726
+ return (sinh(re)*cosh(re)/denom, sin(im)*cos(im)/denom)
727
+
728
+ def _eval_expand_trig(self, **hints):
729
+ arg = self.args[0]
730
+ if arg.is_Add:
731
+ n = len(arg.args)
732
+ TX = [tanh(x, evaluate=False)._eval_expand_trig()
733
+ for x in arg.args]
734
+ p = [0, 0] # [den, num]
735
+ for i in range(n + 1):
736
+ p[i % 2] += symmetric_poly(i, TX)
737
+ return p[1]/p[0]
738
+ elif arg.is_Mul:
739
+ coeff, terms = arg.as_coeff_Mul()
740
+ if coeff.is_Integer and coeff > 1:
741
+ T = tanh(terms)
742
+ n = [nC(range(coeff), k)*T**k for k in range(1, coeff + 1, 2)]
743
+ d = [nC(range(coeff), k)*T**k for k in range(0, coeff + 1, 2)]
744
+ return Add(*n)/Add(*d)
745
+ return tanh(arg)
746
+
747
+ def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs):
748
+ neg_exp, pos_exp = exp(-arg), exp(arg)
749
+ return (pos_exp - neg_exp)/(pos_exp + neg_exp)
750
+
751
+ def _eval_rewrite_as_exp(self, arg, **kwargs):
752
+ neg_exp, pos_exp = exp(-arg), exp(arg)
753
+ return (pos_exp - neg_exp)/(pos_exp + neg_exp)
754
+
755
+ def _eval_rewrite_as_tan(self, arg, **kwargs):
756
+ return -I * tan(I * arg, evaluate=False)
757
+
758
+ def _eval_rewrite_as_cot(self, arg, **kwargs):
759
+ return -I / cot(I * arg, evaluate=False)
760
+
761
+ def _eval_rewrite_as_sinh(self, arg, **kwargs):
762
+ return I*sinh(arg)/sinh(pi*I/2 - arg, evaluate=False)
763
+
764
+ def _eval_rewrite_as_cosh(self, arg, **kwargs):
765
+ return I*cosh(pi*I/2 - arg, evaluate=False)/cosh(arg)
766
+
767
+ def _eval_rewrite_as_coth(self, arg, **kwargs):
768
+ return 1/coth(arg)
769
+
770
+ def _eval_as_leading_term(self, x, logx, cdir):
771
+ from sympy.series.order import Order
772
+ arg = self.args[0].as_leading_term(x)
773
+
774
+ if x in arg.free_symbols and Order(1, x).contains(arg):
775
+ return arg
776
+ else:
777
+ return self.func(arg)
778
+
779
+ def _eval_is_real(self):
780
+ arg = self.args[0]
781
+ if arg.is_real:
782
+ return True
783
+
784
+ re, im = arg.as_real_imag()
785
+
786
+ # if denom = 0, tanh(arg) = zoo
787
+ if re == 0 and im % pi == pi/2:
788
+ return None
789
+
790
+ # check if im is of the form n*pi/2 to make sin(2*im) = 0
791
+ # if not, im could be a number, return False in that case
792
+ return (im % (pi/2)).is_zero
793
+
794
+ def _eval_is_extended_real(self):
795
+ if self.args[0].is_extended_real:
796
+ return True
797
+
798
+ def _eval_is_positive(self):
799
+ if self.args[0].is_extended_real:
800
+ return self.args[0].is_positive
801
+
802
+ def _eval_is_negative(self):
803
+ if self.args[0].is_extended_real:
804
+ return self.args[0].is_negative
805
+
806
+ def _eval_is_finite(self):
807
+ arg = self.args[0]
808
+
809
+ re, im = arg.as_real_imag()
810
+ denom = cos(im)**2 + sinh(re)**2
811
+ if denom == 0:
812
+ return False
813
+ elif denom.is_number:
814
+ return True
815
+ if arg.is_extended_real:
816
+ return True
817
+
818
+ def _eval_is_zero(self):
819
+ arg = self.args[0]
820
+ if arg.is_zero:
821
+ return True
822
+
823
+
824
+ class coth(HyperbolicFunction):
825
+ r"""
826
+ ``coth(x)`` is the hyperbolic cotangent of ``x``.
827
+
828
+ The hyperbolic cotangent function is $\frac{\cosh(x)}{\sinh(x)}$.
829
+
830
+ Examples
831
+ ========
832
+
833
+ >>> from sympy import coth
834
+ >>> from sympy.abc import x
835
+ >>> coth(x)
836
+ coth(x)
837
+
838
+ See Also
839
+ ========
840
+
841
+ sinh, cosh, acoth
842
+ """
843
+
844
+ def fdiff(self, argindex=1):
845
+ if argindex == 1:
846
+ return -1/sinh(self.args[0])**2
847
+ else:
848
+ raise ArgumentIndexError(self, argindex)
849
+
850
+ def inverse(self, argindex=1):
851
+ """
852
+ Returns the inverse of this function.
853
+ """
854
+ return acoth
855
+
856
+ @classmethod
857
+ def eval(cls, arg):
858
+ if arg.is_Number:
859
+ if arg is S.NaN:
860
+ return S.NaN
861
+ elif arg is S.Infinity:
862
+ return S.One
863
+ elif arg is S.NegativeInfinity:
864
+ return S.NegativeOne
865
+ elif arg.is_zero:
866
+ return S.ComplexInfinity
867
+ elif arg.is_negative:
868
+ return -cls(-arg)
869
+ else:
870
+ if arg is S.ComplexInfinity:
871
+ return S.NaN
872
+
873
+ i_coeff = _imaginary_unit_as_coefficient(arg)
874
+
875
+ if i_coeff is not None:
876
+ if i_coeff.could_extract_minus_sign():
877
+ return I * cot(-i_coeff)
878
+ return -I * cot(i_coeff)
879
+ else:
880
+ if arg.could_extract_minus_sign():
881
+ return -cls(-arg)
882
+
883
+ if arg.is_Add:
884
+ x, m = _peeloff_ipi(arg)
885
+ if m:
886
+ cothm = coth(m*pi*I)
887
+ if cothm is S.ComplexInfinity:
888
+ return coth(x)
889
+ else: # cothm == 0
890
+ return tanh(x)
891
+
892
+ if arg.is_zero:
893
+ return S.ComplexInfinity
894
+
895
+ if arg.func == asinh:
896
+ x = arg.args[0]
897
+ return sqrt(1 + x**2)/x
898
+
899
+ if arg.func == acosh:
900
+ x = arg.args[0]
901
+ return x/(sqrt(x - 1) * sqrt(x + 1))
902
+
903
+ if arg.func == atanh:
904
+ return 1/arg.args[0]
905
+
906
+ if arg.func == acoth:
907
+ return arg.args[0]
908
+
909
+ @staticmethod
910
+ @cacheit
911
+ def taylor_term(n, x, *previous_terms):
912
+ if n == 0:
913
+ return 1 / sympify(x)
914
+ elif n < 0 or n % 2 == 0:
915
+ return S.Zero
916
+ else:
917
+ x = sympify(x)
918
+
919
+ B = bernoulli(n + 1)
920
+ F = factorial(n + 1)
921
+
922
+ return 2**(n + 1) * B/F * x**n
923
+
924
+ def _eval_conjugate(self):
925
+ return self.func(self.args[0].conjugate())
926
+
927
+ def as_real_imag(self, deep=True, **hints):
928
+ from sympy.functions.elementary.trigonometric import (cos, sin)
929
+ if self.args[0].is_extended_real:
930
+ if deep:
931
+ hints['complex'] = False
932
+ return (self.expand(deep, **hints), S.Zero)
933
+ else:
934
+ return (self, S.Zero)
935
+ if deep:
936
+ re, im = self.args[0].expand(deep, **hints).as_real_imag()
937
+ else:
938
+ re, im = self.args[0].as_real_imag()
939
+ denom = sinh(re)**2 + sin(im)**2
940
+ return (sinh(re)*cosh(re)/denom, -sin(im)*cos(im)/denom)
941
+
942
+ def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs):
943
+ neg_exp, pos_exp = exp(-arg), exp(arg)
944
+ return (pos_exp + neg_exp)/(pos_exp - neg_exp)
945
+
946
+ def _eval_rewrite_as_exp(self, arg, **kwargs):
947
+ neg_exp, pos_exp = exp(-arg), exp(arg)
948
+ return (pos_exp + neg_exp)/(pos_exp - neg_exp)
949
+
950
+ def _eval_rewrite_as_sinh(self, arg, **kwargs):
951
+ return -I*sinh(pi*I/2 - arg, evaluate=False)/sinh(arg)
952
+
953
+ def _eval_rewrite_as_cosh(self, arg, **kwargs):
954
+ return -I*cosh(arg)/cosh(pi*I/2 - arg, evaluate=False)
955
+
956
+ def _eval_rewrite_as_tanh(self, arg, **kwargs):
957
+ return 1/tanh(arg)
958
+
959
+ def _eval_is_positive(self):
960
+ if self.args[0].is_extended_real:
961
+ return self.args[0].is_positive
962
+
963
+ def _eval_is_negative(self):
964
+ if self.args[0].is_extended_real:
965
+ return self.args[0].is_negative
966
+
967
+ def _eval_as_leading_term(self, x, logx, cdir):
968
+ from sympy.series.order import Order
969
+ arg = self.args[0].as_leading_term(x)
970
+
971
+ if x in arg.free_symbols and Order(1, x).contains(arg):
972
+ return 1/arg
973
+ else:
974
+ return self.func(arg)
975
+
976
+ def _eval_expand_trig(self, **hints):
977
+ arg = self.args[0]
978
+ if arg.is_Add:
979
+ CX = [coth(x, evaluate=False)._eval_expand_trig() for x in arg.args]
980
+ p = [[], []]
981
+ n = len(arg.args)
982
+ for i in range(n, -1, -1):
983
+ p[(n - i) % 2].append(symmetric_poly(i, CX))
984
+ return Add(*p[0])/Add(*p[1])
985
+ elif arg.is_Mul:
986
+ coeff, x = arg.as_coeff_Mul(rational=True)
987
+ if coeff.is_Integer and coeff > 1:
988
+ c = coth(x, evaluate=False)
989
+ p = [[], []]
990
+ for i in range(coeff, -1, -1):
991
+ p[(coeff - i) % 2].append(binomial(coeff, i)*c**i)
992
+ return Add(*p[0])/Add(*p[1])
993
+ return coth(arg)
994
+
995
+
996
+ class ReciprocalHyperbolicFunction(HyperbolicFunction):
997
+ """Base class for reciprocal functions of hyperbolic functions. """
998
+
999
+ #To be defined in class
1000
+ _reciprocal_of = None
1001
+ _is_even: FuzzyBool = None
1002
+ _is_odd: FuzzyBool = None
1003
+
1004
+ @classmethod
1005
+ def eval(cls, arg):
1006
+ if arg.could_extract_minus_sign():
1007
+ if cls._is_even:
1008
+ return cls(-arg)
1009
+ if cls._is_odd:
1010
+ return -cls(-arg)
1011
+
1012
+ t = cls._reciprocal_of.eval(arg)
1013
+ if hasattr(arg, 'inverse') and arg.inverse() == cls:
1014
+ return arg.args[0]
1015
+ return 1/t if t is not None else t
1016
+
1017
+ def _call_reciprocal(self, method_name, *args, **kwargs):
1018
+ # Calls method_name on _reciprocal_of
1019
+ o = self._reciprocal_of(self.args[0])
1020
+ return getattr(o, method_name)(*args, **kwargs)
1021
+
1022
+ def _calculate_reciprocal(self, method_name, *args, **kwargs):
1023
+ # If calling method_name on _reciprocal_of returns a value != None
1024
+ # then return the reciprocal of that value
1025
+ t = self._call_reciprocal(method_name, *args, **kwargs)
1026
+ return 1/t if t is not None else t
1027
+
1028
+ def _rewrite_reciprocal(self, method_name, arg):
1029
+ # Special handling for rewrite functions. If reciprocal rewrite returns
1030
+ # unmodified expression, then return None
1031
+ t = self._call_reciprocal(method_name, arg)
1032
+ if t is not None and t != self._reciprocal_of(arg):
1033
+ return 1/t
1034
+
1035
+ def _eval_rewrite_as_exp(self, arg, **kwargs):
1036
+ return self._rewrite_reciprocal("_eval_rewrite_as_exp", arg)
1037
+
1038
+ def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs):
1039
+ return self._rewrite_reciprocal("_eval_rewrite_as_tractable", arg)
1040
+
1041
+ def _eval_rewrite_as_tanh(self, arg, **kwargs):
1042
+ return self._rewrite_reciprocal("_eval_rewrite_as_tanh", arg)
1043
+
1044
+ def _eval_rewrite_as_coth(self, arg, **kwargs):
1045
+ return self._rewrite_reciprocal("_eval_rewrite_as_coth", arg)
1046
+
1047
+ def as_real_imag(self, deep = True, **hints):
1048
+ return (1 / self._reciprocal_of(self.args[0])).as_real_imag(deep, **hints)
1049
+
1050
+ def _eval_conjugate(self):
1051
+ return self.func(self.args[0].conjugate())
1052
+
1053
+ def _eval_expand_complex(self, deep=True, **hints):
1054
+ re_part, im_part = self.as_real_imag(deep=True, **hints)
1055
+ return re_part + I*im_part
1056
+
1057
+ def _eval_expand_trig(self, **hints):
1058
+ return self._calculate_reciprocal("_eval_expand_trig", **hints)
1059
+
1060
+ def _eval_as_leading_term(self, x, logx, cdir):
1061
+ return (1/self._reciprocal_of(self.args[0]))._eval_as_leading_term(x, logx=logx, cdir=cdir)
1062
+
1063
+ def _eval_is_extended_real(self):
1064
+ return self._reciprocal_of(self.args[0]).is_extended_real
1065
+
1066
+ def _eval_is_finite(self):
1067
+ return (1/self._reciprocal_of(self.args[0])).is_finite
1068
+
1069
+
1070
+ class csch(ReciprocalHyperbolicFunction):
1071
+ r"""
1072
+ ``csch(x)`` is the hyperbolic cosecant of ``x``.
1073
+
1074
+ The hyperbolic cosecant function is $\frac{2}{e^x - e^{-x}}$
1075
+
1076
+ Examples
1077
+ ========
1078
+
1079
+ >>> from sympy import csch
1080
+ >>> from sympy.abc import x
1081
+ >>> csch(x)
1082
+ csch(x)
1083
+
1084
+ See Also
1085
+ ========
1086
+
1087
+ sinh, cosh, tanh, sech, asinh, acosh
1088
+ """
1089
+
1090
+ _reciprocal_of = sinh
1091
+ _is_odd = True
1092
+
1093
+ def fdiff(self, argindex=1):
1094
+ """
1095
+ Returns the first derivative of this function
1096
+ """
1097
+ if argindex == 1:
1098
+ return -coth(self.args[0]) * csch(self.args[0])
1099
+ else:
1100
+ raise ArgumentIndexError(self, argindex)
1101
+
1102
+ @staticmethod
1103
+ @cacheit
1104
+ def taylor_term(n, x, *previous_terms):
1105
+ """
1106
+ Returns the next term in the Taylor series expansion
1107
+ """
1108
+ if n == 0:
1109
+ return 1/sympify(x)
1110
+ elif n < 0 or n % 2 == 0:
1111
+ return S.Zero
1112
+ else:
1113
+ x = sympify(x)
1114
+
1115
+ B = bernoulli(n + 1)
1116
+ F = factorial(n + 1)
1117
+
1118
+ return 2 * (1 - 2**n) * B/F * x**n
1119
+
1120
+ def _eval_rewrite_as_sin(self, arg, **kwargs):
1121
+ return I / sin(I * arg, evaluate=False)
1122
+
1123
+ def _eval_rewrite_as_csc(self, arg, **kwargs):
1124
+ return I * csc(I * arg, evaluate=False)
1125
+
1126
+ def _eval_rewrite_as_cosh(self, arg, **kwargs):
1127
+ return I / cosh(arg + I * pi / 2, evaluate=False)
1128
+
1129
+ def _eval_rewrite_as_sinh(self, arg, **kwargs):
1130
+ return 1 / sinh(arg)
1131
+
1132
+ def _eval_is_positive(self):
1133
+ if self.args[0].is_extended_real:
1134
+ return self.args[0].is_positive
1135
+
1136
+ def _eval_is_negative(self):
1137
+ if self.args[0].is_extended_real:
1138
+ return self.args[0].is_negative
1139
+
1140
+
1141
+ class sech(ReciprocalHyperbolicFunction):
1142
+ r"""
1143
+ ``sech(x)`` is the hyperbolic secant of ``x``.
1144
+
1145
+ The hyperbolic secant function is $\frac{2}{e^x + e^{-x}}$
1146
+
1147
+ Examples
1148
+ ========
1149
+
1150
+ >>> from sympy import sech
1151
+ >>> from sympy.abc import x
1152
+ >>> sech(x)
1153
+ sech(x)
1154
+
1155
+ See Also
1156
+ ========
1157
+
1158
+ sinh, cosh, tanh, coth, csch, asinh, acosh
1159
+ """
1160
+
1161
+ _reciprocal_of = cosh
1162
+ _is_even = True
1163
+
1164
+ def fdiff(self, argindex=1):
1165
+ if argindex == 1:
1166
+ return - tanh(self.args[0])*sech(self.args[0])
1167
+ else:
1168
+ raise ArgumentIndexError(self, argindex)
1169
+
1170
+ @staticmethod
1171
+ @cacheit
1172
+ def taylor_term(n, x, *previous_terms):
1173
+ if n < 0 or n % 2 == 1:
1174
+ return S.Zero
1175
+ else:
1176
+ x = sympify(x)
1177
+ return euler(n) / factorial(n) * x**(n)
1178
+
1179
+ def _eval_rewrite_as_cos(self, arg, **kwargs):
1180
+ return 1 / cos(I * arg, evaluate=False)
1181
+
1182
+ def _eval_rewrite_as_sec(self, arg, **kwargs):
1183
+ return sec(I * arg, evaluate=False)
1184
+
1185
+ def _eval_rewrite_as_sinh(self, arg, **kwargs):
1186
+ return I / sinh(arg + I * pi /2, evaluate=False)
1187
+
1188
+ def _eval_rewrite_as_cosh(self, arg, **kwargs):
1189
+ return 1 / cosh(arg)
1190
+
1191
+ def _eval_is_positive(self):
1192
+ if self.args[0].is_extended_real:
1193
+ return True
1194
+
1195
+
1196
+ ###############################################################################
1197
+ ############################# HYPERBOLIC INVERSES #############################
1198
+ ###############################################################################
1199
+
1200
+ class InverseHyperbolicFunction(DefinedFunction):
1201
+ """Base class for inverse hyperbolic functions."""
1202
+
1203
+ pass
1204
+
1205
+
1206
+ class asinh(InverseHyperbolicFunction):
1207
+ """
1208
+ ``asinh(x)`` is the inverse hyperbolic sine of ``x``.
1209
+
1210
+ The inverse hyperbolic sine function.
1211
+
1212
+ Examples
1213
+ ========
1214
+
1215
+ >>> from sympy import asinh
1216
+ >>> from sympy.abc import x
1217
+ >>> asinh(x).diff(x)
1218
+ 1/sqrt(x**2 + 1)
1219
+ >>> asinh(1)
1220
+ log(1 + sqrt(2))
1221
+
1222
+ See Also
1223
+ ========
1224
+
1225
+ acosh, atanh, sinh
1226
+ """
1227
+
1228
+ def fdiff(self, argindex=1):
1229
+ if argindex == 1:
1230
+ return 1/sqrt(self.args[0]**2 + 1)
1231
+ else:
1232
+ raise ArgumentIndexError(self, argindex)
1233
+
1234
+ @classmethod
1235
+ def eval(cls, arg):
1236
+ if arg.is_Number:
1237
+ if arg is S.NaN:
1238
+ return S.NaN
1239
+ elif arg is S.Infinity:
1240
+ return S.Infinity
1241
+ elif arg is S.NegativeInfinity:
1242
+ return S.NegativeInfinity
1243
+ elif arg.is_zero:
1244
+ return S.Zero
1245
+ elif arg is S.One:
1246
+ return log(sqrt(2) + 1)
1247
+ elif arg is S.NegativeOne:
1248
+ return log(sqrt(2) - 1)
1249
+ elif arg.is_negative:
1250
+ return -cls(-arg)
1251
+ else:
1252
+ if arg is S.ComplexInfinity:
1253
+ return S.ComplexInfinity
1254
+
1255
+ if arg.is_zero:
1256
+ return S.Zero
1257
+
1258
+ i_coeff = _imaginary_unit_as_coefficient(arg)
1259
+
1260
+ if i_coeff is not None:
1261
+ return I * asin(i_coeff)
1262
+ else:
1263
+ if arg.could_extract_minus_sign():
1264
+ return -cls(-arg)
1265
+
1266
+ if isinstance(arg, sinh) and arg.args[0].is_number:
1267
+ z = arg.args[0]
1268
+ if z.is_real:
1269
+ return z
1270
+ r, i = match_real_imag(z)
1271
+ if r is not None and i is not None:
1272
+ f = floor((i + pi/2)/pi)
1273
+ m = z - I*pi*f
1274
+ even = f.is_even
1275
+ if even is True:
1276
+ return m
1277
+ elif even is False:
1278
+ return -m
1279
+
1280
+ @staticmethod
1281
+ @cacheit
1282
+ def taylor_term(n, x, *previous_terms):
1283
+ if n < 0 or n % 2 == 0:
1284
+ return S.Zero
1285
+ else:
1286
+ x = sympify(x)
1287
+ if len(previous_terms) >= 2 and n > 2:
1288
+ p = previous_terms[-2]
1289
+ return -p * (n - 2)**2/(n*(n - 1)) * x**2
1290
+ else:
1291
+ k = (n - 1) // 2
1292
+ R = RisingFactorial(S.Half, k)
1293
+ F = factorial(k)
1294
+ return S.NegativeOne**k * R / F * x**n / n
1295
+
1296
+ def _eval_as_leading_term(self, x, logx, cdir):
1297
+ arg = self.args[0]
1298
+ x0 = arg.subs(x, 0).cancel()
1299
+ if x0.is_zero:
1300
+ return arg.as_leading_term(x)
1301
+
1302
+ if x0 is S.NaN:
1303
+ expr = self.func(arg.as_leading_term(x))
1304
+ if expr.is_finite:
1305
+ return expr
1306
+ else:
1307
+ return self
1308
+
1309
+ # Handling branch points
1310
+ if x0 in (-I, I, S.ComplexInfinity):
1311
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
1312
+ # Handling points lying on branch cuts (-I*oo, -I) U (I, I*oo)
1313
+ if (1 + x0**2).is_negative:
1314
+ ndir = arg.dir(x, cdir if cdir else 1)
1315
+ if re(ndir).is_positive:
1316
+ if im(x0).is_negative:
1317
+ return -self.func(x0) - I*pi
1318
+ elif re(ndir).is_negative:
1319
+ if im(x0).is_positive:
1320
+ return -self.func(x0) + I*pi
1321
+ else:
1322
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
1323
+ return self.func(x0)
1324
+
1325
+ def _eval_nseries(self, x, n, logx, cdir=0): # asinh
1326
+ arg = self.args[0]
1327
+ arg0 = arg.subs(x, 0)
1328
+
1329
+ # Handling branch points
1330
+ if arg0 in (I, -I):
1331
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
1332
+
1333
+ res = super()._eval_nseries(x, n=n, logx=logx)
1334
+ if arg0 is S.ComplexInfinity:
1335
+ return res
1336
+
1337
+ # Handling points lying on branch cuts (-I*oo, -I) U (I, I*oo)
1338
+ if (1 + arg0**2).is_negative:
1339
+ ndir = arg.dir(x, cdir if cdir else 1)
1340
+ if re(ndir).is_positive:
1341
+ if im(arg0).is_negative:
1342
+ return -res - I*pi
1343
+ elif re(ndir).is_negative:
1344
+ if im(arg0).is_positive:
1345
+ return -res + I*pi
1346
+ else:
1347
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
1348
+ return res
1349
+
1350
+ def _eval_rewrite_as_log(self, x, **kwargs):
1351
+ return log(x + sqrt(x**2 + 1))
1352
+
1353
+ _eval_rewrite_as_tractable = _eval_rewrite_as_log
1354
+
1355
+ def _eval_rewrite_as_atanh(self, x, **kwargs):
1356
+ return atanh(x/sqrt(1 + x**2))
1357
+
1358
+ def _eval_rewrite_as_acosh(self, x, **kwargs):
1359
+ ix = I*x
1360
+ return I*(sqrt(1 - ix)/sqrt(ix - 1) * acosh(ix) - pi/2)
1361
+
1362
+ def _eval_rewrite_as_asin(self, x, **kwargs):
1363
+ return -I * asin(I * x, evaluate=False)
1364
+
1365
+ def _eval_rewrite_as_acos(self, x, **kwargs):
1366
+ return I * acos(I * x, evaluate=False) - I*pi/2
1367
+
1368
+ def inverse(self, argindex=1):
1369
+ """
1370
+ Returns the inverse of this function.
1371
+ """
1372
+ return sinh
1373
+
1374
+ def _eval_is_zero(self):
1375
+ return self.args[0].is_zero
1376
+
1377
+ def _eval_is_extended_real(self):
1378
+ return self.args[0].is_extended_real
1379
+
1380
+ def _eval_is_finite(self):
1381
+ return self.args[0].is_finite
1382
+
1383
+
1384
+ class acosh(InverseHyperbolicFunction):
1385
+ """
1386
+ ``acosh(x)`` is the inverse hyperbolic cosine of ``x``.
1387
+
1388
+ The inverse hyperbolic cosine function.
1389
+
1390
+ Examples
1391
+ ========
1392
+
1393
+ >>> from sympy import acosh
1394
+ >>> from sympy.abc import x
1395
+ >>> acosh(x).diff(x)
1396
+ 1/(sqrt(x - 1)*sqrt(x + 1))
1397
+ >>> acosh(1)
1398
+ 0
1399
+
1400
+ See Also
1401
+ ========
1402
+
1403
+ asinh, atanh, cosh
1404
+ """
1405
+
1406
+ def fdiff(self, argindex=1):
1407
+ if argindex == 1:
1408
+ arg = self.args[0]
1409
+ return 1/(sqrt(arg - 1)*sqrt(arg + 1))
1410
+ else:
1411
+ raise ArgumentIndexError(self, argindex)
1412
+
1413
+ @classmethod
1414
+ def eval(cls, arg):
1415
+ if arg.is_Number:
1416
+ if arg is S.NaN:
1417
+ return S.NaN
1418
+ elif arg is S.Infinity:
1419
+ return S.Infinity
1420
+ elif arg is S.NegativeInfinity:
1421
+ return S.Infinity
1422
+ elif arg.is_zero:
1423
+ return pi*I / 2
1424
+ elif arg is S.One:
1425
+ return S.Zero
1426
+ elif arg is S.NegativeOne:
1427
+ return pi*I
1428
+
1429
+ if arg.is_number:
1430
+ cst_table = _acosh_table()
1431
+
1432
+ if arg in cst_table:
1433
+ if arg.is_extended_real:
1434
+ return cst_table[arg]*I
1435
+ return cst_table[arg]
1436
+
1437
+ if arg is S.ComplexInfinity:
1438
+ return S.ComplexInfinity
1439
+ if arg == I*S.Infinity:
1440
+ return S.Infinity + I*pi/2
1441
+ if arg == -I*S.Infinity:
1442
+ return S.Infinity - I*pi/2
1443
+
1444
+ if arg.is_zero:
1445
+ return pi*I*S.Half
1446
+
1447
+ if isinstance(arg, cosh) and arg.args[0].is_number:
1448
+ z = arg.args[0]
1449
+ if z.is_real:
1450
+ return Abs(z)
1451
+ r, i = match_real_imag(z)
1452
+ if r is not None and i is not None:
1453
+ f = floor(i/pi)
1454
+ m = z - I*pi*f
1455
+ even = f.is_even
1456
+ if even is True:
1457
+ if r.is_nonnegative:
1458
+ return m
1459
+ elif r.is_negative:
1460
+ return -m
1461
+ elif even is False:
1462
+ m -= I*pi
1463
+ if r.is_nonpositive:
1464
+ return -m
1465
+ elif r.is_positive:
1466
+ return m
1467
+
1468
+ @staticmethod
1469
+ @cacheit
1470
+ def taylor_term(n, x, *previous_terms):
1471
+ if n == 0:
1472
+ return I*pi/2
1473
+ elif n < 0 or n % 2 == 0:
1474
+ return S.Zero
1475
+ else:
1476
+ x = sympify(x)
1477
+ if len(previous_terms) >= 2 and n > 2:
1478
+ p = previous_terms[-2]
1479
+ return p * (n - 2)**2/(n*(n - 1)) * x**2
1480
+ else:
1481
+ k = (n - 1) // 2
1482
+ R = RisingFactorial(S.Half, k)
1483
+ F = factorial(k)
1484
+ return -R / F * I * x**n / n
1485
+
1486
+ def _eval_as_leading_term(self, x, logx, cdir):
1487
+ arg = self.args[0]
1488
+ x0 = arg.subs(x, 0).cancel()
1489
+ # Handling branch points
1490
+ if x0 in (-S.One, S.Zero, S.One, S.ComplexInfinity):
1491
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
1492
+
1493
+ if x0 is S.NaN:
1494
+ expr = self.func(arg.as_leading_term(x))
1495
+ if expr.is_finite:
1496
+ return expr
1497
+ else:
1498
+ return self
1499
+
1500
+ # Handling points lying on branch cuts (-oo, 1)
1501
+ if (x0 - 1).is_negative:
1502
+ ndir = arg.dir(x, cdir if cdir else 1)
1503
+ if im(ndir).is_negative:
1504
+ if (x0 + 1).is_negative:
1505
+ return self.func(x0) - 2*I*pi
1506
+ return -self.func(x0)
1507
+ elif not im(ndir).is_positive:
1508
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
1509
+ return self.func(x0)
1510
+
1511
+ def _eval_nseries(self, x, n, logx, cdir=0): # acosh
1512
+ arg = self.args[0]
1513
+ arg0 = arg.subs(x, 0)
1514
+
1515
+ # Handling branch points
1516
+ if arg0 in (S.One, S.NegativeOne):
1517
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
1518
+
1519
+ res = super()._eval_nseries(x, n=n, logx=logx)
1520
+ if arg0 is S.ComplexInfinity:
1521
+ return res
1522
+
1523
+ # Handling points lying on branch cuts (-oo, 1)
1524
+ if (arg0 - 1).is_negative:
1525
+ ndir = arg.dir(x, cdir if cdir else 1)
1526
+ if im(ndir).is_negative:
1527
+ if (arg0 + 1).is_negative:
1528
+ return res - 2*I*pi
1529
+ return -res
1530
+ elif not im(ndir).is_positive:
1531
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
1532
+ return res
1533
+
1534
+ def _eval_rewrite_as_log(self, x, **kwargs):
1535
+ return log(x + sqrt(x + 1) * sqrt(x - 1))
1536
+
1537
+ _eval_rewrite_as_tractable = _eval_rewrite_as_log
1538
+
1539
+ def _eval_rewrite_as_acos(self, x, **kwargs):
1540
+ return sqrt(x - 1)/sqrt(1 - x) * acos(x)
1541
+
1542
+ def _eval_rewrite_as_asin(self, x, **kwargs):
1543
+ return sqrt(x - 1)/sqrt(1 - x) * (pi/2 - asin(x))
1544
+
1545
+ def _eval_rewrite_as_asinh(self, x, **kwargs):
1546
+ return sqrt(x - 1)/sqrt(1 - x) * (pi/2 + I*asinh(I*x, evaluate=False))
1547
+
1548
+ def _eval_rewrite_as_atanh(self, x, **kwargs):
1549
+ sxm1 = sqrt(x - 1)
1550
+ s1mx = sqrt(1 - x)
1551
+ sx2m1 = sqrt(x**2 - 1)
1552
+ return (pi/2*sxm1/s1mx*(1 - x * sqrt(1/x**2)) +
1553
+ sxm1*sqrt(x + 1)/sx2m1 * atanh(sx2m1/x))
1554
+
1555
+ def inverse(self, argindex=1):
1556
+ """
1557
+ Returns the inverse of this function.
1558
+ """
1559
+ return cosh
1560
+
1561
+ def _eval_is_zero(self):
1562
+ if (self.args[0] - 1).is_zero:
1563
+ return True
1564
+
1565
+ def _eval_is_extended_real(self):
1566
+ return fuzzy_and([self.args[0].is_extended_real, (self.args[0] - 1).is_extended_nonnegative])
1567
+
1568
+ def _eval_is_finite(self):
1569
+ return self.args[0].is_finite
1570
+
1571
+
1572
+ class atanh(InverseHyperbolicFunction):
1573
+ """
1574
+ ``atanh(x)`` is the inverse hyperbolic tangent of ``x``.
1575
+
1576
+ The inverse hyperbolic tangent function.
1577
+
1578
+ Examples
1579
+ ========
1580
+
1581
+ >>> from sympy import atanh
1582
+ >>> from sympy.abc import x
1583
+ >>> atanh(x).diff(x)
1584
+ 1/(1 - x**2)
1585
+
1586
+ See Also
1587
+ ========
1588
+
1589
+ asinh, acosh, tanh
1590
+ """
1591
+
1592
+ def fdiff(self, argindex=1):
1593
+ if argindex == 1:
1594
+ return 1/(1 - self.args[0]**2)
1595
+ else:
1596
+ raise ArgumentIndexError(self, argindex)
1597
+
1598
+ @classmethod
1599
+ def eval(cls, arg):
1600
+ if arg.is_Number:
1601
+ if arg is S.NaN:
1602
+ return S.NaN
1603
+ elif arg.is_zero:
1604
+ return S.Zero
1605
+ elif arg is S.One:
1606
+ return S.Infinity
1607
+ elif arg is S.NegativeOne:
1608
+ return S.NegativeInfinity
1609
+ elif arg is S.Infinity:
1610
+ return -I * atan(arg)
1611
+ elif arg is S.NegativeInfinity:
1612
+ return I * atan(-arg)
1613
+ elif arg.is_negative:
1614
+ return -cls(-arg)
1615
+ else:
1616
+ if arg is S.ComplexInfinity:
1617
+ from sympy.calculus.accumulationbounds import AccumBounds
1618
+ return I*AccumBounds(-pi/2, pi/2)
1619
+
1620
+ i_coeff = _imaginary_unit_as_coefficient(arg)
1621
+
1622
+ if i_coeff is not None:
1623
+ return I * atan(i_coeff)
1624
+ else:
1625
+ if arg.could_extract_minus_sign():
1626
+ return -cls(-arg)
1627
+
1628
+ if arg.is_zero:
1629
+ return S.Zero
1630
+
1631
+ if isinstance(arg, tanh) and arg.args[0].is_number:
1632
+ z = arg.args[0]
1633
+ if z.is_real:
1634
+ return z
1635
+ r, i = match_real_imag(z)
1636
+ if r is not None and i is not None:
1637
+ f = floor(2*i/pi)
1638
+ even = f.is_even
1639
+ m = z - I*f*pi/2
1640
+ if even is True:
1641
+ return m
1642
+ elif even is False:
1643
+ return m - I*pi/2
1644
+
1645
+ @staticmethod
1646
+ @cacheit
1647
+ def taylor_term(n, x, *previous_terms):
1648
+ if n < 0 or n % 2 == 0:
1649
+ return S.Zero
1650
+ else:
1651
+ x = sympify(x)
1652
+ return x**n / n
1653
+
1654
+ def _eval_as_leading_term(self, x, logx, cdir):
1655
+ arg = self.args[0]
1656
+ x0 = arg.subs(x, 0).cancel()
1657
+ if x0.is_zero:
1658
+ return arg.as_leading_term(x)
1659
+ if x0 is S.NaN:
1660
+ expr = self.func(arg.as_leading_term(x))
1661
+ if expr.is_finite:
1662
+ return expr
1663
+ else:
1664
+ return self
1665
+
1666
+ # Handling branch points
1667
+ if x0 in (-S.One, S.One, S.ComplexInfinity):
1668
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
1669
+ # Handling points lying on branch cuts (-oo, -1] U [1, oo)
1670
+ if (1 - x0**2).is_negative:
1671
+ ndir = arg.dir(x, cdir if cdir else 1)
1672
+ if im(ndir).is_negative:
1673
+ if x0.is_negative:
1674
+ return self.func(x0) - I*pi
1675
+ elif im(ndir).is_positive:
1676
+ if x0.is_positive:
1677
+ return self.func(x0) + I*pi
1678
+ else:
1679
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
1680
+ return self.func(x0)
1681
+
1682
+ def _eval_nseries(self, x, n, logx, cdir=0): # atanh
1683
+ arg = self.args[0]
1684
+ arg0 = arg.subs(x, 0)
1685
+
1686
+ # Handling branch points
1687
+ if arg0 in (S.One, S.NegativeOne):
1688
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
1689
+
1690
+ res = super()._eval_nseries(x, n=n, logx=logx)
1691
+ if arg0 is S.ComplexInfinity:
1692
+ return res
1693
+
1694
+ # Handling points lying on branch cuts (-oo, -1] U [1, oo)
1695
+ if (1 - arg0**2).is_negative:
1696
+ ndir = arg.dir(x, cdir if cdir else 1)
1697
+ if im(ndir).is_negative:
1698
+ if arg0.is_negative:
1699
+ return res - I*pi
1700
+ elif im(ndir).is_positive:
1701
+ if arg0.is_positive:
1702
+ return res + I*pi
1703
+ else:
1704
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
1705
+ return res
1706
+
1707
+ def _eval_rewrite_as_log(self, x, **kwargs):
1708
+ return (log(1 + x) - log(1 - x)) / 2
1709
+
1710
+ _eval_rewrite_as_tractable = _eval_rewrite_as_log
1711
+
1712
+ def _eval_rewrite_as_asinh(self, x, **kwargs):
1713
+ f = sqrt(1/(x**2 - 1))
1714
+ return (pi*x/(2*sqrt(-x**2)) -
1715
+ sqrt(-x)*sqrt(1 - x**2)/sqrt(x)*f*asinh(f))
1716
+
1717
+ def _eval_is_zero(self):
1718
+ if self.args[0].is_zero:
1719
+ return True
1720
+
1721
+ def _eval_is_extended_real(self):
1722
+ return fuzzy_and([self.args[0].is_extended_real, (1 - self.args[0]).is_nonnegative, (self.args[0] + 1).is_nonnegative])
1723
+
1724
+ def _eval_is_finite(self):
1725
+ return fuzzy_not(fuzzy_or([(self.args[0] - 1).is_zero, (self.args[0] + 1).is_zero]))
1726
+
1727
+ def _eval_is_imaginary(self):
1728
+ return self.args[0].is_imaginary
1729
+
1730
+ def inverse(self, argindex=1):
1731
+ """
1732
+ Returns the inverse of this function.
1733
+ """
1734
+ return tanh
1735
+
1736
+
1737
+ class acoth(InverseHyperbolicFunction):
1738
+ """
1739
+ ``acoth(x)`` is the inverse hyperbolic cotangent of ``x``.
1740
+
1741
+ The inverse hyperbolic cotangent function.
1742
+
1743
+ Examples
1744
+ ========
1745
+
1746
+ >>> from sympy import acoth
1747
+ >>> from sympy.abc import x
1748
+ >>> acoth(x).diff(x)
1749
+ 1/(1 - x**2)
1750
+
1751
+ See Also
1752
+ ========
1753
+
1754
+ asinh, acosh, coth
1755
+ """
1756
+
1757
+ def fdiff(self, argindex=1):
1758
+ if argindex == 1:
1759
+ return 1/(1 - self.args[0]**2)
1760
+ else:
1761
+ raise ArgumentIndexError(self, argindex)
1762
+
1763
+ @classmethod
1764
+ def eval(cls, arg):
1765
+ if arg.is_Number:
1766
+ if arg is S.NaN:
1767
+ return S.NaN
1768
+ elif arg is S.Infinity:
1769
+ return S.Zero
1770
+ elif arg is S.NegativeInfinity:
1771
+ return S.Zero
1772
+ elif arg.is_zero:
1773
+ return pi*I / 2
1774
+ elif arg is S.One:
1775
+ return S.Infinity
1776
+ elif arg is S.NegativeOne:
1777
+ return S.NegativeInfinity
1778
+ elif arg.is_negative:
1779
+ return -cls(-arg)
1780
+ else:
1781
+ if arg is S.ComplexInfinity:
1782
+ return S.Zero
1783
+
1784
+ i_coeff = _imaginary_unit_as_coefficient(arg)
1785
+
1786
+ if i_coeff is not None:
1787
+ return -I * acot(i_coeff)
1788
+ else:
1789
+ if arg.could_extract_minus_sign():
1790
+ return -cls(-arg)
1791
+
1792
+ if arg.is_zero:
1793
+ return pi*I*S.Half
1794
+
1795
+ @staticmethod
1796
+ @cacheit
1797
+ def taylor_term(n, x, *previous_terms):
1798
+ if n == 0:
1799
+ return -I*pi/2
1800
+ elif n < 0 or n % 2 == 0:
1801
+ return S.Zero
1802
+ else:
1803
+ x = sympify(x)
1804
+ return x**n / n
1805
+
1806
+ def _eval_as_leading_term(self, x, logx, cdir):
1807
+ arg = self.args[0]
1808
+ x0 = arg.subs(x, 0).cancel()
1809
+ if x0 is S.ComplexInfinity:
1810
+ return (1/arg).as_leading_term(x)
1811
+ if x0 is S.NaN:
1812
+ expr = self.func(arg.as_leading_term(x))
1813
+ if expr.is_finite:
1814
+ return expr
1815
+ else:
1816
+ return self
1817
+
1818
+ # Handling branch points
1819
+ if x0 in (-S.One, S.One, S.Zero):
1820
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
1821
+ # Handling points lying on branch cuts [-1, 1]
1822
+ if x0.is_real and (1 - x0**2).is_positive:
1823
+ ndir = arg.dir(x, cdir if cdir else 1)
1824
+ if im(ndir).is_negative:
1825
+ if x0.is_positive:
1826
+ return self.func(x0) + I*pi
1827
+ elif im(ndir).is_positive:
1828
+ if x0.is_negative:
1829
+ return self.func(x0) - I*pi
1830
+ else:
1831
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
1832
+ return self.func(x0)
1833
+
1834
+ def _eval_nseries(self, x, n, logx, cdir=0): # acoth
1835
+ arg = self.args[0]
1836
+ arg0 = arg.subs(x, 0)
1837
+
1838
+ # Handling branch points
1839
+ if arg0 in (S.One, S.NegativeOne):
1840
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
1841
+
1842
+ res = super()._eval_nseries(x, n=n, logx=logx)
1843
+ if arg0 is S.ComplexInfinity:
1844
+ return res
1845
+
1846
+ # Handling points lying on branch cuts [-1, 1]
1847
+ if arg0.is_real and (1 - arg0**2).is_positive:
1848
+ ndir = arg.dir(x, cdir if cdir else 1)
1849
+ if im(ndir).is_negative:
1850
+ if arg0.is_positive:
1851
+ return res + I*pi
1852
+ elif im(ndir).is_positive:
1853
+ if arg0.is_negative:
1854
+ return res - I*pi
1855
+ else:
1856
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
1857
+ return res
1858
+
1859
+ def _eval_rewrite_as_log(self, x, **kwargs):
1860
+ return (log(1 + 1/x) - log(1 - 1/x)) / 2
1861
+
1862
+ _eval_rewrite_as_tractable = _eval_rewrite_as_log
1863
+
1864
+ def _eval_rewrite_as_atanh(self, x, **kwargs):
1865
+ return atanh(1/x)
1866
+
1867
+ def _eval_rewrite_as_asinh(self, x, **kwargs):
1868
+ return (pi*I/2*(sqrt((x - 1)/x)*sqrt(x/(x - 1)) - sqrt(1 + 1/x)*sqrt(x/(x + 1))) +
1869
+ x*sqrt(1/x**2)*asinh(sqrt(1/(x**2 - 1))))
1870
+
1871
+ def inverse(self, argindex=1):
1872
+ """
1873
+ Returns the inverse of this function.
1874
+ """
1875
+ return coth
1876
+
1877
+ def _eval_is_extended_real(self):
1878
+ return fuzzy_and([self.args[0].is_extended_real, fuzzy_or([(self.args[0] - 1).is_extended_nonnegative, (self.args[0] + 1).is_extended_nonpositive])])
1879
+
1880
+ def _eval_is_finite(self):
1881
+ return fuzzy_not(fuzzy_or([(self.args[0] - 1).is_zero, (self.args[0] + 1).is_zero]))
1882
+
1883
+
1884
+ class asech(InverseHyperbolicFunction):
1885
+ """
1886
+ ``asech(x)`` is the inverse hyperbolic secant of ``x``.
1887
+
1888
+ The inverse hyperbolic secant function.
1889
+
1890
+ Examples
1891
+ ========
1892
+
1893
+ >>> from sympy import asech, sqrt, S
1894
+ >>> from sympy.abc import x
1895
+ >>> asech(x).diff(x)
1896
+ -1/(x*sqrt(1 - x**2))
1897
+ >>> asech(1).diff(x)
1898
+ 0
1899
+ >>> asech(1)
1900
+ 0
1901
+ >>> asech(S(2))
1902
+ I*pi/3
1903
+ >>> asech(-sqrt(2))
1904
+ 3*I*pi/4
1905
+ >>> asech((sqrt(6) - sqrt(2)))
1906
+ I*pi/12
1907
+
1908
+ See Also
1909
+ ========
1910
+
1911
+ asinh, atanh, cosh, acoth
1912
+
1913
+ References
1914
+ ==========
1915
+
1916
+ .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function
1917
+ .. [2] https://dlmf.nist.gov/4.37
1918
+ .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcSech/
1919
+
1920
+ """
1921
+
1922
+ def fdiff(self, argindex=1):
1923
+ if argindex == 1:
1924
+ z = self.args[0]
1925
+ return -1/(z*sqrt(1 - z**2))
1926
+ else:
1927
+ raise ArgumentIndexError(self, argindex)
1928
+
1929
+ @classmethod
1930
+ def eval(cls, arg):
1931
+ if arg.is_Number:
1932
+ if arg is S.NaN:
1933
+ return S.NaN
1934
+ elif arg is S.Infinity:
1935
+ return pi*I / 2
1936
+ elif arg is S.NegativeInfinity:
1937
+ return pi*I / 2
1938
+ elif arg.is_zero:
1939
+ return S.Infinity
1940
+ elif arg is S.One:
1941
+ return S.Zero
1942
+ elif arg is S.NegativeOne:
1943
+ return pi*I
1944
+
1945
+ if arg.is_number:
1946
+ cst_table = _asech_table()
1947
+
1948
+ if arg in cst_table:
1949
+ if arg.is_extended_real:
1950
+ return cst_table[arg]*I
1951
+ return cst_table[arg]
1952
+
1953
+ if arg is S.ComplexInfinity:
1954
+ from sympy.calculus.accumulationbounds import AccumBounds
1955
+ return I*AccumBounds(-pi/2, pi/2)
1956
+
1957
+ if arg.is_zero:
1958
+ return S.Infinity
1959
+
1960
+ @staticmethod
1961
+ @cacheit
1962
+ def taylor_term(n, x, *previous_terms):
1963
+ if n == 0:
1964
+ return log(2 / x)
1965
+ elif n < 0 or n % 2 == 1:
1966
+ return S.Zero
1967
+ else:
1968
+ x = sympify(x)
1969
+ if len(previous_terms) > 2 and n > 2:
1970
+ p = previous_terms[-2]
1971
+ return p * ((n - 1)*(n-2)) * x**2/(4 * (n//2)**2)
1972
+ else:
1973
+ k = n // 2
1974
+ R = RisingFactorial(S.Half, k) * n
1975
+ F = factorial(k) * n // 2 * n // 2
1976
+ return -1 * R / F * x**n / 4
1977
+
1978
+ def _eval_as_leading_term(self, x, logx, cdir):
1979
+ arg = self.args[0]
1980
+ x0 = arg.subs(x, 0).cancel()
1981
+ # Handling branch points
1982
+ if x0 in (-S.One, S.Zero, S.One, S.ComplexInfinity):
1983
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
1984
+
1985
+ if x0 is S.NaN:
1986
+ expr = self.func(arg.as_leading_term(x))
1987
+ if expr.is_finite:
1988
+ return expr
1989
+ else:
1990
+ return self
1991
+
1992
+ # Handling points lying on branch cuts (-oo, 0] U (1, oo)
1993
+ if x0.is_negative or (1 - x0).is_negative:
1994
+ ndir = arg.dir(x, cdir if cdir else 1)
1995
+ if im(ndir).is_positive:
1996
+ if x0.is_positive or (x0 + 1).is_negative:
1997
+ return -self.func(x0)
1998
+ return self.func(x0) - 2*I*pi
1999
+ elif not im(ndir).is_negative:
2000
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
2001
+ return self.func(x0)
2002
+
2003
+ def _eval_nseries(self, x, n, logx, cdir=0): # asech
2004
+ from sympy.series.order import O
2005
+ arg = self.args[0]
2006
+ arg0 = arg.subs(x, 0)
2007
+
2008
+ # Handling branch points
2009
+ if arg0 is S.One:
2010
+ t = Dummy('t', positive=True)
2011
+ ser = asech(S.One - t**2).rewrite(log).nseries(t, 0, 2*n)
2012
+ arg1 = S.One - self.args[0]
2013
+ f = arg1.as_leading_term(x)
2014
+ g = (arg1 - f)/ f
2015
+ if not g.is_meromorphic(x, 0): # cannot be expanded
2016
+ return O(1) if n == 0 else O(sqrt(x))
2017
+ res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx)
2018
+ res = (res1.removeO()*sqrt(f)).expand()
2019
+ return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x)
2020
+
2021
+ if arg0 is S.NegativeOne:
2022
+ t = Dummy('t', positive=True)
2023
+ ser = asech(S.NegativeOne + t**2).rewrite(log).nseries(t, 0, 2*n)
2024
+ arg1 = S.One + self.args[0]
2025
+ f = arg1.as_leading_term(x)
2026
+ g = (arg1 - f)/ f
2027
+ if not g.is_meromorphic(x, 0): # cannot be expanded
2028
+ return O(1) if n == 0 else I*pi + O(sqrt(x))
2029
+ res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx)
2030
+ res = (res1.removeO()*sqrt(f)).expand()
2031
+ return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x)
2032
+
2033
+ res = super()._eval_nseries(x, n=n, logx=logx)
2034
+ if arg0 is S.ComplexInfinity:
2035
+ return res
2036
+
2037
+ # Handling points lying on branch cuts (-oo, 0] U (1, oo)
2038
+ if arg0.is_negative or (1 - arg0).is_negative:
2039
+ ndir = arg.dir(x, cdir if cdir else 1)
2040
+ if im(ndir).is_positive:
2041
+ if arg0.is_positive or (arg0 + 1).is_negative:
2042
+ return -res
2043
+ return res - 2*I*pi
2044
+ elif not im(ndir).is_negative:
2045
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
2046
+ return res
2047
+
2048
+ def inverse(self, argindex=1):
2049
+ """
2050
+ Returns the inverse of this function.
2051
+ """
2052
+ return sech
2053
+
2054
+ def _eval_rewrite_as_log(self, arg, **kwargs):
2055
+ return log(1/arg + sqrt(1/arg - 1) * sqrt(1/arg + 1))
2056
+
2057
+ _eval_rewrite_as_tractable = _eval_rewrite_as_log
2058
+
2059
+ def _eval_rewrite_as_acosh(self, arg, **kwargs):
2060
+ return acosh(1/arg)
2061
+
2062
+ def _eval_rewrite_as_asinh(self, arg, **kwargs):
2063
+ return sqrt(1/arg - 1)/sqrt(1 - 1/arg)*(I*asinh(I/arg, evaluate=False)
2064
+ + pi*S.Half)
2065
+
2066
+ def _eval_rewrite_as_atanh(self, x, **kwargs):
2067
+ return (I*pi*(1 - sqrt(x)*sqrt(1/x) - I/2*sqrt(-x)/sqrt(x) - I/2*sqrt(x**2)/sqrt(-x**2))
2068
+ + sqrt(1/(x + 1))*sqrt(x + 1)*atanh(sqrt(1 - x**2)))
2069
+
2070
+ def _eval_rewrite_as_acsch(self, x, **kwargs):
2071
+ return sqrt(1/x - 1)/sqrt(1 - 1/x)*(pi/2 - I*acsch(I*x, evaluate=False))
2072
+
2073
+ def _eval_is_extended_real(self):
2074
+ return fuzzy_and([self.args[0].is_extended_real, self.args[0].is_nonnegative, (1 - self.args[0]).is_nonnegative])
2075
+
2076
+ def _eval_is_finite(self):
2077
+ return fuzzy_not(self.args[0].is_zero)
2078
+
2079
+
2080
+ class acsch(InverseHyperbolicFunction):
2081
+ """
2082
+ ``acsch(x)`` is the inverse hyperbolic cosecant of ``x``.
2083
+
2084
+ The inverse hyperbolic cosecant function.
2085
+
2086
+ Examples
2087
+ ========
2088
+
2089
+ >>> from sympy import acsch, sqrt, I
2090
+ >>> from sympy.abc import x
2091
+ >>> acsch(x).diff(x)
2092
+ -1/(x**2*sqrt(1 + x**(-2)))
2093
+ >>> acsch(1).diff(x)
2094
+ 0
2095
+ >>> acsch(1)
2096
+ log(1 + sqrt(2))
2097
+ >>> acsch(I)
2098
+ -I*pi/2
2099
+ >>> acsch(-2*I)
2100
+ I*pi/6
2101
+ >>> acsch(I*(sqrt(6) - sqrt(2)))
2102
+ -5*I*pi/12
2103
+
2104
+ See Also
2105
+ ========
2106
+
2107
+ asinh
2108
+
2109
+ References
2110
+ ==========
2111
+
2112
+ .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function
2113
+ .. [2] https://dlmf.nist.gov/4.37
2114
+ .. [3] https://functions.wolfram.com/ElementaryFunctions/ArcCsch/
2115
+
2116
+ """
2117
+
2118
+ def fdiff(self, argindex=1):
2119
+ if argindex == 1:
2120
+ z = self.args[0]
2121
+ return -1/(z**2*sqrt(1 + 1/z**2))
2122
+ else:
2123
+ raise ArgumentIndexError(self, argindex)
2124
+
2125
+ @classmethod
2126
+ def eval(cls, arg):
2127
+ if arg.is_Number:
2128
+ if arg is S.NaN:
2129
+ return S.NaN
2130
+ elif arg is S.Infinity:
2131
+ return S.Zero
2132
+ elif arg is S.NegativeInfinity:
2133
+ return S.Zero
2134
+ elif arg.is_zero:
2135
+ return S.ComplexInfinity
2136
+ elif arg is S.One:
2137
+ return log(1 + sqrt(2))
2138
+ elif arg is S.NegativeOne:
2139
+ return - log(1 + sqrt(2))
2140
+
2141
+ if arg.is_number:
2142
+ cst_table = _acsch_table()
2143
+
2144
+ if arg in cst_table:
2145
+ return cst_table[arg]*I
2146
+
2147
+ if arg is S.ComplexInfinity:
2148
+ return S.Zero
2149
+
2150
+ if arg.is_infinite:
2151
+ return S.Zero
2152
+
2153
+ if arg.is_zero:
2154
+ return S.ComplexInfinity
2155
+
2156
+ if arg.could_extract_minus_sign():
2157
+ return -cls(-arg)
2158
+
2159
+ @staticmethod
2160
+ @cacheit
2161
+ def taylor_term(n, x, *previous_terms):
2162
+ if n == 0:
2163
+ return log(2 / x)
2164
+ elif n < 0 or n % 2 == 1:
2165
+ return S.Zero
2166
+ else:
2167
+ x = sympify(x)
2168
+ if len(previous_terms) > 2 and n > 2:
2169
+ p = previous_terms[-2]
2170
+ return -p * ((n - 1)*(n-2)) * x**2/(4 * (n//2)**2)
2171
+ else:
2172
+ k = n // 2
2173
+ R = RisingFactorial(S.Half, k) * n
2174
+ F = factorial(k) * n // 2 * n // 2
2175
+ return S.NegativeOne**(k +1) * R / F * x**n / 4
2176
+
2177
+ def _eval_as_leading_term(self, x, logx, cdir):
2178
+ arg = self.args[0]
2179
+ x0 = arg.subs(x, 0).cancel()
2180
+ # Handling branch points
2181
+ if x0 in (-I, I, S.Zero):
2182
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
2183
+
2184
+ if x0 is S.NaN:
2185
+ expr = self.func(arg.as_leading_term(x))
2186
+ if expr.is_finite:
2187
+ return expr
2188
+ else:
2189
+ return self
2190
+
2191
+ if x0 is S.ComplexInfinity:
2192
+ return (1/arg).as_leading_term(x)
2193
+ # Handling points lying on branch cuts (-I, I)
2194
+ if x0.is_imaginary and (1 + x0**2).is_positive:
2195
+ ndir = arg.dir(x, cdir if cdir else 1)
2196
+ if re(ndir).is_positive:
2197
+ if im(x0).is_positive:
2198
+ return -self.func(x0) - I*pi
2199
+ elif re(ndir).is_negative:
2200
+ if im(x0).is_negative:
2201
+ return -self.func(x0) + I*pi
2202
+ else:
2203
+ return self.rewrite(log)._eval_as_leading_term(x, logx=logx, cdir=cdir)
2204
+ return self.func(x0)
2205
+
2206
+ def _eval_nseries(self, x, n, logx, cdir=0): # acsch
2207
+ from sympy.series.order import O
2208
+ arg = self.args[0]
2209
+ arg0 = arg.subs(x, 0)
2210
+
2211
+ # Handling branch points
2212
+ if arg0 is I:
2213
+ t = Dummy('t', positive=True)
2214
+ ser = acsch(I + t**2).rewrite(log).nseries(t, 0, 2*n)
2215
+ arg1 = -I + self.args[0]
2216
+ f = arg1.as_leading_term(x)
2217
+ g = (arg1 - f)/ f
2218
+ if not g.is_meromorphic(x, 0): # cannot be expanded
2219
+ return O(1) if n == 0 else -I*pi/2 + O(sqrt(x))
2220
+ res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx)
2221
+ res = (res1.removeO()*sqrt(f)).expand()
2222
+ res = ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x)
2223
+ return res
2224
+
2225
+ if arg0 == S.NegativeOne*I:
2226
+ t = Dummy('t', positive=True)
2227
+ ser = acsch(-I + t**2).rewrite(log).nseries(t, 0, 2*n)
2228
+ arg1 = I + self.args[0]
2229
+ f = arg1.as_leading_term(x)
2230
+ g = (arg1 - f)/ f
2231
+ if not g.is_meromorphic(x, 0): # cannot be expanded
2232
+ return O(1) if n == 0 else I*pi/2 + O(sqrt(x))
2233
+ res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx)
2234
+ res = (res1.removeO()*sqrt(f)).expand()
2235
+ return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x)
2236
+
2237
+ res = super()._eval_nseries(x, n=n, logx=logx)
2238
+ if arg0 is S.ComplexInfinity:
2239
+ return res
2240
+
2241
+ # Handling points lying on branch cuts (-I, I)
2242
+ if arg0.is_imaginary and (1 + arg0**2).is_positive:
2243
+ ndir = self.args[0].dir(x, cdir if cdir else 1)
2244
+ if re(ndir).is_positive:
2245
+ if im(arg0).is_positive:
2246
+ return -res - I*pi
2247
+ elif re(ndir).is_negative:
2248
+ if im(arg0).is_negative:
2249
+ return -res + I*pi
2250
+ else:
2251
+ return self.rewrite(log)._eval_nseries(x, n, logx=logx, cdir=cdir)
2252
+ return res
2253
+
2254
+ def inverse(self, argindex=1):
2255
+ """
2256
+ Returns the inverse of this function.
2257
+ """
2258
+ return csch
2259
+
2260
+ def _eval_rewrite_as_log(self, arg, **kwargs):
2261
+ return log(1/arg + sqrt(1/arg**2 + 1))
2262
+
2263
+ _eval_rewrite_as_tractable = _eval_rewrite_as_log
2264
+
2265
+ def _eval_rewrite_as_asinh(self, arg, **kwargs):
2266
+ return asinh(1/arg)
2267
+
2268
+ def _eval_rewrite_as_acosh(self, arg, **kwargs):
2269
+ return I*(sqrt(1 - I/arg)/sqrt(I/arg - 1)*
2270
+ acosh(I/arg, evaluate=False) - pi*S.Half)
2271
+
2272
+ def _eval_rewrite_as_atanh(self, arg, **kwargs):
2273
+ arg2 = arg**2
2274
+ arg2p1 = arg2 + 1
2275
+ return sqrt(-arg2)/arg*(pi*S.Half -
2276
+ sqrt(-arg2p1**2)/arg2p1*atanh(sqrt(arg2p1)))
2277
+
2278
+ def _eval_is_zero(self):
2279
+ return self.args[0].is_infinite
2280
+
2281
+ def _eval_is_extended_real(self):
2282
+ return self.args[0].is_extended_real
2283
+
2284
+ def _eval_is_finite(self):
2285
+ return fuzzy_not(self.args[0].is_zero)
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/integers.py ADDED
@@ -0,0 +1,710 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from sympy.core.basic import Basic
4
+ from sympy.core.expr import Expr
5
+
6
+ from sympy.core import Add, S
7
+ from sympy.core.evalf import get_integer_part, PrecisionExhausted
8
+ from sympy.core.function import DefinedFunction
9
+ from sympy.core.logic import fuzzy_or, fuzzy_and
10
+ from sympy.core.numbers import Integer, int_valued
11
+ from sympy.core.relational import Gt, Lt, Ge, Le, Relational, is_eq, is_le, is_lt
12
+ from sympy.core.sympify import _sympify
13
+ from sympy.functions.elementary.complexes import im, re
14
+ from sympy.multipledispatch import dispatch
15
+
16
+ ###############################################################################
17
+ ######################### FLOOR and CEILING FUNCTIONS #########################
18
+ ###############################################################################
19
+
20
+
21
+ class RoundFunction(DefinedFunction):
22
+ """Abstract base class for rounding functions."""
23
+
24
+ args: tuple[Expr]
25
+
26
+ @classmethod
27
+ def eval(cls, arg):
28
+ if (v := cls._eval_number(arg)) is not None:
29
+ return v
30
+ if (v := cls._eval_const_number(arg)) is not None:
31
+ return v
32
+
33
+ if arg.is_integer or arg.is_finite is False:
34
+ return arg
35
+ if arg.is_imaginary or (S.ImaginaryUnit*arg).is_real:
36
+ i = im(arg)
37
+ if not i.has(S.ImaginaryUnit):
38
+ return cls(i)*S.ImaginaryUnit
39
+ return cls(arg, evaluate=False)
40
+
41
+ # Integral, numerical, symbolic part
42
+ ipart = npart = spart = S.Zero
43
+
44
+ # Extract integral (or complex integral) terms
45
+ intof = lambda x: int(x) if int_valued(x) else (
46
+ x if x.is_integer else None)
47
+ for t in Add.make_args(arg):
48
+ if t.is_imaginary and (i := intof(im(t))) is not None:
49
+ ipart += i*S.ImaginaryUnit
50
+ elif (i := intof(t)) is not None:
51
+ ipart += i
52
+ elif t.is_number:
53
+ npart += t
54
+ else:
55
+ spart += t
56
+
57
+ if not (npart or spart):
58
+ return ipart
59
+
60
+ # Evaluate npart numerically if independent of spart
61
+ if npart and (
62
+ not spart or
63
+ npart.is_real and (spart.is_imaginary or (S.ImaginaryUnit*spart).is_real) or
64
+ npart.is_imaginary and spart.is_real):
65
+ try:
66
+ r, i = get_integer_part(
67
+ npart, cls._dir, {}, return_ints=True)
68
+ ipart += Integer(r) + Integer(i)*S.ImaginaryUnit
69
+ npart = S.Zero
70
+ except (PrecisionExhausted, NotImplementedError):
71
+ pass
72
+
73
+ spart += npart
74
+ if not spart:
75
+ return ipart
76
+ elif spart.is_imaginary or (S.ImaginaryUnit*spart).is_real:
77
+ return ipart + cls(im(spart), evaluate=False)*S.ImaginaryUnit
78
+ elif isinstance(spart, (floor, ceiling)):
79
+ return ipart + spart
80
+ else:
81
+ return ipart + cls(spart, evaluate=False)
82
+
83
+ @classmethod
84
+ def _eval_number(cls, arg):
85
+ raise NotImplementedError()
86
+
87
+ def _eval_is_finite(self):
88
+ return self.args[0].is_finite
89
+
90
+ def _eval_is_real(self):
91
+ return self.args[0].is_real
92
+
93
+ def _eval_is_integer(self):
94
+ return self.args[0].is_real
95
+
96
+
97
+ class floor(RoundFunction):
98
+ """
99
+ Floor is a univariate function which returns the largest integer
100
+ value not greater than its argument. This implementation
101
+ generalizes floor to complex numbers by taking the floor of the
102
+ real and imaginary parts separately.
103
+
104
+ Examples
105
+ ========
106
+
107
+ >>> from sympy import floor, E, I, S, Float, Rational
108
+ >>> floor(17)
109
+ 17
110
+ >>> floor(Rational(23, 10))
111
+ 2
112
+ >>> floor(2*E)
113
+ 5
114
+ >>> floor(-Float(0.567))
115
+ -1
116
+ >>> floor(-I/2)
117
+ -I
118
+ >>> floor(S(5)/2 + 5*I/2)
119
+ 2 + 2*I
120
+
121
+ See Also
122
+ ========
123
+
124
+ sympy.functions.elementary.integers.ceiling
125
+
126
+ References
127
+ ==========
128
+
129
+ .. [1] "Concrete mathematics" by Graham, pp. 87
130
+ .. [2] https://mathworld.wolfram.com/FloorFunction.html
131
+
132
+ """
133
+ _dir = -1
134
+
135
+ @classmethod
136
+ def _eval_number(cls, arg):
137
+ if arg.is_Number:
138
+ return arg.floor()
139
+ if any(isinstance(i, j)
140
+ for i in (arg, -arg) for j in (floor, ceiling)):
141
+ return arg
142
+ if arg.is_NumberSymbol:
143
+ return arg.approximation_interval(Integer)[0]
144
+
145
+ @classmethod
146
+ def _eval_const_number(cls, arg):
147
+ if arg.is_real:
148
+ if arg.is_zero:
149
+ return S.Zero
150
+ if arg.is_positive:
151
+ num, den = arg.as_numer_denom()
152
+ s = den.is_negative
153
+ if s is None:
154
+ return None
155
+ if s:
156
+ num, den = -num, -den
157
+ # 0 <= num/den < 1 -> 0
158
+ if is_lt(num, den):
159
+ return S.Zero
160
+ # 1 <= num/den < 2 -> 1
161
+ if fuzzy_and([is_le(den, num), is_lt(num, 2*den)]):
162
+ return S.One
163
+ if arg.is_negative:
164
+ num, den = arg.as_numer_denom()
165
+ s = den.is_negative
166
+ if s is None:
167
+ return None
168
+ if s:
169
+ num, den = -num, -den
170
+ # -1 <= num/den < 0 -> -1
171
+ if is_le(-den, num):
172
+ return S.NegativeOne
173
+ # -2 <= num/den < -1 -> -2
174
+ if fuzzy_and([is_le(-2*den, num), is_lt(num, -den)]):
175
+ return Integer(-2)
176
+
177
+ def _eval_as_leading_term(self, x, logx, cdir):
178
+ from sympy.calculus.accumulationbounds import AccumBounds
179
+ arg = self.args[0]
180
+ arg0 = arg.subs(x, 0)
181
+ r = self.subs(x, 0)
182
+ if arg0 is S.NaN or isinstance(arg0, AccumBounds):
183
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
184
+ r = floor(arg0)
185
+ if arg0.is_finite:
186
+ if arg0 == r:
187
+ ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
188
+ if ndir.is_negative:
189
+ return r - 1
190
+ elif ndir.is_positive:
191
+ return r
192
+ else:
193
+ raise NotImplementedError("Not sure of sign of %s" % ndir)
194
+ else:
195
+ return r
196
+ return arg.as_leading_term(x, logx=logx, cdir=cdir)
197
+
198
+ def _eval_nseries(self, x, n, logx, cdir=0):
199
+ arg = self.args[0]
200
+ arg0 = arg.subs(x, 0)
201
+ r = self.subs(x, 0)
202
+ if arg0 is S.NaN:
203
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
204
+ r = floor(arg0)
205
+ if arg0.is_infinite:
206
+ from sympy.calculus.accumulationbounds import AccumBounds
207
+ from sympy.series.order import Order
208
+ s = arg._eval_nseries(x, n, logx, cdir)
209
+ o = Order(1, (x, 0)) if n <= 0 else AccumBounds(-1, 0)
210
+ return s + o
211
+ if arg0 == r:
212
+ ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
213
+ if ndir.is_negative:
214
+ return r - 1
215
+ elif ndir.is_positive:
216
+ return r
217
+ else:
218
+ raise NotImplementedError("Not sure of sign of %s" % ndir)
219
+ else:
220
+ return r
221
+
222
+ def _eval_is_negative(self):
223
+ return self.args[0].is_negative
224
+
225
+ def _eval_is_nonnegative(self):
226
+ return self.args[0].is_nonnegative
227
+
228
+ def _eval_rewrite_as_ceiling(self, arg, **kwargs):
229
+ return -ceiling(-arg)
230
+
231
+ def _eval_rewrite_as_frac(self, arg, **kwargs):
232
+ return arg - frac(arg)
233
+
234
+ def __le__(self, other):
235
+ other = S(other)
236
+ if self.args[0].is_real:
237
+ if other.is_integer:
238
+ return self.args[0] < other + 1
239
+ if other.is_number and other.is_real:
240
+ return self.args[0] < ceiling(other)
241
+ if self.args[0] == other and other.is_real:
242
+ return S.true
243
+ if other is S.Infinity and self.is_finite:
244
+ return S.true
245
+
246
+ return Le(self, other, evaluate=False)
247
+
248
+ def __ge__(self, other):
249
+ other = S(other)
250
+ if self.args[0].is_real:
251
+ if other.is_integer:
252
+ return self.args[0] >= other
253
+ if other.is_number and other.is_real:
254
+ return self.args[0] >= ceiling(other)
255
+ if self.args[0] == other and other.is_real and other.is_noninteger:
256
+ return S.false
257
+ if other is S.NegativeInfinity and self.is_finite:
258
+ return S.true
259
+
260
+ return Ge(self, other, evaluate=False)
261
+
262
+ def __gt__(self, other):
263
+ other = S(other)
264
+ if self.args[0].is_real:
265
+ if other.is_integer:
266
+ return self.args[0] >= other + 1
267
+ if other.is_number and other.is_real:
268
+ return self.args[0] >= ceiling(other)
269
+ if self.args[0] == other and other.is_real:
270
+ return S.false
271
+ if other is S.NegativeInfinity and self.is_finite:
272
+ return S.true
273
+
274
+ return Gt(self, other, evaluate=False)
275
+
276
+ def __lt__(self, other):
277
+ other = S(other)
278
+ if self.args[0].is_real:
279
+ if other.is_integer:
280
+ return self.args[0] < other
281
+ if other.is_number and other.is_real:
282
+ return self.args[0] < ceiling(other)
283
+ if self.args[0] == other and other.is_real and other.is_noninteger:
284
+ return S.true
285
+ if other is S.Infinity and self.is_finite:
286
+ return S.true
287
+
288
+ return Lt(self, other, evaluate=False)
289
+
290
+
291
+ @dispatch(floor, Expr)
292
+ def _eval_is_eq(lhs, rhs): # noqa:F811
293
+ return is_eq(lhs.rewrite(ceiling), rhs) or \
294
+ is_eq(lhs.rewrite(frac),rhs)
295
+
296
+
297
+ class ceiling(RoundFunction):
298
+ """
299
+ Ceiling is a univariate function which returns the smallest integer
300
+ value not less than its argument. This implementation
301
+ generalizes ceiling to complex numbers by taking the ceiling of the
302
+ real and imaginary parts separately.
303
+
304
+ Examples
305
+ ========
306
+
307
+ >>> from sympy import ceiling, E, I, S, Float, Rational
308
+ >>> ceiling(17)
309
+ 17
310
+ >>> ceiling(Rational(23, 10))
311
+ 3
312
+ >>> ceiling(2*E)
313
+ 6
314
+ >>> ceiling(-Float(0.567))
315
+ 0
316
+ >>> ceiling(I/2)
317
+ I
318
+ >>> ceiling(S(5)/2 + 5*I/2)
319
+ 3 + 3*I
320
+
321
+ See Also
322
+ ========
323
+
324
+ sympy.functions.elementary.integers.floor
325
+
326
+ References
327
+ ==========
328
+
329
+ .. [1] "Concrete mathematics" by Graham, pp. 87
330
+ .. [2] https://mathworld.wolfram.com/CeilingFunction.html
331
+
332
+ """
333
+ _dir = 1
334
+
335
+ @classmethod
336
+ def _eval_number(cls, arg):
337
+ if arg.is_Number:
338
+ return arg.ceiling()
339
+ if any(isinstance(i, j)
340
+ for i in (arg, -arg) for j in (floor, ceiling)):
341
+ return arg
342
+ if arg.is_NumberSymbol:
343
+ return arg.approximation_interval(Integer)[1]
344
+
345
+ @classmethod
346
+ def _eval_const_number(cls, arg):
347
+ if arg.is_real:
348
+ if arg.is_zero:
349
+ return S.Zero
350
+ if arg.is_positive:
351
+ num, den = arg.as_numer_denom()
352
+ s = den.is_negative
353
+ if s is None:
354
+ return None
355
+ if s:
356
+ num, den = -num, -den
357
+ # 0 < num/den <= 1 -> 1
358
+ if is_le(num, den):
359
+ return S.One
360
+ # 1 < num/den <= 2 -> 2
361
+ if fuzzy_and([is_lt(den, num), is_le(num, 2*den)]):
362
+ return Integer(2)
363
+ if arg.is_negative:
364
+ num, den = arg.as_numer_denom()
365
+ s = den.is_negative
366
+ if s is None:
367
+ return None
368
+ if s:
369
+ num, den = -num, -den
370
+ # -1 < num/den <= 0 -> 0
371
+ if is_lt(-den, num):
372
+ return S.Zero
373
+ # -2 < num/den <= -1 -> -1
374
+ if fuzzy_and([is_lt(-2*den, num), is_le(num, -den)]):
375
+ return S.NegativeOne
376
+
377
+ def _eval_as_leading_term(self, x, logx, cdir):
378
+ from sympy.calculus.accumulationbounds import AccumBounds
379
+ arg = self.args[0]
380
+ arg0 = arg.subs(x, 0)
381
+ r = self.subs(x, 0)
382
+ if arg0 is S.NaN or isinstance(arg0, AccumBounds):
383
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
384
+ r = ceiling(arg0)
385
+ if arg0.is_finite:
386
+ if arg0 == r:
387
+ ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
388
+ if ndir.is_negative:
389
+ return r
390
+ elif ndir.is_positive:
391
+ return r + 1
392
+ else:
393
+ raise NotImplementedError("Not sure of sign of %s" % ndir)
394
+ else:
395
+ return r
396
+ return arg.as_leading_term(x, logx=logx, cdir=cdir)
397
+
398
+ def _eval_nseries(self, x, n, logx, cdir=0):
399
+ arg = self.args[0]
400
+ arg0 = arg.subs(x, 0)
401
+ r = self.subs(x, 0)
402
+ if arg0 is S.NaN:
403
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
404
+ r = ceiling(arg0)
405
+ if arg0.is_infinite:
406
+ from sympy.calculus.accumulationbounds import AccumBounds
407
+ from sympy.series.order import Order
408
+ s = arg._eval_nseries(x, n, logx, cdir)
409
+ o = Order(1, (x, 0)) if n <= 0 else AccumBounds(0, 1)
410
+ return s + o
411
+ if arg0 == r:
412
+ ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
413
+ if ndir.is_negative:
414
+ return r
415
+ elif ndir.is_positive:
416
+ return r + 1
417
+ else:
418
+ raise NotImplementedError("Not sure of sign of %s" % ndir)
419
+ else:
420
+ return r
421
+
422
+ def _eval_rewrite_as_floor(self, arg, **kwargs):
423
+ return -floor(-arg)
424
+
425
+ def _eval_rewrite_as_frac(self, arg, **kwargs):
426
+ return arg + frac(-arg)
427
+
428
+ def _eval_is_positive(self):
429
+ return self.args[0].is_positive
430
+
431
+ def _eval_is_nonpositive(self):
432
+ return self.args[0].is_nonpositive
433
+
434
+ def __lt__(self, other):
435
+ other = S(other)
436
+ if self.args[0].is_real:
437
+ if other.is_integer:
438
+ return self.args[0] <= other - 1
439
+ if other.is_number and other.is_real:
440
+ return self.args[0] <= floor(other)
441
+ if self.args[0] == other and other.is_real:
442
+ return S.false
443
+ if other is S.Infinity and self.is_finite:
444
+ return S.true
445
+
446
+ return Lt(self, other, evaluate=False)
447
+
448
+ def __gt__(self, other):
449
+ other = S(other)
450
+ if self.args[0].is_real:
451
+ if other.is_integer:
452
+ return self.args[0] > other
453
+ if other.is_number and other.is_real:
454
+ return self.args[0] > floor(other)
455
+ if self.args[0] == other and other.is_real and other.is_noninteger:
456
+ return S.true
457
+ if other is S.NegativeInfinity and self.is_finite:
458
+ return S.true
459
+
460
+ return Gt(self, other, evaluate=False)
461
+
462
+ def __ge__(self, other):
463
+ other = S(other)
464
+ if self.args[0].is_real:
465
+ if other.is_integer:
466
+ return self.args[0] > other - 1
467
+ if other.is_number and other.is_real:
468
+ return self.args[0] > floor(other)
469
+ if self.args[0] == other and other.is_real:
470
+ return S.true
471
+ if other is S.NegativeInfinity and self.is_finite:
472
+ return S.true
473
+
474
+ return Ge(self, other, evaluate=False)
475
+
476
+ def __le__(self, other):
477
+ other = S(other)
478
+ if self.args[0].is_real:
479
+ if other.is_integer:
480
+ return self.args[0] <= other
481
+ if other.is_number and other.is_real:
482
+ return self.args[0] <= floor(other)
483
+ if self.args[0] == other and other.is_real and other.is_noninteger:
484
+ return S.false
485
+ if other is S.Infinity and self.is_finite:
486
+ return S.true
487
+
488
+ return Le(self, other, evaluate=False)
489
+
490
+
491
+ @dispatch(ceiling, Basic) # type:ignore
492
+ def _eval_is_eq(lhs, rhs): # noqa:F811
493
+ return is_eq(lhs.rewrite(floor), rhs) or is_eq(lhs.rewrite(frac),rhs)
494
+
495
+
496
+ class frac(DefinedFunction):
497
+ r"""Represents the fractional part of x
498
+
499
+ For real numbers it is defined [1]_ as
500
+
501
+ .. math::
502
+ x - \left\lfloor{x}\right\rfloor
503
+
504
+ Examples
505
+ ========
506
+
507
+ >>> from sympy import Symbol, frac, Rational, floor, I
508
+ >>> frac(Rational(4, 3))
509
+ 1/3
510
+ >>> frac(-Rational(4, 3))
511
+ 2/3
512
+
513
+ returns zero for integer arguments
514
+
515
+ >>> n = Symbol('n', integer=True)
516
+ >>> frac(n)
517
+ 0
518
+
519
+ rewrite as floor
520
+
521
+ >>> x = Symbol('x')
522
+ >>> frac(x).rewrite(floor)
523
+ x - floor(x)
524
+
525
+ for complex arguments
526
+
527
+ >>> r = Symbol('r', real=True)
528
+ >>> t = Symbol('t', real=True)
529
+ >>> frac(t + I*r)
530
+ I*frac(r) + frac(t)
531
+
532
+ See Also
533
+ ========
534
+
535
+ sympy.functions.elementary.integers.floor
536
+ sympy.functions.elementary.integers.ceiling
537
+
538
+ References
539
+ ===========
540
+
541
+ .. [1] https://en.wikipedia.org/wiki/Fractional_part
542
+ .. [2] https://mathworld.wolfram.com/FractionalPart.html
543
+
544
+ """
545
+ @classmethod
546
+ def eval(cls, arg):
547
+ from sympy.calculus.accumulationbounds import AccumBounds
548
+
549
+ def _eval(arg):
550
+ if arg in (S.Infinity, S.NegativeInfinity):
551
+ return AccumBounds(0, 1)
552
+ if arg.is_integer:
553
+ return S.Zero
554
+ if arg.is_number:
555
+ if arg is S.NaN:
556
+ return S.NaN
557
+ elif arg is S.ComplexInfinity:
558
+ return S.NaN
559
+ else:
560
+ return arg - floor(arg)
561
+ return cls(arg, evaluate=False)
562
+
563
+ real, imag = S.Zero, S.Zero
564
+ for t in Add.make_args(arg):
565
+ # Two checks are needed for complex arguments
566
+ # see issue-7649 for details
567
+ if t.is_imaginary or (S.ImaginaryUnit*t).is_real:
568
+ i = im(t)
569
+ if not i.has(S.ImaginaryUnit):
570
+ imag += i
571
+ else:
572
+ real += t
573
+ else:
574
+ real += t
575
+
576
+ real = _eval(real)
577
+ imag = _eval(imag)
578
+ return real + S.ImaginaryUnit*imag
579
+
580
+ def _eval_rewrite_as_floor(self, arg, **kwargs):
581
+ return arg - floor(arg)
582
+
583
+ def _eval_rewrite_as_ceiling(self, arg, **kwargs):
584
+ return arg + ceiling(-arg)
585
+
586
+ def _eval_is_finite(self):
587
+ return True
588
+
589
+ def _eval_is_real(self):
590
+ return self.args[0].is_extended_real
591
+
592
+ def _eval_is_imaginary(self):
593
+ return self.args[0].is_imaginary
594
+
595
+ def _eval_is_integer(self):
596
+ return self.args[0].is_integer
597
+
598
+ def _eval_is_zero(self):
599
+ return fuzzy_or([self.args[0].is_zero, self.args[0].is_integer])
600
+
601
+ def _eval_is_negative(self):
602
+ return False
603
+
604
+ def __ge__(self, other):
605
+ if self.is_extended_real:
606
+ other = _sympify(other)
607
+ # Check if other <= 0
608
+ if other.is_extended_nonpositive:
609
+ return S.true
610
+ # Check if other >= 1
611
+ res = self._value_one_or_more(other)
612
+ if res is not None:
613
+ return not(res)
614
+ return Ge(self, other, evaluate=False)
615
+
616
+ def __gt__(self, other):
617
+ if self.is_extended_real:
618
+ other = _sympify(other)
619
+ # Check if other < 0
620
+ res = self._value_one_or_more(other)
621
+ if res is not None:
622
+ return not(res)
623
+ # Check if other >= 1
624
+ if other.is_extended_negative:
625
+ return S.true
626
+ return Gt(self, other, evaluate=False)
627
+
628
+ def __le__(self, other):
629
+ if self.is_extended_real:
630
+ other = _sympify(other)
631
+ # Check if other < 0
632
+ if other.is_extended_negative:
633
+ return S.false
634
+ # Check if other >= 1
635
+ res = self._value_one_or_more(other)
636
+ if res is not None:
637
+ return res
638
+ return Le(self, other, evaluate=False)
639
+
640
+ def __lt__(self, other):
641
+ if self.is_extended_real:
642
+ other = _sympify(other)
643
+ # Check if other <= 0
644
+ if other.is_extended_nonpositive:
645
+ return S.false
646
+ # Check if other >= 1
647
+ res = self._value_one_or_more(other)
648
+ if res is not None:
649
+ return res
650
+ return Lt(self, other, evaluate=False)
651
+
652
+ def _value_one_or_more(self, other):
653
+ if other.is_extended_real:
654
+ if other.is_number:
655
+ res = other >= 1
656
+ if res and not isinstance(res, Relational):
657
+ return S.true
658
+ if other.is_integer and other.is_positive:
659
+ return S.true
660
+
661
+ def _eval_as_leading_term(self, x, logx, cdir):
662
+ from sympy.calculus.accumulationbounds import AccumBounds
663
+ arg = self.args[0]
664
+ arg0 = arg.subs(x, 0)
665
+ r = self.subs(x, 0)
666
+
667
+ if arg0.is_finite:
668
+ if r.is_zero:
669
+ ndir = arg.dir(x, cdir=cdir)
670
+ if ndir.is_negative:
671
+ return S.One
672
+ return (arg - arg0).as_leading_term(x, logx=logx, cdir=cdir)
673
+ else:
674
+ return r
675
+ elif arg0 in (S.ComplexInfinity, S.Infinity, S.NegativeInfinity):
676
+ return AccumBounds(0, 1)
677
+ return arg.as_leading_term(x, logx=logx, cdir=cdir)
678
+
679
+ def _eval_nseries(self, x, n, logx, cdir=0):
680
+ from sympy.series.order import Order
681
+ arg = self.args[0]
682
+ arg0 = arg.subs(x, 0)
683
+ r = self.subs(x, 0)
684
+
685
+ if arg0.is_infinite:
686
+ from sympy.calculus.accumulationbounds import AccumBounds
687
+ o = Order(1, (x, 0)) if n <= 0 else AccumBounds(0, 1) + Order(x**n, (x, 0))
688
+ return o
689
+ else:
690
+ res = (arg - arg0)._eval_nseries(x, n, logx=logx, cdir=cdir)
691
+ if r.is_zero:
692
+ ndir = arg.dir(x, cdir=cdir)
693
+ res += S.One if ndir.is_negative else S.Zero
694
+ else:
695
+ res += r
696
+ return res
697
+
698
+
699
+ @dispatch(frac, Basic) # type:ignore
700
+ def _eval_is_eq(lhs, rhs): # noqa:F811
701
+ if (lhs.rewrite(floor) == rhs) or \
702
+ (lhs.rewrite(ceiling) == rhs):
703
+ return True
704
+ # Check if other < 0
705
+ if rhs.is_extended_negative:
706
+ return False
707
+ # Check if other >= 1
708
+ res = lhs._value_one_or_more(rhs)
709
+ if res is not None:
710
+ return False
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/miscellaneous.py ADDED
@@ -0,0 +1,915 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import S, sympify, NumberKind
2
+ from sympy.utilities.iterables import sift
3
+ from sympy.core.add import Add
4
+ from sympy.core.containers import Tuple
5
+ from sympy.core.operations import LatticeOp, ShortCircuit
6
+ from sympy.core.function import (Application, Lambda,
7
+ ArgumentIndexError, DefinedFunction)
8
+ from sympy.core.expr import Expr
9
+ from sympy.core.exprtools import factor_terms
10
+ from sympy.core.mod import Mod
11
+ from sympy.core.mul import Mul
12
+ from sympy.core.numbers import Rational
13
+ from sympy.core.power import Pow
14
+ from sympy.core.relational import Eq, Relational
15
+ from sympy.core.singleton import Singleton
16
+ from sympy.core.sorting import ordered
17
+ from sympy.core.symbol import Dummy
18
+ from sympy.core.rules import Transform
19
+ from sympy.core.logic import fuzzy_and, fuzzy_or, _torf
20
+ from sympy.core.traversal import walk
21
+ from sympy.core.numbers import Integer
22
+ from sympy.logic.boolalg import And, Or
23
+
24
+
25
+ def _minmax_as_Piecewise(op, *args):
26
+ # helper for Min/Max rewrite as Piecewise
27
+ from sympy.functions.elementary.piecewise import Piecewise
28
+ ec = []
29
+ for i, a in enumerate(args):
30
+ c = [Relational(a, args[j], op) for j in range(i + 1, len(args))]
31
+ ec.append((a, And(*c)))
32
+ return Piecewise(*ec)
33
+
34
+
35
+ class IdentityFunction(Lambda, metaclass=Singleton):
36
+ """
37
+ The identity function
38
+
39
+ Examples
40
+ ========
41
+
42
+ >>> from sympy import Id, Symbol
43
+ >>> x = Symbol('x')
44
+ >>> Id(x)
45
+ x
46
+
47
+ """
48
+
49
+ _symbol = Dummy('x')
50
+
51
+ @property
52
+ def signature(self):
53
+ return Tuple(self._symbol)
54
+
55
+ @property
56
+ def expr(self):
57
+ return self._symbol
58
+
59
+
60
+ Id = S.IdentityFunction
61
+
62
+ ###############################################################################
63
+ ############################# ROOT and SQUARE ROOT FUNCTION ###################
64
+ ###############################################################################
65
+
66
+
67
+ def sqrt(arg, evaluate=None):
68
+ """Returns the principal square root.
69
+
70
+ Parameters
71
+ ==========
72
+
73
+ evaluate : bool, optional
74
+ The parameter determines if the expression should be evaluated.
75
+ If ``None``, its value is taken from
76
+ ``global_parameters.evaluate``.
77
+
78
+ Examples
79
+ ========
80
+
81
+ >>> from sympy import sqrt, Symbol, S
82
+ >>> x = Symbol('x')
83
+
84
+ >>> sqrt(x)
85
+ sqrt(x)
86
+
87
+ >>> sqrt(x)**2
88
+ x
89
+
90
+ Note that sqrt(x**2) does not simplify to x.
91
+
92
+ >>> sqrt(x**2)
93
+ sqrt(x**2)
94
+
95
+ This is because the two are not equal to each other in general.
96
+ For example, consider x == -1:
97
+
98
+ >>> from sympy import Eq
99
+ >>> Eq(sqrt(x**2), x).subs(x, -1)
100
+ False
101
+
102
+ This is because sqrt computes the principal square root, so the square may
103
+ put the argument in a different branch. This identity does hold if x is
104
+ positive:
105
+
106
+ >>> y = Symbol('y', positive=True)
107
+ >>> sqrt(y**2)
108
+ y
109
+
110
+ You can force this simplification by using the powdenest() function with
111
+ the force option set to True:
112
+
113
+ >>> from sympy import powdenest
114
+ >>> sqrt(x**2)
115
+ sqrt(x**2)
116
+ >>> powdenest(sqrt(x**2), force=True)
117
+ x
118
+
119
+ To get both branches of the square root you can use the rootof function:
120
+
121
+ >>> from sympy import rootof
122
+
123
+ >>> [rootof(x**2-3,i) for i in (0,1)]
124
+ [-sqrt(3), sqrt(3)]
125
+
126
+ Although ``sqrt`` is printed, there is no ``sqrt`` function so looking for
127
+ ``sqrt`` in an expression will fail:
128
+
129
+ >>> from sympy.utilities.misc import func_name
130
+ >>> func_name(sqrt(x))
131
+ 'Pow'
132
+ >>> sqrt(x).has(sqrt)
133
+ False
134
+
135
+ To find ``sqrt`` look for ``Pow`` with an exponent of ``1/2``:
136
+
137
+ >>> (x + 1/sqrt(x)).find(lambda i: i.is_Pow and abs(i.exp) is S.Half)
138
+ {1/sqrt(x)}
139
+
140
+ See Also
141
+ ========
142
+
143
+ sympy.polys.rootoftools.rootof, root, real_root
144
+
145
+ References
146
+ ==========
147
+
148
+ .. [1] https://en.wikipedia.org/wiki/Square_root
149
+ .. [2] https://en.wikipedia.org/wiki/Principal_value
150
+ """
151
+ # arg = sympify(arg) is handled by Pow
152
+ return Pow(arg, S.Half, evaluate=evaluate)
153
+
154
+
155
+ def cbrt(arg, evaluate=None):
156
+ """Returns the principal cube root.
157
+
158
+ Parameters
159
+ ==========
160
+
161
+ evaluate : bool, optional
162
+ The parameter determines if the expression should be evaluated.
163
+ If ``None``, its value is taken from
164
+ ``global_parameters.evaluate``.
165
+
166
+ Examples
167
+ ========
168
+
169
+ >>> from sympy import cbrt, Symbol
170
+ >>> x = Symbol('x')
171
+
172
+ >>> cbrt(x)
173
+ x**(1/3)
174
+
175
+ >>> cbrt(x)**3
176
+ x
177
+
178
+ Note that cbrt(x**3) does not simplify to x.
179
+
180
+ >>> cbrt(x**3)
181
+ (x**3)**(1/3)
182
+
183
+ This is because the two are not equal to each other in general.
184
+ For example, consider `x == -1`:
185
+
186
+ >>> from sympy import Eq
187
+ >>> Eq(cbrt(x**3), x).subs(x, -1)
188
+ False
189
+
190
+ This is because cbrt computes the principal cube root, this
191
+ identity does hold if `x` is positive:
192
+
193
+ >>> y = Symbol('y', positive=True)
194
+ >>> cbrt(y**3)
195
+ y
196
+
197
+ See Also
198
+ ========
199
+
200
+ sympy.polys.rootoftools.rootof, root, real_root
201
+
202
+ References
203
+ ==========
204
+
205
+ .. [1] https://en.wikipedia.org/wiki/Cube_root
206
+ .. [2] https://en.wikipedia.org/wiki/Principal_value
207
+
208
+ """
209
+ return Pow(arg, Rational(1, 3), evaluate=evaluate)
210
+
211
+
212
+ def root(arg, n, k=0, evaluate=None):
213
+ r"""Returns the *k*-th *n*-th root of ``arg``.
214
+
215
+ Parameters
216
+ ==========
217
+
218
+ k : int, optional
219
+ Should be an integer in $\{0, 1, ..., n-1\}$.
220
+ Defaults to the principal root if $0$.
221
+
222
+ evaluate : bool, optional
223
+ The parameter determines if the expression should be evaluated.
224
+ If ``None``, its value is taken from
225
+ ``global_parameters.evaluate``.
226
+
227
+ Examples
228
+ ========
229
+
230
+ >>> from sympy import root, Rational
231
+ >>> from sympy.abc import x, n
232
+
233
+ >>> root(x, 2)
234
+ sqrt(x)
235
+
236
+ >>> root(x, 3)
237
+ x**(1/3)
238
+
239
+ >>> root(x, n)
240
+ x**(1/n)
241
+
242
+ >>> root(x, -Rational(2, 3))
243
+ x**(-3/2)
244
+
245
+ To get the k-th n-th root, specify k:
246
+
247
+ >>> root(-2, 3, 2)
248
+ -(-1)**(2/3)*2**(1/3)
249
+
250
+ To get all n n-th roots you can use the rootof function.
251
+ The following examples show the roots of unity for n
252
+ equal 2, 3 and 4:
253
+
254
+ >>> from sympy import rootof
255
+
256
+ >>> [rootof(x**2 - 1, i) for i in range(2)]
257
+ [-1, 1]
258
+
259
+ >>> [rootof(x**3 - 1,i) for i in range(3)]
260
+ [1, -1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2]
261
+
262
+ >>> [rootof(x**4 - 1,i) for i in range(4)]
263
+ [-1, 1, -I, I]
264
+
265
+ SymPy, like other symbolic algebra systems, returns the
266
+ complex root of negative numbers. This is the principal
267
+ root and differs from the text-book result that one might
268
+ be expecting. For example, the cube root of -8 does not
269
+ come back as -2:
270
+
271
+ >>> root(-8, 3)
272
+ 2*(-1)**(1/3)
273
+
274
+ The real_root function can be used to either make the principal
275
+ result real (or simply to return the real root directly):
276
+
277
+ >>> from sympy import real_root
278
+ >>> real_root(_)
279
+ -2
280
+ >>> real_root(-32, 5)
281
+ -2
282
+
283
+ Alternatively, the n//2-th n-th root of a negative number can be
284
+ computed with root:
285
+
286
+ >>> root(-32, 5, 5//2)
287
+ -2
288
+
289
+ See Also
290
+ ========
291
+
292
+ sympy.polys.rootoftools.rootof
293
+ sympy.core.intfunc.integer_nthroot
294
+ sqrt, real_root
295
+
296
+ References
297
+ ==========
298
+
299
+ .. [1] https://en.wikipedia.org/wiki/Square_root
300
+ .. [2] https://en.wikipedia.org/wiki/Real_root
301
+ .. [3] https://en.wikipedia.org/wiki/Root_of_unity
302
+ .. [4] https://en.wikipedia.org/wiki/Principal_value
303
+ .. [5] https://mathworld.wolfram.com/CubeRoot.html
304
+
305
+ """
306
+ n = sympify(n)
307
+ if k:
308
+ return Mul(Pow(arg, S.One/n, evaluate=evaluate), S.NegativeOne**(2*k/n), evaluate=evaluate)
309
+ return Pow(arg, 1/n, evaluate=evaluate)
310
+
311
+
312
+ def real_root(arg, n=None, evaluate=None):
313
+ r"""Return the real *n*'th-root of *arg* if possible.
314
+
315
+ Parameters
316
+ ==========
317
+
318
+ n : int or None, optional
319
+ If *n* is ``None``, then all instances of
320
+ $(-n)^{1/\text{odd}}$ will be changed to $-n^{1/\text{odd}}$.
321
+ This will only create a real root of a principal root.
322
+ The presence of other factors may cause the result to not be
323
+ real.
324
+
325
+ evaluate : bool, optional
326
+ The parameter determines if the expression should be evaluated.
327
+ If ``None``, its value is taken from
328
+ ``global_parameters.evaluate``.
329
+
330
+ Examples
331
+ ========
332
+
333
+ >>> from sympy import root, real_root
334
+
335
+ >>> real_root(-8, 3)
336
+ -2
337
+ >>> root(-8, 3)
338
+ 2*(-1)**(1/3)
339
+ >>> real_root(_)
340
+ -2
341
+
342
+ If one creates a non-principal root and applies real_root, the
343
+ result will not be real (so use with caution):
344
+
345
+ >>> root(-8, 3, 2)
346
+ -2*(-1)**(2/3)
347
+ >>> real_root(_)
348
+ -2*(-1)**(2/3)
349
+
350
+ See Also
351
+ ========
352
+
353
+ sympy.polys.rootoftools.rootof
354
+ sympy.core.intfunc.integer_nthroot
355
+ root, sqrt
356
+ """
357
+ from sympy.functions.elementary.complexes import Abs, im, sign
358
+ from sympy.functions.elementary.piecewise import Piecewise
359
+ if n is not None:
360
+ return Piecewise(
361
+ (root(arg, n, evaluate=evaluate), Or(Eq(n, S.One), Eq(n, S.NegativeOne))),
362
+ (Mul(sign(arg), root(Abs(arg), n, evaluate=evaluate), evaluate=evaluate),
363
+ And(Eq(im(arg), S.Zero), Eq(Mod(n, 2), S.One))),
364
+ (root(arg, n, evaluate=evaluate), True))
365
+ rv = sympify(arg)
366
+ n1pow = Transform(lambda x: -(-x.base)**x.exp,
367
+ lambda x:
368
+ x.is_Pow and
369
+ x.base.is_negative and
370
+ x.exp.is_Rational and
371
+ x.exp.p == 1 and x.exp.q % 2)
372
+ return rv.xreplace(n1pow)
373
+
374
+ ###############################################################################
375
+ ############################# MINIMUM and MAXIMUM #############################
376
+ ###############################################################################
377
+
378
+
379
+ class MinMaxBase(Expr, LatticeOp):
380
+ def __new__(cls, *args, **assumptions):
381
+ from sympy.core.parameters import global_parameters
382
+ evaluate = assumptions.pop('evaluate', global_parameters.evaluate)
383
+ args = (sympify(arg) for arg in args)
384
+
385
+ # first standard filter, for cls.zero and cls.identity
386
+ # also reshape Max(a, Max(b, c)) to Max(a, b, c)
387
+
388
+ if evaluate:
389
+ try:
390
+ args = frozenset(cls._new_args_filter(args))
391
+ except ShortCircuit:
392
+ return cls.zero
393
+ # remove redundant args that are easily identified
394
+ args = cls._collapse_arguments(args, **assumptions)
395
+ # find local zeros
396
+ args = cls._find_localzeros(args, **assumptions)
397
+ args = frozenset(args)
398
+
399
+ if not args:
400
+ return cls.identity
401
+
402
+ if len(args) == 1:
403
+ return list(args).pop()
404
+
405
+ # base creation
406
+ obj = Expr.__new__(cls, *ordered(args), **assumptions)
407
+ obj._argset = args
408
+ return obj
409
+
410
+ @classmethod
411
+ def _collapse_arguments(cls, args, **assumptions):
412
+ """Remove redundant args.
413
+
414
+ Examples
415
+ ========
416
+
417
+ >>> from sympy import Min, Max
418
+ >>> from sympy.abc import a, b, c, d, e
419
+
420
+ Any arg in parent that appears in any
421
+ parent-like function in any of the flat args
422
+ of parent can be removed from that sub-arg:
423
+
424
+ >>> Min(a, Max(b, Min(a, c, d)))
425
+ Min(a, Max(b, Min(c, d)))
426
+
427
+ If the arg of parent appears in an opposite-than parent
428
+ function in any of the flat args of parent that function
429
+ can be replaced with the arg:
430
+
431
+ >>> Min(a, Max(b, Min(c, d, Max(a, e))))
432
+ Min(a, Max(b, Min(a, c, d)))
433
+ """
434
+ if not args:
435
+ return args
436
+ args = list(ordered(args))
437
+ if cls == Min:
438
+ other = Max
439
+ else:
440
+ other = Min
441
+
442
+ # find global comparable max of Max and min of Min if a new
443
+ # value is being introduced in these args at position 0 of
444
+ # the ordered args
445
+ if args[0].is_number:
446
+ sifted = mins, maxs = [], []
447
+ for i in args:
448
+ for v in walk(i, Min, Max):
449
+ if v.args[0].is_comparable:
450
+ sifted[isinstance(v, Max)].append(v)
451
+ small = Min.identity
452
+ for i in mins:
453
+ v = i.args[0]
454
+ if v.is_number and (v < small) == True:
455
+ small = v
456
+ big = Max.identity
457
+ for i in maxs:
458
+ v = i.args[0]
459
+ if v.is_number and (v > big) == True:
460
+ big = v
461
+ # at the point when this function is called from __new__,
462
+ # there may be more than one numeric arg present since
463
+ # local zeros have not been handled yet, so look through
464
+ # more than the first arg
465
+ if cls == Min:
466
+ for arg in args:
467
+ if not arg.is_number:
468
+ break
469
+ if (arg < small) == True:
470
+ small = arg
471
+ elif cls == Max:
472
+ for arg in args:
473
+ if not arg.is_number:
474
+ break
475
+ if (arg > big) == True:
476
+ big = arg
477
+ T = None
478
+ if cls == Min:
479
+ if small != Min.identity:
480
+ other = Max
481
+ T = small
482
+ elif big != Max.identity:
483
+ other = Min
484
+ T = big
485
+ if T is not None:
486
+ # remove numerical redundancy
487
+ for i in range(len(args)):
488
+ a = args[i]
489
+ if isinstance(a, other):
490
+ a0 = a.args[0]
491
+ if ((a0 > T) if other == Max else (a0 < T)) == True:
492
+ args[i] = cls.identity
493
+
494
+ # remove redundant symbolic args
495
+ def do(ai, a):
496
+ if not isinstance(ai, (Min, Max)):
497
+ return ai
498
+ cond = a in ai.args
499
+ if not cond:
500
+ return ai.func(*[do(i, a) for i in ai.args],
501
+ evaluate=False)
502
+ if isinstance(ai, cls):
503
+ return ai.func(*[do(i, a) for i in ai.args if i != a],
504
+ evaluate=False)
505
+ return a
506
+ for i, a in enumerate(args):
507
+ args[i + 1:] = [do(ai, a) for ai in args[i + 1:]]
508
+
509
+ # factor out common elements as for
510
+ # Min(Max(x, y), Max(x, z)) -> Max(x, Min(y, z))
511
+ # and vice versa when swapping Min/Max -- do this only for the
512
+ # easy case where all functions contain something in common;
513
+ # trying to find some optimal subset of args to modify takes
514
+ # too long
515
+
516
+ def factor_minmax(args):
517
+ is_other = lambda arg: isinstance(arg, other)
518
+ other_args, remaining_args = sift(args, is_other, binary=True)
519
+ if not other_args:
520
+ return args
521
+
522
+ # Min(Max(x, y, z), Max(x, y, u, v)) -> {x,y}, ({z}, {u,v})
523
+ arg_sets = [set(arg.args) for arg in other_args]
524
+ common = set.intersection(*arg_sets)
525
+ if not common:
526
+ return args
527
+
528
+ new_other_args = list(common)
529
+ arg_sets_diff = [arg_set - common for arg_set in arg_sets]
530
+
531
+ # If any set is empty after removing common then all can be
532
+ # discarded e.g. Min(Max(a, b, c), Max(a, b)) -> Max(a, b)
533
+ if all(arg_sets_diff):
534
+ other_args_diff = [other(*s, evaluate=False) for s in arg_sets_diff]
535
+ new_other_args.append(cls(*other_args_diff, evaluate=False))
536
+
537
+ other_args_factored = other(*new_other_args, evaluate=False)
538
+ return remaining_args + [other_args_factored]
539
+
540
+ if len(args) > 1:
541
+ args = factor_minmax(args)
542
+
543
+ return args
544
+
545
+ @classmethod
546
+ def _new_args_filter(cls, arg_sequence):
547
+ """
548
+ Generator filtering args.
549
+
550
+ first standard filter, for cls.zero and cls.identity.
551
+ Also reshape ``Max(a, Max(b, c))`` to ``Max(a, b, c)``,
552
+ and check arguments for comparability
553
+ """
554
+ for arg in arg_sequence:
555
+ # pre-filter, checking comparability of arguments
556
+ if not isinstance(arg, Expr) or arg.is_extended_real is False or (
557
+ arg.is_number and
558
+ not arg.is_comparable):
559
+ raise ValueError("The argument '%s' is not comparable." % arg)
560
+
561
+ if arg == cls.zero:
562
+ raise ShortCircuit(arg)
563
+ elif arg == cls.identity:
564
+ continue
565
+ elif arg.func == cls:
566
+ yield from arg.args
567
+ else:
568
+ yield arg
569
+
570
+ @classmethod
571
+ def _find_localzeros(cls, values, **options):
572
+ """
573
+ Sequentially allocate values to localzeros.
574
+
575
+ When a value is identified as being more extreme than another member it
576
+ replaces that member; if this is never true, then the value is simply
577
+ appended to the localzeros.
578
+ """
579
+ localzeros = set()
580
+ for v in values:
581
+ is_newzero = True
582
+ localzeros_ = list(localzeros)
583
+ for z in localzeros_:
584
+ if id(v) == id(z):
585
+ is_newzero = False
586
+ else:
587
+ con = cls._is_connected(v, z)
588
+ if con:
589
+ is_newzero = False
590
+ if con is True or con == cls:
591
+ localzeros.remove(z)
592
+ localzeros.update([v])
593
+ if is_newzero:
594
+ localzeros.update([v])
595
+ return localzeros
596
+
597
+ @classmethod
598
+ def _is_connected(cls, x, y):
599
+ """
600
+ Check if x and y are connected somehow.
601
+ """
602
+ for i in range(2):
603
+ if x == y:
604
+ return True
605
+ t, f = Max, Min
606
+ for op in "><":
607
+ for j in range(2):
608
+ try:
609
+ if op == ">":
610
+ v = x >= y
611
+ else:
612
+ v = x <= y
613
+ except TypeError:
614
+ return False # non-real arg
615
+ if not v.is_Relational:
616
+ return t if v else f
617
+ t, f = f, t
618
+ x, y = y, x
619
+ x, y = y, x # run next pass with reversed order relative to start
620
+ # simplification can be expensive, so be conservative
621
+ # in what is attempted
622
+ x = factor_terms(x - y)
623
+ y = S.Zero
624
+
625
+ return False
626
+
627
+ def _eval_derivative(self, s):
628
+ # f(x).diff(s) -> x.diff(s) * f.fdiff(1)(s)
629
+ i = 0
630
+ l = []
631
+ for a in self.args:
632
+ i += 1
633
+ da = a.diff(s)
634
+ if da.is_zero:
635
+ continue
636
+ try:
637
+ df = self.fdiff(i)
638
+ except ArgumentIndexError:
639
+ df = super().fdiff(i)
640
+ l.append(df * da)
641
+ return Add(*l)
642
+
643
+ def _eval_rewrite_as_Abs(self, *args, **kwargs):
644
+ from sympy.functions.elementary.complexes import Abs
645
+ s = (args[0] + self.func(*args[1:]))/2
646
+ d = abs(args[0] - self.func(*args[1:]))/2
647
+ return (s + d if isinstance(self, Max) else s - d).rewrite(Abs)
648
+
649
+ def evalf(self, n=15, **options):
650
+ return self.func(*[a.evalf(n, **options) for a in self.args])
651
+
652
+ def n(self, *args, **kwargs):
653
+ return self.evalf(*args, **kwargs)
654
+
655
+ _eval_is_algebraic = lambda s: _torf(i.is_algebraic for i in s.args)
656
+ _eval_is_antihermitian = lambda s: _torf(i.is_antihermitian for i in s.args)
657
+ _eval_is_commutative = lambda s: _torf(i.is_commutative for i in s.args)
658
+ _eval_is_complex = lambda s: _torf(i.is_complex for i in s.args)
659
+ _eval_is_composite = lambda s: _torf(i.is_composite for i in s.args)
660
+ _eval_is_even = lambda s: _torf(i.is_even for i in s.args)
661
+ _eval_is_finite = lambda s: _torf(i.is_finite for i in s.args)
662
+ _eval_is_hermitian = lambda s: _torf(i.is_hermitian for i in s.args)
663
+ _eval_is_imaginary = lambda s: _torf(i.is_imaginary for i in s.args)
664
+ _eval_is_infinite = lambda s: _torf(i.is_infinite for i in s.args)
665
+ _eval_is_integer = lambda s: _torf(i.is_integer for i in s.args)
666
+ _eval_is_irrational = lambda s: _torf(i.is_irrational for i in s.args)
667
+ _eval_is_negative = lambda s: _torf(i.is_negative for i in s.args)
668
+ _eval_is_noninteger = lambda s: _torf(i.is_noninteger for i in s.args)
669
+ _eval_is_nonnegative = lambda s: _torf(i.is_nonnegative for i in s.args)
670
+ _eval_is_nonpositive = lambda s: _torf(i.is_nonpositive for i in s.args)
671
+ _eval_is_nonzero = lambda s: _torf(i.is_nonzero for i in s.args)
672
+ _eval_is_odd = lambda s: _torf(i.is_odd for i in s.args)
673
+ _eval_is_polar = lambda s: _torf(i.is_polar for i in s.args)
674
+ _eval_is_positive = lambda s: _torf(i.is_positive for i in s.args)
675
+ _eval_is_prime = lambda s: _torf(i.is_prime for i in s.args)
676
+ _eval_is_rational = lambda s: _torf(i.is_rational for i in s.args)
677
+ _eval_is_real = lambda s: _torf(i.is_real for i in s.args)
678
+ _eval_is_extended_real = lambda s: _torf(i.is_extended_real for i in s.args)
679
+ _eval_is_transcendental = lambda s: _torf(i.is_transcendental for i in s.args)
680
+ _eval_is_zero = lambda s: _torf(i.is_zero for i in s.args)
681
+
682
+
683
+ class Max(MinMaxBase, Application):
684
+ r"""
685
+ Return, if possible, the maximum value of the list.
686
+
687
+ When number of arguments is equal one, then
688
+ return this argument.
689
+
690
+ When number of arguments is equal two, then
691
+ return, if possible, the value from (a, b) that is $\ge$ the other.
692
+
693
+ In common case, when the length of list greater than 2, the task
694
+ is more complicated. Return only the arguments, which are greater
695
+ than others, if it is possible to determine directional relation.
696
+
697
+ If is not possible to determine such a relation, return a partially
698
+ evaluated result.
699
+
700
+ Assumptions are used to make the decision too.
701
+
702
+ Also, only comparable arguments are permitted.
703
+
704
+ It is named ``Max`` and not ``max`` to avoid conflicts
705
+ with the built-in function ``max``.
706
+
707
+
708
+ Examples
709
+ ========
710
+
711
+ >>> from sympy import Max, Symbol, oo
712
+ >>> from sympy.abc import x, y, z
713
+ >>> p = Symbol('p', positive=True)
714
+ >>> n = Symbol('n', negative=True)
715
+
716
+ >>> Max(x, -2)
717
+ Max(-2, x)
718
+ >>> Max(x, -2).subs(x, 3)
719
+ 3
720
+ >>> Max(p, -2)
721
+ p
722
+ >>> Max(x, y)
723
+ Max(x, y)
724
+ >>> Max(x, y) == Max(y, x)
725
+ True
726
+ >>> Max(x, Max(y, z))
727
+ Max(x, y, z)
728
+ >>> Max(n, 8, p, 7, -oo)
729
+ Max(8, p)
730
+ >>> Max (1, x, oo)
731
+ oo
732
+
733
+ * Algorithm
734
+
735
+ The task can be considered as searching of supremums in the
736
+ directed complete partial orders [1]_.
737
+
738
+ The source values are sequentially allocated by the isolated subsets
739
+ in which supremums are searched and result as Max arguments.
740
+
741
+ If the resulted supremum is single, then it is returned.
742
+
743
+ The isolated subsets are the sets of values which are only the comparable
744
+ with each other in the current set. E.g. natural numbers are comparable with
745
+ each other, but not comparable with the `x` symbol. Another example: the
746
+ symbol `x` with negative assumption is comparable with a natural number.
747
+
748
+ Also there are "least" elements, which are comparable with all others,
749
+ and have a zero property (maximum or minimum for all elements).
750
+ For example, in case of $\infty$, the allocation operation is terminated
751
+ and only this value is returned.
752
+
753
+ Assumption:
754
+ - if $A > B > C$ then $A > C$
755
+ - if $A = B$ then $B$ can be removed
756
+
757
+ References
758
+ ==========
759
+
760
+ .. [1] https://en.wikipedia.org/wiki/Directed_complete_partial_order
761
+ .. [2] https://en.wikipedia.org/wiki/Lattice_%28order%29
762
+
763
+ See Also
764
+ ========
765
+
766
+ Min : find minimum values
767
+ """
768
+ zero = S.Infinity
769
+ identity = S.NegativeInfinity
770
+
771
+ def fdiff( self, argindex ):
772
+ from sympy.functions.special.delta_functions import Heaviside
773
+ n = len(self.args)
774
+ if 0 < argindex and argindex <= n:
775
+ argindex -= 1
776
+ if n == 2:
777
+ return Heaviside(self.args[argindex] - self.args[1 - argindex])
778
+ newargs = tuple([self.args[i] for i in range(n) if i != argindex])
779
+ return Heaviside(self.args[argindex] - Max(*newargs))
780
+ else:
781
+ raise ArgumentIndexError(self, argindex)
782
+
783
+ def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
784
+ from sympy.functions.special.delta_functions import Heaviside
785
+ return Add(*[j*Mul(*[Heaviside(j - i) for i in args if i!=j]) \
786
+ for j in args])
787
+
788
+ def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
789
+ return _minmax_as_Piecewise('>=', *args)
790
+
791
+ def _eval_is_positive(self):
792
+ return fuzzy_or(a.is_positive for a in self.args)
793
+
794
+ def _eval_is_nonnegative(self):
795
+ return fuzzy_or(a.is_nonnegative for a in self.args)
796
+
797
+ def _eval_is_negative(self):
798
+ return fuzzy_and(a.is_negative for a in self.args)
799
+
800
+
801
+ class Min(MinMaxBase, Application):
802
+ """
803
+ Return, if possible, the minimum value of the list.
804
+ It is named ``Min`` and not ``min`` to avoid conflicts
805
+ with the built-in function ``min``.
806
+
807
+ Examples
808
+ ========
809
+
810
+ >>> from sympy import Min, Symbol, oo
811
+ >>> from sympy.abc import x, y
812
+ >>> p = Symbol('p', positive=True)
813
+ >>> n = Symbol('n', negative=True)
814
+
815
+ >>> Min(x, -2)
816
+ Min(-2, x)
817
+ >>> Min(x, -2).subs(x, 3)
818
+ -2
819
+ >>> Min(p, -3)
820
+ -3
821
+ >>> Min(x, y)
822
+ Min(x, y)
823
+ >>> Min(n, 8, p, -7, p, oo)
824
+ Min(-7, n)
825
+
826
+ See Also
827
+ ========
828
+
829
+ Max : find maximum values
830
+ """
831
+ zero = S.NegativeInfinity
832
+ identity = S.Infinity
833
+
834
+ def fdiff( self, argindex ):
835
+ from sympy.functions.special.delta_functions import Heaviside
836
+ n = len(self.args)
837
+ if 0 < argindex and argindex <= n:
838
+ argindex -= 1
839
+ if n == 2:
840
+ return Heaviside( self.args[1-argindex] - self.args[argindex] )
841
+ newargs = tuple([ self.args[i] for i in range(n) if i != argindex])
842
+ return Heaviside( Min(*newargs) - self.args[argindex] )
843
+ else:
844
+ raise ArgumentIndexError(self, argindex)
845
+
846
+ def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
847
+ from sympy.functions.special.delta_functions import Heaviside
848
+ return Add(*[j*Mul(*[Heaviside(i-j) for i in args if i!=j]) \
849
+ for j in args])
850
+
851
+ def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
852
+ return _minmax_as_Piecewise('<=', *args)
853
+
854
+ def _eval_is_positive(self):
855
+ return fuzzy_and(a.is_positive for a in self.args)
856
+
857
+ def _eval_is_nonnegative(self):
858
+ return fuzzy_and(a.is_nonnegative for a in self.args)
859
+
860
+ def _eval_is_negative(self):
861
+ return fuzzy_or(a.is_negative for a in self.args)
862
+
863
+
864
+ class Rem(DefinedFunction):
865
+ """Returns the remainder when ``p`` is divided by ``q`` where ``p`` is finite
866
+ and ``q`` is not equal to zero. The result, ``p - int(p/q)*q``, has the same sign
867
+ as the divisor.
868
+
869
+ Parameters
870
+ ==========
871
+
872
+ p : Expr
873
+ Dividend.
874
+
875
+ q : Expr
876
+ Divisor.
877
+
878
+ Notes
879
+ =====
880
+
881
+ ``Rem`` corresponds to the ``%`` operator in C.
882
+
883
+ Examples
884
+ ========
885
+
886
+ >>> from sympy.abc import x, y
887
+ >>> from sympy import Rem
888
+ >>> Rem(x**3, y)
889
+ Rem(x**3, y)
890
+ >>> Rem(x**3, y).subs({x: -5, y: 3})
891
+ -2
892
+
893
+ See Also
894
+ ========
895
+
896
+ Mod
897
+ """
898
+ kind = NumberKind
899
+
900
+ @classmethod
901
+ def eval(cls, p, q):
902
+ """Return the function remainder if both p, q are numbers and q is not
903
+ zero.
904
+ """
905
+
906
+ if q.is_zero:
907
+ raise ZeroDivisionError("Division by zero")
908
+ if p is S.NaN or q is S.NaN or p.is_finite is False or q.is_finite is False:
909
+ return S.NaN
910
+ if p is S.Zero or p in (q, -q) or (p.is_integer and q == 1):
911
+ return S.Zero
912
+
913
+ if q.is_Number:
914
+ if p.is_Number:
915
+ return p - Integer(p/q)*q
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/piecewise.py ADDED
@@ -0,0 +1,1517 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import S, diff, Tuple, Dummy, Mul
2
+ from sympy.core.basic import Basic, as_Basic
3
+ from sympy.core.function import DefinedFunction
4
+ from sympy.core.numbers import Rational, NumberSymbol, _illegal
5
+ from sympy.core.parameters import global_parameters
6
+ from sympy.core.relational import (Lt, Gt, Eq, Ne, Relational,
7
+ _canonical, _canonical_coeff)
8
+ from sympy.core.sorting import ordered
9
+ from sympy.functions.elementary.miscellaneous import Max, Min
10
+ from sympy.logic.boolalg import (And, Boolean, distribute_and_over_or, Not,
11
+ true, false, Or, ITE, simplify_logic, to_cnf, distribute_or_over_and)
12
+ from sympy.utilities.iterables import uniq, sift, common_prefix
13
+ from sympy.utilities.misc import filldedent, func_name
14
+
15
+ from itertools import product
16
+
17
+ Undefined = S.NaN # Piecewise()
18
+
19
+ class ExprCondPair(Tuple):
20
+ """Represents an expression, condition pair."""
21
+
22
+ def __new__(cls, expr, cond):
23
+ expr = as_Basic(expr)
24
+ if cond == True:
25
+ return Tuple.__new__(cls, expr, true)
26
+ elif cond == False:
27
+ return Tuple.__new__(cls, expr, false)
28
+ elif isinstance(cond, Basic) and cond.has(Piecewise):
29
+ cond = piecewise_fold(cond)
30
+ if isinstance(cond, Piecewise):
31
+ cond = cond.rewrite(ITE)
32
+
33
+ if not isinstance(cond, Boolean):
34
+ raise TypeError(filldedent('''
35
+ Second argument must be a Boolean,
36
+ not `%s`''' % func_name(cond)))
37
+ return Tuple.__new__(cls, expr, cond)
38
+
39
+ @property
40
+ def expr(self):
41
+ """
42
+ Returns the expression of this pair.
43
+ """
44
+ return self.args[0]
45
+
46
+ @property
47
+ def cond(self):
48
+ """
49
+ Returns the condition of this pair.
50
+ """
51
+ return self.args[1]
52
+
53
+ @property
54
+ def is_commutative(self):
55
+ return self.expr.is_commutative
56
+
57
+ def __iter__(self):
58
+ yield self.expr
59
+ yield self.cond
60
+
61
+ def _eval_simplify(self, **kwargs):
62
+ return self.func(*[a.simplify(**kwargs) for a in self.args])
63
+
64
+
65
+ class Piecewise(DefinedFunction):
66
+ """
67
+ Represents a piecewise function.
68
+
69
+ Usage:
70
+
71
+ Piecewise( (expr,cond), (expr,cond), ... )
72
+ - Each argument is a 2-tuple defining an expression and condition
73
+ - The conds are evaluated in turn returning the first that is True.
74
+ If any of the evaluated conds are not explicitly False,
75
+ e.g. ``x < 1``, the function is returned in symbolic form.
76
+ - If the function is evaluated at a place where all conditions are False,
77
+ nan will be returned.
78
+ - Pairs where the cond is explicitly False, will be removed and no pair
79
+ appearing after a True condition will ever be retained. If a single
80
+ pair with a True condition remains, it will be returned, even when
81
+ evaluation is False.
82
+
83
+ Examples
84
+ ========
85
+
86
+ >>> from sympy import Piecewise, log, piecewise_fold
87
+ >>> from sympy.abc import x, y
88
+ >>> f = x**2
89
+ >>> g = log(x)
90
+ >>> p = Piecewise((0, x < -1), (f, x <= 1), (g, True))
91
+ >>> p.subs(x,1)
92
+ 1
93
+ >>> p.subs(x,5)
94
+ log(5)
95
+
96
+ Booleans can contain Piecewise elements:
97
+
98
+ >>> cond = (x < y).subs(x, Piecewise((2, x < 0), (3, True))); cond
99
+ Piecewise((2, x < 0), (3, True)) < y
100
+
101
+ The folded version of this results in a Piecewise whose
102
+ expressions are Booleans:
103
+
104
+ >>> folded_cond = piecewise_fold(cond); folded_cond
105
+ Piecewise((2 < y, x < 0), (3 < y, True))
106
+
107
+ When a Boolean containing Piecewise (like cond) or a Piecewise
108
+ with Boolean expressions (like folded_cond) is used as a condition,
109
+ it is converted to an equivalent :class:`~.ITE` object:
110
+
111
+ >>> Piecewise((1, folded_cond))
112
+ Piecewise((1, ITE(x < 0, y > 2, y > 3)))
113
+
114
+ When a condition is an ``ITE``, it will be converted to a simplified
115
+ Boolean expression:
116
+
117
+ >>> piecewise_fold(_)
118
+ Piecewise((1, ((x >= 0) | (y > 2)) & ((y > 3) | (x < 0))))
119
+
120
+ See Also
121
+ ========
122
+
123
+ piecewise_fold
124
+ piecewise_exclusive
125
+ ITE
126
+ """
127
+
128
+ nargs = None
129
+ is_Piecewise = True
130
+
131
+ def __new__(cls, *args, **options):
132
+ if len(args) == 0:
133
+ raise TypeError("At least one (expr, cond) pair expected.")
134
+ # (Try to) sympify args first
135
+ newargs = []
136
+ for ec in args:
137
+ # ec could be a ExprCondPair or a tuple
138
+ pair = ExprCondPair(*getattr(ec, 'args', ec))
139
+ cond = pair.cond
140
+ if cond is false:
141
+ continue
142
+ newargs.append(pair)
143
+ if cond is true:
144
+ break
145
+
146
+ eval = options.pop('evaluate', global_parameters.evaluate)
147
+ if eval:
148
+ r = cls.eval(*newargs)
149
+ if r is not None:
150
+ return r
151
+ elif len(newargs) == 1 and newargs[0].cond == True:
152
+ return newargs[0].expr
153
+
154
+ return Basic.__new__(cls, *newargs, **options)
155
+
156
+ @classmethod
157
+ def eval(cls, *_args):
158
+ """Either return a modified version of the args or, if no
159
+ modifications were made, return None.
160
+
161
+ Modifications that are made here:
162
+
163
+ 1. relationals are made canonical
164
+ 2. any False conditions are dropped
165
+ 3. any repeat of a previous condition is ignored
166
+ 4. any args past one with a true condition are dropped
167
+
168
+ If there are no args left, nan will be returned.
169
+ If there is a single arg with a True condition, its
170
+ corresponding expression will be returned.
171
+
172
+ EXAMPLES
173
+ ========
174
+
175
+ >>> from sympy import Piecewise
176
+ >>> from sympy.abc import x
177
+ >>> cond = -x < -1
178
+ >>> args = [(1, cond), (4, cond), (3, False), (2, True), (5, x < 1)]
179
+ >>> Piecewise(*args, evaluate=False)
180
+ Piecewise((1, -x < -1), (4, -x < -1), (2, True))
181
+ >>> Piecewise(*args)
182
+ Piecewise((1, x > 1), (2, True))
183
+ """
184
+ if not _args:
185
+ return Undefined
186
+
187
+ if len(_args) == 1 and _args[0][-1] == True:
188
+ return _args[0][0]
189
+
190
+ newargs = _piecewise_collapse_arguments(_args)
191
+
192
+ # some conditions may have been redundant
193
+ missing = len(newargs) != len(_args)
194
+ # some conditions may have changed
195
+ same = all(a == b for a, b in zip(newargs, _args))
196
+ # if either change happened we return the expr with the
197
+ # updated args
198
+ if not newargs:
199
+ raise ValueError(filldedent('''
200
+ There are no conditions (or none that
201
+ are not trivially false) to define an
202
+ expression.'''))
203
+ if missing or not same:
204
+ return cls(*newargs)
205
+
206
+ def doit(self, **hints):
207
+ """
208
+ Evaluate this piecewise function.
209
+ """
210
+ newargs = []
211
+ for e, c in self.args:
212
+ if hints.get('deep', True):
213
+ if isinstance(e, Basic):
214
+ newe = e.doit(**hints)
215
+ if newe != self:
216
+ e = newe
217
+ if isinstance(c, Basic):
218
+ c = c.doit(**hints)
219
+ newargs.append((e, c))
220
+ return self.func(*newargs)
221
+
222
+ def _eval_simplify(self, **kwargs):
223
+ return piecewise_simplify(self, **kwargs)
224
+
225
+ def _eval_as_leading_term(self, x, logx, cdir):
226
+ for e, c in self.args:
227
+ if c == True or c.subs(x, 0) == True:
228
+ return e.as_leading_term(x)
229
+
230
+ def _eval_adjoint(self):
231
+ return self.func(*[(e.adjoint(), c) for e, c in self.args])
232
+
233
+ def _eval_conjugate(self):
234
+ return self.func(*[(e.conjugate(), c) for e, c in self.args])
235
+
236
+ def _eval_derivative(self, x):
237
+ return self.func(*[(diff(e, x), c) for e, c in self.args])
238
+
239
+ def _eval_evalf(self, prec):
240
+ return self.func(*[(e._evalf(prec), c) for e, c in self.args])
241
+
242
+ def _eval_is_meromorphic(self, x, a):
243
+ # Conditions often implicitly assume that the argument is real.
244
+ # Hence, there needs to be some check for as_set.
245
+ if not a.is_real:
246
+ return None
247
+
248
+ # Then, scan ExprCondPairs in the given order to find a piece that would contain a,
249
+ # possibly as a boundary point.
250
+ for e, c in self.args:
251
+ cond = c.subs(x, a)
252
+
253
+ if cond.is_Relational:
254
+ return None
255
+ if a in c.as_set().boundary:
256
+ return None
257
+ # Apply expression if a is an interior point of the domain of e.
258
+ if cond:
259
+ return e._eval_is_meromorphic(x, a)
260
+
261
+ def piecewise_integrate(self, x, **kwargs):
262
+ """Return the Piecewise with each expression being
263
+ replaced with its antiderivative. To obtain a continuous
264
+ antiderivative, use the :func:`~.integrate` function or method.
265
+
266
+ Examples
267
+ ========
268
+
269
+ >>> from sympy import Piecewise
270
+ >>> from sympy.abc import x
271
+ >>> p = Piecewise((0, x < 0), (1, x < 1), (2, True))
272
+ >>> p.piecewise_integrate(x)
273
+ Piecewise((0, x < 0), (x, x < 1), (2*x, True))
274
+
275
+ Note that this does not give a continuous function, e.g.
276
+ at x = 1 the 3rd condition applies and the antiderivative
277
+ there is 2*x so the value of the antiderivative is 2:
278
+
279
+ >>> anti = _
280
+ >>> anti.subs(x, 1)
281
+ 2
282
+
283
+ The continuous derivative accounts for the integral *up to*
284
+ the point of interest, however:
285
+
286
+ >>> p.integrate(x)
287
+ Piecewise((0, x < 0), (x, x < 1), (2*x - 1, True))
288
+ >>> _.subs(x, 1)
289
+ 1
290
+
291
+ See Also
292
+ ========
293
+ Piecewise._eval_integral
294
+ """
295
+ from sympy.integrals import integrate
296
+ return self.func(*[(integrate(e, x, **kwargs), c) for e, c in self.args])
297
+
298
+ def _handle_irel(self, x, handler):
299
+ """Return either None (if the conditions of self depend only on x) else
300
+ a Piecewise expression whose expressions (handled by the handler that
301
+ was passed) are paired with the governing x-independent relationals,
302
+ e.g. Piecewise((A, a(x) & b(y)), (B, c(x) | c(y)) ->
303
+ Piecewise(
304
+ (handler(Piecewise((A, a(x) & True), (B, c(x) | True)), b(y) & c(y)),
305
+ (handler(Piecewise((A, a(x) & True), (B, c(x) | False)), b(y)),
306
+ (handler(Piecewise((A, a(x) & False), (B, c(x) | True)), c(y)),
307
+ (handler(Piecewise((A, a(x) & False), (B, c(x) | False)), True))
308
+ """
309
+ # identify governing relationals
310
+ rel = self.atoms(Relational)
311
+ irel = list(ordered([r for r in rel if x not in r.free_symbols
312
+ and r not in (S.true, S.false)]))
313
+ if irel:
314
+ args = {}
315
+ exprinorder = []
316
+ for truth in product((1, 0), repeat=len(irel)):
317
+ reps = dict(zip(irel, truth))
318
+ # only store the true conditions since the false are implied
319
+ # when they appear lower in the Piecewise args
320
+ if 1 not in truth:
321
+ cond = None # flag this one so it doesn't get combined
322
+ else:
323
+ andargs = Tuple(*[i for i in reps if reps[i]])
324
+ free = list(andargs.free_symbols)
325
+ if len(free) == 1:
326
+ from sympy.solvers.inequalities import (
327
+ reduce_inequalities, _solve_inequality)
328
+ try:
329
+ t = reduce_inequalities(andargs, free[0])
330
+ # ValueError when there are potentially
331
+ # nonvanishing imaginary parts
332
+ except (ValueError, NotImplementedError):
333
+ # at least isolate free symbol on left
334
+ t = And(*[_solve_inequality(
335
+ a, free[0], linear=True)
336
+ for a in andargs])
337
+ else:
338
+ t = And(*andargs)
339
+ if t is S.false:
340
+ continue # an impossible combination
341
+ cond = t
342
+ expr = handler(self.xreplace(reps))
343
+ if isinstance(expr, self.func) and len(expr.args) == 1:
344
+ expr, econd = expr.args[0]
345
+ cond = And(econd, True if cond is None else cond)
346
+ # the ec pairs are being collected since all possibilities
347
+ # are being enumerated, but don't put the last one in since
348
+ # its expr might match a previous expression and it
349
+ # must appear last in the args
350
+ if cond is not None:
351
+ args.setdefault(expr, []).append(cond)
352
+ # but since we only store the true conditions we must maintain
353
+ # the order so that the expression with the most true values
354
+ # comes first
355
+ exprinorder.append(expr)
356
+ # convert collected conditions as args of Or
357
+ for k in args:
358
+ args[k] = Or(*args[k])
359
+ # take them in the order obtained
360
+ args = [(e, args[e]) for e in uniq(exprinorder)]
361
+ # add in the last arg
362
+ args.append((expr, True))
363
+ return Piecewise(*args)
364
+
365
+ def _eval_integral(self, x, _first=True, **kwargs):
366
+ """Return the indefinite integral of the
367
+ Piecewise such that subsequent substitution of x with a
368
+ value will give the value of the integral (not including
369
+ the constant of integration) up to that point. To only
370
+ integrate the individual parts of Piecewise, use the
371
+ ``piecewise_integrate`` method.
372
+
373
+ Examples
374
+ ========
375
+
376
+ >>> from sympy import Piecewise
377
+ >>> from sympy.abc import x
378
+ >>> p = Piecewise((0, x < 0), (1, x < 1), (2, True))
379
+ >>> p.integrate(x)
380
+ Piecewise((0, x < 0), (x, x < 1), (2*x - 1, True))
381
+ >>> p.piecewise_integrate(x)
382
+ Piecewise((0, x < 0), (x, x < 1), (2*x, True))
383
+
384
+ See Also
385
+ ========
386
+ Piecewise.piecewise_integrate
387
+ """
388
+ from sympy.integrals.integrals import integrate
389
+
390
+ if _first:
391
+ def handler(ipw):
392
+ if isinstance(ipw, self.func):
393
+ return ipw._eval_integral(x, _first=False, **kwargs)
394
+ else:
395
+ return ipw.integrate(x, **kwargs)
396
+ irv = self._handle_irel(x, handler)
397
+ if irv is not None:
398
+ return irv
399
+
400
+ # handle a Piecewise from -oo to oo with and no x-independent relationals
401
+ # -----------------------------------------------------------------------
402
+ ok, abei = self._intervals(x)
403
+ if not ok:
404
+ from sympy.integrals.integrals import Integral
405
+ return Integral(self, x) # unevaluated
406
+
407
+ pieces = [(a, b) for a, b, _, _ in abei]
408
+ oo = S.Infinity
409
+ done = [(-oo, oo, -1)]
410
+ for k, p in enumerate(pieces):
411
+ if p == (-oo, oo):
412
+ # all undone intervals will get this key
413
+ for j, (a, b, i) in enumerate(done):
414
+ if i == -1:
415
+ done[j] = a, b, k
416
+ break # nothing else to consider
417
+ N = len(done) - 1
418
+ for j, (a, b, i) in enumerate(reversed(done)):
419
+ if i == -1:
420
+ j = N - j
421
+ done[j: j + 1] = _clip(p, (a, b), k)
422
+ done = [(a, b, i) for a, b, i in done if a != b]
423
+
424
+ # append an arg if there is a hole so a reference to
425
+ # argument -1 will give Undefined
426
+ if any(i == -1 for (a, b, i) in done):
427
+ abei.append((-oo, oo, Undefined, -1))
428
+
429
+ # return the sum of the intervals
430
+ args = []
431
+ sum = None
432
+ for a, b, i in done:
433
+ anti = integrate(abei[i][-2], x, **kwargs)
434
+ if sum is None:
435
+ sum = anti
436
+ else:
437
+ sum = sum.subs(x, a)
438
+ e = anti._eval_interval(x, a, x)
439
+ if sum.has(*_illegal) or e.has(*_illegal):
440
+ sum = anti
441
+ else:
442
+ sum += e
443
+ # see if we know whether b is contained in original
444
+ # condition
445
+ if b is S.Infinity:
446
+ cond = True
447
+ elif self.args[abei[i][-1]].cond.subs(x, b) == False:
448
+ cond = (x < b)
449
+ else:
450
+ cond = (x <= b)
451
+ args.append((sum, cond))
452
+ return Piecewise(*args)
453
+
454
+ def _eval_interval(self, sym, a, b, _first=True):
455
+ """Evaluates the function along the sym in a given interval [a, b]"""
456
+ # FIXME: Currently complex intervals are not supported. A possible
457
+ # replacement algorithm, discussed in issue 5227, can be found in the
458
+ # following papers;
459
+ # http://portal.acm.org/citation.cfm?id=281649
460
+ # http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.4127&rep=rep1&type=pdf
461
+
462
+ if a is None or b is None:
463
+ # In this case, it is just simple substitution
464
+ return super()._eval_interval(sym, a, b)
465
+ else:
466
+ x, lo, hi = map(as_Basic, (sym, a, b))
467
+
468
+ if _first: # get only x-dependent relationals
469
+ def handler(ipw):
470
+ if isinstance(ipw, self.func):
471
+ return ipw._eval_interval(x, lo, hi, _first=None)
472
+ else:
473
+ return ipw._eval_interval(x, lo, hi)
474
+ irv = self._handle_irel(x, handler)
475
+ if irv is not None:
476
+ return irv
477
+
478
+ if (lo < hi) is S.false or (
479
+ lo is S.Infinity or hi is S.NegativeInfinity):
480
+ rv = self._eval_interval(x, hi, lo, _first=False)
481
+ if isinstance(rv, Piecewise):
482
+ rv = Piecewise(*[(-e, c) for e, c in rv.args])
483
+ else:
484
+ rv = -rv
485
+ return rv
486
+
487
+ if (lo < hi) is S.true or (
488
+ hi is S.Infinity or lo is S.NegativeInfinity):
489
+ pass
490
+ else:
491
+ _a = Dummy('lo')
492
+ _b = Dummy('hi')
493
+ a = lo if lo.is_comparable else _a
494
+ b = hi if hi.is_comparable else _b
495
+ pos = self._eval_interval(x, a, b, _first=False)
496
+ if a == _a and b == _b:
497
+ # it's purely symbolic so just swap lo and hi and
498
+ # change the sign to get the value for when lo > hi
499
+ neg, pos = (-pos.xreplace({_a: hi, _b: lo}),
500
+ pos.xreplace({_a: lo, _b: hi}))
501
+ else:
502
+ # at least one of the bounds was comparable, so allow
503
+ # _eval_interval to use that information when computing
504
+ # the interval with lo and hi reversed
505
+ neg, pos = (-self._eval_interval(x, hi, lo, _first=False),
506
+ pos.xreplace({_a: lo, _b: hi}))
507
+
508
+ # allow simplification based on ordering of lo and hi
509
+ p = Dummy('', positive=True)
510
+ if lo.is_Symbol:
511
+ pos = pos.xreplace({lo: hi - p}).xreplace({p: hi - lo})
512
+ neg = neg.xreplace({lo: hi + p}).xreplace({p: lo - hi})
513
+ elif hi.is_Symbol:
514
+ pos = pos.xreplace({hi: lo + p}).xreplace({p: hi - lo})
515
+ neg = neg.xreplace({hi: lo - p}).xreplace({p: lo - hi})
516
+ # evaluate limits that may have unevaluate Min/Max
517
+ touch = lambda _: _.replace(
518
+ lambda x: isinstance(x, (Min, Max)),
519
+ lambda x: x.func(*x.args))
520
+ neg = touch(neg)
521
+ pos = touch(pos)
522
+ # assemble return expression; make the first condition be Lt
523
+ # b/c then the first expression will look the same whether
524
+ # the lo or hi limit is symbolic
525
+ if a == _a: # the lower limit was symbolic
526
+ rv = Piecewise(
527
+ (pos,
528
+ lo < hi),
529
+ (neg,
530
+ True))
531
+ else:
532
+ rv = Piecewise(
533
+ (neg,
534
+ hi < lo),
535
+ (pos,
536
+ True))
537
+
538
+ if rv == Undefined:
539
+ raise ValueError("Can't integrate across undefined region.")
540
+ if any(isinstance(i, Piecewise) for i in (pos, neg)):
541
+ rv = piecewise_fold(rv)
542
+ return rv
543
+
544
+ # handle a Piecewise with lo <= hi and no x-independent relationals
545
+ # -----------------------------------------------------------------
546
+ ok, abei = self._intervals(x)
547
+ if not ok:
548
+ from sympy.integrals.integrals import Integral
549
+ # not being able to do the interval of f(x) can
550
+ # be stated as not being able to do the integral
551
+ # of f'(x) over the same range
552
+ return Integral(self.diff(x), (x, lo, hi)) # unevaluated
553
+
554
+ pieces = [(a, b) for a, b, _, _ in abei]
555
+ done = [(lo, hi, -1)]
556
+ oo = S.Infinity
557
+ for k, p in enumerate(pieces):
558
+ if p[:2] == (-oo, oo):
559
+ # all undone intervals will get this key
560
+ for j, (a, b, i) in enumerate(done):
561
+ if i == -1:
562
+ done[j] = a, b, k
563
+ break # nothing else to consider
564
+ N = len(done) - 1
565
+ for j, (a, b, i) in enumerate(reversed(done)):
566
+ if i == -1:
567
+ j = N - j
568
+ done[j: j + 1] = _clip(p, (a, b), k)
569
+ done = [(a, b, i) for a, b, i in done if a != b]
570
+
571
+ # return the sum of the intervals
572
+ sum = S.Zero
573
+ upto = None
574
+ for a, b, i in done:
575
+ if i == -1:
576
+ if upto is None:
577
+ return Undefined
578
+ # TODO simplify hi <= upto
579
+ return Piecewise((sum, hi <= upto), (Undefined, True))
580
+ sum += abei[i][-2]._eval_interval(x, a, b)
581
+ upto = b
582
+ return sum
583
+
584
+ def _intervals(self, sym, err_on_Eq=False):
585
+ r"""Return a bool and a message (when bool is False), else a
586
+ list of unique tuples, (a, b, e, i), where a and b
587
+ are the lower and upper bounds in which the expression e of
588
+ argument i in self is defined and $a < b$ (when involving
589
+ numbers) or $a \le b$ when involving symbols.
590
+
591
+ If there are any relationals not involving sym, or any
592
+ relational cannot be solved for sym, the bool will be False
593
+ a message be given as the second return value. The calling
594
+ routine should have removed such relationals before calling
595
+ this routine.
596
+
597
+ The evaluated conditions will be returned as ranges.
598
+ Discontinuous ranges will be returned separately with
599
+ identical expressions. The first condition that evaluates to
600
+ True will be returned as the last tuple with a, b = -oo, oo.
601
+ """
602
+ from sympy.solvers.inequalities import _solve_inequality
603
+
604
+ assert isinstance(self, Piecewise)
605
+
606
+ def nonsymfail(cond):
607
+ return False, filldedent('''
608
+ A condition not involving
609
+ %s appeared: %s''' % (sym, cond))
610
+
611
+ def _solve_relational(r):
612
+ if sym not in r.free_symbols:
613
+ return nonsymfail(r)
614
+ try:
615
+ rv = _solve_inequality(r, sym)
616
+ except NotImplementedError:
617
+ return False, 'Unable to solve relational %s for %s.' % (r, sym)
618
+ if isinstance(rv, Relational):
619
+ free = rv.args[1].free_symbols
620
+ if rv.args[0] != sym or sym in free:
621
+ return False, 'Unable to solve relational %s for %s.' % (r, sym)
622
+ if rv.rel_op == '==':
623
+ # this equality has been affirmed to have the form
624
+ # Eq(sym, rhs) where rhs is sym-free; it represents
625
+ # a zero-width interval which will be ignored
626
+ # whether it is an isolated condition or contained
627
+ # within an And or an Or
628
+ rv = S.false
629
+ elif rv.rel_op == '!=':
630
+ try:
631
+ rv = Or(sym < rv.rhs, sym > rv.rhs)
632
+ except TypeError:
633
+ # e.g. x != I ==> all real x satisfy
634
+ rv = S.true
635
+ elif rv == (S.NegativeInfinity < sym) & (sym < S.Infinity):
636
+ rv = S.true
637
+ return True, rv
638
+
639
+ args = list(self.args)
640
+ # make self canonical wrt Relationals
641
+ keys = self.atoms(Relational)
642
+ reps = {}
643
+ for r in keys:
644
+ ok, s = _solve_relational(r)
645
+ if ok != True:
646
+ return False, ok
647
+ reps[r] = s
648
+ # process args individually so if any evaluate, their position
649
+ # in the original Piecewise will be known
650
+ args = [i.xreplace(reps) for i in self.args]
651
+
652
+ # precondition args
653
+ expr_cond = []
654
+ default = idefault = None
655
+ for i, (expr, cond) in enumerate(args):
656
+ if cond is S.false:
657
+ continue
658
+ if cond is S.true:
659
+ default = expr
660
+ idefault = i
661
+ break
662
+ if isinstance(cond, Eq):
663
+ # unanticipated condition, but it is here in case a
664
+ # replacement caused an Eq to appear
665
+ if err_on_Eq:
666
+ return False, 'encountered Eq condition: %s' % cond
667
+ continue # zero width interval
668
+
669
+ cond = to_cnf(cond)
670
+ if isinstance(cond, And):
671
+ cond = distribute_or_over_and(cond)
672
+
673
+ if isinstance(cond, Or):
674
+ expr_cond.extend(
675
+ [(i, expr, o) for o in cond.args
676
+ if not isinstance(o, Eq)])
677
+ elif cond is not S.false:
678
+ expr_cond.append((i, expr, cond))
679
+ elif cond is S.true:
680
+ default = expr
681
+ idefault = i
682
+ break
683
+
684
+ # determine intervals represented by conditions
685
+ int_expr = []
686
+ for iarg, expr, cond in expr_cond:
687
+ if isinstance(cond, And):
688
+ lower = S.NegativeInfinity
689
+ upper = S.Infinity
690
+ exclude = []
691
+ for cond2 in cond.args:
692
+ if not isinstance(cond2, Relational):
693
+ return False, 'expecting only Relationals'
694
+ if isinstance(cond2, Eq):
695
+ lower = upper # ignore
696
+ if err_on_Eq:
697
+ return False, 'encountered secondary Eq condition'
698
+ break
699
+ elif isinstance(cond2, Ne):
700
+ l, r = cond2.args
701
+ if l == sym:
702
+ exclude.append(r)
703
+ elif r == sym:
704
+ exclude.append(l)
705
+ else:
706
+ return nonsymfail(cond2)
707
+ continue
708
+ elif cond2.lts == sym:
709
+ upper = Min(cond2.gts, upper)
710
+ elif cond2.gts == sym:
711
+ lower = Max(cond2.lts, lower)
712
+ else:
713
+ return nonsymfail(cond2) # should never get here
714
+ if exclude:
715
+ exclude = list(ordered(exclude))
716
+ newcond = []
717
+ for i, e in enumerate(exclude):
718
+ if e < lower == True or e > upper == True:
719
+ continue
720
+ if not newcond:
721
+ newcond.append((None, lower)) # add a primer
722
+ newcond.append((newcond[-1][1], e))
723
+ newcond.append((newcond[-1][1], upper))
724
+ newcond.pop(0) # remove the primer
725
+ expr_cond.extend([(iarg, expr, And(i[0] < sym, sym < i[1])) for i in newcond])
726
+ continue
727
+ elif isinstance(cond, Relational) and cond.rel_op != '!=':
728
+ lower, upper = cond.lts, cond.gts # part 1: initialize with givens
729
+ if cond.lts == sym: # part 1a: expand the side ...
730
+ lower = S.NegativeInfinity # e.g. x <= 0 ---> -oo <= 0
731
+ elif cond.gts == sym: # part 1a: ... that can be expanded
732
+ upper = S.Infinity # e.g. x >= 0 ---> oo >= 0
733
+ else:
734
+ return nonsymfail(cond)
735
+ else:
736
+ return False, 'unrecognized condition: %s' % cond
737
+
738
+ upper = Max(lower, upper)
739
+ if err_on_Eq and lower == upper:
740
+ return False, 'encountered Eq condition'
741
+ if (lower >= upper) is not S.true:
742
+ int_expr.append((lower, upper, expr, iarg))
743
+
744
+ if default is not None:
745
+ int_expr.append(
746
+ (S.NegativeInfinity, S.Infinity, default, idefault))
747
+
748
+ return True, list(uniq(int_expr))
749
+
750
+ def _eval_nseries(self, x, n, logx, cdir=0):
751
+ args = [(ec.expr._eval_nseries(x, n, logx), ec.cond) for ec in self.args]
752
+ return self.func(*args)
753
+
754
+ def _eval_power(self, s):
755
+ return self.func(*[(e**s, c) for e, c in self.args])
756
+
757
+ def _eval_subs(self, old, new):
758
+ # this is strictly not necessary, but we can keep track
759
+ # of whether True or False conditions arise and be
760
+ # somewhat more efficient by avoiding other substitutions
761
+ # and avoiding invalid conditions that appear after a
762
+ # True condition
763
+ args = list(self.args)
764
+ args_exist = False
765
+ for i, (e, c) in enumerate(args):
766
+ c = c._subs(old, new)
767
+ if c != False:
768
+ args_exist = True
769
+ e = e._subs(old, new)
770
+ args[i] = (e, c)
771
+ if c == True:
772
+ break
773
+ if not args_exist:
774
+ args = ((Undefined, True),)
775
+ return self.func(*args)
776
+
777
+ def _eval_transpose(self):
778
+ return self.func(*[(e.transpose(), c) for e, c in self.args])
779
+
780
+ def _eval_template_is_attr(self, is_attr):
781
+ b = None
782
+ for expr, _ in self.args:
783
+ a = getattr(expr, is_attr)
784
+ if a is None:
785
+ return
786
+ if b is None:
787
+ b = a
788
+ elif b is not a:
789
+ return
790
+ return b
791
+
792
+ _eval_is_finite = lambda self: self._eval_template_is_attr(
793
+ 'is_finite')
794
+ _eval_is_complex = lambda self: self._eval_template_is_attr('is_complex')
795
+ _eval_is_even = lambda self: self._eval_template_is_attr('is_even')
796
+ _eval_is_imaginary = lambda self: self._eval_template_is_attr(
797
+ 'is_imaginary')
798
+ _eval_is_integer = lambda self: self._eval_template_is_attr('is_integer')
799
+ _eval_is_irrational = lambda self: self._eval_template_is_attr(
800
+ 'is_irrational')
801
+ _eval_is_negative = lambda self: self._eval_template_is_attr('is_negative')
802
+ _eval_is_nonnegative = lambda self: self._eval_template_is_attr(
803
+ 'is_nonnegative')
804
+ _eval_is_nonpositive = lambda self: self._eval_template_is_attr(
805
+ 'is_nonpositive')
806
+ _eval_is_nonzero = lambda self: self._eval_template_is_attr(
807
+ 'is_nonzero')
808
+ _eval_is_odd = lambda self: self._eval_template_is_attr('is_odd')
809
+ _eval_is_polar = lambda self: self._eval_template_is_attr('is_polar')
810
+ _eval_is_positive = lambda self: self._eval_template_is_attr('is_positive')
811
+ _eval_is_extended_real = lambda self: self._eval_template_is_attr(
812
+ 'is_extended_real')
813
+ _eval_is_extended_positive = lambda self: self._eval_template_is_attr(
814
+ 'is_extended_positive')
815
+ _eval_is_extended_negative = lambda self: self._eval_template_is_attr(
816
+ 'is_extended_negative')
817
+ _eval_is_extended_nonzero = lambda self: self._eval_template_is_attr(
818
+ 'is_extended_nonzero')
819
+ _eval_is_extended_nonpositive = lambda self: self._eval_template_is_attr(
820
+ 'is_extended_nonpositive')
821
+ _eval_is_extended_nonnegative = lambda self: self._eval_template_is_attr(
822
+ 'is_extended_nonnegative')
823
+ _eval_is_real = lambda self: self._eval_template_is_attr('is_real')
824
+ _eval_is_zero = lambda self: self._eval_template_is_attr(
825
+ 'is_zero')
826
+
827
+ @classmethod
828
+ def __eval_cond(cls, cond):
829
+ """Return the truth value of the condition."""
830
+ if cond == True:
831
+ return True
832
+ if isinstance(cond, Eq):
833
+ try:
834
+ diff = cond.lhs - cond.rhs
835
+ if diff.is_commutative:
836
+ return diff.is_zero
837
+ except TypeError:
838
+ pass
839
+
840
+ def as_expr_set_pairs(self, domain=None):
841
+ """Return tuples for each argument of self that give
842
+ the expression and the interval in which it is valid
843
+ which is contained within the given domain.
844
+ If a condition cannot be converted to a set, an error
845
+ will be raised. The variable of the conditions is
846
+ assumed to be real; sets of real values are returned.
847
+
848
+ Examples
849
+ ========
850
+
851
+ >>> from sympy import Piecewise, Interval
852
+ >>> from sympy.abc import x
853
+ >>> p = Piecewise(
854
+ ... (1, x < 2),
855
+ ... (2,(x > 0) & (x < 4)),
856
+ ... (3, True))
857
+ >>> p.as_expr_set_pairs()
858
+ [(1, Interval.open(-oo, 2)),
859
+ (2, Interval.Ropen(2, 4)),
860
+ (3, Interval(4, oo))]
861
+ >>> p.as_expr_set_pairs(Interval(0, 3))
862
+ [(1, Interval.Ropen(0, 2)),
863
+ (2, Interval(2, 3))]
864
+ """
865
+ if domain is None:
866
+ domain = S.Reals
867
+ exp_sets = []
868
+ U = domain
869
+ complex = not domain.is_subset(S.Reals)
870
+ cond_free = set()
871
+ for expr, cond in self.args:
872
+ cond_free |= cond.free_symbols
873
+ if len(cond_free) > 1:
874
+ raise NotImplementedError(filldedent('''
875
+ multivariate conditions are not handled.'''))
876
+ if complex:
877
+ for i in cond.atoms(Relational):
878
+ if not isinstance(i, (Eq, Ne)):
879
+ raise ValueError(filldedent('''
880
+ Inequalities in the complex domain are
881
+ not supported. Try the real domain by
882
+ setting domain=S.Reals'''))
883
+ cond_int = U.intersect(cond.as_set())
884
+ U = U - cond_int
885
+ if cond_int != S.EmptySet:
886
+ exp_sets.append((expr, cond_int))
887
+ return exp_sets
888
+
889
+ def _eval_rewrite_as_ITE(self, *args, **kwargs):
890
+ byfree = {}
891
+ args = list(args)
892
+ default = any(c == True for b, c in args)
893
+ for i, (b, c) in enumerate(args):
894
+ if not isinstance(b, Boolean) and b != True:
895
+ raise TypeError(filldedent('''
896
+ Expecting Boolean or bool but got `%s`
897
+ ''' % func_name(b)))
898
+ if c == True:
899
+ break
900
+ # loop over independent conditions for this b
901
+ for c in c.args if isinstance(c, Or) else [c]:
902
+ free = c.free_symbols
903
+ x = free.pop()
904
+ try:
905
+ byfree[x] = byfree.setdefault(
906
+ x, S.EmptySet).union(c.as_set())
907
+ except NotImplementedError:
908
+ if not default:
909
+ raise NotImplementedError(filldedent('''
910
+ A method to determine whether a multivariate
911
+ conditional is consistent with a complete coverage
912
+ of all variables has not been implemented so the
913
+ rewrite is being stopped after encountering `%s`.
914
+ This error would not occur if a default expression
915
+ like `(foo, True)` were given.
916
+ ''' % c))
917
+ if byfree[x] in (S.UniversalSet, S.Reals):
918
+ # collapse the ith condition to True and break
919
+ args[i] = list(args[i])
920
+ c = args[i][1] = True
921
+ break
922
+ if c == True:
923
+ break
924
+ if c != True:
925
+ raise ValueError(filldedent('''
926
+ Conditions must cover all reals or a final default
927
+ condition `(foo, True)` must be given.
928
+ '''))
929
+ last, _ = args[i] # ignore all past ith arg
930
+ for a, c in reversed(args[:i]):
931
+ last = ITE(c, a, last)
932
+ return _canonical(last)
933
+
934
+ def _eval_rewrite_as_KroneckerDelta(self, *args, **kwargs):
935
+ from sympy.functions.special.tensor_functions import KroneckerDelta
936
+
937
+ rules = {
938
+ And: [False, False],
939
+ Or: [True, True],
940
+ Not: [True, False],
941
+ Eq: [None, None],
942
+ Ne: [None, None]
943
+ }
944
+
945
+ class UnrecognizedCondition(Exception):
946
+ pass
947
+
948
+ def rewrite(cond):
949
+ if isinstance(cond, Eq):
950
+ return KroneckerDelta(*cond.args)
951
+ if isinstance(cond, Ne):
952
+ return 1 - KroneckerDelta(*cond.args)
953
+
954
+ cls, args = type(cond), cond.args
955
+ if cls not in rules:
956
+ raise UnrecognizedCondition(cls)
957
+
958
+ b1, b2 = rules[cls]
959
+ k = Mul(*[1 - rewrite(c) for c in args]) if b1 else Mul(*[rewrite(c) for c in args])
960
+
961
+ if b2:
962
+ return 1 - k
963
+ return k
964
+
965
+ conditions = []
966
+ true_value = None
967
+ for value, cond in args:
968
+ if type(cond) in rules:
969
+ conditions.append((value, cond))
970
+ elif cond is S.true:
971
+ if true_value is None:
972
+ true_value = value
973
+ else:
974
+ return
975
+
976
+ if true_value is not None:
977
+ result = true_value
978
+
979
+ for value, cond in conditions[::-1]:
980
+ try:
981
+ k = rewrite(cond)
982
+ result = k * value + (1 - k) * result
983
+ except UnrecognizedCondition:
984
+ return
985
+
986
+ return result
987
+
988
+
989
+ def piecewise_fold(expr, evaluate=True):
990
+ """
991
+ Takes an expression containing a piecewise function and returns the
992
+ expression in piecewise form. In addition, any ITE conditions are
993
+ rewritten in negation normal form and simplified.
994
+
995
+ The final Piecewise is evaluated (default) but if the raw form
996
+ is desired, send ``evaluate=False``; if trivial evaluation is
997
+ desired, send ``evaluate=None`` and duplicate conditions and
998
+ processing of True and False will be handled.
999
+
1000
+ Examples
1001
+ ========
1002
+
1003
+ >>> from sympy import Piecewise, piecewise_fold, S
1004
+ >>> from sympy.abc import x
1005
+ >>> p = Piecewise((x, x < 1), (1, S(1) <= x))
1006
+ >>> piecewise_fold(x*p)
1007
+ Piecewise((x**2, x < 1), (x, True))
1008
+
1009
+ See Also
1010
+ ========
1011
+
1012
+ Piecewise
1013
+ piecewise_exclusive
1014
+ """
1015
+ if not isinstance(expr, Basic) or not expr.has(Piecewise):
1016
+ return expr
1017
+
1018
+ new_args = []
1019
+ if isinstance(expr, (ExprCondPair, Piecewise)):
1020
+ for e, c in expr.args:
1021
+ if not isinstance(e, Piecewise):
1022
+ e = piecewise_fold(e)
1023
+ # we don't keep Piecewise in condition because
1024
+ # it has to be checked to see that it's complete
1025
+ # and we convert it to ITE at that time
1026
+ assert not c.has(Piecewise) # pragma: no cover
1027
+ if isinstance(c, ITE):
1028
+ c = c.to_nnf()
1029
+ c = simplify_logic(c, form='cnf')
1030
+ if isinstance(e, Piecewise):
1031
+ new_args.extend([(piecewise_fold(ei), And(ci, c))
1032
+ for ei, ci in e.args])
1033
+ else:
1034
+ new_args.append((e, c))
1035
+ else:
1036
+ # Given
1037
+ # P1 = Piecewise((e11, c1), (e12, c2), A)
1038
+ # P2 = Piecewise((e21, c1), (e22, c2), B)
1039
+ # ...
1040
+ # the folding of f(P1, P2) is trivially
1041
+ # Piecewise(
1042
+ # (f(e11, e21), c1),
1043
+ # (f(e12, e22), c2),
1044
+ # (f(Piecewise(A), Piecewise(B)), True))
1045
+ # Certain objects end up rewriting themselves as thus, so
1046
+ # we do that grouping before the more generic folding.
1047
+ # The following applies this idea when f = Add or f = Mul
1048
+ # (and the expression is commutative).
1049
+ if expr.is_Add or expr.is_Mul and expr.is_commutative:
1050
+ p, args = sift(expr.args, lambda x: x.is_Piecewise, binary=True)
1051
+ pc = sift(p, lambda x: tuple([c for e,c in x.args]))
1052
+ for c in list(ordered(pc)):
1053
+ if len(pc[c]) > 1:
1054
+ pargs = [list(i.args) for i in pc[c]]
1055
+ # the first one is the same; there may be more
1056
+ com = common_prefix(*[
1057
+ [i.cond for i in j] for j in pargs])
1058
+ n = len(com)
1059
+ collected = []
1060
+ for i in range(n):
1061
+ collected.append((
1062
+ expr.func(*[ai[i].expr for ai in pargs]),
1063
+ com[i]))
1064
+ remains = []
1065
+ for a in pargs:
1066
+ if n == len(a): # no more args
1067
+ continue
1068
+ if a[n].cond == True: # no longer Piecewise
1069
+ remains.append(a[n].expr)
1070
+ else: # restore the remaining Piecewise
1071
+ remains.append(
1072
+ Piecewise(*a[n:], evaluate=False))
1073
+ if remains:
1074
+ collected.append((expr.func(*remains), True))
1075
+ args.append(Piecewise(*collected, evaluate=False))
1076
+ continue
1077
+ args.extend(pc[c])
1078
+ else:
1079
+ args = expr.args
1080
+ # fold
1081
+ folded = list(map(piecewise_fold, args))
1082
+ for ec in product(*[
1083
+ (i.args if isinstance(i, Piecewise) else
1084
+ [(i, true)]) for i in folded]):
1085
+ e, c = zip(*ec)
1086
+ new_args.append((expr.func(*e), And(*c)))
1087
+
1088
+ if evaluate is None:
1089
+ # don't return duplicate conditions, otherwise don't evaluate
1090
+ new_args = list(reversed([(e, c) for c, e in {
1091
+ c: e for e, c in reversed(new_args)}.items()]))
1092
+ rv = Piecewise(*new_args, evaluate=evaluate)
1093
+ if evaluate is None and len(rv.args) == 1 and rv.args[0].cond == True:
1094
+ return rv.args[0].expr
1095
+ if any(s.expr.has(Piecewise) for p in rv.atoms(Piecewise) for s in p.args):
1096
+ return piecewise_fold(rv)
1097
+ return rv
1098
+
1099
+
1100
+ def _clip(A, B, k):
1101
+ """Return interval B as intervals that are covered by A (keyed
1102
+ to k) and all other intervals of B not covered by A keyed to -1.
1103
+
1104
+ The reference point of each interval is the rhs; if the lhs is
1105
+ greater than the rhs then an interval of zero width interval will
1106
+ result, e.g. (4, 1) is treated like (1, 1).
1107
+
1108
+ Examples
1109
+ ========
1110
+
1111
+ >>> from sympy.functions.elementary.piecewise import _clip
1112
+ >>> from sympy import Tuple
1113
+ >>> A = Tuple(1, 3)
1114
+ >>> B = Tuple(2, 4)
1115
+ >>> _clip(A, B, 0)
1116
+ [(2, 3, 0), (3, 4, -1)]
1117
+
1118
+ Interpretation: interval portion (2, 3) of interval (2, 4) is
1119
+ covered by interval (1, 3) and is keyed to 0 as requested;
1120
+ interval (3, 4) was not covered by (1, 3) and is keyed to -1.
1121
+ """
1122
+ a, b = B
1123
+ c, d = A
1124
+ c, d = Min(Max(c, a), b), Min(Max(d, a), b)
1125
+ a = Min(a, b)
1126
+ p = []
1127
+ if a != c:
1128
+ p.append((a, c, -1))
1129
+ else:
1130
+ pass
1131
+ if c != d:
1132
+ p.append((c, d, k))
1133
+ else:
1134
+ pass
1135
+ if b != d:
1136
+ if d == c and p and p[-1][-1] == -1:
1137
+ p[-1] = p[-1][0], b, -1
1138
+ else:
1139
+ p.append((d, b, -1))
1140
+ else:
1141
+ pass
1142
+
1143
+ return p
1144
+
1145
+
1146
+ def piecewise_simplify_arguments(expr, **kwargs):
1147
+ from sympy.simplify.simplify import simplify
1148
+
1149
+ # simplify conditions
1150
+ f1 = expr.args[0].cond.free_symbols
1151
+ args = None
1152
+ if len(f1) == 1 and not expr.atoms(Eq):
1153
+ x = f1.pop()
1154
+ # this won't return intervals involving Eq
1155
+ # and it won't handle symbols treated as
1156
+ # booleans
1157
+ ok, abe_ = expr._intervals(x, err_on_Eq=True)
1158
+ def include(c, x, a):
1159
+ "return True if c.subs(x, a) is True, else False"
1160
+ try:
1161
+ return c.subs(x, a) == True
1162
+ except TypeError:
1163
+ return False
1164
+ if ok:
1165
+ args = []
1166
+ covered = S.EmptySet
1167
+ from sympy.sets.sets import Interval
1168
+ for a, b, e, i in abe_:
1169
+ c = expr.args[i].cond
1170
+ incl_a = include(c, x, a)
1171
+ incl_b = include(c, x, b)
1172
+ iv = Interval(a, b, not incl_a, not incl_b)
1173
+ cset = iv - covered
1174
+ if not cset:
1175
+ continue
1176
+ try:
1177
+ a = cset.inf
1178
+ except NotImplementedError:
1179
+ pass # continue with the given `a`
1180
+ else:
1181
+ incl_a = include(c, x, a)
1182
+ if incl_a and incl_b:
1183
+ if a.is_infinite and b.is_infinite:
1184
+ c = S.true
1185
+ elif b.is_infinite:
1186
+ c = (x > a) if a in covered else (x >= a)
1187
+ elif a.is_infinite:
1188
+ c = (x <= b)
1189
+ elif a in covered:
1190
+ c = And(a < x, x <= b)
1191
+ else:
1192
+ c = And(a <= x, x <= b)
1193
+ elif incl_a:
1194
+ if a.is_infinite:
1195
+ c = (x < b)
1196
+ elif a in covered:
1197
+ c = And(a < x, x < b)
1198
+ else:
1199
+ c = And(a <= x, x < b)
1200
+ elif incl_b:
1201
+ if b.is_infinite:
1202
+ c = (x > a)
1203
+ else:
1204
+ c = And(a < x, x <= b)
1205
+ else:
1206
+ if a in covered:
1207
+ c = (x < b)
1208
+ else:
1209
+ c = And(a < x, x < b)
1210
+ covered |= iv
1211
+ if a is S.NegativeInfinity and incl_a:
1212
+ covered |= {S.NegativeInfinity}
1213
+ if b is S.Infinity and incl_b:
1214
+ covered |= {S.Infinity}
1215
+ args.append((e, c))
1216
+ if not S.Reals.is_subset(covered):
1217
+ args.append((Undefined, True))
1218
+ if args is None:
1219
+ args = list(expr.args)
1220
+ for i in range(len(args)):
1221
+ e, c = args[i]
1222
+ if isinstance(c, Basic):
1223
+ c = simplify(c, **kwargs)
1224
+ args[i] = (e, c)
1225
+
1226
+ # simplify expressions
1227
+ doit = kwargs.pop('doit', None)
1228
+ for i in range(len(args)):
1229
+ e, c = args[i]
1230
+ if isinstance(e, Basic):
1231
+ # Skip doit to avoid growth at every call for some integrals
1232
+ # and sums, see sympy/sympy#17165
1233
+ newe = simplify(e, doit=False, **kwargs)
1234
+ if newe != e:
1235
+ e = newe
1236
+ args[i] = (e, c)
1237
+
1238
+ # restore kwargs flag
1239
+ if doit is not None:
1240
+ kwargs['doit'] = doit
1241
+
1242
+ return Piecewise(*args)
1243
+
1244
+
1245
+ def _piecewise_collapse_arguments(_args):
1246
+ newargs = [] # the unevaluated conditions
1247
+ current_cond = set() # the conditions up to a given e, c pair
1248
+ for expr, cond in _args:
1249
+ cond = cond.replace(
1250
+ lambda _: _.is_Relational, _canonical_coeff)
1251
+ # Check here if expr is a Piecewise and collapse if one of
1252
+ # the conds in expr matches cond. This allows the collapsing
1253
+ # of Piecewise((Piecewise((x,x<0)),x<0)) to Piecewise((x,x<0)).
1254
+ # This is important when using piecewise_fold to simplify
1255
+ # multiple Piecewise instances having the same conds.
1256
+ # Eventually, this code should be able to collapse Piecewise's
1257
+ # having different intervals, but this will probably require
1258
+ # using the new assumptions.
1259
+ if isinstance(expr, Piecewise):
1260
+ unmatching = []
1261
+ for i, (e, c) in enumerate(expr.args):
1262
+ if c in current_cond:
1263
+ # this would already have triggered
1264
+ continue
1265
+ if c == cond:
1266
+ if c != True:
1267
+ # nothing past this condition will ever
1268
+ # trigger and only those args before this
1269
+ # that didn't match a previous condition
1270
+ # could possibly trigger
1271
+ if unmatching:
1272
+ expr = Piecewise(*(
1273
+ unmatching + [(e, c)]))
1274
+ else:
1275
+ expr = e
1276
+ break
1277
+ else:
1278
+ unmatching.append((e, c))
1279
+
1280
+ # check for condition repeats
1281
+ got = False
1282
+ # -- if an And contains a condition that was
1283
+ # already encountered, then the And will be
1284
+ # False: if the previous condition was False
1285
+ # then the And will be False and if the previous
1286
+ # condition is True then then we wouldn't get to
1287
+ # this point. In either case, we can skip this condition.
1288
+ for i in ([cond] +
1289
+ (list(cond.args) if isinstance(cond, And) else
1290
+ [])):
1291
+ if i in current_cond:
1292
+ got = True
1293
+ break
1294
+ if got:
1295
+ continue
1296
+
1297
+ # -- if not(c) is already in current_cond then c is
1298
+ # a redundant condition in an And. This does not
1299
+ # apply to Or, however: (e1, c), (e2, Or(~c, d))
1300
+ # is not (e1, c), (e2, d) because if c and d are
1301
+ # both False this would give no results when the
1302
+ # true answer should be (e2, True)
1303
+ if isinstance(cond, And):
1304
+ nonredundant = []
1305
+ for c in cond.args:
1306
+ if isinstance(c, Relational):
1307
+ if c.negated.canonical in current_cond:
1308
+ continue
1309
+ # if a strict inequality appears after
1310
+ # a non-strict one, then the condition is
1311
+ # redundant
1312
+ if isinstance(c, (Lt, Gt)) and (
1313
+ c.weak in current_cond):
1314
+ cond = False
1315
+ break
1316
+ nonredundant.append(c)
1317
+ else:
1318
+ cond = cond.func(*nonredundant)
1319
+ elif isinstance(cond, Relational):
1320
+ if cond.negated.canonical in current_cond:
1321
+ cond = S.true
1322
+
1323
+ current_cond.add(cond)
1324
+
1325
+ # collect successive e,c pairs when exprs or cond match
1326
+ if newargs:
1327
+ if newargs[-1].expr == expr:
1328
+ orcond = Or(cond, newargs[-1].cond)
1329
+ if isinstance(orcond, (And, Or)):
1330
+ orcond = distribute_and_over_or(orcond)
1331
+ newargs[-1] = ExprCondPair(expr, orcond)
1332
+ continue
1333
+ elif newargs[-1].cond == cond:
1334
+ continue
1335
+ newargs.append(ExprCondPair(expr, cond))
1336
+ return newargs
1337
+
1338
+
1339
+ _blessed = lambda e: getattr(e.lhs, '_diff_wrt', False) and (
1340
+ getattr(e.rhs, '_diff_wrt', None) or
1341
+ isinstance(e.rhs, (Rational, NumberSymbol)))
1342
+
1343
+
1344
+ def piecewise_simplify(expr, **kwargs):
1345
+ expr = piecewise_simplify_arguments(expr, **kwargs)
1346
+ if not isinstance(expr, Piecewise):
1347
+ return expr
1348
+ args = list(expr.args)
1349
+
1350
+ args = _piecewise_simplify_eq_and(args)
1351
+ args = _piecewise_simplify_equal_to_next_segment(args)
1352
+ return Piecewise(*args)
1353
+
1354
+
1355
+ def _piecewise_simplify_equal_to_next_segment(args):
1356
+ """
1357
+ See if expressions valid for an Equal expression happens to evaluate
1358
+ to the same function as in the next piecewise segment, see:
1359
+ https://github.com/sympy/sympy/issues/8458
1360
+ """
1361
+ prevexpr = None
1362
+ for i, (expr, cond) in reversed(list(enumerate(args))):
1363
+ if prevexpr is not None:
1364
+ if isinstance(cond, And):
1365
+ eqs, other = sift(cond.args,
1366
+ lambda i: isinstance(i, Eq), binary=True)
1367
+ elif isinstance(cond, Eq):
1368
+ eqs, other = [cond], []
1369
+ else:
1370
+ eqs = other = []
1371
+ _prevexpr = prevexpr
1372
+ _expr = expr
1373
+ if eqs and not other:
1374
+ eqs = list(ordered(eqs))
1375
+ for e in eqs:
1376
+ # allow 2 args to collapse into 1 for any e
1377
+ # otherwise limit simplification to only simple-arg
1378
+ # Eq instances
1379
+ if len(args) == 2 or _blessed(e):
1380
+ _prevexpr = _prevexpr.subs(*e.args)
1381
+ _expr = _expr.subs(*e.args)
1382
+ # Did it evaluate to the same?
1383
+ if _prevexpr == _expr:
1384
+ # Set the expression for the Not equal section to the same
1385
+ # as the next. These will be merged when creating the new
1386
+ # Piecewise
1387
+ args[i] = args[i].func(args[i + 1][0], cond)
1388
+ else:
1389
+ # Update the expression that we compare against
1390
+ prevexpr = expr
1391
+ else:
1392
+ prevexpr = expr
1393
+ return args
1394
+
1395
+
1396
+ def _piecewise_simplify_eq_and(args):
1397
+ """
1398
+ Try to simplify conditions and the expression for
1399
+ equalities that are part of the condition, e.g.
1400
+ Piecewise((n, And(Eq(n,0), Eq(n + m, 0))), (1, True))
1401
+ -> Piecewise((0, And(Eq(n, 0), Eq(m, 0))), (1, True))
1402
+ """
1403
+ for i, (expr, cond) in enumerate(args):
1404
+ if isinstance(cond, And):
1405
+ eqs, other = sift(cond.args,
1406
+ lambda i: isinstance(i, Eq), binary=True)
1407
+ elif isinstance(cond, Eq):
1408
+ eqs, other = [cond], []
1409
+ else:
1410
+ eqs = other = []
1411
+ if eqs:
1412
+ eqs = list(ordered(eqs))
1413
+ for j, e in enumerate(eqs):
1414
+ # these blessed lhs objects behave like Symbols
1415
+ # and the rhs are simple replacements for the "symbols"
1416
+ if _blessed(e):
1417
+ expr = expr.subs(*e.args)
1418
+ eqs[j + 1:] = [ei.subs(*e.args) for ei in eqs[j + 1:]]
1419
+ other = [ei.subs(*e.args) for ei in other]
1420
+ cond = And(*(eqs + other))
1421
+ args[i] = args[i].func(expr, cond)
1422
+ return args
1423
+
1424
+
1425
+ def piecewise_exclusive(expr, *, skip_nan=False, deep=True):
1426
+ """
1427
+ Rewrite :class:`Piecewise` with mutually exclusive conditions.
1428
+
1429
+ Explanation
1430
+ ===========
1431
+
1432
+ SymPy represents the conditions of a :class:`Piecewise` in an
1433
+ "if-elif"-fashion, allowing more than one condition to be simultaneously
1434
+ True. The interpretation is that the first condition that is True is the
1435
+ case that holds. While this is a useful representation computationally it
1436
+ is not how a piecewise formula is typically shown in a mathematical text.
1437
+ The :func:`piecewise_exclusive` function can be used to rewrite any
1438
+ :class:`Piecewise` with more typical mutually exclusive conditions.
1439
+
1440
+ Note that further manipulation of the resulting :class:`Piecewise`, e.g.
1441
+ simplifying it, will most likely make it non-exclusive. Hence, this is
1442
+ primarily a function to be used in conjunction with printing the Piecewise
1443
+ or if one would like to reorder the expression-condition pairs.
1444
+
1445
+ If it is not possible to determine that all possibilities are covered by
1446
+ the different cases of the :class:`Piecewise` then a final
1447
+ :class:`~sympy.core.numbers.NaN` case will be included explicitly. This
1448
+ can be prevented by passing ``skip_nan=True``.
1449
+
1450
+ Examples
1451
+ ========
1452
+
1453
+ >>> from sympy import piecewise_exclusive, Symbol, Piecewise, S
1454
+ >>> x = Symbol('x', real=True)
1455
+ >>> p = Piecewise((0, x < 0), (S.Half, x <= 0), (1, True))
1456
+ >>> piecewise_exclusive(p)
1457
+ Piecewise((0, x < 0), (1/2, Eq(x, 0)), (1, x > 0))
1458
+ >>> piecewise_exclusive(Piecewise((2, x > 1)))
1459
+ Piecewise((2, x > 1), (nan, x <= 1))
1460
+ >>> piecewise_exclusive(Piecewise((2, x > 1)), skip_nan=True)
1461
+ Piecewise((2, x > 1))
1462
+
1463
+ Parameters
1464
+ ==========
1465
+
1466
+ expr: a SymPy expression.
1467
+ Any :class:`Piecewise` in the expression will be rewritten.
1468
+ skip_nan: ``bool`` (default ``False``)
1469
+ If ``skip_nan`` is set to ``True`` then a final
1470
+ :class:`~sympy.core.numbers.NaN` case will not be included.
1471
+ deep: ``bool`` (default ``True``)
1472
+ If ``deep`` is ``True`` then :func:`piecewise_exclusive` will rewrite
1473
+ any :class:`Piecewise` subexpressions in ``expr`` rather than just
1474
+ rewriting ``expr`` itself.
1475
+
1476
+ Returns
1477
+ =======
1478
+
1479
+ An expression equivalent to ``expr`` but where all :class:`Piecewise` have
1480
+ been rewritten with mutually exclusive conditions.
1481
+
1482
+ See Also
1483
+ ========
1484
+
1485
+ Piecewise
1486
+ piecewise_fold
1487
+ """
1488
+
1489
+ def make_exclusive(*pwargs):
1490
+
1491
+ cumcond = false
1492
+ newargs = []
1493
+
1494
+ # Handle the first n-1 cases
1495
+ for expr_i, cond_i in pwargs[:-1]:
1496
+ cancond = And(cond_i, Not(cumcond)).simplify()
1497
+ cumcond = Or(cond_i, cumcond).simplify()
1498
+ newargs.append((expr_i, cancond))
1499
+
1500
+ # For the nth case defer simplification of cumcond
1501
+ expr_n, cond_n = pwargs[-1]
1502
+ cancond_n = And(cond_n, Not(cumcond)).simplify()
1503
+ newargs.append((expr_n, cancond_n))
1504
+
1505
+ if not skip_nan:
1506
+ cumcond = Or(cond_n, cumcond).simplify()
1507
+ if cumcond is not true:
1508
+ newargs.append((Undefined, Not(cumcond).simplify()))
1509
+
1510
+ return Piecewise(*newargs, evaluate=False)
1511
+
1512
+ if deep:
1513
+ return expr.replace(Piecewise, make_exclusive)
1514
+ elif isinstance(expr, Piecewise):
1515
+ return make_exclusive(*expr.args)
1516
+ else:
1517
+ return expr
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/tests/test_complexes.py ADDED
@@ -0,0 +1,1030 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.function import (Derivative, Function, Lambda, expand, PoleError)
2
+ from sympy.core.numbers import (E, I, Rational, comp, nan, oo, pi, zoo)
3
+ from sympy.core.relational import Eq
4
+ from sympy.core.singleton import S
5
+ from sympy.core.symbol import (Symbol, symbols)
6
+ from sympy.functions.elementary.complexes import (Abs, adjoint, arg, conjugate, im, re, sign, transpose)
7
+ from sympy.functions.elementary.exponential import (exp, exp_polar, log)
8
+ from sympy.functions.elementary.miscellaneous import sqrt
9
+ from sympy.functions.elementary.piecewise import Piecewise
10
+ from sympy.functions.elementary.trigonometric import (acos, atan, atan2, cos, sin)
11
+ from sympy.functions.elementary.hyperbolic import sinh
12
+ from sympy.functions.special.delta_functions import (DiracDelta, Heaviside)
13
+ from sympy.integrals.integrals import Integral
14
+ from sympy.matrices.dense import Matrix
15
+ from sympy.matrices.expressions.funcmatrix import FunctionMatrix
16
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
17
+ from sympy.matrices.immutable import (ImmutableMatrix, ImmutableSparseMatrix)
18
+ from sympy.matrices import SparseMatrix
19
+ from sympy.sets.sets import Interval
20
+ from sympy.core.expr import unchanged
21
+ from sympy.core.function import ArgumentIndexError
22
+ from sympy.series.order import Order
23
+ from sympy.testing.pytest import XFAIL, raises, _both_exp_pow
24
+
25
+
26
+ def N_equals(a, b):
27
+ """Check whether two complex numbers are numerically close"""
28
+ return comp(a.n(), b.n(), 1.e-6)
29
+
30
+
31
+ def test_re():
32
+ x, y = symbols('x,y')
33
+ a, b = symbols('a,b', real=True)
34
+
35
+ r = Symbol('r', real=True)
36
+ i = Symbol('i', imaginary=True)
37
+
38
+ assert re(nan) is nan
39
+
40
+ assert re(oo) is oo
41
+ assert re(-oo) is -oo
42
+
43
+ assert re(0) == 0
44
+
45
+ assert re(1) == 1
46
+ assert re(-1) == -1
47
+
48
+ assert re(E) == E
49
+ assert re(-E) == -E
50
+
51
+ assert unchanged(re, x)
52
+ assert re(x*I) == -im(x)
53
+ assert re(r*I) == 0
54
+ assert re(r) == r
55
+ assert re(i*I) == I * i
56
+ assert re(i) == 0
57
+
58
+ assert re(x + y) == re(x) + re(y)
59
+ assert re(x + r) == re(x) + r
60
+
61
+ assert re(re(x)) == re(x)
62
+
63
+ assert re(2 + I) == 2
64
+ assert re(x + I) == re(x)
65
+
66
+ assert re(x + y*I) == re(x) - im(y)
67
+ assert re(x + r*I) == re(x)
68
+
69
+ assert re(log(2*I)) == log(2)
70
+
71
+ assert re((2 + I)**2).expand(complex=True) == 3
72
+
73
+ assert re(conjugate(x)) == re(x)
74
+ assert conjugate(re(x)) == re(x)
75
+
76
+ assert re(x).as_real_imag() == (re(x), 0)
77
+
78
+ assert re(i*r*x).diff(r) == re(i*x)
79
+ assert re(i*r*x).diff(i) == I*r*im(x)
80
+
81
+ assert re(
82
+ sqrt(a + b*I)) == (a**2 + b**2)**Rational(1, 4)*cos(atan2(b, a)/2)
83
+ assert re(a * (2 + b*I)) == 2*a
84
+
85
+ assert re((1 + sqrt(a + b*I))/2) == \
86
+ (a**2 + b**2)**Rational(1, 4)*cos(atan2(b, a)/2)/2 + S.Half
87
+
88
+ assert re(x).rewrite(im) == x - S.ImaginaryUnit*im(x)
89
+ assert (x + re(y)).rewrite(re, im) == x + y - S.ImaginaryUnit*im(y)
90
+
91
+ a = Symbol('a', algebraic=True)
92
+ t = Symbol('t', transcendental=True)
93
+ x = Symbol('x')
94
+ assert re(a).is_algebraic
95
+ assert re(x).is_algebraic is None
96
+ assert re(t).is_algebraic is False
97
+
98
+ assert re(S.ComplexInfinity) is S.NaN
99
+
100
+ n, m, l = symbols('n m l')
101
+ A = MatrixSymbol('A',n,m)
102
+ assert re(A) == (S.Half) * (A + conjugate(A))
103
+
104
+ A = Matrix([[1 + 4*I,2],[0, -3*I]])
105
+ assert re(A) == Matrix([[1, 2],[0, 0]])
106
+
107
+ A = ImmutableMatrix([[1 + 3*I, 3-2*I],[0, 2*I]])
108
+ assert re(A) == ImmutableMatrix([[1, 3],[0, 0]])
109
+
110
+ X = SparseMatrix([[2*j + i*I for i in range(5)] for j in range(5)])
111
+ assert re(X) - Matrix([[0, 0, 0, 0, 0],
112
+ [2, 2, 2, 2, 2],
113
+ [4, 4, 4, 4, 4],
114
+ [6, 6, 6, 6, 6],
115
+ [8, 8, 8, 8, 8]]) == Matrix.zeros(5)
116
+
117
+ assert im(X) - Matrix([[0, 1, 2, 3, 4],
118
+ [0, 1, 2, 3, 4],
119
+ [0, 1, 2, 3, 4],
120
+ [0, 1, 2, 3, 4],
121
+ [0, 1, 2, 3, 4]]) == Matrix.zeros(5)
122
+
123
+ X = FunctionMatrix(3, 3, Lambda((n, m), n + m*I))
124
+ assert re(X) == Matrix([[0, 0, 0], [1, 1, 1], [2, 2, 2]])
125
+
126
+
127
+ def test_im():
128
+ x, y = symbols('x,y')
129
+ a, b = symbols('a,b', real=True)
130
+
131
+ r = Symbol('r', real=True)
132
+ i = Symbol('i', imaginary=True)
133
+
134
+ assert im(nan) is nan
135
+
136
+ assert im(oo*I) is oo
137
+ assert im(-oo*I) is -oo
138
+
139
+ assert im(0) == 0
140
+
141
+ assert im(1) == 0
142
+ assert im(-1) == 0
143
+
144
+ assert im(E*I) == E
145
+ assert im(-E*I) == -E
146
+
147
+ assert unchanged(im, x)
148
+ assert im(x*I) == re(x)
149
+ assert im(r*I) == r
150
+ assert im(r) == 0
151
+ assert im(i*I) == 0
152
+ assert im(i) == -I * i
153
+
154
+ assert im(x + y) == im(x) + im(y)
155
+ assert im(x + r) == im(x)
156
+ assert im(x + r*I) == im(x) + r
157
+
158
+ assert im(im(x)*I) == im(x)
159
+
160
+ assert im(2 + I) == 1
161
+ assert im(x + I) == im(x) + 1
162
+
163
+ assert im(x + y*I) == im(x) + re(y)
164
+ assert im(x + r*I) == im(x) + r
165
+
166
+ assert im(log(2*I)) == pi/2
167
+
168
+ assert im((2 + I)**2).expand(complex=True) == 4
169
+
170
+ assert im(conjugate(x)) == -im(x)
171
+ assert conjugate(im(x)) == im(x)
172
+
173
+ assert im(x).as_real_imag() == (im(x), 0)
174
+
175
+ assert im(i*r*x).diff(r) == im(i*x)
176
+ assert im(i*r*x).diff(i) == -I * re(r*x)
177
+
178
+ assert im(
179
+ sqrt(a + b*I)) == (a**2 + b**2)**Rational(1, 4)*sin(atan2(b, a)/2)
180
+ assert im(a * (2 + b*I)) == a*b
181
+
182
+ assert im((1 + sqrt(a + b*I))/2) == \
183
+ (a**2 + b**2)**Rational(1, 4)*sin(atan2(b, a)/2)/2
184
+
185
+ assert im(x).rewrite(re) == -S.ImaginaryUnit * (x - re(x))
186
+ assert (x + im(y)).rewrite(im, re) == x - S.ImaginaryUnit * (y - re(y))
187
+
188
+ a = Symbol('a', algebraic=True)
189
+ t = Symbol('t', transcendental=True)
190
+ x = Symbol('x')
191
+ assert re(a).is_algebraic
192
+ assert re(x).is_algebraic is None
193
+ assert re(t).is_algebraic is False
194
+
195
+ assert im(S.ComplexInfinity) is S.NaN
196
+
197
+ n, m, l = symbols('n m l')
198
+ A = MatrixSymbol('A',n,m)
199
+
200
+ assert im(A) == (S.One/(2*I)) * (A - conjugate(A))
201
+
202
+ A = Matrix([[1 + 4*I, 2],[0, -3*I]])
203
+ assert im(A) == Matrix([[4, 0],[0, -3]])
204
+
205
+ A = ImmutableMatrix([[1 + 3*I, 3-2*I],[0, 2*I]])
206
+ assert im(A) == ImmutableMatrix([[3, -2],[0, 2]])
207
+
208
+ X = ImmutableSparseMatrix(
209
+ [[i*I + i for i in range(5)] for i in range(5)])
210
+ Y = SparseMatrix([list(range(5)) for i in range(5)])
211
+ assert im(X).as_immutable() == Y
212
+
213
+ X = FunctionMatrix(3, 3, Lambda((n, m), n + m*I))
214
+ assert im(X) == Matrix([[0, 1, 2], [0, 1, 2], [0, 1, 2]])
215
+
216
+ def test_sign():
217
+ assert sign(1.2) == 1
218
+ assert sign(-1.2) == -1
219
+ assert sign(3*I) == I
220
+ assert sign(-3*I) == -I
221
+ assert sign(0) == 0
222
+ assert sign(0, evaluate=False).doit() == 0
223
+ assert sign(oo, evaluate=False).doit() == 1
224
+ assert sign(nan) is nan
225
+ assert sign(2 + 2*I).doit() == sqrt(2)*(2 + 2*I)/4
226
+ assert sign(2 + 3*I).simplify() == sign(2 + 3*I)
227
+ assert sign(2 + 2*I).simplify() == sign(1 + I)
228
+ assert sign(im(sqrt(1 - sqrt(3)))) == 1
229
+ assert sign(sqrt(1 - sqrt(3))) == I
230
+
231
+ x = Symbol('x')
232
+ assert sign(x).is_finite is True
233
+ assert sign(x).is_complex is True
234
+ assert sign(x).is_imaginary is None
235
+ assert sign(x).is_integer is None
236
+ assert sign(x).is_real is None
237
+ assert sign(x).is_zero is None
238
+ assert sign(x).doit() == sign(x)
239
+ assert sign(1.2*x) == sign(x)
240
+ assert sign(2*x) == sign(x)
241
+ assert sign(I*x) == I*sign(x)
242
+ assert sign(-2*I*x) == -I*sign(x)
243
+ assert sign(conjugate(x)) == conjugate(sign(x))
244
+
245
+ p = Symbol('p', positive=True)
246
+ n = Symbol('n', negative=True)
247
+ m = Symbol('m', negative=True)
248
+ assert sign(2*p*x) == sign(x)
249
+ assert sign(n*x) == -sign(x)
250
+ assert sign(n*m*x) == sign(x)
251
+
252
+ x = Symbol('x', imaginary=True)
253
+ assert sign(x).is_imaginary is True
254
+ assert sign(x).is_integer is False
255
+ assert sign(x).is_real is False
256
+ assert sign(x).is_zero is False
257
+ assert sign(x).diff(x) == 2*DiracDelta(-I*x)
258
+ assert sign(x).doit() == x / Abs(x)
259
+ assert conjugate(sign(x)) == -sign(x)
260
+
261
+ x = Symbol('x', real=True)
262
+ assert sign(x).is_imaginary is False
263
+ assert sign(x).is_integer is True
264
+ assert sign(x).is_real is True
265
+ assert sign(x).is_zero is None
266
+ assert sign(x).diff(x) == 2*DiracDelta(x)
267
+ assert sign(x).doit() == sign(x)
268
+ assert conjugate(sign(x)) == sign(x)
269
+
270
+ x = Symbol('x', nonzero=True)
271
+ assert sign(x).is_imaginary is False
272
+ assert sign(x).is_integer is True
273
+ assert sign(x).is_real is True
274
+ assert sign(x).is_zero is False
275
+ assert sign(x).doit() == x / Abs(x)
276
+ assert sign(Abs(x)) == 1
277
+ assert Abs(sign(x)) == 1
278
+
279
+ x = Symbol('x', positive=True)
280
+ assert sign(x).is_imaginary is False
281
+ assert sign(x).is_integer is True
282
+ assert sign(x).is_real is True
283
+ assert sign(x).is_zero is False
284
+ assert sign(x).doit() == x / Abs(x)
285
+ assert sign(Abs(x)) == 1
286
+ assert Abs(sign(x)) == 1
287
+
288
+ x = 0
289
+ assert sign(x).is_imaginary is False
290
+ assert sign(x).is_integer is True
291
+ assert sign(x).is_real is True
292
+ assert sign(x).is_zero is True
293
+ assert sign(x).doit() == 0
294
+ assert sign(Abs(x)) == 0
295
+ assert Abs(sign(x)) == 0
296
+
297
+ nz = Symbol('nz', nonzero=True, integer=True)
298
+ assert sign(nz).is_imaginary is False
299
+ assert sign(nz).is_integer is True
300
+ assert sign(nz).is_real is True
301
+ assert sign(nz).is_zero is False
302
+ assert sign(nz)**2 == 1
303
+ assert (sign(nz)**3).args == (sign(nz), 3)
304
+
305
+ assert sign(Symbol('x', nonnegative=True)).is_nonnegative
306
+ assert sign(Symbol('x', nonnegative=True)).is_nonpositive is None
307
+ assert sign(Symbol('x', nonpositive=True)).is_nonnegative is None
308
+ assert sign(Symbol('x', nonpositive=True)).is_nonpositive
309
+ assert sign(Symbol('x', real=True)).is_nonnegative is None
310
+ assert sign(Symbol('x', real=True)).is_nonpositive is None
311
+ assert sign(Symbol('x', real=True, zero=False)).is_nonpositive is None
312
+
313
+ x, y = Symbol('x', real=True), Symbol('y')
314
+ f = Function('f')
315
+ assert sign(x).rewrite(Piecewise) == \
316
+ Piecewise((1, x > 0), (-1, x < 0), (0, True))
317
+ assert sign(y).rewrite(Piecewise) == sign(y)
318
+ assert sign(x).rewrite(Heaviside) == 2*Heaviside(x, H0=S(1)/2) - 1
319
+ assert sign(y).rewrite(Heaviside) == sign(y)
320
+ assert sign(y).rewrite(Abs) == Piecewise((0, Eq(y, 0)), (y/Abs(y), True))
321
+ assert sign(f(y)).rewrite(Abs) == Piecewise((0, Eq(f(y), 0)), (f(y)/Abs(f(y)), True))
322
+
323
+ # evaluate what can be evaluated
324
+ assert sign(exp_polar(I*pi)*pi) is S.NegativeOne
325
+
326
+ eq = -sqrt(10 + 6*sqrt(3)) + sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3))
327
+ # if there is a fast way to know when and when you cannot prove an
328
+ # expression like this is zero then the equality to zero is ok
329
+ assert sign(eq).func is sign or sign(eq) == 0
330
+ # but sometimes it's hard to do this so it's better not to load
331
+ # abs down with tests that will be very slow
332
+ q = 1 + sqrt(2) - 2*sqrt(3) + 1331*sqrt(6)
333
+ p = expand(q**3)**Rational(1, 3)
334
+ d = p - q
335
+ assert sign(d).func is sign or sign(d) == 0
336
+
337
+
338
+ def test_as_real_imag():
339
+ n = pi**1000
340
+ # the special code for working out the real
341
+ # and complex parts of a power with Integer exponent
342
+ # should not run if there is no imaginary part, hence
343
+ # this should not hang
344
+ assert n.as_real_imag() == (n, 0)
345
+
346
+ # issue 6261
347
+ x = Symbol('x')
348
+ assert sqrt(x).as_real_imag() == \
349
+ ((re(x)**2 + im(x)**2)**Rational(1, 4)*cos(atan2(im(x), re(x))/2),
350
+ (re(x)**2 + im(x)**2)**Rational(1, 4)*sin(atan2(im(x), re(x))/2))
351
+
352
+ # issue 3853
353
+ a, b = symbols('a,b', real=True)
354
+ assert ((1 + sqrt(a + b*I))/2).as_real_imag() == \
355
+ (
356
+ (a**2 + b**2)**Rational(
357
+ 1, 4)*cos(atan2(b, a)/2)/2 + S.Half,
358
+ (a**2 + b**2)**Rational(1, 4)*sin(atan2(b, a)/2)/2)
359
+
360
+ assert sqrt(a**2).as_real_imag() == (sqrt(a**2), 0)
361
+ i = symbols('i', imaginary=True)
362
+ assert sqrt(i**2).as_real_imag() == (0, abs(i))
363
+
364
+ assert ((1 + I)/(1 - I)).as_real_imag() == (0, 1)
365
+ assert ((1 + I)**3/(1 - I)).as_real_imag() == (-2, 0)
366
+
367
+
368
+ @XFAIL
369
+ def test_sign_issue_3068():
370
+ n = pi**1000
371
+ i = int(n)
372
+ x = Symbol('x')
373
+ assert (n - i).round() == 1 # doesn't hang
374
+ assert sign(n - i) == 1
375
+ # perhaps it's not possible to get the sign right when
376
+ # only 1 digit is being requested for this situation;
377
+ # 2 digits works
378
+ assert (n - x).n(1, subs={x: i}) > 0
379
+ assert (n - x).n(2, subs={x: i}) > 0
380
+
381
+
382
+ def test_Abs():
383
+ raises(TypeError, lambda: Abs(Interval(2, 3))) # issue 8717
384
+
385
+ x, y = symbols('x,y')
386
+ assert sign(sign(x)) == sign(x)
387
+ assert sign(x*y).func is sign
388
+ assert Abs(0) == 0
389
+ assert Abs(1) == 1
390
+ assert Abs(-1) == 1
391
+ assert Abs(I) == 1
392
+ assert Abs(-I) == 1
393
+ assert Abs(nan) is nan
394
+ assert Abs(zoo) is oo
395
+ assert Abs(I * pi) == pi
396
+ assert Abs(-I * pi) == pi
397
+ assert Abs(I * x) == Abs(x)
398
+ assert Abs(-I * x) == Abs(x)
399
+ assert Abs(-2*x) == 2*Abs(x)
400
+ assert Abs(-2.0*x) == 2.0*Abs(x)
401
+ assert Abs(2*pi*x*y) == 2*pi*Abs(x*y)
402
+ assert Abs(conjugate(x)) == Abs(x)
403
+ assert conjugate(Abs(x)) == Abs(x)
404
+ assert Abs(x).expand(complex=True) == sqrt(re(x)**2 + im(x)**2)
405
+
406
+ a = Symbol('a', positive=True)
407
+ assert Abs(2*pi*x*a) == 2*pi*a*Abs(x)
408
+ assert Abs(2*pi*I*x*a) == 2*pi*a*Abs(x)
409
+
410
+ x = Symbol('x', real=True)
411
+ n = Symbol('n', integer=True)
412
+ assert Abs((-1)**n) == 1
413
+ assert x**(2*n) == Abs(x)**(2*n)
414
+ assert Abs(x).diff(x) == sign(x)
415
+ assert abs(x) == Abs(x) # Python built-in
416
+ assert Abs(x)**3 == x**2*Abs(x)
417
+ assert Abs(x)**4 == x**4
418
+ assert (
419
+ Abs(x)**(3*n)).args == (Abs(x), 3*n) # leave symbolic odd unchanged
420
+ assert (1/Abs(x)).args == (Abs(x), -1)
421
+ assert 1/Abs(x)**3 == 1/(x**2*Abs(x))
422
+ assert Abs(x)**-3 == Abs(x)/(x**4)
423
+ assert Abs(x**3) == x**2*Abs(x)
424
+ assert Abs(I**I) == exp(-pi/2)
425
+ assert Abs((4 + 5*I)**(6 + 7*I)) == 68921*exp(-7*atan(Rational(5, 4)))
426
+ y = Symbol('y', real=True)
427
+ assert Abs(I**y) == 1
428
+ y = Symbol('y')
429
+ assert Abs(I**y) == exp(-pi*im(y)/2)
430
+
431
+ x = Symbol('x', imaginary=True)
432
+ assert Abs(x).diff(x) == -sign(x)
433
+
434
+ eq = -sqrt(10 + 6*sqrt(3)) + sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3))
435
+ # if there is a fast way to know when you can and when you cannot prove an
436
+ # expression like this is zero then the equality to zero is ok
437
+ assert abs(eq).func is Abs or abs(eq) == 0
438
+ # but sometimes it's hard to do this so it's better not to load
439
+ # abs down with tests that will be very slow
440
+ q = 1 + sqrt(2) - 2*sqrt(3) + 1331*sqrt(6)
441
+ p = expand(q**3)**Rational(1, 3)
442
+ d = p - q
443
+ assert abs(d).func is Abs or abs(d) == 0
444
+
445
+ assert Abs(4*exp(pi*I/4)) == 4
446
+ assert Abs(3**(2 + I)) == 9
447
+ assert Abs((-3)**(1 - I)) == 3*exp(pi)
448
+
449
+ assert Abs(oo) is oo
450
+ assert Abs(-oo) is oo
451
+ assert Abs(oo + I) is oo
452
+ assert Abs(oo + I*oo) is oo
453
+
454
+ a = Symbol('a', algebraic=True)
455
+ t = Symbol('t', transcendental=True)
456
+ x = Symbol('x')
457
+ assert re(a).is_algebraic
458
+ assert re(x).is_algebraic is None
459
+ assert re(t).is_algebraic is False
460
+ assert Abs(x).fdiff() == sign(x)
461
+ raises(ArgumentIndexError, lambda: Abs(x).fdiff(2))
462
+
463
+ # doesn't have recursion error
464
+ arg = sqrt(acos(1 - I)*acos(1 + I))
465
+ assert abs(arg) == arg
466
+
467
+ # special handling to put Abs in denom
468
+ assert abs(1/x) == 1/Abs(x)
469
+ e = abs(2/x**2)
470
+ assert e.is_Mul and e == 2/Abs(x**2)
471
+ assert unchanged(Abs, y/x)
472
+ assert unchanged(Abs, x/(x + 1))
473
+ assert unchanged(Abs, x*y)
474
+ p = Symbol('p', positive=True)
475
+ assert abs(x/p) == abs(x)/p
476
+
477
+ # coverage
478
+ assert unchanged(Abs, Symbol('x', real=True)**y)
479
+ # issue 19627
480
+ f = Function('f', positive=True)
481
+ assert sqrt(f(x)**2) == f(x)
482
+ # issue 21625
483
+ assert unchanged(Abs, S("im(acos(-i + acosh(-g + i)))"))
484
+
485
+
486
+ def test_Abs_rewrite():
487
+ x = Symbol('x', real=True)
488
+ a = Abs(x).rewrite(Heaviside).expand()
489
+ assert a == x*Heaviside(x) - x*Heaviside(-x)
490
+ for i in [-2, -1, 0, 1, 2]:
491
+ assert a.subs(x, i) == abs(i)
492
+ y = Symbol('y')
493
+ assert Abs(y).rewrite(Heaviside) == Abs(y)
494
+
495
+ x, y = Symbol('x', real=True), Symbol('y')
496
+ assert Abs(x).rewrite(Piecewise) == Piecewise((x, x >= 0), (-x, True))
497
+ assert Abs(y).rewrite(Piecewise) == Abs(y)
498
+ assert Abs(y).rewrite(sign) == y/sign(y)
499
+
500
+ i = Symbol('i', imaginary=True)
501
+ assert abs(i).rewrite(Piecewise) == Piecewise((I*i, I*i >= 0), (-I*i, True))
502
+
503
+
504
+ assert Abs(y).rewrite(conjugate) == sqrt(y*conjugate(y))
505
+ assert Abs(i).rewrite(conjugate) == sqrt(-i**2) # == -I*i
506
+
507
+ y = Symbol('y', extended_real=True)
508
+ assert (Abs(exp(-I*x)-exp(-I*y))**2).rewrite(conjugate) == \
509
+ -exp(I*x)*exp(-I*y) + 2 - exp(-I*x)*exp(I*y)
510
+
511
+
512
+ def test_Abs_real():
513
+ # test some properties of abs that only apply
514
+ # to real numbers
515
+ x = Symbol('x', complex=True)
516
+ assert sqrt(x**2) != Abs(x)
517
+ assert Abs(x**2) != x**2
518
+
519
+ x = Symbol('x', real=True)
520
+ assert sqrt(x**2) == Abs(x)
521
+ assert Abs(x**2) == x**2
522
+
523
+ # if the symbol is zero, the following will still apply
524
+ nn = Symbol('nn', nonnegative=True, real=True)
525
+ np = Symbol('np', nonpositive=True, real=True)
526
+ assert Abs(nn) == nn
527
+ assert Abs(np) == -np
528
+
529
+
530
+ def test_Abs_properties():
531
+ x = Symbol('x')
532
+ assert Abs(x).is_real is None
533
+ assert Abs(x).is_extended_real is True
534
+ assert Abs(x).is_rational is None
535
+ assert Abs(x).is_positive is None
536
+ assert Abs(x).is_nonnegative is None
537
+ assert Abs(x).is_extended_positive is None
538
+ assert Abs(x).is_extended_nonnegative is True
539
+
540
+ f = Symbol('x', finite=True)
541
+ assert Abs(f).is_real is True
542
+ assert Abs(f).is_extended_real is True
543
+ assert Abs(f).is_rational is None
544
+ assert Abs(f).is_positive is None
545
+ assert Abs(f).is_nonnegative is True
546
+ assert Abs(f).is_extended_positive is None
547
+ assert Abs(f).is_extended_nonnegative is True
548
+
549
+ z = Symbol('z', complex=True, zero=False)
550
+ assert Abs(z).is_real is True # since complex implies finite
551
+ assert Abs(z).is_extended_real is True
552
+ assert Abs(z).is_rational is None
553
+ assert Abs(z).is_positive is True
554
+ assert Abs(z).is_extended_positive is True
555
+ assert Abs(z).is_zero is False
556
+
557
+ p = Symbol('p', positive=True)
558
+ assert Abs(p).is_real is True
559
+ assert Abs(p).is_extended_real is True
560
+ assert Abs(p).is_rational is None
561
+ assert Abs(p).is_positive is True
562
+ assert Abs(p).is_zero is False
563
+
564
+ q = Symbol('q', rational=True)
565
+ assert Abs(q).is_real is True
566
+ assert Abs(q).is_rational is True
567
+ assert Abs(q).is_integer is None
568
+ assert Abs(q).is_positive is None
569
+ assert Abs(q).is_nonnegative is True
570
+
571
+ i = Symbol('i', integer=True)
572
+ assert Abs(i).is_real is True
573
+ assert Abs(i).is_integer is True
574
+ assert Abs(i).is_positive is None
575
+ assert Abs(i).is_nonnegative is True
576
+
577
+ e = Symbol('n', even=True)
578
+ ne = Symbol('ne', real=True, even=False)
579
+ assert Abs(e).is_even is True
580
+ assert Abs(ne).is_even is False
581
+ assert Abs(i).is_even is None
582
+
583
+ o = Symbol('n', odd=True)
584
+ no = Symbol('no', real=True, odd=False)
585
+ assert Abs(o).is_odd is True
586
+ assert Abs(no).is_odd is False
587
+ assert Abs(i).is_odd is None
588
+
589
+
590
+ def test_abs():
591
+ # this tests that abs calls Abs; don't rename to
592
+ # test_Abs since that test is already above
593
+ a = Symbol('a', positive=True)
594
+ assert abs(I*(1 + a)**2) == (1 + a)**2
595
+
596
+
597
+ def test_arg():
598
+ assert arg(0) is nan
599
+ assert arg(1) == 0
600
+ assert arg(-1) == pi
601
+ assert arg(I) == pi/2
602
+ assert arg(-I) == -pi/2
603
+ assert arg(1 + I) == pi/4
604
+ assert arg(-1 + I) == pi*Rational(3, 4)
605
+ assert arg(1 - I) == -pi/4
606
+ assert arg(exp_polar(4*pi*I)) == 4*pi
607
+ assert arg(exp_polar(-7*pi*I)) == -7*pi
608
+ assert arg(exp_polar(5 - 3*pi*I/4)) == pi*Rational(-3, 4)
609
+
610
+ assert arg(exp(I*pi/7)) == pi/7 # issue 17300
611
+ assert arg(exp(16*I)) == 16 - 6*pi
612
+ assert arg(exp(13*I*pi/12)) == -11*pi/12
613
+ assert arg(exp(123 - 5*I)) == -5 + 2*pi
614
+ assert arg(exp(sin(1 + 3*I))) == -2*pi + cos(1)*sinh(3)
615
+ r = Symbol('r', real=True)
616
+ assert arg(exp(r - 2*I)) == -2
617
+
618
+ f = Function('f')
619
+ assert not arg(f(0) + I*f(1)).atoms(re)
620
+
621
+ # check nesting
622
+ x = Symbol('x')
623
+ assert arg(arg(arg(x))) is not S.NaN
624
+ assert arg(arg(arg(arg(x)))) is S.NaN
625
+ r = Symbol('r', extended_real=True)
626
+ assert arg(arg(r)) is not S.NaN
627
+ assert arg(arg(arg(r))) is S.NaN
628
+
629
+ p = Function('p', extended_positive=True)
630
+ assert arg(p(x)) == 0
631
+ assert arg((3 + I)*p(x)) == arg(3 + I)
632
+
633
+ p = Symbol('p', positive=True)
634
+ assert arg(p) == 0
635
+ assert arg(p*I) == pi/2
636
+
637
+ n = Symbol('n', negative=True)
638
+ assert arg(n) == pi
639
+ assert arg(n*I) == -pi/2
640
+
641
+ x = Symbol('x')
642
+ assert conjugate(arg(x)) == arg(x)
643
+
644
+ e = p + I*p**2
645
+ assert arg(e) == arg(1 + p*I)
646
+ # make sure sign doesn't swap
647
+ e = -2*p + 4*I*p**2
648
+ assert arg(e) == arg(-1 + 2*p*I)
649
+ # make sure sign isn't lost
650
+ x = symbols('x', real=True) # could be zero
651
+ e = x + I*x
652
+ assert arg(e) == arg(x*(1 + I))
653
+ assert arg(e/p) == arg(x*(1 + I))
654
+ e = p*cos(p) + I*log(p)*exp(p)
655
+ assert arg(e).args[0] == e
656
+ # keep it simple -- let the user do more advanced cancellation
657
+ e = (p + 1) + I*(p**2 - 1)
658
+ assert arg(e).args[0] == e
659
+
660
+ f = Function('f')
661
+ e = 2*x*(f(0) - 1) - 2*x*f(0)
662
+ assert arg(e) == arg(-2*x)
663
+ assert arg(f(0)).func == arg and arg(f(0)).args == (f(0),)
664
+
665
+
666
+ def test_arg_rewrite():
667
+ assert arg(1 + I) == atan2(1, 1)
668
+
669
+ x = Symbol('x', real=True)
670
+ y = Symbol('y', real=True)
671
+ assert arg(x + I*y).rewrite(atan2) == atan2(y, x)
672
+
673
+
674
+ def test_arg_leading_term_and_series():
675
+ x = Symbol('x')
676
+ assert arg(x).as_leading_term(x, cdir = 1) == 0
677
+ assert arg(x).as_leading_term(x, cdir = -1) == pi
678
+ raises(PoleError, lambda: arg(x + I).as_leading_term(x, cdir = 1))
679
+ raises(PoleError, lambda: arg(2*x).as_leading_term(x, cdir = I))
680
+
681
+ assert arg(x).nseries(x) == 0
682
+ assert arg(x).nseries(x, n=0) == Order(1)
683
+
684
+
685
+ def test_adjoint():
686
+ a = Symbol('a', antihermitian=True)
687
+ b = Symbol('b', hermitian=True)
688
+ assert adjoint(a) == -a
689
+ assert adjoint(I*a) == I*a
690
+ assert adjoint(b) == b
691
+ assert adjoint(I*b) == -I*b
692
+ assert adjoint(a*b) == -b*a
693
+ assert adjoint(I*a*b) == I*b*a
694
+
695
+ x, y = symbols('x y')
696
+ assert adjoint(adjoint(x)) == x
697
+ assert adjoint(x + y) == conjugate(x) + conjugate(y)
698
+ assert adjoint(x - y) == conjugate(x) - conjugate(y)
699
+ assert adjoint(x * y) == conjugate(x) * conjugate(y)
700
+ assert adjoint(x / y) == conjugate(x) / conjugate(y)
701
+ assert adjoint(-x) == -conjugate(x)
702
+
703
+ x, y = symbols('x y', commutative=False)
704
+ assert adjoint(adjoint(x)) == x
705
+ assert adjoint(x + y) == adjoint(x) + adjoint(y)
706
+ assert adjoint(x - y) == adjoint(x) - adjoint(y)
707
+ assert adjoint(x * y) == adjoint(y) * adjoint(x)
708
+ assert adjoint(x / y) == 1 / adjoint(y) * adjoint(x)
709
+ assert adjoint(-x) == -adjoint(x)
710
+
711
+
712
+ def test_conjugate():
713
+ a = Symbol('a', real=True)
714
+ b = Symbol('b', imaginary=True)
715
+ assert conjugate(a) == a
716
+ assert conjugate(I*a) == -I*a
717
+ assert conjugate(b) == -b
718
+ assert conjugate(I*b) == I*b
719
+ assert conjugate(a*b) == -a*b
720
+ assert conjugate(I*a*b) == I*a*b
721
+
722
+ x, y = symbols('x y')
723
+ assert conjugate(conjugate(x)) == x
724
+ assert conjugate(x).inverse() == conjugate
725
+ assert conjugate(x + y) == conjugate(x) + conjugate(y)
726
+ assert conjugate(x - y) == conjugate(x) - conjugate(y)
727
+ assert conjugate(x * y) == conjugate(x) * conjugate(y)
728
+ assert conjugate(x / y) == conjugate(x) / conjugate(y)
729
+ assert conjugate(-x) == -conjugate(x)
730
+
731
+ a = Symbol('a', algebraic=True)
732
+ t = Symbol('t', transcendental=True)
733
+ assert re(a).is_algebraic
734
+ assert re(x).is_algebraic is None
735
+ assert re(t).is_algebraic is False
736
+
737
+
738
+ def test_conjugate_transpose():
739
+ x = Symbol('x', commutative=False)
740
+ assert conjugate(transpose(x)) == adjoint(x)
741
+ assert transpose(conjugate(x)) == adjoint(x)
742
+ assert adjoint(transpose(x)) == conjugate(x)
743
+ assert transpose(adjoint(x)) == conjugate(x)
744
+ assert adjoint(conjugate(x)) == transpose(x)
745
+ assert conjugate(adjoint(x)) == transpose(x)
746
+
747
+ x = Symbol('x')
748
+ assert conjugate(x) == adjoint(x)
749
+ assert transpose(x) == x
750
+
751
+
752
+ def test_transpose():
753
+ a = Symbol('a', complex=True)
754
+ assert transpose(a) == a
755
+ assert transpose(I*a) == I*a
756
+
757
+ x, y = symbols('x y')
758
+ assert transpose(transpose(x)) == x
759
+ assert transpose(x + y) == x + y
760
+ assert transpose(x - y) == x - y
761
+ assert transpose(x * y) == x * y
762
+ assert transpose(x / y) == x / y
763
+ assert transpose(-x) == -x
764
+
765
+ x, y = symbols('x y', commutative=False)
766
+ assert transpose(transpose(x)) == x
767
+ assert transpose(x + y) == transpose(x) + transpose(y)
768
+ assert transpose(x - y) == transpose(x) - transpose(y)
769
+ assert transpose(x * y) == transpose(y) * transpose(x)
770
+ assert transpose(x / y) == 1 / transpose(y) * transpose(x)
771
+ assert transpose(-x) == -transpose(x)
772
+
773
+
774
+ @_both_exp_pow
775
+ def test_polarify():
776
+ from sympy.functions.elementary.complexes import (polar_lift, polarify)
777
+ x = Symbol('x')
778
+ z = Symbol('z', polar=True)
779
+ f = Function('f')
780
+ ES = {}
781
+
782
+ assert polarify(-1) == (polar_lift(-1), ES)
783
+ assert polarify(1 + I) == (polar_lift(1 + I), ES)
784
+
785
+ assert polarify(exp(x), subs=False) == exp(x)
786
+ assert polarify(1 + x, subs=False) == 1 + x
787
+ assert polarify(f(I) + x, subs=False) == f(polar_lift(I)) + x
788
+
789
+ assert polarify(x, lift=True) == polar_lift(x)
790
+ assert polarify(z, lift=True) == z
791
+ assert polarify(f(x), lift=True) == f(polar_lift(x))
792
+ assert polarify(1 + x, lift=True) == polar_lift(1 + x)
793
+ assert polarify(1 + f(x), lift=True) == polar_lift(1 + f(polar_lift(x)))
794
+
795
+ newex, subs = polarify(f(x) + z)
796
+ assert newex.subs(subs) == f(x) + z
797
+
798
+ mu = Symbol("mu")
799
+ sigma = Symbol("sigma", positive=True)
800
+
801
+ # Make sure polarify(lift=True) doesn't try to lift the integration
802
+ # variable
803
+ assert polarify(
804
+ Integral(sqrt(2)*x*exp(-(-mu + x)**2/(2*sigma**2))/(2*sqrt(pi)*sigma),
805
+ (x, -oo, oo)), lift=True) == Integral(sqrt(2)*(sigma*exp_polar(0))**exp_polar(I*pi)*
806
+ exp((sigma*exp_polar(0))**(2*exp_polar(I*pi))*exp_polar(I*pi)*polar_lift(-mu + x)**
807
+ (2*exp_polar(0))/2)*exp_polar(0)*polar_lift(x)/(2*sqrt(pi)), (x, -oo, oo))
808
+
809
+
810
+ def test_unpolarify():
811
+ from sympy.functions.elementary.complexes import (polar_lift, principal_branch, unpolarify)
812
+ from sympy.core.relational import Ne
813
+ from sympy.functions.elementary.hyperbolic import tanh
814
+ from sympy.functions.special.error_functions import erf
815
+ from sympy.functions.special.gamma_functions import (gamma, uppergamma)
816
+ from sympy.abc import x
817
+ p = exp_polar(7*I) + 1
818
+ u = exp(7*I) + 1
819
+
820
+ assert unpolarify(1) == 1
821
+ assert unpolarify(p) == u
822
+ assert unpolarify(p**2) == u**2
823
+ assert unpolarify(p**x) == p**x
824
+ assert unpolarify(p*x) == u*x
825
+ assert unpolarify(p + x) == u + x
826
+ assert unpolarify(sqrt(sin(p))) == sqrt(sin(u))
827
+
828
+ # Test reduction to principal branch 2*pi.
829
+ t = principal_branch(x, 2*pi)
830
+ assert unpolarify(t) == x
831
+ assert unpolarify(sqrt(t)) == sqrt(t)
832
+
833
+ # Test exponents_only.
834
+ assert unpolarify(p**p, exponents_only=True) == p**u
835
+ assert unpolarify(uppergamma(x, p**p)) == uppergamma(x, p**u)
836
+
837
+ # Test functions.
838
+ assert unpolarify(sin(p)) == sin(u)
839
+ assert unpolarify(tanh(p)) == tanh(u)
840
+ assert unpolarify(gamma(p)) == gamma(u)
841
+ assert unpolarify(erf(p)) == erf(u)
842
+ assert unpolarify(uppergamma(x, p)) == uppergamma(x, p)
843
+
844
+ assert unpolarify(uppergamma(sin(p), sin(p + exp_polar(0)))) == \
845
+ uppergamma(sin(u), sin(u + 1))
846
+ assert unpolarify(uppergamma(polar_lift(0), 2*exp_polar(0))) == \
847
+ uppergamma(0, 2)
848
+
849
+ assert unpolarify(Eq(p, 0)) == Eq(u, 0)
850
+ assert unpolarify(Ne(p, 0)) == Ne(u, 0)
851
+ assert unpolarify(polar_lift(x) > 0) == (x > 0)
852
+
853
+ # Test bools
854
+ assert unpolarify(True) is True
855
+
856
+
857
+ def test_issue_4035():
858
+ x = Symbol('x')
859
+ assert Abs(x).expand(trig=True) == Abs(x)
860
+ assert sign(x).expand(trig=True) == sign(x)
861
+ assert arg(x).expand(trig=True) == arg(x)
862
+
863
+
864
+ def test_issue_3206():
865
+ x = Symbol('x')
866
+ assert Abs(Abs(x)) == Abs(x)
867
+
868
+
869
+ def test_issue_4754_derivative_conjugate():
870
+ x = Symbol('x', real=True)
871
+ y = Symbol('y', imaginary=True)
872
+ f = Function('f')
873
+ assert (f(x).conjugate()).diff(x) == (f(x).diff(x)).conjugate()
874
+ assert (f(y).conjugate()).diff(y) == -(f(y).diff(y)).conjugate()
875
+
876
+
877
+ def test_derivatives_issue_4757():
878
+ x = Symbol('x', real=True)
879
+ y = Symbol('y', imaginary=True)
880
+ f = Function('f')
881
+ assert re(f(x)).diff(x) == re(f(x).diff(x))
882
+ assert im(f(x)).diff(x) == im(f(x).diff(x))
883
+ assert re(f(y)).diff(y) == -I*im(f(y).diff(y))
884
+ assert im(f(y)).diff(y) == -I*re(f(y).diff(y))
885
+ assert Abs(f(x)).diff(x).subs(f(x), 1 + I*x).doit() == x/sqrt(1 + x**2)
886
+ assert arg(f(x)).diff(x).subs(f(x), 1 + I*x**2).doit() == 2*x/(1 + x**4)
887
+ assert Abs(f(y)).diff(y).subs(f(y), 1 + y).doit() == -y/sqrt(1 - y**2)
888
+ assert arg(f(y)).diff(y).subs(f(y), I + y**2).doit() == 2*y/(1 + y**4)
889
+
890
+
891
+ def test_issue_11413():
892
+ from sympy.simplify.simplify import simplify
893
+ v0 = Symbol('v0')
894
+ v1 = Symbol('v1')
895
+ v2 = Symbol('v2')
896
+ V = Matrix([[v0],[v1],[v2]])
897
+ U = V.normalized()
898
+ assert U == Matrix([
899
+ [v0/sqrt(Abs(v0)**2 + Abs(v1)**2 + Abs(v2)**2)],
900
+ [v1/sqrt(Abs(v0)**2 + Abs(v1)**2 + Abs(v2)**2)],
901
+ [v2/sqrt(Abs(v0)**2 + Abs(v1)**2 + Abs(v2)**2)]])
902
+ U.norm = sqrt(v0**2/(v0**2 + v1**2 + v2**2) + v1**2/(v0**2 + v1**2 + v2**2) + v2**2/(v0**2 + v1**2 + v2**2))
903
+ assert simplify(U.norm) == 1
904
+
905
+
906
+ def test_periodic_argument():
907
+ from sympy.functions.elementary.complexes import (periodic_argument, polar_lift, principal_branch, unbranched_argument)
908
+ x = Symbol('x')
909
+ p = Symbol('p', positive=True)
910
+
911
+ assert unbranched_argument(2 + I) == periodic_argument(2 + I, oo)
912
+ assert unbranched_argument(1 + x) == periodic_argument(1 + x, oo)
913
+ assert N_equals(unbranched_argument((1 + I)**2), pi/2)
914
+ assert N_equals(unbranched_argument((1 - I)**2), -pi/2)
915
+ assert N_equals(periodic_argument((1 + I)**2, 3*pi), pi/2)
916
+ assert N_equals(periodic_argument((1 - I)**2, 3*pi), -pi/2)
917
+
918
+ assert unbranched_argument(principal_branch(x, pi)) == \
919
+ periodic_argument(x, pi)
920
+
921
+ assert unbranched_argument(polar_lift(2 + I)) == unbranched_argument(2 + I)
922
+ assert periodic_argument(polar_lift(2 + I), 2*pi) == \
923
+ periodic_argument(2 + I, 2*pi)
924
+ assert periodic_argument(polar_lift(2 + I), 3*pi) == \
925
+ periodic_argument(2 + I, 3*pi)
926
+ assert periodic_argument(polar_lift(2 + I), pi) == \
927
+ periodic_argument(polar_lift(2 + I), pi)
928
+
929
+ assert unbranched_argument(polar_lift(1 + I)) == pi/4
930
+ assert periodic_argument(2*p, p) == periodic_argument(p, p)
931
+ assert periodic_argument(pi*p, p) == periodic_argument(p, p)
932
+
933
+ assert Abs(polar_lift(1 + I)) == Abs(1 + I)
934
+
935
+
936
+ @XFAIL
937
+ def test_principal_branch_fail():
938
+ # TODO XXX why does abs(x)._eval_evalf() not fall back to global evalf?
939
+ from sympy.functions.elementary.complexes import principal_branch
940
+ assert N_equals(principal_branch((1 + I)**2, pi/2), 0)
941
+
942
+
943
+ def test_principal_branch():
944
+ from sympy.functions.elementary.complexes import (polar_lift, principal_branch)
945
+ p = Symbol('p', positive=True)
946
+ x = Symbol('x')
947
+ neg = Symbol('x', negative=True)
948
+
949
+ assert principal_branch(polar_lift(x), p) == principal_branch(x, p)
950
+ assert principal_branch(polar_lift(2 + I), p) == principal_branch(2 + I, p)
951
+ assert principal_branch(2*x, p) == 2*principal_branch(x, p)
952
+ assert principal_branch(1, pi) == exp_polar(0)
953
+ assert principal_branch(-1, 2*pi) == exp_polar(I*pi)
954
+ assert principal_branch(-1, pi) == exp_polar(0)
955
+ assert principal_branch(exp_polar(3*pi*I)*x, 2*pi) == \
956
+ principal_branch(exp_polar(I*pi)*x, 2*pi)
957
+ assert principal_branch(neg*exp_polar(pi*I), 2*pi) == neg*exp_polar(-I*pi)
958
+ # related to issue #14692
959
+ assert principal_branch(exp_polar(-I*pi/2)/polar_lift(neg), 2*pi) == \
960
+ exp_polar(-I*pi/2)/neg
961
+
962
+ assert N_equals(principal_branch((1 + I)**2, 2*pi), 2*I)
963
+ assert N_equals(principal_branch((1 + I)**2, 3*pi), 2*I)
964
+ assert N_equals(principal_branch((1 + I)**2, 1*pi), 2*I)
965
+
966
+ # test argument sanitization
967
+ assert principal_branch(x, I).func is principal_branch
968
+ assert principal_branch(x, -4).func is principal_branch
969
+ assert principal_branch(x, -oo).func is principal_branch
970
+ assert principal_branch(x, zoo).func is principal_branch
971
+
972
+
973
+ @XFAIL
974
+ def test_issue_6167_6151():
975
+ n = pi**1000
976
+ i = int(n)
977
+ assert sign(n - i) == 1
978
+ assert abs(n - i) == n - i
979
+ x = Symbol('x')
980
+ eps = pi**-1500
981
+ big = pi**1000
982
+ one = cos(x)**2 + sin(x)**2
983
+ e = big*one - big + eps
984
+ from sympy.simplify.simplify import simplify
985
+ assert sign(simplify(e)) == 1
986
+ for xi in (111, 11, 1, Rational(1, 10)):
987
+ assert sign(e.subs(x, xi)) == 1
988
+
989
+
990
+ def test_issue_14216():
991
+ from sympy.functions.elementary.complexes import unpolarify
992
+ A = MatrixSymbol("A", 2, 2)
993
+ assert unpolarify(A[0, 0]) == A[0, 0]
994
+ assert unpolarify(A[0, 0]*A[1, 0]) == A[0, 0]*A[1, 0]
995
+
996
+
997
+ def test_issue_14238():
998
+ # doesn't cause recursion error
999
+ r = Symbol('r', real=True)
1000
+ assert Abs(r + Piecewise((0, r > 0), (1 - r, True)))
1001
+
1002
+
1003
+ def test_issue_22189():
1004
+ x = Symbol('x')
1005
+ for a in (sqrt(7 - 2*x) - 2, 1 - x):
1006
+ assert Abs(a) - Abs(-a) == 0, a
1007
+
1008
+
1009
+ def test_zero_assumptions():
1010
+ nr = Symbol('nonreal', real=False, finite=True)
1011
+ ni = Symbol('nonimaginary', imaginary=False)
1012
+ # imaginary implies not zero
1013
+ nzni = Symbol('nonzerononimaginary', zero=False, imaginary=False)
1014
+
1015
+ assert re(nr).is_zero is None
1016
+ assert im(nr).is_zero is False
1017
+
1018
+ assert re(ni).is_zero is None
1019
+ assert im(ni).is_zero is None
1020
+
1021
+ assert re(nzni).is_zero is False
1022
+ assert im(nzni).is_zero is None
1023
+
1024
+
1025
+ @_both_exp_pow
1026
+ def test_issue_15893():
1027
+ f = Function('f', real=True)
1028
+ x = Symbol('x', real=True)
1029
+ eq = Derivative(Abs(f(x)), f(x))
1030
+ assert eq.doit() == sign(f(x))
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/tests/test_miscellaneous.py ADDED
@@ -0,0 +1,504 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import itertools as it
2
+
3
+ from sympy.core.expr import unchanged
4
+ from sympy.core.function import Function
5
+ from sympy.core.numbers import I, oo, Rational
6
+ from sympy.core.power import Pow
7
+ from sympy.core.singleton import S
8
+ from sympy.core.symbol import Symbol
9
+ from sympy.external import import_module
10
+ from sympy.functions.elementary.exponential import log
11
+ from sympy.functions.elementary.integers import floor, ceiling
12
+ from sympy.functions.elementary.miscellaneous import (sqrt, cbrt, root, Min,
13
+ Max, real_root, Rem)
14
+ from sympy.functions.elementary.trigonometric import cos, sin
15
+ from sympy.functions.special.delta_functions import Heaviside
16
+
17
+ from sympy.utilities.lambdify import lambdify
18
+ from sympy.testing.pytest import raises, skip, ignore_warnings
19
+
20
+ def test_Min():
21
+ from sympy.abc import x, y, z
22
+ n = Symbol('n', negative=True)
23
+ n_ = Symbol('n_', negative=True)
24
+ nn = Symbol('nn', nonnegative=True)
25
+ nn_ = Symbol('nn_', nonnegative=True)
26
+ p = Symbol('p', positive=True)
27
+ p_ = Symbol('p_', positive=True)
28
+ np = Symbol('np', nonpositive=True)
29
+ np_ = Symbol('np_', nonpositive=True)
30
+ r = Symbol('r', real=True)
31
+
32
+ assert Min(5, 4) == 4
33
+ assert Min(-oo, -oo) is -oo
34
+ assert Min(-oo, n) is -oo
35
+ assert Min(n, -oo) is -oo
36
+ assert Min(-oo, np) is -oo
37
+ assert Min(np, -oo) is -oo
38
+ assert Min(-oo, 0) is -oo
39
+ assert Min(0, -oo) is -oo
40
+ assert Min(-oo, nn) is -oo
41
+ assert Min(nn, -oo) is -oo
42
+ assert Min(-oo, p) is -oo
43
+ assert Min(p, -oo) is -oo
44
+ assert Min(-oo, oo) is -oo
45
+ assert Min(oo, -oo) is -oo
46
+ assert Min(n, n) == n
47
+ assert unchanged(Min, n, np)
48
+ assert Min(np, n) == Min(n, np)
49
+ assert Min(n, 0) == n
50
+ assert Min(0, n) == n
51
+ assert Min(n, nn) == n
52
+ assert Min(nn, n) == n
53
+ assert Min(n, p) == n
54
+ assert Min(p, n) == n
55
+ assert Min(n, oo) == n
56
+ assert Min(oo, n) == n
57
+ assert Min(np, np) == np
58
+ assert Min(np, 0) == np
59
+ assert Min(0, np) == np
60
+ assert Min(np, nn) == np
61
+ assert Min(nn, np) == np
62
+ assert Min(np, p) == np
63
+ assert Min(p, np) == np
64
+ assert Min(np, oo) == np
65
+ assert Min(oo, np) == np
66
+ assert Min(0, 0) == 0
67
+ assert Min(0, nn) == 0
68
+ assert Min(nn, 0) == 0
69
+ assert Min(0, p) == 0
70
+ assert Min(p, 0) == 0
71
+ assert Min(0, oo) == 0
72
+ assert Min(oo, 0) == 0
73
+ assert Min(nn, nn) == nn
74
+ assert unchanged(Min, nn, p)
75
+ assert Min(p, nn) == Min(nn, p)
76
+ assert Min(nn, oo) == nn
77
+ assert Min(oo, nn) == nn
78
+ assert Min(p, p) == p
79
+ assert Min(p, oo) == p
80
+ assert Min(oo, p) == p
81
+ assert Min(oo, oo) is oo
82
+
83
+ assert Min(n, n_).func is Min
84
+ assert Min(nn, nn_).func is Min
85
+ assert Min(np, np_).func is Min
86
+ assert Min(p, p_).func is Min
87
+
88
+ # lists
89
+ assert Min() is S.Infinity
90
+ assert Min(x) == x
91
+ assert Min(x, y) == Min(y, x)
92
+ assert Min(x, y, z) == Min(z, y, x)
93
+ assert Min(x, Min(y, z)) == Min(z, y, x)
94
+ assert Min(x, Max(y, -oo)) == Min(x, y)
95
+ assert Min(p, oo, n, p, p, p_) == n
96
+ assert Min(p_, n_, p) == n_
97
+ assert Min(n, oo, -7, p, p, 2) == Min(n, -7)
98
+ assert Min(2, x, p, n, oo, n_, p, 2, -2, -2) == Min(-2, x, n, n_)
99
+ assert Min(0, x, 1, y) == Min(0, x, y)
100
+ assert Min(1000, 100, -100, x, p, n) == Min(n, x, -100)
101
+ assert unchanged(Min, sin(x), cos(x))
102
+ assert Min(sin(x), cos(x)) == Min(cos(x), sin(x))
103
+ assert Min(cos(x), sin(x)).subs(x, 1) == cos(1)
104
+ assert Min(cos(x), sin(x)).subs(x, S.Half) == sin(S.Half)
105
+ raises(ValueError, lambda: Min(cos(x), sin(x)).subs(x, I))
106
+ raises(ValueError, lambda: Min(I))
107
+ raises(ValueError, lambda: Min(I, x))
108
+ raises(ValueError, lambda: Min(S.ComplexInfinity, x))
109
+
110
+ assert Min(1, x).diff(x) == Heaviside(1 - x)
111
+ assert Min(x, 1).diff(x) == Heaviside(1 - x)
112
+ assert Min(0, -x, 1 - 2*x).diff(x) == -Heaviside(x + Min(0, -2*x + 1)) \
113
+ - 2*Heaviside(2*x + Min(0, -x) - 1)
114
+
115
+ # issue 7619
116
+ f = Function('f')
117
+ assert Min(1, 2*Min(f(1), 2)) # doesn't fail
118
+
119
+ # issue 7233
120
+ e = Min(0, x)
121
+ assert e.n().args == (0, x)
122
+
123
+ # issue 8643
124
+ m = Min(n, p_, n_, r)
125
+ assert m.is_positive is False
126
+ assert m.is_nonnegative is False
127
+ assert m.is_negative is True
128
+
129
+ m = Min(p, p_)
130
+ assert m.is_positive is True
131
+ assert m.is_nonnegative is True
132
+ assert m.is_negative is False
133
+
134
+ m = Min(p, nn_, p_)
135
+ assert m.is_positive is None
136
+ assert m.is_nonnegative is True
137
+ assert m.is_negative is False
138
+
139
+ m = Min(nn, p, r)
140
+ assert m.is_positive is None
141
+ assert m.is_nonnegative is None
142
+ assert m.is_negative is None
143
+
144
+
145
+ def test_Max():
146
+ from sympy.abc import x, y, z
147
+ n = Symbol('n', negative=True)
148
+ n_ = Symbol('n_', negative=True)
149
+ nn = Symbol('nn', nonnegative=True)
150
+ p = Symbol('p', positive=True)
151
+ p_ = Symbol('p_', positive=True)
152
+ r = Symbol('r', real=True)
153
+
154
+ assert Max(5, 4) == 5
155
+
156
+ # lists
157
+
158
+ assert Max() is S.NegativeInfinity
159
+ assert Max(x) == x
160
+ assert Max(x, y) == Max(y, x)
161
+ assert Max(x, y, z) == Max(z, y, x)
162
+ assert Max(x, Max(y, z)) == Max(z, y, x)
163
+ assert Max(x, Min(y, oo)) == Max(x, y)
164
+ assert Max(n, -oo, n_, p, 2) == Max(p, 2)
165
+ assert Max(n, -oo, n_, p) == p
166
+ assert Max(2, x, p, n, -oo, S.NegativeInfinity, n_, p, 2) == Max(2, x, p)
167
+ assert Max(0, x, 1, y) == Max(1, x, y)
168
+ assert Max(r, r + 1, r - 1) == 1 + r
169
+ assert Max(1000, 100, -100, x, p, n) == Max(p, x, 1000)
170
+ assert Max(cos(x), sin(x)) == Max(sin(x), cos(x))
171
+ assert Max(cos(x), sin(x)).subs(x, 1) == sin(1)
172
+ assert Max(cos(x), sin(x)).subs(x, S.Half) == cos(S.Half)
173
+ raises(ValueError, lambda: Max(cos(x), sin(x)).subs(x, I))
174
+ raises(ValueError, lambda: Max(I))
175
+ raises(ValueError, lambda: Max(I, x))
176
+ raises(ValueError, lambda: Max(S.ComplexInfinity, 1))
177
+ assert Max(n, -oo, n_, p, 2) == Max(p, 2)
178
+ assert Max(n, -oo, n_, p, 1000) == Max(p, 1000)
179
+
180
+ assert Max(1, x).diff(x) == Heaviside(x - 1)
181
+ assert Max(x, 1).diff(x) == Heaviside(x - 1)
182
+ assert Max(x**2, 1 + x, 1).diff(x) == \
183
+ 2*x*Heaviside(x**2 - Max(1, x + 1)) \
184
+ + Heaviside(x - Max(1, x**2) + 1)
185
+
186
+ e = Max(0, x)
187
+ assert e.n().args == (0, x)
188
+
189
+ # issue 8643
190
+ m = Max(p, p_, n, r)
191
+ assert m.is_positive is True
192
+ assert m.is_nonnegative is True
193
+ assert m.is_negative is False
194
+
195
+ m = Max(n, n_)
196
+ assert m.is_positive is False
197
+ assert m.is_nonnegative is False
198
+ assert m.is_negative is True
199
+
200
+ m = Max(n, n_, r)
201
+ assert m.is_positive is None
202
+ assert m.is_nonnegative is None
203
+ assert m.is_negative is None
204
+
205
+ m = Max(n, nn, r)
206
+ assert m.is_positive is None
207
+ assert m.is_nonnegative is True
208
+ assert m.is_negative is False
209
+
210
+
211
+ def test_minmax_assumptions():
212
+ r = Symbol('r', real=True)
213
+ a = Symbol('a', real=True, algebraic=True)
214
+ t = Symbol('t', real=True, transcendental=True)
215
+ q = Symbol('q', rational=True)
216
+ p = Symbol('p', irrational=True)
217
+ n = Symbol('n', rational=True, integer=False)
218
+ i = Symbol('i', integer=True)
219
+ o = Symbol('o', odd=True)
220
+ e = Symbol('e', even=True)
221
+ k = Symbol('k', prime=True)
222
+ reals = [r, a, t, q, p, n, i, o, e, k]
223
+
224
+ for ext in (Max, Min):
225
+ for x, y in it.product(reals, repeat=2):
226
+
227
+ # Must be real
228
+ assert ext(x, y).is_real
229
+
230
+ # Algebraic?
231
+ if x.is_algebraic and y.is_algebraic:
232
+ assert ext(x, y).is_algebraic
233
+ elif x.is_transcendental and y.is_transcendental:
234
+ assert ext(x, y).is_transcendental
235
+ else:
236
+ assert ext(x, y).is_algebraic is None
237
+
238
+ # Rational?
239
+ if x.is_rational and y.is_rational:
240
+ assert ext(x, y).is_rational
241
+ elif x.is_irrational and y.is_irrational:
242
+ assert ext(x, y).is_irrational
243
+ else:
244
+ assert ext(x, y).is_rational is None
245
+
246
+ # Integer?
247
+ if x.is_integer and y.is_integer:
248
+ assert ext(x, y).is_integer
249
+ elif x.is_noninteger and y.is_noninteger:
250
+ assert ext(x, y).is_noninteger
251
+ else:
252
+ assert ext(x, y).is_integer is None
253
+
254
+ # Odd?
255
+ if x.is_odd and y.is_odd:
256
+ assert ext(x, y).is_odd
257
+ elif x.is_odd is False and y.is_odd is False:
258
+ assert ext(x, y).is_odd is False
259
+ else:
260
+ assert ext(x, y).is_odd is None
261
+
262
+ # Even?
263
+ if x.is_even and y.is_even:
264
+ assert ext(x, y).is_even
265
+ elif x.is_even is False and y.is_even is False:
266
+ assert ext(x, y).is_even is False
267
+ else:
268
+ assert ext(x, y).is_even is None
269
+
270
+ # Prime?
271
+ if x.is_prime and y.is_prime:
272
+ assert ext(x, y).is_prime
273
+ elif x.is_prime is False and y.is_prime is False:
274
+ assert ext(x, y).is_prime is False
275
+ else:
276
+ assert ext(x, y).is_prime is None
277
+
278
+
279
+ def test_issue_8413():
280
+ x = Symbol('x', real=True)
281
+ # we can't evaluate in general because non-reals are not
282
+ # comparable: Min(floor(3.2 + I), 3.2 + I) -> ValueError
283
+ assert Min(floor(x), x) == floor(x)
284
+ assert Min(ceiling(x), x) == x
285
+ assert Max(floor(x), x) == x
286
+ assert Max(ceiling(x), x) == ceiling(x)
287
+
288
+
289
+ def test_root():
290
+ from sympy.abc import x
291
+ n = Symbol('n', integer=True)
292
+ k = Symbol('k', integer=True)
293
+
294
+ assert root(2, 2) == sqrt(2)
295
+ assert root(2, 1) == 2
296
+ assert root(2, 3) == 2**Rational(1, 3)
297
+ assert root(2, 3) == cbrt(2)
298
+ assert root(2, -5) == 2**Rational(4, 5)/2
299
+
300
+ assert root(-2, 1) == -2
301
+
302
+ assert root(-2, 2) == sqrt(2)*I
303
+ assert root(-2, 1) == -2
304
+
305
+ assert root(x, 2) == sqrt(x)
306
+ assert root(x, 1) == x
307
+ assert root(x, 3) == x**Rational(1, 3)
308
+ assert root(x, 3) == cbrt(x)
309
+ assert root(x, -5) == x**Rational(-1, 5)
310
+
311
+ assert root(x, n) == x**(1/n)
312
+ assert root(x, -n) == x**(-1/n)
313
+
314
+ assert root(x, n, k) == (-1)**(2*k/n)*x**(1/n)
315
+
316
+
317
+ def test_real_root():
318
+ assert real_root(-8, 3) == -2
319
+ assert real_root(-16, 4) == root(-16, 4)
320
+ r = root(-7, 4)
321
+ assert real_root(r) == r
322
+ r1 = root(-1, 3)
323
+ r2 = r1**2
324
+ r3 = root(-1, 4)
325
+ assert real_root(r1 + r2 + r3) == -1 + r2 + r3
326
+ assert real_root(root(-2, 3)) == -root(2, 3)
327
+ assert real_root(-8., 3) == -2.0
328
+ x = Symbol('x')
329
+ n = Symbol('n')
330
+ g = real_root(x, n)
331
+ assert g.subs({"x": -8, "n": 3}) == -2
332
+ assert g.subs({"x": 8, "n": 3}) == 2
333
+ # give principle root if there is no real root -- if this is not desired
334
+ # then maybe a Root class is needed to raise an error instead
335
+ assert g.subs({"x": I, "n": 3}) == cbrt(I)
336
+ assert g.subs({"x": -8, "n": 2}) == sqrt(-8)
337
+ assert g.subs({"x": I, "n": 2}) == sqrt(I)
338
+
339
+
340
+ def test_issue_11463():
341
+ numpy = import_module('numpy')
342
+ if not numpy:
343
+ skip("numpy not installed.")
344
+ x = Symbol('x')
345
+ f = lambdify(x, real_root((log(x/(x-2))), 3), 'numpy')
346
+ # numpy.select evaluates all options before considering conditions,
347
+ # so it raises a warning about root of negative number which does
348
+ # not affect the outcome. This warning is suppressed here
349
+ with ignore_warnings(RuntimeWarning):
350
+ assert f(numpy.array(-1)) < -1
351
+
352
+
353
+ def test_rewrite_MaxMin_as_Heaviside():
354
+ from sympy.abc import x
355
+ assert Max(0, x).rewrite(Heaviside) == x*Heaviside(x)
356
+ assert Max(3, x).rewrite(Heaviside) == x*Heaviside(x - 3) + \
357
+ 3*Heaviside(-x + 3)
358
+ assert Max(0, x+2, 2*x).rewrite(Heaviside) == \
359
+ 2*x*Heaviside(2*x)*Heaviside(x - 2) + \
360
+ (x + 2)*Heaviside(-x + 2)*Heaviside(x + 2)
361
+
362
+ assert Min(0, x).rewrite(Heaviside) == x*Heaviside(-x)
363
+ assert Min(3, x).rewrite(Heaviside) == x*Heaviside(-x + 3) + \
364
+ 3*Heaviside(x - 3)
365
+ assert Min(x, -x, -2).rewrite(Heaviside) == \
366
+ x*Heaviside(-2*x)*Heaviside(-x - 2) - \
367
+ x*Heaviside(2*x)*Heaviside(x - 2) \
368
+ - 2*Heaviside(-x + 2)*Heaviside(x + 2)
369
+
370
+
371
+ def test_rewrite_MaxMin_as_Piecewise():
372
+ from sympy.core.symbol import symbols
373
+ from sympy.functions.elementary.piecewise import Piecewise
374
+ x, y, z, a, b = symbols('x y z a b', real=True)
375
+ vx, vy, va = symbols('vx vy va')
376
+ assert Max(a, b).rewrite(Piecewise) == Piecewise((a, a >= b), (b, True))
377
+ assert Max(x, y, z).rewrite(Piecewise) == Piecewise((x, (x >= y) & (x >= z)), (y, y >= z), (z, True))
378
+ assert Max(x, y, a, b).rewrite(Piecewise) == Piecewise((a, (a >= b) & (a >= x) & (a >= y)),
379
+ (b, (b >= x) & (b >= y)), (x, x >= y), (y, True))
380
+ assert Min(a, b).rewrite(Piecewise) == Piecewise((a, a <= b), (b, True))
381
+ assert Min(x, y, z).rewrite(Piecewise) == Piecewise((x, (x <= y) & (x <= z)), (y, y <= z), (z, True))
382
+ assert Min(x, y, a, b).rewrite(Piecewise) == Piecewise((a, (a <= b) & (a <= x) & (a <= y)),
383
+ (b, (b <= x) & (b <= y)), (x, x <= y), (y, True))
384
+
385
+ # Piecewise rewriting of Min/Max does also takes place for not explicitly real arguments
386
+ assert Max(vx, vy).rewrite(Piecewise) == Piecewise((vx, vx >= vy), (vy, True))
387
+ assert Min(va, vx, vy).rewrite(Piecewise) == Piecewise((va, (va <= vx) & (va <= vy)), (vx, vx <= vy), (vy, True))
388
+
389
+
390
+ def test_issue_11099():
391
+ from sympy.abc import x, y
392
+ # some fixed value tests
393
+ fixed_test_data = {x: -2, y: 3}
394
+ assert Min(x, y).evalf(subs=fixed_test_data) == \
395
+ Min(x, y).subs(fixed_test_data).evalf()
396
+ assert Max(x, y).evalf(subs=fixed_test_data) == \
397
+ Max(x, y).subs(fixed_test_data).evalf()
398
+ # randomly generate some test data
399
+ from sympy.core.random import randint
400
+ for i in range(20):
401
+ random_test_data = {x: randint(-100, 100), y: randint(-100, 100)}
402
+ assert Min(x, y).evalf(subs=random_test_data) == \
403
+ Min(x, y).subs(random_test_data).evalf()
404
+ assert Max(x, y).evalf(subs=random_test_data) == \
405
+ Max(x, y).subs(random_test_data).evalf()
406
+
407
+
408
+ def test_issue_12638():
409
+ from sympy.abc import a, b, c
410
+ assert Min(a, b, c, Max(a, b)) == Min(a, b, c)
411
+ assert Min(a, b, Max(a, b, c)) == Min(a, b)
412
+ assert Min(a, b, Max(a, c)) == Min(a, b)
413
+
414
+ def test_issue_21399():
415
+ from sympy.abc import a, b, c
416
+ assert Max(Min(a, b), Min(a, b, c)) == Min(a, b)
417
+
418
+
419
+ def test_instantiation_evaluation():
420
+ from sympy.abc import v, w, x, y, z
421
+ assert Min(1, Max(2, x)) == 1
422
+ assert Max(3, Min(2, x)) == 3
423
+ assert Min(Max(x, y), Max(x, z)) == Max(x, Min(y, z))
424
+ assert set(Min(Max(w, x), Max(y, z)).args) == {
425
+ Max(w, x), Max(y, z)}
426
+ assert Min(Max(x, y), Max(x, z), w) == Min(
427
+ w, Max(x, Min(y, z)))
428
+ A, B = Min, Max
429
+ for i in range(2):
430
+ assert A(x, B(x, y)) == x
431
+ assert A(x, B(y, A(x, w, z))) == A(x, B(y, A(w, z)))
432
+ A, B = B, A
433
+ assert Min(w, Max(x, y), Max(v, x, z)) == Min(
434
+ w, Max(x, Min(y, Max(v, z))))
435
+
436
+ def test_rewrite_as_Abs():
437
+ from itertools import permutations
438
+ from sympy.functions.elementary.complexes import Abs
439
+ from sympy.abc import x, y, z, w
440
+ def test(e):
441
+ free = e.free_symbols
442
+ a = e.rewrite(Abs)
443
+ assert not a.has(Min, Max)
444
+ for i in permutations(range(len(free))):
445
+ reps = dict(zip(free, i))
446
+ assert a.xreplace(reps) == e.xreplace(reps)
447
+ test(Min(x, y))
448
+ test(Max(x, y))
449
+ test(Min(x, y, z))
450
+ test(Min(Max(w, x), Max(y, z)))
451
+
452
+ def test_issue_14000():
453
+ assert isinstance(sqrt(4, evaluate=False), Pow) == True
454
+ assert isinstance(cbrt(3.5, evaluate=False), Pow) == True
455
+ assert isinstance(root(16, 4, evaluate=False), Pow) == True
456
+
457
+ assert sqrt(4, evaluate=False) == Pow(4, S.Half, evaluate=False)
458
+ assert cbrt(3.5, evaluate=False) == Pow(3.5, Rational(1, 3), evaluate=False)
459
+ assert root(4, 2, evaluate=False) == Pow(4, S.Half, evaluate=False)
460
+
461
+ assert root(16, 4, 2, evaluate=False).has(Pow) == True
462
+ assert real_root(-8, 3, evaluate=False).has(Pow) == True
463
+
464
+ def test_issue_6899():
465
+ from sympy.core.function import Lambda
466
+ x = Symbol('x')
467
+ eqn = Lambda(x, x)
468
+ assert eqn.func(*eqn.args) == eqn
469
+
470
+ def test_Rem():
471
+ from sympy.abc import x, y
472
+ assert Rem(5, 3) == 2
473
+ assert Rem(-5, 3) == -2
474
+ assert Rem(5, -3) == 2
475
+ assert Rem(-5, -3) == -2
476
+ assert Rem(x**3, y) == Rem(x**3, y)
477
+ assert Rem(Rem(-5, 3) + 3, 3) == 1
478
+
479
+
480
+ def test_minmax_no_evaluate():
481
+ from sympy import evaluate
482
+ p = Symbol('p', positive=True)
483
+
484
+ assert Max(1, 3) == 3
485
+ assert Max(1, 3).args == ()
486
+ assert Max(0, p) == p
487
+ assert Max(0, p).args == ()
488
+ assert Min(0, p) == 0
489
+ assert Min(0, p).args == ()
490
+
491
+ assert Max(1, 3, evaluate=False) != 3
492
+ assert Max(1, 3, evaluate=False).args == (1, 3)
493
+ assert Max(0, p, evaluate=False) != p
494
+ assert Max(0, p, evaluate=False).args == (0, p)
495
+ assert Min(0, p, evaluate=False) != 0
496
+ assert Min(0, p, evaluate=False).args == (0, p)
497
+
498
+ with evaluate(False):
499
+ assert Max(1, 3) != 3
500
+ assert Max(1, 3).args == (1, 3)
501
+ assert Max(0, p) != p
502
+ assert Max(0, p).args == (0, p)
503
+ assert Min(0, p) != 0
504
+ assert Min(0, p).args == (0, p)
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/elementary/trigonometric.py ADDED
The diff for this file is too large to render. See raw diff
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ # Stub __init__.py for the sympy.functions.special package
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/bessel.py ADDED
@@ -0,0 +1,2208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from functools import wraps
2
+
3
+ from sympy.core import S
4
+ from sympy.core.add import Add
5
+ from sympy.core.cache import cacheit
6
+ from sympy.core.expr import Expr
7
+ from sympy.core.function import DefinedFunction, ArgumentIndexError, _mexpand
8
+ from sympy.core.logic import fuzzy_or, fuzzy_not
9
+ from sympy.core.numbers import Rational, pi, I
10
+ from sympy.core.power import Pow
11
+ from sympy.core.symbol import Dummy, uniquely_named_symbol, Wild
12
+ from sympy.core.sympify import sympify
13
+ from sympy.functions.combinatorial.factorials import factorial, RisingFactorial
14
+ from sympy.functions.elementary.trigonometric import sin, cos, csc, cot
15
+ from sympy.functions.elementary.integers import ceiling
16
+ from sympy.functions.elementary.exponential import exp, log
17
+ from sympy.functions.elementary.miscellaneous import cbrt, sqrt, root
18
+ from sympy.functions.elementary.complexes import (Abs, re, im, polar_lift, unpolarify)
19
+ from sympy.functions.special.gamma_functions import gamma, digamma, uppergamma
20
+ from sympy.functions.special.hyper import hyper
21
+ from sympy.polys.orthopolys import spherical_bessel_fn
22
+
23
+ from mpmath import mp, workprec
24
+
25
+ # TODO
26
+ # o Scorer functions G1 and G2
27
+ # o Asymptotic expansions
28
+ # These are possible, e.g. for fixed order, but since the bessel type
29
+ # functions are oscillatory they are not actually tractable at
30
+ # infinity, so this is not particularly useful right now.
31
+ # o Nicer series expansions.
32
+ # o More rewriting.
33
+ # o Add solvers to ode.py (or rather add solvers for the hypergeometric equation).
34
+
35
+
36
+ class BesselBase(DefinedFunction):
37
+ """
38
+ Abstract base class for Bessel-type functions.
39
+
40
+ This class is meant to reduce code duplication.
41
+ All Bessel-type functions can 1) be differentiated, with the derivatives
42
+ expressed in terms of similar functions, and 2) be rewritten in terms
43
+ of other Bessel-type functions.
44
+
45
+ Here, Bessel-type functions are assumed to have one complex parameter.
46
+
47
+ To use this base class, define class attributes ``_a`` and ``_b`` such that
48
+ ``2*F_n' = -_a*F_{n+1} + b*F_{n-1}``.
49
+
50
+ """
51
+
52
+ @property
53
+ def order(self):
54
+ """ The order of the Bessel-type function. """
55
+ return self.args[0]
56
+
57
+ @property
58
+ def argument(self):
59
+ """ The argument of the Bessel-type function. """
60
+ return self.args[1]
61
+
62
+ @classmethod
63
+ def eval(cls, nu, z):
64
+ return
65
+
66
+ def fdiff(self, argindex=2):
67
+ if argindex != 2:
68
+ raise ArgumentIndexError(self, argindex)
69
+ return (self._b/2 * self.__class__(self.order - 1, self.argument) -
70
+ self._a/2 * self.__class__(self.order + 1, self.argument))
71
+
72
+ def _eval_conjugate(self):
73
+ z = self.argument
74
+ if z.is_extended_negative is False:
75
+ return self.__class__(self.order.conjugate(), z.conjugate())
76
+
77
+ def _eval_is_meromorphic(self, x, a):
78
+ nu, z = self.order, self.argument
79
+
80
+ if nu.has(x):
81
+ return False
82
+ if not z._eval_is_meromorphic(x, a):
83
+ return None
84
+ z0 = z.subs(x, a)
85
+ if nu.is_integer:
86
+ if isinstance(self, (besselj, besseli, hn1, hn2, jn, yn)) or not nu.is_zero:
87
+ return fuzzy_not(z0.is_infinite)
88
+ return fuzzy_not(fuzzy_or([z0.is_zero, z0.is_infinite]))
89
+
90
+ def _eval_expand_func(self, **hints):
91
+ nu, z, f = self.order, self.argument, self.__class__
92
+ if nu.is_real:
93
+ if (nu - 1).is_positive:
94
+ return (-self._a*self._b*f(nu - 2, z)._eval_expand_func() +
95
+ 2*self._a*(nu - 1)*f(nu - 1, z)._eval_expand_func()/z)
96
+ elif (nu + 1).is_negative:
97
+ return (2*self._b*(nu + 1)*f(nu + 1, z)._eval_expand_func()/z -
98
+ self._a*self._b*f(nu + 2, z)._eval_expand_func())
99
+ return self
100
+
101
+ def _eval_simplify(self, **kwargs):
102
+ from sympy.simplify.simplify import besselsimp
103
+ return besselsimp(self)
104
+
105
+
106
+ class besselj(BesselBase):
107
+ r"""
108
+ Bessel function of the first kind.
109
+
110
+ Explanation
111
+ ===========
112
+
113
+ The Bessel $J$ function of order $\nu$ is defined to be the function
114
+ satisfying Bessel's differential equation
115
+
116
+ .. math ::
117
+ z^2 \frac{\mathrm{d}^2 w}{\mathrm{d}z^2}
118
+ + z \frac{\mathrm{d}w}{\mathrm{d}z} + (z^2 - \nu^2) w = 0,
119
+
120
+ with Laurent expansion
121
+
122
+ .. math ::
123
+ J_\nu(z) = z^\nu \left(\frac{1}{\Gamma(\nu + 1) 2^\nu} + O(z^2) \right),
124
+
125
+ if $\nu$ is not a negative integer. If $\nu=-n \in \mathbb{Z}_{<0}$
126
+ *is* a negative integer, then the definition is
127
+
128
+ .. math ::
129
+ J_{-n}(z) = (-1)^n J_n(z).
130
+
131
+ Examples
132
+ ========
133
+
134
+ Create a Bessel function object:
135
+
136
+ >>> from sympy import besselj, jn
137
+ >>> from sympy.abc import z, n
138
+ >>> b = besselj(n, z)
139
+
140
+ Differentiate it:
141
+
142
+ >>> b.diff(z)
143
+ besselj(n - 1, z)/2 - besselj(n + 1, z)/2
144
+
145
+ Rewrite in terms of spherical Bessel functions:
146
+
147
+ >>> b.rewrite(jn)
148
+ sqrt(2)*sqrt(z)*jn(n - 1/2, z)/sqrt(pi)
149
+
150
+ Access the parameter and argument:
151
+
152
+ >>> b.order
153
+ n
154
+ >>> b.argument
155
+ z
156
+
157
+ See Also
158
+ ========
159
+
160
+ bessely, besseli, besselk
161
+
162
+ References
163
+ ==========
164
+
165
+ .. [1] Abramowitz, Milton; Stegun, Irene A., eds. (1965), "Chapter 9",
166
+ Handbook of Mathematical Functions with Formulas, Graphs, and
167
+ Mathematical Tables
168
+ .. [2] Luke, Y. L. (1969), The Special Functions and Their
169
+ Approximations, Volume 1
170
+ .. [3] https://en.wikipedia.org/wiki/Bessel_function
171
+ .. [4] https://functions.wolfram.com/Bessel-TypeFunctions/BesselJ/
172
+
173
+ """
174
+
175
+ _a = S.One
176
+ _b = S.One
177
+
178
+ @classmethod
179
+ def eval(cls, nu, z):
180
+ if z.is_zero:
181
+ if nu.is_zero:
182
+ return S.One
183
+ elif (nu.is_integer and nu.is_zero is False) or re(nu).is_positive:
184
+ return S.Zero
185
+ elif re(nu).is_negative and not (nu.is_integer is True):
186
+ return S.ComplexInfinity
187
+ elif nu.is_imaginary:
188
+ return S.NaN
189
+ if z in (S.Infinity, S.NegativeInfinity):
190
+ return S.Zero
191
+
192
+ if z.could_extract_minus_sign():
193
+ return (z)**nu*(-z)**(-nu)*besselj(nu, -z)
194
+ if nu.is_integer:
195
+ if nu.could_extract_minus_sign():
196
+ return S.NegativeOne**(-nu)*besselj(-nu, z)
197
+ newz = z.extract_multiplicatively(I)
198
+ if newz: # NOTE we don't want to change the function if z==0
199
+ return I**(nu)*besseli(nu, newz)
200
+
201
+ # branch handling:
202
+ if nu.is_integer:
203
+ newz = unpolarify(z)
204
+ if newz != z:
205
+ return besselj(nu, newz)
206
+ else:
207
+ newz, n = z.extract_branch_factor()
208
+ if n != 0:
209
+ return exp(2*n*pi*nu*I)*besselj(nu, newz)
210
+ nnu = unpolarify(nu)
211
+ if nu != nnu:
212
+ return besselj(nnu, z)
213
+
214
+ def _eval_rewrite_as_besseli(self, nu, z, **kwargs):
215
+ return exp(I*pi*nu/2)*besseli(nu, polar_lift(-I)*z)
216
+
217
+ def _eval_rewrite_as_bessely(self, nu, z, **kwargs):
218
+ if nu.is_integer is False:
219
+ return csc(pi*nu)*bessely(-nu, z) - cot(pi*nu)*bessely(nu, z)
220
+
221
+ def _eval_rewrite_as_jn(self, nu, z, **kwargs):
222
+ return sqrt(2*z/pi)*jn(nu - S.Half, self.argument)
223
+
224
+ def _eval_as_leading_term(self, x, logx, cdir):
225
+ nu, z = self.args
226
+ try:
227
+ arg = z.as_leading_term(x)
228
+ except NotImplementedError:
229
+ return self
230
+ c, e = arg.as_coeff_exponent(x)
231
+
232
+ if e.is_positive:
233
+ return arg**nu/(2**nu*gamma(nu + 1))
234
+ elif e.is_negative:
235
+ cdir = 1 if cdir == 0 else cdir
236
+ sign = c*cdir**e
237
+ if not sign.is_negative:
238
+ # Refer Abramowitz and Stegun 1965, p. 364 for more information on
239
+ # asymptotic approximation of besselj function.
240
+ return sqrt(2)*cos(z - pi*(2*nu + 1)/4)/sqrt(pi*z)
241
+ return self
242
+
243
+ return super(besselj, self)._eval_as_leading_term(x, logx=logx, cdir=cdir)
244
+
245
+ def _eval_is_extended_real(self):
246
+ nu, z = self.args
247
+ if nu.is_integer and z.is_extended_real:
248
+ return True
249
+
250
+ def _eval_nseries(self, x, n, logx, cdir=0):
251
+ # Refer https://functions.wolfram.com/Bessel-TypeFunctions/BesselJ/06/01/04/01/01/0003/
252
+ # for more information on nseries expansion of besselj function.
253
+ from sympy.series.order import Order
254
+ nu, z = self.args
255
+
256
+ # In case of powers less than 1, number of terms need to be computed
257
+ # separately to avoid repeated callings of _eval_nseries with wrong n
258
+ try:
259
+ _, exp = z.leadterm(x)
260
+ except (ValueError, NotImplementedError):
261
+ return self
262
+
263
+ if exp.is_positive:
264
+ newn = ceiling(n/exp)
265
+ o = Order(x**n, x)
266
+ r = (z/2)._eval_nseries(x, n, logx, cdir).removeO()
267
+ if r is S.Zero:
268
+ return o
269
+ t = (_mexpand(r**2) + o).removeO()
270
+
271
+ term = r**nu/gamma(nu + 1)
272
+ s = [term]
273
+ for k in range(1, (newn + 1)//2):
274
+ term *= -t/(k*(nu + k))
275
+ term = (_mexpand(term) + o).removeO()
276
+ s.append(term)
277
+ return Add(*s) + o
278
+
279
+ return super(besselj, self)._eval_nseries(x, n, logx, cdir)
280
+
281
+
282
+ class bessely(BesselBase):
283
+ r"""
284
+ Bessel function of the second kind.
285
+
286
+ Explanation
287
+ ===========
288
+
289
+ The Bessel $Y$ function of order $\nu$ is defined as
290
+
291
+ .. math ::
292
+ Y_\nu(z) = \lim_{\mu \to \nu} \frac{J_\mu(z) \cos(\pi \mu)
293
+ - J_{-\mu}(z)}{\sin(\pi \mu)},
294
+
295
+ where $J_\mu(z)$ is the Bessel function of the first kind.
296
+
297
+ It is a solution to Bessel's equation, and linearly independent from
298
+ $J_\nu$.
299
+
300
+ Examples
301
+ ========
302
+
303
+ >>> from sympy import bessely, yn
304
+ >>> from sympy.abc import z, n
305
+ >>> b = bessely(n, z)
306
+ >>> b.diff(z)
307
+ bessely(n - 1, z)/2 - bessely(n + 1, z)/2
308
+ >>> b.rewrite(yn)
309
+ sqrt(2)*sqrt(z)*yn(n - 1/2, z)/sqrt(pi)
310
+
311
+ See Also
312
+ ========
313
+
314
+ besselj, besseli, besselk
315
+
316
+ References
317
+ ==========
318
+
319
+ .. [1] https://functions.wolfram.com/Bessel-TypeFunctions/BesselY/
320
+
321
+ """
322
+
323
+ _a = S.One
324
+ _b = S.One
325
+
326
+ @classmethod
327
+ def eval(cls, nu, z):
328
+ if z.is_zero:
329
+ if nu.is_zero:
330
+ return S.NegativeInfinity
331
+ elif re(nu).is_zero is False:
332
+ return S.ComplexInfinity
333
+ elif re(nu).is_zero:
334
+ return S.NaN
335
+ if z in (S.Infinity, S.NegativeInfinity):
336
+ return S.Zero
337
+ if z == I*S.Infinity:
338
+ return exp(I*pi*(nu + 1)/2) * S.Infinity
339
+ if z == I*S.NegativeInfinity:
340
+ return exp(-I*pi*(nu + 1)/2) * S.Infinity
341
+
342
+ if nu.is_integer:
343
+ if nu.could_extract_minus_sign():
344
+ return S.NegativeOne**(-nu)*bessely(-nu, z)
345
+
346
+ def _eval_rewrite_as_besselj(self, nu, z, **kwargs):
347
+ if nu.is_integer is False:
348
+ return csc(pi*nu)*(cos(pi*nu)*besselj(nu, z) - besselj(-nu, z))
349
+
350
+ def _eval_rewrite_as_besseli(self, nu, z, **kwargs):
351
+ aj = self._eval_rewrite_as_besselj(*self.args)
352
+ if aj:
353
+ return aj.rewrite(besseli)
354
+
355
+ def _eval_rewrite_as_yn(self, nu, z, **kwargs):
356
+ return sqrt(2*z/pi) * yn(nu - S.Half, self.argument)
357
+
358
+ def _eval_as_leading_term(self, x, logx, cdir):
359
+ nu, z = self.args
360
+ try:
361
+ arg = z.as_leading_term(x)
362
+ except NotImplementedError:
363
+ return self
364
+ c, e = arg.as_coeff_exponent(x)
365
+
366
+ if e.is_positive:
367
+ term_one = ((2/pi)*log(z/2)*besselj(nu, z))
368
+ term_two = -(z/2)**(-nu)*factorial(nu - 1)/pi if (nu).is_positive else S.Zero
369
+ term_three = -(z/2)**nu/(pi*factorial(nu))*(digamma(nu + 1) - S.EulerGamma)
370
+ arg = Add(*[term_one, term_two, term_three]).as_leading_term(x, logx=logx)
371
+ return arg
372
+ elif e.is_negative:
373
+ cdir = 1 if cdir == 0 else cdir
374
+ sign = c*cdir**e
375
+ if not sign.is_negative:
376
+ # Refer Abramowitz and Stegun 1965, p. 364 for more information on
377
+ # asymptotic approximation of bessely function.
378
+ return sqrt(2)*(-sin(pi*nu/2 - z + pi/4) + 3*cos(pi*nu/2 - z + pi/4)/(8*z))*sqrt(1/z)/sqrt(pi)
379
+ return self
380
+
381
+ return super(bessely, self)._eval_as_leading_term(x, logx=logx, cdir=cdir)
382
+
383
+ def _eval_is_extended_real(self):
384
+ nu, z = self.args
385
+ if nu.is_integer and z.is_positive:
386
+ return True
387
+
388
+ def _eval_nseries(self, x, n, logx, cdir=0):
389
+ # Refer https://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/02/0008/
390
+ # for more information on nseries expansion of bessely function.
391
+ from sympy.series.order import Order
392
+ nu, z = self.args
393
+
394
+ # In case of powers less than 1, number of terms need to be computed
395
+ # separately to avoid repeated callings of _eval_nseries with wrong n
396
+ try:
397
+ _, exp = z.leadterm(x)
398
+ except (ValueError, NotImplementedError):
399
+ return self
400
+
401
+ if exp.is_positive and nu.is_integer:
402
+ newn = ceiling(n/exp)
403
+ bn = besselj(nu, z)
404
+ a = ((2/pi)*log(z/2)*bn)._eval_nseries(x, n, logx, cdir)
405
+
406
+ b, c = [], []
407
+ o = Order(x**n, x)
408
+ r = (z/2)._eval_nseries(x, n, logx, cdir).removeO()
409
+ if r is S.Zero:
410
+ return o
411
+ t = (_mexpand(r**2) + o).removeO()
412
+
413
+ if nu > S.Zero:
414
+ term = r**(-nu)*factorial(nu - 1)/pi
415
+ b.append(term)
416
+ for k in range(1, nu):
417
+ denom = (nu - k)*k
418
+ if denom == S.Zero:
419
+ term *= t/k
420
+ else:
421
+ term *= t/denom
422
+ term = (_mexpand(term) + o).removeO()
423
+ b.append(term)
424
+
425
+ p = r**nu/(pi*factorial(nu))
426
+ term = p*(digamma(nu + 1) - S.EulerGamma)
427
+ c.append(term)
428
+ for k in range(1, (newn + 1)//2):
429
+ p *= -t/(k*(k + nu))
430
+ p = (_mexpand(p) + o).removeO()
431
+ term = p*(digamma(k + nu + 1) + digamma(k + 1))
432
+ c.append(term)
433
+ return a - Add(*b) - Add(*c) # Order term comes from a
434
+
435
+ return super(bessely, self)._eval_nseries(x, n, logx, cdir)
436
+
437
+
438
+ class besseli(BesselBase):
439
+ r"""
440
+ Modified Bessel function of the first kind.
441
+
442
+ Explanation
443
+ ===========
444
+
445
+ The Bessel $I$ function is a solution to the modified Bessel equation
446
+
447
+ .. math ::
448
+ z^2 \frac{\mathrm{d}^2 w}{\mathrm{d}z^2}
449
+ + z \frac{\mathrm{d}w}{\mathrm{d}z} + (z^2 + \nu^2)^2 w = 0.
450
+
451
+ It can be defined as
452
+
453
+ .. math ::
454
+ I_\nu(z) = i^{-\nu} J_\nu(iz),
455
+
456
+ where $J_\nu(z)$ is the Bessel function of the first kind.
457
+
458
+ Examples
459
+ ========
460
+
461
+ >>> from sympy import besseli
462
+ >>> from sympy.abc import z, n
463
+ >>> besseli(n, z).diff(z)
464
+ besseli(n - 1, z)/2 + besseli(n + 1, z)/2
465
+
466
+ See Also
467
+ ========
468
+
469
+ besselj, bessely, besselk
470
+
471
+ References
472
+ ==========
473
+
474
+ .. [1] https://functions.wolfram.com/Bessel-TypeFunctions/BesselI/
475
+
476
+ """
477
+
478
+ _a = -S.One
479
+ _b = S.One
480
+
481
+ @classmethod
482
+ def eval(cls, nu, z):
483
+ if z.is_zero:
484
+ if nu.is_zero:
485
+ return S.One
486
+ elif (nu.is_integer and nu.is_zero is False) or re(nu).is_positive:
487
+ return S.Zero
488
+ elif re(nu).is_negative and not (nu.is_integer is True):
489
+ return S.ComplexInfinity
490
+ elif nu.is_imaginary:
491
+ return S.NaN
492
+ if im(z) in (S.Infinity, S.NegativeInfinity):
493
+ return S.Zero
494
+ if z is S.Infinity:
495
+ return S.Infinity
496
+ if z is S.NegativeInfinity:
497
+ return (-1)**nu*S.Infinity
498
+
499
+ if z.could_extract_minus_sign():
500
+ return (z)**nu*(-z)**(-nu)*besseli(nu, -z)
501
+ if nu.is_integer:
502
+ if nu.could_extract_minus_sign():
503
+ return besseli(-nu, z)
504
+ newz = z.extract_multiplicatively(I)
505
+ if newz: # NOTE we don't want to change the function if z==0
506
+ return I**(-nu)*besselj(nu, -newz)
507
+
508
+ # branch handling:
509
+ if nu.is_integer:
510
+ newz = unpolarify(z)
511
+ if newz != z:
512
+ return besseli(nu, newz)
513
+ else:
514
+ newz, n = z.extract_branch_factor()
515
+ if n != 0:
516
+ return exp(2*n*pi*nu*I)*besseli(nu, newz)
517
+ nnu = unpolarify(nu)
518
+ if nu != nnu:
519
+ return besseli(nnu, z)
520
+
521
+ def _eval_rewrite_as_tractable(self, nu, z, limitvar=None, **kwargs):
522
+ if z.is_extended_real:
523
+ return exp(z)*_besseli(nu, z)
524
+
525
+ def _eval_rewrite_as_besselj(self, nu, z, **kwargs):
526
+ return exp(-I*pi*nu/2)*besselj(nu, polar_lift(I)*z)
527
+
528
+ def _eval_rewrite_as_bessely(self, nu, z, **kwargs):
529
+ aj = self._eval_rewrite_as_besselj(*self.args)
530
+ if aj:
531
+ return aj.rewrite(bessely)
532
+
533
+ def _eval_rewrite_as_jn(self, nu, z, **kwargs):
534
+ return self._eval_rewrite_as_besselj(*self.args).rewrite(jn)
535
+
536
+ def _eval_is_extended_real(self):
537
+ nu, z = self.args
538
+ if nu.is_integer and z.is_extended_real:
539
+ return True
540
+
541
+ def _eval_as_leading_term(self, x, logx, cdir):
542
+ nu, z = self.args
543
+ try:
544
+ arg = z.as_leading_term(x)
545
+ except NotImplementedError:
546
+ return self
547
+ c, e = arg.as_coeff_exponent(x)
548
+
549
+ if e.is_positive:
550
+ return arg**nu/(2**nu*gamma(nu + 1))
551
+ elif e.is_negative:
552
+ cdir = 1 if cdir == 0 else cdir
553
+ sign = c*cdir**e
554
+ if not sign.is_negative:
555
+ # Refer Abramowitz and Stegun 1965, p. 377 for more information on
556
+ # asymptotic approximation of besseli function.
557
+ return exp(z)/sqrt(2*pi*z)
558
+ return self
559
+
560
+ return super(besseli, self)._eval_as_leading_term(x, logx=logx, cdir=cdir)
561
+
562
+ def _eval_nseries(self, x, n, logx, cdir=0):
563
+ # Refer https://functions.wolfram.com/Bessel-TypeFunctions/BesselI/06/01/04/01/01/0003/
564
+ # for more information on nseries expansion of besseli function.
565
+ from sympy.series.order import Order
566
+ nu, z = self.args
567
+
568
+ # In case of powers less than 1, number of terms need to be computed
569
+ # separately to avoid repeated callings of _eval_nseries with wrong n
570
+ try:
571
+ _, exp = z.leadterm(x)
572
+ except (ValueError, NotImplementedError):
573
+ return self
574
+
575
+ if exp.is_positive:
576
+ newn = ceiling(n/exp)
577
+ o = Order(x**n, x)
578
+ r = (z/2)._eval_nseries(x, n, logx, cdir).removeO()
579
+ if r is S.Zero:
580
+ return o
581
+ t = (_mexpand(r**2) + o).removeO()
582
+
583
+ term = r**nu/gamma(nu + 1)
584
+ s = [term]
585
+ for k in range(1, (newn + 1)//2):
586
+ term *= t/(k*(nu + k))
587
+ term = (_mexpand(term) + o).removeO()
588
+ s.append(term)
589
+ return Add(*s) + o
590
+
591
+ return super(besseli, self)._eval_nseries(x, n, logx, cdir)
592
+
593
+ def _eval_aseries(self, n, args0, x, logx):
594
+ from sympy.functions.combinatorial.factorials import RisingFactorial
595
+ from sympy.series.order import Order
596
+ point = args0[1]
597
+
598
+ if point in [S.Infinity, S.NegativeInfinity]:
599
+ nu, z = self.args
600
+ s = [(RisingFactorial(Rational(2*nu - 1, 2), k)*RisingFactorial(Rational(2*nu + 1, 2), k))/\
601
+ ((2)**(k)*z**(Rational(2*k + 1, 2))*factorial(k)) for k in range(n)] + [Order(1/z**(Rational(2*n + 1, 2)), x)]
602
+ return exp(z)/sqrt(2*pi) * (Add(*s))
603
+
604
+ return super()._eval_aseries(n, args0, x, logx)
605
+
606
+
607
+ class besselk(BesselBase):
608
+ r"""
609
+ Modified Bessel function of the second kind.
610
+
611
+ Explanation
612
+ ===========
613
+
614
+ The Bessel $K$ function of order $\nu$ is defined as
615
+
616
+ .. math ::
617
+ K_\nu(z) = \lim_{\mu \to \nu} \frac{\pi}{2}
618
+ \frac{I_{-\mu}(z) -I_\mu(z)}{\sin(\pi \mu)},
619
+
620
+ where $I_\mu(z)$ is the modified Bessel function of the first kind.
621
+
622
+ It is a solution of the modified Bessel equation, and linearly independent
623
+ from $Y_\nu$.
624
+
625
+ Examples
626
+ ========
627
+
628
+ >>> from sympy import besselk
629
+ >>> from sympy.abc import z, n
630
+ >>> besselk(n, z).diff(z)
631
+ -besselk(n - 1, z)/2 - besselk(n + 1, z)/2
632
+
633
+ See Also
634
+ ========
635
+
636
+ besselj, besseli, bessely
637
+
638
+ References
639
+ ==========
640
+
641
+ .. [1] https://functions.wolfram.com/Bessel-TypeFunctions/BesselK/
642
+
643
+ """
644
+
645
+ _a = S.One
646
+ _b = -S.One
647
+
648
+ @classmethod
649
+ def eval(cls, nu, z):
650
+ if z.is_zero:
651
+ if nu.is_zero:
652
+ return S.Infinity
653
+ elif re(nu).is_zero is False:
654
+ return S.ComplexInfinity
655
+ elif re(nu).is_zero:
656
+ return S.NaN
657
+ if z in (S.Infinity, I*S.Infinity, I*S.NegativeInfinity):
658
+ return S.Zero
659
+
660
+ if nu.is_integer:
661
+ if nu.could_extract_minus_sign():
662
+ return besselk(-nu, z)
663
+
664
+ def _eval_rewrite_as_besseli(self, nu, z, **kwargs):
665
+ if nu.is_integer is False:
666
+ return pi*csc(pi*nu)*(besseli(-nu, z) - besseli(nu, z))/2
667
+
668
+ def _eval_rewrite_as_besselj(self, nu, z, **kwargs):
669
+ ai = self._eval_rewrite_as_besseli(*self.args)
670
+ if ai:
671
+ return ai.rewrite(besselj)
672
+
673
+ def _eval_rewrite_as_bessely(self, nu, z, **kwargs):
674
+ aj = self._eval_rewrite_as_besselj(*self.args)
675
+ if aj:
676
+ return aj.rewrite(bessely)
677
+
678
+ def _eval_rewrite_as_yn(self, nu, z, **kwargs):
679
+ ay = self._eval_rewrite_as_bessely(*self.args)
680
+ if ay:
681
+ return ay.rewrite(yn)
682
+
683
+ def _eval_is_extended_real(self):
684
+ nu, z = self.args
685
+ if nu.is_integer and z.is_positive:
686
+ return True
687
+
688
+ def _eval_rewrite_as_tractable(self, nu, z, limitvar=None, **kwargs):
689
+ if z.is_extended_real:
690
+ return exp(-z)*_besselk(nu, z)
691
+
692
+ def _eval_as_leading_term(self, x, logx, cdir):
693
+ nu, z = self.args
694
+ try:
695
+ arg = z.as_leading_term(x)
696
+ except NotImplementedError:
697
+ return self
698
+ _, e = arg.as_coeff_exponent(x)
699
+
700
+ if e.is_positive:
701
+ if nu.is_zero:
702
+ # Equation 9.6.8 of Abramowitz and Stegun (10th ed, 1972).
703
+ term = -log(z) - S.EulerGamma + log(2)
704
+ elif nu.is_nonzero:
705
+ # Equation 9.6.9 of Abramowitz and Stegun (10th ed, 1972).
706
+ term = gamma(Abs(nu))*(z/2)**(-Abs(nu))/2
707
+ else:
708
+ raise NotImplementedError(f"Cannot proceed without knowing if {nu} is zero or not.")
709
+
710
+ return term.as_leading_term(x, logx=logx)
711
+ elif e.is_negative:
712
+ # Equation 9.7.2 of Abramowitz and Stegun (10th ed, 1972).
713
+ return sqrt(pi)*exp(-arg)/sqrt(2*arg)
714
+ else:
715
+ return self.func(nu, arg)
716
+
717
+ def _eval_nseries(self, x, n, logx, cdir=0):
718
+ from sympy.series.order import Order
719
+ nu, z = self.args
720
+
721
+ try:
722
+ _, exp = z.leadterm(x)
723
+ except (ValueError, NotImplementedError):
724
+ return self
725
+
726
+ # In case of powers less than 1, number of terms need to be computed
727
+ # separately to avoid repeated callings of _eval_nseries with wrong n
728
+ if exp.is_positive:
729
+ r = (z/2)._eval_nseries(x, n, logx, cdir).removeO()
730
+ if r is S.Zero:
731
+ return Order(z**(-nu) + z**nu, x)
732
+
733
+ o = Order(x**n, x)
734
+ if nu.is_integer:
735
+ # Reference: https://functions.wolfram.com/Bessel-TypeFunctions/BesselK/06/01/04/01/02/0008/ (only for integer order)
736
+ newn = ceiling(n/exp)
737
+ bn = besseli(nu, z)
738
+ a = ((-1)**(nu - 1)*log(z/2)*bn)._eval_nseries(x, n, logx, cdir)
739
+
740
+ b, c = [], []
741
+ t = _mexpand(r**2)
742
+
743
+ if nu > S.Zero:
744
+ term = r**(-nu)*factorial(nu - 1)/2
745
+ b.append(term)
746
+ for k in range(1, nu):
747
+ term *= t/((k - nu)*k)
748
+ term = (_mexpand(term) + o).removeO()
749
+ b.append(term)
750
+
751
+ p = r**nu*(-1)**nu/(2*factorial(nu))
752
+ term = p*(digamma(nu + 1) - S.EulerGamma)
753
+ c.append(term)
754
+ for k in range(1, (newn + 1)//2):
755
+ p *= t/(k*(k + nu))
756
+ p = (_mexpand(p) + o).removeO()
757
+ term = p*(digamma(k + nu + 1) + digamma(k + 1))
758
+ c.append(term)
759
+ return a + Add(*b) + Add(*c) + o
760
+ elif nu.is_noninteger:
761
+ # Reference: https://functions.wolfram.com/Bessel-TypeFunctions/BesselK/06/01/04/01/01/0003/
762
+ # (only for non-integer order).
763
+ # While the expression in the reference above seems correct
764
+ # for non-real order as well, it would need some manipulation
765
+ # (not implemented) to be written as a power series in x with
766
+ # real exponents [e.g. Dunster 1990. "Bessel functions
767
+ # of purely imaginary order, with an application to second-order
768
+ # linear differential equations having a large parameter".
769
+ # SIAM J. Math. Anal. Vol 21, No. 4, pp 995-1018.].
770
+ newn_a = ceiling((n+nu)/exp)
771
+ newn_b = ceiling((n-nu)/exp)
772
+
773
+ a, b = [], []
774
+ for k in range((newn_a+1)//2):
775
+ term = gamma(nu)*r**(2*k-nu)/(2*RisingFactorial(1-nu, k)*factorial(k))
776
+ a.append(_mexpand(term))
777
+ for k in range((newn_b+1)//2):
778
+ term = gamma(-nu)*r**(2*k+nu)/(2*RisingFactorial(nu+1, k)*factorial(k))
779
+ b.append(_mexpand(term))
780
+ return Add(*a) + Add(*b) + o
781
+ else:
782
+ raise NotImplementedError("besselk expansion is only implemented for real order")
783
+
784
+ return super(besselk, self)._eval_nseries(x, n, logx, cdir)
785
+
786
+ def _eval_aseries(self, n, args0, x, logx):
787
+ from sympy.functions.combinatorial.factorials import RisingFactorial
788
+ from sympy.series.order import Order
789
+ point = args0[1]
790
+
791
+ if point in [S.Infinity, S.NegativeInfinity]:
792
+ nu, z = self.args
793
+ s = [(RisingFactorial(Rational(2*nu - 1, 2), k)*RisingFactorial(Rational(2*nu + 1, 2), k))/\
794
+ ((-2)**(k)*z**(Rational(2*k + 1, 2))*factorial(k)) for k in range(n)] +[Order(1/z**(Rational(2*n + 1, 2)), x)]
795
+ return (exp(-z)*sqrt(pi/2))*Add(*s)
796
+
797
+ return super()._eval_aseries(n, args0, x, logx)
798
+
799
+
800
+ class hankel1(BesselBase):
801
+ r"""
802
+ Hankel function of the first kind.
803
+
804
+ Explanation
805
+ ===========
806
+
807
+ This function is defined as
808
+
809
+ .. math ::
810
+ H_\nu^{(1)} = J_\nu(z) + iY_\nu(z),
811
+
812
+ where $J_\nu(z)$ is the Bessel function of the first kind, and
813
+ $Y_\nu(z)$ is the Bessel function of the second kind.
814
+
815
+ It is a solution to Bessel's equation.
816
+
817
+ Examples
818
+ ========
819
+
820
+ >>> from sympy import hankel1
821
+ >>> from sympy.abc import z, n
822
+ >>> hankel1(n, z).diff(z)
823
+ hankel1(n - 1, z)/2 - hankel1(n + 1, z)/2
824
+
825
+ See Also
826
+ ========
827
+
828
+ hankel2, besselj, bessely
829
+
830
+ References
831
+ ==========
832
+
833
+ .. [1] https://functions.wolfram.com/Bessel-TypeFunctions/HankelH1/
834
+
835
+ """
836
+
837
+ _a = S.One
838
+ _b = S.One
839
+
840
+ def _eval_conjugate(self):
841
+ z = self.argument
842
+ if z.is_extended_negative is False:
843
+ return hankel2(self.order.conjugate(), z.conjugate())
844
+
845
+
846
+ class hankel2(BesselBase):
847
+ r"""
848
+ Hankel function of the second kind.
849
+
850
+ Explanation
851
+ ===========
852
+
853
+ This function is defined as
854
+
855
+ .. math ::
856
+ H_\nu^{(2)} = J_\nu(z) - iY_\nu(z),
857
+
858
+ where $J_\nu(z)$ is the Bessel function of the first kind, and
859
+ $Y_\nu(z)$ is the Bessel function of the second kind.
860
+
861
+ It is a solution to Bessel's equation, and linearly independent from
862
+ $H_\nu^{(1)}$.
863
+
864
+ Examples
865
+ ========
866
+
867
+ >>> from sympy import hankel2
868
+ >>> from sympy.abc import z, n
869
+ >>> hankel2(n, z).diff(z)
870
+ hankel2(n - 1, z)/2 - hankel2(n + 1, z)/2
871
+
872
+ See Also
873
+ ========
874
+
875
+ hankel1, besselj, bessely
876
+
877
+ References
878
+ ==========
879
+
880
+ .. [1] https://functions.wolfram.com/Bessel-TypeFunctions/HankelH2/
881
+
882
+ """
883
+
884
+ _a = S.One
885
+ _b = S.One
886
+
887
+ def _eval_conjugate(self):
888
+ z = self.argument
889
+ if z.is_extended_negative is False:
890
+ return hankel1(self.order.conjugate(), z.conjugate())
891
+
892
+
893
+ def assume_integer_order(fn):
894
+ @wraps(fn)
895
+ def g(self, nu, z):
896
+ if nu.is_integer:
897
+ return fn(self, nu, z)
898
+ return g
899
+
900
+
901
+ class SphericalBesselBase(BesselBase):
902
+ """
903
+ Base class for spherical Bessel functions.
904
+
905
+ These are thin wrappers around ordinary Bessel functions,
906
+ since spherical Bessel functions differ from the ordinary
907
+ ones just by a slight change in order.
908
+
909
+ To use this class, define the ``_eval_evalf()`` and ``_expand()`` methods.
910
+
911
+ """
912
+
913
+ def _expand(self, **hints):
914
+ """ Expand self into a polynomial. Nu is guaranteed to be Integer. """
915
+ raise NotImplementedError('expansion')
916
+
917
+ def _eval_expand_func(self, **hints):
918
+ if self.order.is_Integer:
919
+ return self._expand(**hints)
920
+ return self
921
+
922
+ def fdiff(self, argindex=2):
923
+ if argindex != 2:
924
+ raise ArgumentIndexError(self, argindex)
925
+ return self.__class__(self.order - 1, self.argument) - \
926
+ self * (self.order + 1)/self.argument
927
+
928
+
929
+ def _jn(n, z):
930
+ return (spherical_bessel_fn(n, z)*sin(z) +
931
+ S.NegativeOne**(n + 1)*spherical_bessel_fn(-n - 1, z)*cos(z))
932
+
933
+
934
+ def _yn(n, z):
935
+ # (-1)**(n + 1) * _jn(-n - 1, z)
936
+ return (S.NegativeOne**(n + 1) * spherical_bessel_fn(-n - 1, z)*sin(z) -
937
+ spherical_bessel_fn(n, z)*cos(z))
938
+
939
+
940
+ class jn(SphericalBesselBase):
941
+ r"""
942
+ Spherical Bessel function of the first kind.
943
+
944
+ Explanation
945
+ ===========
946
+
947
+ This function is a solution to the spherical Bessel equation
948
+
949
+ .. math ::
950
+ z^2 \frac{\mathrm{d}^2 w}{\mathrm{d}z^2}
951
+ + 2z \frac{\mathrm{d}w}{\mathrm{d}z} + (z^2 - \nu(\nu + 1)) w = 0.
952
+
953
+ It can be defined as
954
+
955
+ .. math ::
956
+ j_\nu(z) = \sqrt{\frac{\pi}{2z}} J_{\nu + \frac{1}{2}}(z),
957
+
958
+ where $J_\nu(z)$ is the Bessel function of the first kind.
959
+
960
+ The spherical Bessel functions of integral order are
961
+ calculated using the formula:
962
+
963
+ .. math:: j_n(z) = f_n(z) \sin{z} + (-1)^{n+1} f_{-n-1}(z) \cos{z},
964
+
965
+ where the coefficients $f_n(z)$ are available as
966
+ :func:`sympy.polys.orthopolys.spherical_bessel_fn`.
967
+
968
+ Examples
969
+ ========
970
+
971
+ >>> from sympy import Symbol, jn, sin, cos, expand_func, besselj, bessely
972
+ >>> z = Symbol("z")
973
+ >>> nu = Symbol("nu", integer=True)
974
+ >>> print(expand_func(jn(0, z)))
975
+ sin(z)/z
976
+ >>> expand_func(jn(1, z)) == sin(z)/z**2 - cos(z)/z
977
+ True
978
+ >>> expand_func(jn(3, z))
979
+ (-6/z**2 + 15/z**4)*sin(z) + (1/z - 15/z**3)*cos(z)
980
+ >>> jn(nu, z).rewrite(besselj)
981
+ sqrt(2)*sqrt(pi)*sqrt(1/z)*besselj(nu + 1/2, z)/2
982
+ >>> jn(nu, z).rewrite(bessely)
983
+ (-1)**nu*sqrt(2)*sqrt(pi)*sqrt(1/z)*bessely(-nu - 1/2, z)/2
984
+ >>> jn(2, 5.2+0.3j).evalf(20)
985
+ 0.099419756723640344491 - 0.054525080242173562897*I
986
+
987
+ See Also
988
+ ========
989
+
990
+ besselj, bessely, besselk, yn
991
+
992
+ References
993
+ ==========
994
+
995
+ .. [1] https://dlmf.nist.gov/10.47
996
+
997
+ """
998
+ @classmethod
999
+ def eval(cls, nu, z):
1000
+ if z.is_zero:
1001
+ if nu.is_zero:
1002
+ return S.One
1003
+ elif nu.is_integer:
1004
+ if nu.is_positive:
1005
+ return S.Zero
1006
+ else:
1007
+ return S.ComplexInfinity
1008
+ if z in (S.NegativeInfinity, S.Infinity):
1009
+ return S.Zero
1010
+
1011
+ def _eval_rewrite_as_besselj(self, nu, z, **kwargs):
1012
+ return sqrt(pi/(2*z)) * besselj(nu + S.Half, z)
1013
+
1014
+ def _eval_rewrite_as_bessely(self, nu, z, **kwargs):
1015
+ return S.NegativeOne**nu * sqrt(pi/(2*z)) * bessely(-nu - S.Half, z)
1016
+
1017
+ def _eval_rewrite_as_yn(self, nu, z, **kwargs):
1018
+ return S.NegativeOne**(nu) * yn(-nu - 1, z)
1019
+
1020
+ def _expand(self, **hints):
1021
+ return _jn(self.order, self.argument)
1022
+
1023
+ def _eval_evalf(self, prec):
1024
+ if self.order.is_Integer:
1025
+ return self.rewrite(besselj)._eval_evalf(prec)
1026
+
1027
+
1028
+ class yn(SphericalBesselBase):
1029
+ r"""
1030
+ Spherical Bessel function of the second kind.
1031
+
1032
+ Explanation
1033
+ ===========
1034
+
1035
+ This function is another solution to the spherical Bessel equation, and
1036
+ linearly independent from $j_n$. It can be defined as
1037
+
1038
+ .. math ::
1039
+ y_\nu(z) = \sqrt{\frac{\pi}{2z}} Y_{\nu + \frac{1}{2}}(z),
1040
+
1041
+ where $Y_\nu(z)$ is the Bessel function of the second kind.
1042
+
1043
+ For integral orders $n$, $y_n$ is calculated using the formula:
1044
+
1045
+ .. math:: y_n(z) = (-1)^{n+1} j_{-n-1}(z)
1046
+
1047
+ Examples
1048
+ ========
1049
+
1050
+ >>> from sympy import Symbol, yn, sin, cos, expand_func, besselj, bessely
1051
+ >>> z = Symbol("z")
1052
+ >>> nu = Symbol("nu", integer=True)
1053
+ >>> print(expand_func(yn(0, z)))
1054
+ -cos(z)/z
1055
+ >>> expand_func(yn(1, z)) == -cos(z)/z**2-sin(z)/z
1056
+ True
1057
+ >>> yn(nu, z).rewrite(besselj)
1058
+ (-1)**(nu + 1)*sqrt(2)*sqrt(pi)*sqrt(1/z)*besselj(-nu - 1/2, z)/2
1059
+ >>> yn(nu, z).rewrite(bessely)
1060
+ sqrt(2)*sqrt(pi)*sqrt(1/z)*bessely(nu + 1/2, z)/2
1061
+ >>> yn(2, 5.2+0.3j).evalf(20)
1062
+ 0.18525034196069722536 + 0.014895573969924817587*I
1063
+
1064
+ See Also
1065
+ ========
1066
+
1067
+ besselj, bessely, besselk, jn
1068
+
1069
+ References
1070
+ ==========
1071
+
1072
+ .. [1] https://dlmf.nist.gov/10.47
1073
+
1074
+ """
1075
+ @assume_integer_order
1076
+ def _eval_rewrite_as_besselj(self, nu, z, **kwargs):
1077
+ return S.NegativeOne**(nu+1) * sqrt(pi/(2*z)) * besselj(-nu - S.Half, z)
1078
+
1079
+ @assume_integer_order
1080
+ def _eval_rewrite_as_bessely(self, nu, z, **kwargs):
1081
+ return sqrt(pi/(2*z)) * bessely(nu + S.Half, z)
1082
+
1083
+ def _eval_rewrite_as_jn(self, nu, z, **kwargs):
1084
+ return S.NegativeOne**(nu + 1) * jn(-nu - 1, z)
1085
+
1086
+ def _expand(self, **hints):
1087
+ return _yn(self.order, self.argument)
1088
+
1089
+ def _eval_evalf(self, prec):
1090
+ if self.order.is_Integer:
1091
+ return self.rewrite(bessely)._eval_evalf(prec)
1092
+
1093
+
1094
+ class SphericalHankelBase(SphericalBesselBase):
1095
+
1096
+ @assume_integer_order
1097
+ def _eval_rewrite_as_besselj(self, nu, z, **kwargs):
1098
+ # jn +- I*yn
1099
+ # jn as beeselj: sqrt(pi/(2*z)) * besselj(nu + S.Half, z)
1100
+ # yn as besselj: (-1)**(nu+1) * sqrt(pi/(2*z)) * besselj(-nu - S.Half, z)
1101
+ hks = self._hankel_kind_sign
1102
+ return sqrt(pi/(2*z))*(besselj(nu + S.Half, z) +
1103
+ hks*I*S.NegativeOne**(nu+1)*besselj(-nu - S.Half, z))
1104
+
1105
+ @assume_integer_order
1106
+ def _eval_rewrite_as_bessely(self, nu, z, **kwargs):
1107
+ # jn +- I*yn
1108
+ # jn as bessely: (-1)**nu * sqrt(pi/(2*z)) * bessely(-nu - S.Half, z)
1109
+ # yn as bessely: sqrt(pi/(2*z)) * bessely(nu + S.Half, z)
1110
+ hks = self._hankel_kind_sign
1111
+ return sqrt(pi/(2*z))*(S.NegativeOne**nu*bessely(-nu - S.Half, z) +
1112
+ hks*I*bessely(nu + S.Half, z))
1113
+
1114
+ def _eval_rewrite_as_yn(self, nu, z, **kwargs):
1115
+ hks = self._hankel_kind_sign
1116
+ return jn(nu, z).rewrite(yn) + hks*I*yn(nu, z)
1117
+
1118
+ def _eval_rewrite_as_jn(self, nu, z, **kwargs):
1119
+ hks = self._hankel_kind_sign
1120
+ return jn(nu, z) + hks*I*yn(nu, z).rewrite(jn)
1121
+
1122
+ def _eval_expand_func(self, **hints):
1123
+ if self.order.is_Integer:
1124
+ return self._expand(**hints)
1125
+ else:
1126
+ nu = self.order
1127
+ z = self.argument
1128
+ hks = self._hankel_kind_sign
1129
+ return jn(nu, z) + hks*I*yn(nu, z)
1130
+
1131
+ def _expand(self, **hints):
1132
+ n = self.order
1133
+ z = self.argument
1134
+ hks = self._hankel_kind_sign
1135
+
1136
+ # fully expanded version
1137
+ # return ((fn(n, z) * sin(z) +
1138
+ # (-1)**(n + 1) * fn(-n - 1, z) * cos(z)) + # jn
1139
+ # (hks * I * (-1)**(n + 1) *
1140
+ # (fn(-n - 1, z) * hk * I * sin(z) +
1141
+ # (-1)**(-n) * fn(n, z) * I * cos(z))) # +-I*yn
1142
+ # )
1143
+
1144
+ return (_jn(n, z) + hks*I*_yn(n, z)).expand()
1145
+
1146
+ def _eval_evalf(self, prec):
1147
+ if self.order.is_Integer:
1148
+ return self.rewrite(besselj)._eval_evalf(prec)
1149
+
1150
+
1151
+ class hn1(SphericalHankelBase):
1152
+ r"""
1153
+ Spherical Hankel function of the first kind.
1154
+
1155
+ Explanation
1156
+ ===========
1157
+
1158
+ This function is defined as
1159
+
1160
+ .. math:: h_\nu^(1)(z) = j_\nu(z) + i y_\nu(z),
1161
+
1162
+ where $j_\nu(z)$ and $y_\nu(z)$ are the spherical
1163
+ Bessel function of the first and second kinds.
1164
+
1165
+ For integral orders $n$, $h_n^(1)$ is calculated using the formula:
1166
+
1167
+ .. math:: h_n^(1)(z) = j_{n}(z) + i (-1)^{n+1} j_{-n-1}(z)
1168
+
1169
+ Examples
1170
+ ========
1171
+
1172
+ >>> from sympy import Symbol, hn1, hankel1, expand_func, yn, jn
1173
+ >>> z = Symbol("z")
1174
+ >>> nu = Symbol("nu", integer=True)
1175
+ >>> print(expand_func(hn1(nu, z)))
1176
+ jn(nu, z) + I*yn(nu, z)
1177
+ >>> print(expand_func(hn1(0, z)))
1178
+ sin(z)/z - I*cos(z)/z
1179
+ >>> print(expand_func(hn1(1, z)))
1180
+ -I*sin(z)/z - cos(z)/z + sin(z)/z**2 - I*cos(z)/z**2
1181
+ >>> hn1(nu, z).rewrite(jn)
1182
+ (-1)**(nu + 1)*I*jn(-nu - 1, z) + jn(nu, z)
1183
+ >>> hn1(nu, z).rewrite(yn)
1184
+ (-1)**nu*yn(-nu - 1, z) + I*yn(nu, z)
1185
+ >>> hn1(nu, z).rewrite(hankel1)
1186
+ sqrt(2)*sqrt(pi)*sqrt(1/z)*hankel1(nu, z)/2
1187
+
1188
+ See Also
1189
+ ========
1190
+
1191
+ hn2, jn, yn, hankel1, hankel2
1192
+
1193
+ References
1194
+ ==========
1195
+
1196
+ .. [1] https://dlmf.nist.gov/10.47
1197
+
1198
+ """
1199
+
1200
+ _hankel_kind_sign = S.One
1201
+
1202
+ @assume_integer_order
1203
+ def _eval_rewrite_as_hankel1(self, nu, z, **kwargs):
1204
+ return sqrt(pi/(2*z))*hankel1(nu, z)
1205
+
1206
+
1207
+ class hn2(SphericalHankelBase):
1208
+ r"""
1209
+ Spherical Hankel function of the second kind.
1210
+
1211
+ Explanation
1212
+ ===========
1213
+
1214
+ This function is defined as
1215
+
1216
+ .. math:: h_\nu^(2)(z) = j_\nu(z) - i y_\nu(z),
1217
+
1218
+ where $j_\nu(z)$ and $y_\nu(z)$ are the spherical
1219
+ Bessel function of the first and second kinds.
1220
+
1221
+ For integral orders $n$, $h_n^(2)$ is calculated using the formula:
1222
+
1223
+ .. math:: h_n^(2)(z) = j_{n} - i (-1)^{n+1} j_{-n-1}(z)
1224
+
1225
+ Examples
1226
+ ========
1227
+
1228
+ >>> from sympy import Symbol, hn2, hankel2, expand_func, jn, yn
1229
+ >>> z = Symbol("z")
1230
+ >>> nu = Symbol("nu", integer=True)
1231
+ >>> print(expand_func(hn2(nu, z)))
1232
+ jn(nu, z) - I*yn(nu, z)
1233
+ >>> print(expand_func(hn2(0, z)))
1234
+ sin(z)/z + I*cos(z)/z
1235
+ >>> print(expand_func(hn2(1, z)))
1236
+ I*sin(z)/z - cos(z)/z + sin(z)/z**2 + I*cos(z)/z**2
1237
+ >>> hn2(nu, z).rewrite(hankel2)
1238
+ sqrt(2)*sqrt(pi)*sqrt(1/z)*hankel2(nu, z)/2
1239
+ >>> hn2(nu, z).rewrite(jn)
1240
+ -(-1)**(nu + 1)*I*jn(-nu - 1, z) + jn(nu, z)
1241
+ >>> hn2(nu, z).rewrite(yn)
1242
+ (-1)**nu*yn(-nu - 1, z) - I*yn(nu, z)
1243
+
1244
+ See Also
1245
+ ========
1246
+
1247
+ hn1, jn, yn, hankel1, hankel2
1248
+
1249
+ References
1250
+ ==========
1251
+
1252
+ .. [1] https://dlmf.nist.gov/10.47
1253
+
1254
+ """
1255
+
1256
+ _hankel_kind_sign = -S.One
1257
+
1258
+ @assume_integer_order
1259
+ def _eval_rewrite_as_hankel2(self, nu, z, **kwargs):
1260
+ return sqrt(pi/(2*z))*hankel2(nu, z)
1261
+
1262
+
1263
+ def jn_zeros(n, k, method="sympy", dps=15):
1264
+ """
1265
+ Zeros of the spherical Bessel function of the first kind.
1266
+
1267
+ Explanation
1268
+ ===========
1269
+
1270
+ This returns an array of zeros of $jn$ up to the $k$-th zero.
1271
+
1272
+ * method = "sympy": uses `mpmath.besseljzero
1273
+ <https://mpmath.org/doc/current/functions/bessel.html#mpmath.besseljzero>`_
1274
+ * method = "scipy": uses the
1275
+ `SciPy's sph_jn <https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.jn_zeros.html>`_
1276
+ and
1277
+ `newton <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.newton.html>`_
1278
+ to find all
1279
+ roots, which is faster than computing the zeros using a general
1280
+ numerical solver, but it requires SciPy and only works with low
1281
+ precision floating point numbers. (The function used with
1282
+ method="sympy" is a recent addition to mpmath; before that a general
1283
+ solver was used.)
1284
+
1285
+ Examples
1286
+ ========
1287
+
1288
+ >>> from sympy import jn_zeros
1289
+ >>> jn_zeros(2, 4, dps=5)
1290
+ [5.7635, 9.095, 12.323, 15.515]
1291
+
1292
+ See Also
1293
+ ========
1294
+
1295
+ jn, yn, besselj, besselk, bessely
1296
+
1297
+ Parameters
1298
+ ==========
1299
+
1300
+ n : integer
1301
+ order of Bessel function
1302
+
1303
+ k : integer
1304
+ number of zeros to return
1305
+
1306
+
1307
+ """
1308
+ from math import pi as math_pi
1309
+
1310
+ if method == "sympy":
1311
+ from mpmath import besseljzero
1312
+ from mpmath.libmp.libmpf import dps_to_prec
1313
+ prec = dps_to_prec(dps)
1314
+ return [Expr._from_mpmath(besseljzero(S(n + 0.5)._to_mpmath(prec),
1315
+ int(l)), prec)
1316
+ for l in range(1, k + 1)]
1317
+ elif method == "scipy":
1318
+ from scipy.optimize import newton
1319
+ try:
1320
+ from scipy.special import spherical_jn
1321
+ f = lambda x: spherical_jn(n, x)
1322
+ except ImportError:
1323
+ from scipy.special import sph_jn
1324
+ f = lambda x: sph_jn(n, x)[0][-1]
1325
+ else:
1326
+ raise NotImplementedError("Unknown method.")
1327
+
1328
+ def solver(f, x):
1329
+ if method == "scipy":
1330
+ root = newton(f, x)
1331
+ else:
1332
+ raise NotImplementedError("Unknown method.")
1333
+ return root
1334
+
1335
+ # we need to approximate the position of the first root:
1336
+ root = n + math_pi
1337
+ # determine the first root exactly:
1338
+ root = solver(f, root)
1339
+ roots = [root]
1340
+ for i in range(k - 1):
1341
+ # estimate the position of the next root using the last root + pi:
1342
+ root = solver(f, root + math_pi)
1343
+ roots.append(root)
1344
+ return roots
1345
+
1346
+
1347
+ class AiryBase(DefinedFunction):
1348
+ """
1349
+ Abstract base class for Airy functions.
1350
+
1351
+ This class is meant to reduce code duplication.
1352
+
1353
+ """
1354
+
1355
+ def _eval_conjugate(self):
1356
+ return self.func(self.args[0].conjugate())
1357
+
1358
+ def _eval_is_extended_real(self):
1359
+ return self.args[0].is_extended_real
1360
+
1361
+ def as_real_imag(self, deep=True, **hints):
1362
+ z = self.args[0]
1363
+ zc = z.conjugate()
1364
+ f = self.func
1365
+ u = (f(z)+f(zc))/2
1366
+ v = I*(f(zc)-f(z))/2
1367
+ return u, v
1368
+
1369
+ def _eval_expand_complex(self, deep=True, **hints):
1370
+ re_part, im_part = self.as_real_imag(deep=deep, **hints)
1371
+ return re_part + im_part*I
1372
+
1373
+
1374
+ class airyai(AiryBase):
1375
+ r"""
1376
+ The Airy function $\operatorname{Ai}$ of the first kind.
1377
+
1378
+ Explanation
1379
+ ===========
1380
+
1381
+ The Airy function $\operatorname{Ai}(z)$ is defined to be the function
1382
+ satisfying Airy's differential equation
1383
+
1384
+ .. math::
1385
+ \frac{\mathrm{d}^2 w(z)}{\mathrm{d}z^2} - z w(z) = 0.
1386
+
1387
+ Equivalently, for real $z$
1388
+
1389
+ .. math::
1390
+ \operatorname{Ai}(z) := \frac{1}{\pi}
1391
+ \int_0^\infty \cos\left(\frac{t^3}{3} + z t\right) \mathrm{d}t.
1392
+
1393
+ Examples
1394
+ ========
1395
+
1396
+ Create an Airy function object:
1397
+
1398
+ >>> from sympy import airyai
1399
+ >>> from sympy.abc import z
1400
+
1401
+ >>> airyai(z)
1402
+ airyai(z)
1403
+
1404
+ Several special values are known:
1405
+
1406
+ >>> airyai(0)
1407
+ 3**(1/3)/(3*gamma(2/3))
1408
+ >>> from sympy import oo
1409
+ >>> airyai(oo)
1410
+ 0
1411
+ >>> airyai(-oo)
1412
+ 0
1413
+
1414
+ The Airy function obeys the mirror symmetry:
1415
+
1416
+ >>> from sympy import conjugate
1417
+ >>> conjugate(airyai(z))
1418
+ airyai(conjugate(z))
1419
+
1420
+ Differentiation with respect to $z$ is supported:
1421
+
1422
+ >>> from sympy import diff
1423
+ >>> diff(airyai(z), z)
1424
+ airyaiprime(z)
1425
+ >>> diff(airyai(z), z, 2)
1426
+ z*airyai(z)
1427
+
1428
+ Series expansion is also supported:
1429
+
1430
+ >>> from sympy import series
1431
+ >>> series(airyai(z), z, 0, 3)
1432
+ 3**(5/6)*gamma(1/3)/(6*pi) - 3**(1/6)*z*gamma(2/3)/(2*pi) + O(z**3)
1433
+
1434
+ We can numerically evaluate the Airy function to arbitrary precision
1435
+ on the whole complex plane:
1436
+
1437
+ >>> airyai(-2).evalf(50)
1438
+ 0.22740742820168557599192443603787379946077222541710
1439
+
1440
+ Rewrite $\operatorname{Ai}(z)$ in terms of hypergeometric functions:
1441
+
1442
+ >>> from sympy import hyper
1443
+ >>> airyai(z).rewrite(hyper)
1444
+ -3**(2/3)*z*hyper((), (4/3,), z**3/9)/(3*gamma(1/3)) + 3**(1/3)*hyper((), (2/3,), z**3/9)/(3*gamma(2/3))
1445
+
1446
+ See Also
1447
+ ========
1448
+
1449
+ airybi: Airy function of the second kind.
1450
+ airyaiprime: Derivative of the Airy function of the first kind.
1451
+ airybiprime: Derivative of the Airy function of the second kind.
1452
+
1453
+ References
1454
+ ==========
1455
+
1456
+ .. [1] https://en.wikipedia.org/wiki/Airy_function
1457
+ .. [2] https://dlmf.nist.gov/9
1458
+ .. [3] https://encyclopediaofmath.org/wiki/Airy_functions
1459
+ .. [4] https://mathworld.wolfram.com/AiryFunctions.html
1460
+
1461
+ """
1462
+
1463
+ nargs = 1
1464
+ unbranched = True
1465
+
1466
+ @classmethod
1467
+ def eval(cls, arg):
1468
+ if arg.is_Number:
1469
+ if arg is S.NaN:
1470
+ return S.NaN
1471
+ elif arg is S.Infinity:
1472
+ return S.Zero
1473
+ elif arg is S.NegativeInfinity:
1474
+ return S.Zero
1475
+ elif arg.is_zero:
1476
+ return S.One / (3**Rational(2, 3) * gamma(Rational(2, 3)))
1477
+ if arg.is_zero:
1478
+ return S.One / (3**Rational(2, 3) * gamma(Rational(2, 3)))
1479
+
1480
+ def fdiff(self, argindex=1):
1481
+ if argindex == 1:
1482
+ return airyaiprime(self.args[0])
1483
+ else:
1484
+ raise ArgumentIndexError(self, argindex)
1485
+
1486
+ @staticmethod
1487
+ @cacheit
1488
+ def taylor_term(n, x, *previous_terms):
1489
+ if n < 0:
1490
+ return S.Zero
1491
+ else:
1492
+ x = sympify(x)
1493
+ if len(previous_terms) > 1:
1494
+ p = previous_terms[-1]
1495
+ return ((cbrt(3)*x)**(-n)*(cbrt(3)*x)**(n + 1)*sin(pi*(n*Rational(2, 3) + Rational(4, 3)))*factorial(n) *
1496
+ gamma(n/3 + Rational(2, 3))/(sin(pi*(n*Rational(2, 3) + Rational(2, 3)))*factorial(n + 1)*gamma(n/3 + Rational(1, 3))) * p)
1497
+ else:
1498
+ return (S.One/(3**Rational(2, 3)*pi) * gamma((n+S.One)/S(3)) * sin(Rational(2, 3)*pi*(n+S.One)) /
1499
+ factorial(n) * (cbrt(3)*x)**n)
1500
+
1501
+ def _eval_rewrite_as_besselj(self, z, **kwargs):
1502
+ ot = Rational(1, 3)
1503
+ tt = Rational(2, 3)
1504
+ a = Pow(-z, Rational(3, 2))
1505
+ if re(z).is_negative:
1506
+ return ot*sqrt(-z) * (besselj(-ot, tt*a) + besselj(ot, tt*a))
1507
+
1508
+ def _eval_rewrite_as_besseli(self, z, **kwargs):
1509
+ ot = Rational(1, 3)
1510
+ tt = Rational(2, 3)
1511
+ a = Pow(z, Rational(3, 2))
1512
+ if re(z).is_positive:
1513
+ return ot*sqrt(z) * (besseli(-ot, tt*a) - besseli(ot, tt*a))
1514
+ else:
1515
+ return ot*(Pow(a, ot)*besseli(-ot, tt*a) - z*Pow(a, -ot)*besseli(ot, tt*a))
1516
+
1517
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
1518
+ pf1 = S.One / (3**Rational(2, 3)*gamma(Rational(2, 3)))
1519
+ pf2 = z / (root(3, 3)*gamma(Rational(1, 3)))
1520
+ return pf1 * hyper([], [Rational(2, 3)], z**3/9) - pf2 * hyper([], [Rational(4, 3)], z**3/9)
1521
+
1522
+ def _eval_expand_func(self, **hints):
1523
+ arg = self.args[0]
1524
+ symbs = arg.free_symbols
1525
+
1526
+ if len(symbs) == 1:
1527
+ z = symbs.pop()
1528
+ c = Wild("c", exclude=[z])
1529
+ d = Wild("d", exclude=[z])
1530
+ m = Wild("m", exclude=[z])
1531
+ n = Wild("n", exclude=[z])
1532
+ M = arg.match(c*(d*z**n)**m)
1533
+ if M is not None:
1534
+ m = M[m]
1535
+ # The transformation is given by 03.05.16.0001.01
1536
+ # https://functions.wolfram.com/Bessel-TypeFunctions/AiryAi/16/01/01/0001/
1537
+ if (3*m).is_integer:
1538
+ c = M[c]
1539
+ d = M[d]
1540
+ n = M[n]
1541
+ pf = (d * z**n)**m / (d**m * z**(m*n))
1542
+ newarg = c * d**m * z**(m*n)
1543
+ return S.Half * ((pf + S.One)*airyai(newarg) - (pf - S.One)/sqrt(3)*airybi(newarg))
1544
+
1545
+
1546
+ class airybi(AiryBase):
1547
+ r"""
1548
+ The Airy function $\operatorname{Bi}$ of the second kind.
1549
+
1550
+ Explanation
1551
+ ===========
1552
+
1553
+ The Airy function $\operatorname{Bi}(z)$ is defined to be the function
1554
+ satisfying Airy's differential equation
1555
+
1556
+ .. math::
1557
+ \frac{\mathrm{d}^2 w(z)}{\mathrm{d}z^2} - z w(z) = 0.
1558
+
1559
+ Equivalently, for real $z$
1560
+
1561
+ .. math::
1562
+ \operatorname{Bi}(z) := \frac{1}{\pi}
1563
+ \int_0^\infty
1564
+ \exp\left(-\frac{t^3}{3} + z t\right)
1565
+ + \sin\left(\frac{t^3}{3} + z t\right) \mathrm{d}t.
1566
+
1567
+ Examples
1568
+ ========
1569
+
1570
+ Create an Airy function object:
1571
+
1572
+ >>> from sympy import airybi
1573
+ >>> from sympy.abc import z
1574
+
1575
+ >>> airybi(z)
1576
+ airybi(z)
1577
+
1578
+ Several special values are known:
1579
+
1580
+ >>> airybi(0)
1581
+ 3**(5/6)/(3*gamma(2/3))
1582
+ >>> from sympy import oo
1583
+ >>> airybi(oo)
1584
+ oo
1585
+ >>> airybi(-oo)
1586
+ 0
1587
+
1588
+ The Airy function obeys the mirror symmetry:
1589
+
1590
+ >>> from sympy import conjugate
1591
+ >>> conjugate(airybi(z))
1592
+ airybi(conjugate(z))
1593
+
1594
+ Differentiation with respect to $z$ is supported:
1595
+
1596
+ >>> from sympy import diff
1597
+ >>> diff(airybi(z), z)
1598
+ airybiprime(z)
1599
+ >>> diff(airybi(z), z, 2)
1600
+ z*airybi(z)
1601
+
1602
+ Series expansion is also supported:
1603
+
1604
+ >>> from sympy import series
1605
+ >>> series(airybi(z), z, 0, 3)
1606
+ 3**(1/3)*gamma(1/3)/(2*pi) + 3**(2/3)*z*gamma(2/3)/(2*pi) + O(z**3)
1607
+
1608
+ We can numerically evaluate the Airy function to arbitrary precision
1609
+ on the whole complex plane:
1610
+
1611
+ >>> airybi(-2).evalf(50)
1612
+ -0.41230258795639848808323405461146104203453483447240
1613
+
1614
+ Rewrite $\operatorname{Bi}(z)$ in terms of hypergeometric functions:
1615
+
1616
+ >>> from sympy import hyper
1617
+ >>> airybi(z).rewrite(hyper)
1618
+ 3**(1/6)*z*hyper((), (4/3,), z**3/9)/gamma(1/3) + 3**(5/6)*hyper((), (2/3,), z**3/9)/(3*gamma(2/3))
1619
+
1620
+ See Also
1621
+ ========
1622
+
1623
+ airyai: Airy function of the first kind.
1624
+ airyaiprime: Derivative of the Airy function of the first kind.
1625
+ airybiprime: Derivative of the Airy function of the second kind.
1626
+
1627
+ References
1628
+ ==========
1629
+
1630
+ .. [1] https://en.wikipedia.org/wiki/Airy_function
1631
+ .. [2] https://dlmf.nist.gov/9
1632
+ .. [3] https://encyclopediaofmath.org/wiki/Airy_functions
1633
+ .. [4] https://mathworld.wolfram.com/AiryFunctions.html
1634
+
1635
+ """
1636
+
1637
+ nargs = 1
1638
+ unbranched = True
1639
+
1640
+ @classmethod
1641
+ def eval(cls, arg):
1642
+ if arg.is_Number:
1643
+ if arg is S.NaN:
1644
+ return S.NaN
1645
+ elif arg is S.Infinity:
1646
+ return S.Infinity
1647
+ elif arg is S.NegativeInfinity:
1648
+ return S.Zero
1649
+ elif arg.is_zero:
1650
+ return S.One / (3**Rational(1, 6) * gamma(Rational(2, 3)))
1651
+
1652
+ if arg.is_zero:
1653
+ return S.One / (3**Rational(1, 6) * gamma(Rational(2, 3)))
1654
+
1655
+ def fdiff(self, argindex=1):
1656
+ if argindex == 1:
1657
+ return airybiprime(self.args[0])
1658
+ else:
1659
+ raise ArgumentIndexError(self, argindex)
1660
+
1661
+ @staticmethod
1662
+ @cacheit
1663
+ def taylor_term(n, x, *previous_terms):
1664
+ if n < 0:
1665
+ return S.Zero
1666
+ else:
1667
+ x = sympify(x)
1668
+ if len(previous_terms) > 1:
1669
+ p = previous_terms[-1]
1670
+ return (cbrt(3)*x * Abs(sin(Rational(2, 3)*pi*(n + S.One))) * factorial((n - S.One)/S(3)) /
1671
+ ((n + S.One) * Abs(cos(Rational(2, 3)*pi*(n + S.Half))) * factorial((n - 2)/S(3))) * p)
1672
+ else:
1673
+ return (S.One/(root(3, 6)*pi) * gamma((n + S.One)/S(3)) * Abs(sin(Rational(2, 3)*pi*(n + S.One))) /
1674
+ factorial(n) * (cbrt(3)*x)**n)
1675
+
1676
+ def _eval_rewrite_as_besselj(self, z, **kwargs):
1677
+ ot = Rational(1, 3)
1678
+ tt = Rational(2, 3)
1679
+ a = Pow(-z, Rational(3, 2))
1680
+ if re(z).is_negative:
1681
+ return sqrt(-z/3) * (besselj(-ot, tt*a) - besselj(ot, tt*a))
1682
+
1683
+ def _eval_rewrite_as_besseli(self, z, **kwargs):
1684
+ ot = Rational(1, 3)
1685
+ tt = Rational(2, 3)
1686
+ a = Pow(z, Rational(3, 2))
1687
+ if re(z).is_positive:
1688
+ return sqrt(z)/sqrt(3) * (besseli(-ot, tt*a) + besseli(ot, tt*a))
1689
+ else:
1690
+ b = Pow(a, ot)
1691
+ c = Pow(a, -ot)
1692
+ return sqrt(ot)*(b*besseli(-ot, tt*a) + z*c*besseli(ot, tt*a))
1693
+
1694
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
1695
+ pf1 = S.One / (root(3, 6)*gamma(Rational(2, 3)))
1696
+ pf2 = z*root(3, 6) / gamma(Rational(1, 3))
1697
+ return pf1 * hyper([], [Rational(2, 3)], z**3/9) + pf2 * hyper([], [Rational(4, 3)], z**3/9)
1698
+
1699
+ def _eval_expand_func(self, **hints):
1700
+ arg = self.args[0]
1701
+ symbs = arg.free_symbols
1702
+
1703
+ if len(symbs) == 1:
1704
+ z = symbs.pop()
1705
+ c = Wild("c", exclude=[z])
1706
+ d = Wild("d", exclude=[z])
1707
+ m = Wild("m", exclude=[z])
1708
+ n = Wild("n", exclude=[z])
1709
+ M = arg.match(c*(d*z**n)**m)
1710
+ if M is not None:
1711
+ m = M[m]
1712
+ # The transformation is given by 03.06.16.0001.01
1713
+ # https://functions.wolfram.com/Bessel-TypeFunctions/AiryBi/16/01/01/0001/
1714
+ if (3*m).is_integer:
1715
+ c = M[c]
1716
+ d = M[d]
1717
+ n = M[n]
1718
+ pf = (d * z**n)**m / (d**m * z**(m*n))
1719
+ newarg = c * d**m * z**(m*n)
1720
+ return S.Half * (sqrt(3)*(S.One - pf)*airyai(newarg) + (S.One + pf)*airybi(newarg))
1721
+
1722
+
1723
+ class airyaiprime(AiryBase):
1724
+ r"""
1725
+ The derivative $\operatorname{Ai}^\prime$ of the Airy function of the first
1726
+ kind.
1727
+
1728
+ Explanation
1729
+ ===========
1730
+
1731
+ The Airy function $\operatorname{Ai}^\prime(z)$ is defined to be the
1732
+ function
1733
+
1734
+ .. math::
1735
+ \operatorname{Ai}^\prime(z) := \frac{\mathrm{d} \operatorname{Ai}(z)}{\mathrm{d} z}.
1736
+
1737
+ Examples
1738
+ ========
1739
+
1740
+ Create an Airy function object:
1741
+
1742
+ >>> from sympy import airyaiprime
1743
+ >>> from sympy.abc import z
1744
+
1745
+ >>> airyaiprime(z)
1746
+ airyaiprime(z)
1747
+
1748
+ Several special values are known:
1749
+
1750
+ >>> airyaiprime(0)
1751
+ -3**(2/3)/(3*gamma(1/3))
1752
+ >>> from sympy import oo
1753
+ >>> airyaiprime(oo)
1754
+ 0
1755
+
1756
+ The Airy function obeys the mirror symmetry:
1757
+
1758
+ >>> from sympy import conjugate
1759
+ >>> conjugate(airyaiprime(z))
1760
+ airyaiprime(conjugate(z))
1761
+
1762
+ Differentiation with respect to $z$ is supported:
1763
+
1764
+ >>> from sympy import diff
1765
+ >>> diff(airyaiprime(z), z)
1766
+ z*airyai(z)
1767
+ >>> diff(airyaiprime(z), z, 2)
1768
+ z*airyaiprime(z) + airyai(z)
1769
+
1770
+ Series expansion is also supported:
1771
+
1772
+ >>> from sympy import series
1773
+ >>> series(airyaiprime(z), z, 0, 3)
1774
+ -3**(2/3)/(3*gamma(1/3)) + 3**(1/3)*z**2/(6*gamma(2/3)) + O(z**3)
1775
+
1776
+ We can numerically evaluate the Airy function to arbitrary precision
1777
+ on the whole complex plane:
1778
+
1779
+ >>> airyaiprime(-2).evalf(50)
1780
+ 0.61825902074169104140626429133247528291577794512415
1781
+
1782
+ Rewrite $\operatorname{Ai}^\prime(z)$ in terms of hypergeometric functions:
1783
+
1784
+ >>> from sympy import hyper
1785
+ >>> airyaiprime(z).rewrite(hyper)
1786
+ 3**(1/3)*z**2*hyper((), (5/3,), z**3/9)/(6*gamma(2/3)) - 3**(2/3)*hyper((), (1/3,), z**3/9)/(3*gamma(1/3))
1787
+
1788
+ See Also
1789
+ ========
1790
+
1791
+ airyai: Airy function of the first kind.
1792
+ airybi: Airy function of the second kind.
1793
+ airybiprime: Derivative of the Airy function of the second kind.
1794
+
1795
+ References
1796
+ ==========
1797
+
1798
+ .. [1] https://en.wikipedia.org/wiki/Airy_function
1799
+ .. [2] https://dlmf.nist.gov/9
1800
+ .. [3] https://encyclopediaofmath.org/wiki/Airy_functions
1801
+ .. [4] https://mathworld.wolfram.com/AiryFunctions.html
1802
+
1803
+ """
1804
+
1805
+ nargs = 1
1806
+ unbranched = True
1807
+
1808
+ @classmethod
1809
+ def eval(cls, arg):
1810
+ if arg.is_Number:
1811
+ if arg is S.NaN:
1812
+ return S.NaN
1813
+ elif arg is S.Infinity:
1814
+ return S.Zero
1815
+
1816
+ if arg.is_zero:
1817
+ return S.NegativeOne / (3**Rational(1, 3) * gamma(Rational(1, 3)))
1818
+
1819
+ def fdiff(self, argindex=1):
1820
+ if argindex == 1:
1821
+ return self.args[0]*airyai(self.args[0])
1822
+ else:
1823
+ raise ArgumentIndexError(self, argindex)
1824
+
1825
+ def _eval_evalf(self, prec):
1826
+ z = self.args[0]._to_mpmath(prec)
1827
+ with workprec(prec):
1828
+ res = mp.airyai(z, derivative=1)
1829
+ return Expr._from_mpmath(res, prec)
1830
+
1831
+ def _eval_rewrite_as_besselj(self, z, **kwargs):
1832
+ tt = Rational(2, 3)
1833
+ a = Pow(-z, Rational(3, 2))
1834
+ if re(z).is_negative:
1835
+ return z/3 * (besselj(-tt, tt*a) - besselj(tt, tt*a))
1836
+
1837
+ def _eval_rewrite_as_besseli(self, z, **kwargs):
1838
+ ot = Rational(1, 3)
1839
+ tt = Rational(2, 3)
1840
+ a = tt * Pow(z, Rational(3, 2))
1841
+ if re(z).is_positive:
1842
+ return z/3 * (besseli(tt, a) - besseli(-tt, a))
1843
+ else:
1844
+ a = Pow(z, Rational(3, 2))
1845
+ b = Pow(a, tt)
1846
+ c = Pow(a, -tt)
1847
+ return ot * (z**2*c*besseli(tt, tt*a) - b*besseli(-ot, tt*a))
1848
+
1849
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
1850
+ pf1 = z**2 / (2*3**Rational(2, 3)*gamma(Rational(2, 3)))
1851
+ pf2 = 1 / (root(3, 3)*gamma(Rational(1, 3)))
1852
+ return pf1 * hyper([], [Rational(5, 3)], z**3/9) - pf2 * hyper([], [Rational(1, 3)], z**3/9)
1853
+
1854
+ def _eval_expand_func(self, **hints):
1855
+ arg = self.args[0]
1856
+ symbs = arg.free_symbols
1857
+
1858
+ if len(symbs) == 1:
1859
+ z = symbs.pop()
1860
+ c = Wild("c", exclude=[z])
1861
+ d = Wild("d", exclude=[z])
1862
+ m = Wild("m", exclude=[z])
1863
+ n = Wild("n", exclude=[z])
1864
+ M = arg.match(c*(d*z**n)**m)
1865
+ if M is not None:
1866
+ m = M[m]
1867
+ # The transformation is in principle
1868
+ # given by 03.07.16.0001.01 but note
1869
+ # that there is an error in this formula.
1870
+ # https://functions.wolfram.com/Bessel-TypeFunctions/AiryAiPrime/16/01/01/0001/
1871
+ if (3*m).is_integer:
1872
+ c = M[c]
1873
+ d = M[d]
1874
+ n = M[n]
1875
+ pf = (d**m * z**(n*m)) / (d * z**n)**m
1876
+ newarg = c * d**m * z**(n*m)
1877
+ return S.Half * ((pf + S.One)*airyaiprime(newarg) + (pf - S.One)/sqrt(3)*airybiprime(newarg))
1878
+
1879
+
1880
+ class airybiprime(AiryBase):
1881
+ r"""
1882
+ The derivative $\operatorname{Bi}^\prime$ of the Airy function of the first
1883
+ kind.
1884
+
1885
+ Explanation
1886
+ ===========
1887
+
1888
+ The Airy function $\operatorname{Bi}^\prime(z)$ is defined to be the
1889
+ function
1890
+
1891
+ .. math::
1892
+ \operatorname{Bi}^\prime(z) := \frac{\mathrm{d} \operatorname{Bi}(z)}{\mathrm{d} z}.
1893
+
1894
+ Examples
1895
+ ========
1896
+
1897
+ Create an Airy function object:
1898
+
1899
+ >>> from sympy import airybiprime
1900
+ >>> from sympy.abc import z
1901
+
1902
+ >>> airybiprime(z)
1903
+ airybiprime(z)
1904
+
1905
+ Several special values are known:
1906
+
1907
+ >>> airybiprime(0)
1908
+ 3**(1/6)/gamma(1/3)
1909
+ >>> from sympy import oo
1910
+ >>> airybiprime(oo)
1911
+ oo
1912
+ >>> airybiprime(-oo)
1913
+ 0
1914
+
1915
+ The Airy function obeys the mirror symmetry:
1916
+
1917
+ >>> from sympy import conjugate
1918
+ >>> conjugate(airybiprime(z))
1919
+ airybiprime(conjugate(z))
1920
+
1921
+ Differentiation with respect to $z$ is supported:
1922
+
1923
+ >>> from sympy import diff
1924
+ >>> diff(airybiprime(z), z)
1925
+ z*airybi(z)
1926
+ >>> diff(airybiprime(z), z, 2)
1927
+ z*airybiprime(z) + airybi(z)
1928
+
1929
+ Series expansion is also supported:
1930
+
1931
+ >>> from sympy import series
1932
+ >>> series(airybiprime(z), z, 0, 3)
1933
+ 3**(1/6)/gamma(1/3) + 3**(5/6)*z**2/(6*gamma(2/3)) + O(z**3)
1934
+
1935
+ We can numerically evaluate the Airy function to arbitrary precision
1936
+ on the whole complex plane:
1937
+
1938
+ >>> airybiprime(-2).evalf(50)
1939
+ 0.27879516692116952268509756941098324140300059345163
1940
+
1941
+ Rewrite $\operatorname{Bi}^\prime(z)$ in terms of hypergeometric functions:
1942
+
1943
+ >>> from sympy import hyper
1944
+ >>> airybiprime(z).rewrite(hyper)
1945
+ 3**(5/6)*z**2*hyper((), (5/3,), z**3/9)/(6*gamma(2/3)) + 3**(1/6)*hyper((), (1/3,), z**3/9)/gamma(1/3)
1946
+
1947
+ See Also
1948
+ ========
1949
+
1950
+ airyai: Airy function of the first kind.
1951
+ airybi: Airy function of the second kind.
1952
+ airyaiprime: Derivative of the Airy function of the first kind.
1953
+
1954
+ References
1955
+ ==========
1956
+
1957
+ .. [1] https://en.wikipedia.org/wiki/Airy_function
1958
+ .. [2] https://dlmf.nist.gov/9
1959
+ .. [3] https://encyclopediaofmath.org/wiki/Airy_functions
1960
+ .. [4] https://mathworld.wolfram.com/AiryFunctions.html
1961
+
1962
+ """
1963
+
1964
+ nargs = 1
1965
+ unbranched = True
1966
+
1967
+ @classmethod
1968
+ def eval(cls, arg):
1969
+ if arg.is_Number:
1970
+ if arg is S.NaN:
1971
+ return S.NaN
1972
+ elif arg is S.Infinity:
1973
+ return S.Infinity
1974
+ elif arg is S.NegativeInfinity:
1975
+ return S.Zero
1976
+ elif arg.is_zero:
1977
+ return 3**Rational(1, 6) / gamma(Rational(1, 3))
1978
+
1979
+ if arg.is_zero:
1980
+ return 3**Rational(1, 6) / gamma(Rational(1, 3))
1981
+
1982
+
1983
+ def fdiff(self, argindex=1):
1984
+ if argindex == 1:
1985
+ return self.args[0]*airybi(self.args[0])
1986
+ else:
1987
+ raise ArgumentIndexError(self, argindex)
1988
+
1989
+ def _eval_evalf(self, prec):
1990
+ z = self.args[0]._to_mpmath(prec)
1991
+ with workprec(prec):
1992
+ res = mp.airybi(z, derivative=1)
1993
+ return Expr._from_mpmath(res, prec)
1994
+
1995
+ def _eval_rewrite_as_besselj(self, z, **kwargs):
1996
+ tt = Rational(2, 3)
1997
+ a = tt * Pow(-z, Rational(3, 2))
1998
+ if re(z).is_negative:
1999
+ return -z/sqrt(3) * (besselj(-tt, a) + besselj(tt, a))
2000
+
2001
+ def _eval_rewrite_as_besseli(self, z, **kwargs):
2002
+ ot = Rational(1, 3)
2003
+ tt = Rational(2, 3)
2004
+ a = tt * Pow(z, Rational(3, 2))
2005
+ if re(z).is_positive:
2006
+ return z/sqrt(3) * (besseli(-tt, a) + besseli(tt, a))
2007
+ else:
2008
+ a = Pow(z, Rational(3, 2))
2009
+ b = Pow(a, tt)
2010
+ c = Pow(a, -tt)
2011
+ return sqrt(ot) * (b*besseli(-tt, tt*a) + z**2*c*besseli(tt, tt*a))
2012
+
2013
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
2014
+ pf1 = z**2 / (2*root(3, 6)*gamma(Rational(2, 3)))
2015
+ pf2 = root(3, 6) / gamma(Rational(1, 3))
2016
+ return pf1 * hyper([], [Rational(5, 3)], z**3/9) + pf2 * hyper([], [Rational(1, 3)], z**3/9)
2017
+
2018
+ def _eval_expand_func(self, **hints):
2019
+ arg = self.args[0]
2020
+ symbs = arg.free_symbols
2021
+
2022
+ if len(symbs) == 1:
2023
+ z = symbs.pop()
2024
+ c = Wild("c", exclude=[z])
2025
+ d = Wild("d", exclude=[z])
2026
+ m = Wild("m", exclude=[z])
2027
+ n = Wild("n", exclude=[z])
2028
+ M = arg.match(c*(d*z**n)**m)
2029
+ if M is not None:
2030
+ m = M[m]
2031
+ # The transformation is in principle
2032
+ # given by 03.08.16.0001.01 but note
2033
+ # that there is an error in this formula.
2034
+ # https://functions.wolfram.com/Bessel-TypeFunctions/AiryBiPrime/16/01/01/0001/
2035
+ if (3*m).is_integer:
2036
+ c = M[c]
2037
+ d = M[d]
2038
+ n = M[n]
2039
+ pf = (d**m * z**(n*m)) / (d * z**n)**m
2040
+ newarg = c * d**m * z**(n*m)
2041
+ return S.Half * (sqrt(3)*(pf - S.One)*airyaiprime(newarg) + (pf + S.One)*airybiprime(newarg))
2042
+
2043
+
2044
+ class marcumq(DefinedFunction):
2045
+ r"""
2046
+ The Marcum Q-function.
2047
+
2048
+ Explanation
2049
+ ===========
2050
+
2051
+ The Marcum Q-function is defined by the meromorphic continuation of
2052
+
2053
+ .. math::
2054
+ Q_m(a, b) = a^{- m + 1} \int_{b}^{\infty} x^{m} e^{- \frac{a^{2}}{2} - \frac{x^{2}}{2}} I_{m - 1}\left(a x\right)\, dx
2055
+
2056
+ Examples
2057
+ ========
2058
+
2059
+ >>> from sympy import marcumq
2060
+ >>> from sympy.abc import m, a, b
2061
+ >>> marcumq(m, a, b)
2062
+ marcumq(m, a, b)
2063
+
2064
+ Special values:
2065
+
2066
+ >>> marcumq(m, 0, b)
2067
+ uppergamma(m, b**2/2)/gamma(m)
2068
+ >>> marcumq(0, 0, 0)
2069
+ 0
2070
+ >>> marcumq(0, a, 0)
2071
+ 1 - exp(-a**2/2)
2072
+ >>> marcumq(1, a, a)
2073
+ 1/2 + exp(-a**2)*besseli(0, a**2)/2
2074
+ >>> marcumq(2, a, a)
2075
+ 1/2 + exp(-a**2)*besseli(0, a**2)/2 + exp(-a**2)*besseli(1, a**2)
2076
+
2077
+ Differentiation with respect to $a$ and $b$ is supported:
2078
+
2079
+ >>> from sympy import diff
2080
+ >>> diff(marcumq(m, a, b), a)
2081
+ a*(-marcumq(m, a, b) + marcumq(m + 1, a, b))
2082
+ >>> diff(marcumq(m, a, b), b)
2083
+ -a**(1 - m)*b**m*exp(-a**2/2 - b**2/2)*besseli(m - 1, a*b)
2084
+
2085
+ References
2086
+ ==========
2087
+
2088
+ .. [1] https://en.wikipedia.org/wiki/Marcum_Q-function
2089
+ .. [2] https://mathworld.wolfram.com/MarcumQ-Function.html
2090
+
2091
+ """
2092
+
2093
+ @classmethod
2094
+ def eval(cls, m, a, b):
2095
+ if a is S.Zero:
2096
+ if m is S.Zero and b is S.Zero:
2097
+ return S.Zero
2098
+ return uppergamma(m, b**2 * S.Half) / gamma(m)
2099
+
2100
+ if m is S.Zero and b is S.Zero:
2101
+ return 1 - 1 / exp(a**2 * S.Half)
2102
+
2103
+ if a == b:
2104
+ if m is S.One:
2105
+ return (1 + exp(-a**2) * besseli(0, a**2))*S.Half
2106
+ if m == 2:
2107
+ return S.Half + S.Half * exp(-a**2) * besseli(0, a**2) + exp(-a**2) * besseli(1, a**2)
2108
+
2109
+ if a.is_zero:
2110
+ if m.is_zero and b.is_zero:
2111
+ return S.Zero
2112
+ return uppergamma(m, b**2*S.Half) / gamma(m)
2113
+
2114
+ if m.is_zero and b.is_zero:
2115
+ return 1 - 1 / exp(a**2*S.Half)
2116
+
2117
+ def fdiff(self, argindex=2):
2118
+ m, a, b = self.args
2119
+ if argindex == 2:
2120
+ return a * (-marcumq(m, a, b) + marcumq(1+m, a, b))
2121
+ elif argindex == 3:
2122
+ return (-b**m / a**(m-1)) * exp(-(a**2 + b**2)/2) * besseli(m-1, a*b)
2123
+ else:
2124
+ raise ArgumentIndexError(self, argindex)
2125
+
2126
+ def _eval_rewrite_as_Integral(self, m, a, b, **kwargs):
2127
+ from sympy.integrals.integrals import Integral
2128
+ x = kwargs.get('x', Dummy(uniquely_named_symbol('x').name))
2129
+ return a ** (1 - m) * \
2130
+ Integral(x**m * exp(-(x**2 + a**2)/2) * besseli(m-1, a*x), [x, b, S.Infinity])
2131
+
2132
+ def _eval_rewrite_as_Sum(self, m, a, b, **kwargs):
2133
+ from sympy.concrete.summations import Sum
2134
+ k = kwargs.get('k', Dummy('k'))
2135
+ return exp(-(a**2 + b**2) / 2) * Sum((a/b)**k * besseli(k, a*b), [k, 1-m, S.Infinity])
2136
+
2137
+ def _eval_rewrite_as_besseli(self, m, a, b, **kwargs):
2138
+ if a == b:
2139
+ if m == 1:
2140
+ return (1 + exp(-a**2) * besseli(0, a**2)) / 2
2141
+ if m.is_Integer and m >= 2:
2142
+ s = sum(besseli(i, a**2) for i in range(1, m))
2143
+ return S.Half + exp(-a**2) * besseli(0, a**2) / 2 + exp(-a**2) * s
2144
+
2145
+ def _eval_is_zero(self):
2146
+ if all(arg.is_zero for arg in self.args):
2147
+ return True
2148
+
2149
+ class _besseli(DefinedFunction):
2150
+ """
2151
+ Helper function to make the $\\mathrm{besseli}(nu, z)$
2152
+ function tractable for the Gruntz algorithm.
2153
+
2154
+ """
2155
+
2156
+ def _eval_aseries(self, n, args0, x, logx):
2157
+ from sympy.functions.combinatorial.factorials import RisingFactorial
2158
+ from sympy.series.order import Order
2159
+ point = args0[1]
2160
+
2161
+ if point in [S.Infinity, S.NegativeInfinity]:
2162
+ nu, z = self.args
2163
+ l = [((RisingFactorial(Rational(2*nu - 1, 2), k)*RisingFactorial(
2164
+ Rational(2*nu + 1, 2), k))/((2)**(k)*z**(Rational(2*k + 1, 2))*factorial(k))) for k in range(n)]
2165
+ return sqrt(pi/(2))*(Add(*l)) + Order(1/z**(Rational(2*n + 1, 2)), x)
2166
+
2167
+ return super()._eval_aseries(n, args0, x, logx)
2168
+
2169
+ def _eval_rewrite_as_intractable(self, nu, z, **kwargs):
2170
+ return exp(-z)*besseli(nu, z)
2171
+
2172
+ def _eval_nseries(self, x, n, logx, cdir=0):
2173
+ x0 = self.args[0].limit(x, 0)
2174
+ if x0.is_zero:
2175
+ f = self._eval_rewrite_as_intractable(*self.args)
2176
+ return f._eval_nseries(x, n, logx)
2177
+ return super()._eval_nseries(x, n, logx)
2178
+
2179
+
2180
+ class _besselk(DefinedFunction):
2181
+ """
2182
+ Helper function to make the $\\mathrm{besselk}(nu, z)$
2183
+ function tractable for the Gruntz algorithm.
2184
+
2185
+ """
2186
+
2187
+ def _eval_aseries(self, n, args0, x, logx):
2188
+ from sympy.functions.combinatorial.factorials import RisingFactorial
2189
+ from sympy.series.order import Order
2190
+ point = args0[1]
2191
+
2192
+ if point in [S.Infinity, S.NegativeInfinity]:
2193
+ nu, z = self.args
2194
+ l = [((RisingFactorial(Rational(2*nu - 1, 2), k)*RisingFactorial(
2195
+ Rational(2*nu + 1, 2), k))/((-2)**(k)*z**(Rational(2*k + 1, 2))*factorial(k))) for k in range(n)]
2196
+ return sqrt(pi/(2))*(Add(*l)) + Order(1/z**(Rational(2*n + 1, 2)), x)
2197
+
2198
+ return super()._eval_aseries(n, args0, x, logx)
2199
+
2200
+ def _eval_rewrite_as_intractable(self,nu, z, **kwargs):
2201
+ return exp(z)*besselk(nu, z)
2202
+
2203
+ def _eval_nseries(self, x, n, logx, cdir=0):
2204
+ x0 = self.args[0].limit(x, 0)
2205
+ if x0.is_zero:
2206
+ f = self._eval_rewrite_as_intractable(*self.args)
2207
+ return f._eval_nseries(x, n, logx)
2208
+ return super()._eval_nseries(x, n, logx)
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/beta_functions.py ADDED
@@ -0,0 +1,389 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import S
2
+ from sympy.core.function import DefinedFunction, ArgumentIndexError
3
+ from sympy.core.symbol import Dummy, uniquely_named_symbol
4
+ from sympy.functions.special.gamma_functions import gamma, digamma
5
+ from sympy.functions.combinatorial.numbers import catalan
6
+ from sympy.functions.elementary.complexes import conjugate
7
+
8
+ # See mpmath #569 and SymPy #20569
9
+ def betainc_mpmath_fix(a, b, x1, x2, reg=0):
10
+ from mpmath import betainc, mpf
11
+ if x1 == x2:
12
+ return mpf(0)
13
+ else:
14
+ return betainc(a, b, x1, x2, reg)
15
+
16
+ ###############################################################################
17
+ ############################ COMPLETE BETA FUNCTION ##########################
18
+ ###############################################################################
19
+
20
+ class beta(DefinedFunction):
21
+ r"""
22
+ The beta integral is called the Eulerian integral of the first kind by
23
+ Legendre:
24
+
25
+ .. math::
26
+ \mathrm{B}(x,y) \int^{1}_{0} t^{x-1} (1-t)^{y-1} \mathrm{d}t.
27
+
28
+ Explanation
29
+ ===========
30
+
31
+ The Beta function or Euler's first integral is closely associated
32
+ with the gamma function. The Beta function is often used in probability
33
+ theory and mathematical statistics. It satisfies properties like:
34
+
35
+ .. math::
36
+ \mathrm{B}(a,1) = \frac{1}{a} \\
37
+ \mathrm{B}(a,b) = \mathrm{B}(b,a) \\
38
+ \mathrm{B}(a,b) = \frac{\Gamma(a) \Gamma(b)}{\Gamma(a+b)}
39
+
40
+ Therefore for integral values of $a$ and $b$:
41
+
42
+ .. math::
43
+ \mathrm{B} = \frac{(a-1)! (b-1)!}{(a+b-1)!}
44
+
45
+ A special case of the Beta function when `x = y` is the
46
+ Central Beta function. It satisfies properties like:
47
+
48
+ .. math::
49
+ \mathrm{B}(x) = 2^{1 - 2x}\mathrm{B}(x, \frac{1}{2})
50
+ \mathrm{B}(x) = 2^{1 - 2x} cos(\pi x) \mathrm{B}(\frac{1}{2} - x, x)
51
+ \mathrm{B}(x) = \int_{0}^{1} \frac{t^x}{(1 + t)^{2x}} dt
52
+ \mathrm{B}(x) = \frac{2}{x} \prod_{n = 1}^{\infty} \frac{n(n + 2x)}{(n + x)^2}
53
+
54
+ Examples
55
+ ========
56
+
57
+ >>> from sympy import I, pi
58
+ >>> from sympy.abc import x, y
59
+
60
+ The Beta function obeys the mirror symmetry:
61
+
62
+ >>> from sympy import beta, conjugate
63
+ >>> conjugate(beta(x, y))
64
+ beta(conjugate(x), conjugate(y))
65
+
66
+ Differentiation with respect to both $x$ and $y$ is supported:
67
+
68
+ >>> from sympy import beta, diff
69
+ >>> diff(beta(x, y), x)
70
+ (polygamma(0, x) - polygamma(0, x + y))*beta(x, y)
71
+
72
+ >>> diff(beta(x, y), y)
73
+ (polygamma(0, y) - polygamma(0, x + y))*beta(x, y)
74
+
75
+ >>> diff(beta(x), x)
76
+ 2*(polygamma(0, x) - polygamma(0, 2*x))*beta(x, x)
77
+
78
+ We can numerically evaluate the Beta function to
79
+ arbitrary precision for any complex numbers x and y:
80
+
81
+ >>> from sympy import beta
82
+ >>> beta(pi).evalf(40)
83
+ 0.02671848900111377452242355235388489324562
84
+
85
+ >>> beta(1 + I).evalf(20)
86
+ -0.2112723729365330143 - 0.7655283165378005676*I
87
+
88
+ See Also
89
+ ========
90
+
91
+ gamma: Gamma function.
92
+ uppergamma: Upper incomplete gamma function.
93
+ lowergamma: Lower incomplete gamma function.
94
+ polygamma: Polygamma function.
95
+ loggamma: Log Gamma function.
96
+ digamma: Digamma function.
97
+ trigamma: Trigamma function.
98
+
99
+ References
100
+ ==========
101
+
102
+ .. [1] https://en.wikipedia.org/wiki/Beta_function
103
+ .. [2] https://mathworld.wolfram.com/BetaFunction.html
104
+ .. [3] https://dlmf.nist.gov/5.12
105
+
106
+ """
107
+ unbranched = True
108
+
109
+ def fdiff(self, argindex):
110
+ x, y = self.args
111
+ if argindex == 1:
112
+ # Diff wrt x
113
+ return beta(x, y)*(digamma(x) - digamma(x + y))
114
+ elif argindex == 2:
115
+ # Diff wrt y
116
+ return beta(x, y)*(digamma(y) - digamma(x + y))
117
+ else:
118
+ raise ArgumentIndexError(self, argindex)
119
+
120
+ @classmethod
121
+ def eval(cls, x, y=None):
122
+ if y is None:
123
+ return beta(x, x)
124
+ if x.is_Number and y.is_Number:
125
+ return beta(x, y, evaluate=False).doit()
126
+
127
+ def doit(self, **hints):
128
+ x = xold = self.args[0]
129
+ # Deal with unevaluated single argument beta
130
+ single_argument = len(self.args) == 1
131
+ y = yold = self.args[0] if single_argument else self.args[1]
132
+ if hints.get('deep', True):
133
+ x = x.doit(**hints)
134
+ y = y.doit(**hints)
135
+ if y.is_zero or x.is_zero:
136
+ return S.ComplexInfinity
137
+ if y is S.One:
138
+ return 1/x
139
+ if x is S.One:
140
+ return 1/y
141
+ if y == x + 1:
142
+ return 1/(x*y*catalan(x))
143
+ s = x + y
144
+ if (s.is_integer and s.is_negative and x.is_integer is False and
145
+ y.is_integer is False):
146
+ return S.Zero
147
+ if x == xold and y == yold and not single_argument:
148
+ return self
149
+ return beta(x, y)
150
+
151
+ def _eval_expand_func(self, **hints):
152
+ x, y = self.args
153
+ return gamma(x)*gamma(y) / gamma(x + y)
154
+
155
+ def _eval_is_real(self):
156
+ return self.args[0].is_real and self.args[1].is_real
157
+
158
+ def _eval_conjugate(self):
159
+ return self.func(self.args[0].conjugate(), self.args[1].conjugate())
160
+
161
+ def _eval_rewrite_as_gamma(self, x, y, piecewise=True, **kwargs):
162
+ return self._eval_expand_func(**kwargs)
163
+
164
+ def _eval_rewrite_as_Integral(self, x, y, **kwargs):
165
+ from sympy.integrals.integrals import Integral
166
+ t = Dummy(uniquely_named_symbol('t', [x, y]).name)
167
+ return Integral(t**(x - 1)*(1 - t)**(y - 1), (t, 0, 1))
168
+
169
+ ###############################################################################
170
+ ########################## INCOMPLETE BETA FUNCTION ###########################
171
+ ###############################################################################
172
+
173
+ class betainc(DefinedFunction):
174
+ r"""
175
+ The Generalized Incomplete Beta function is defined as
176
+
177
+ .. math::
178
+ \mathrm{B}_{(x_1, x_2)}(a, b) = \int_{x_1}^{x_2} t^{a - 1} (1 - t)^{b - 1} dt
179
+
180
+ The Incomplete Beta function is a special case
181
+ of the Generalized Incomplete Beta function :
182
+
183
+ .. math:: \mathrm{B}_z (a, b) = \mathrm{B}_{(0, z)}(a, b)
184
+
185
+ The Incomplete Beta function satisfies :
186
+
187
+ .. math:: \mathrm{B}_z (a, b) = (-1)^a \mathrm{B}_{\frac{z}{z - 1}} (a, 1 - a - b)
188
+
189
+ The Beta function is a special case of the Incomplete Beta function :
190
+
191
+ .. math:: \mathrm{B}(a, b) = \mathrm{B}_{1}(a, b)
192
+
193
+ Examples
194
+ ========
195
+
196
+ >>> from sympy import betainc, symbols, conjugate
197
+ >>> a, b, x, x1, x2 = symbols('a b x x1 x2')
198
+
199
+ The Generalized Incomplete Beta function is given by:
200
+
201
+ >>> betainc(a, b, x1, x2)
202
+ betainc(a, b, x1, x2)
203
+
204
+ The Incomplete Beta function can be obtained as follows:
205
+
206
+ >>> betainc(a, b, 0, x)
207
+ betainc(a, b, 0, x)
208
+
209
+ The Incomplete Beta function obeys the mirror symmetry:
210
+
211
+ >>> conjugate(betainc(a, b, x1, x2))
212
+ betainc(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
213
+
214
+ We can numerically evaluate the Incomplete Beta function to
215
+ arbitrary precision for any complex numbers a, b, x1 and x2:
216
+
217
+ >>> from sympy import betainc, I
218
+ >>> betainc(2, 3, 4, 5).evalf(10)
219
+ 56.08333333
220
+ >>> betainc(0.75, 1 - 4*I, 0, 2 + 3*I).evalf(25)
221
+ 0.2241657956955709603655887 + 0.3619619242700451992411724*I
222
+
223
+ The Generalized Incomplete Beta function can be expressed
224
+ in terms of the Generalized Hypergeometric function.
225
+
226
+ >>> from sympy import hyper
227
+ >>> betainc(a, b, x1, x2).rewrite(hyper)
228
+ (-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/a
229
+
230
+ See Also
231
+ ========
232
+
233
+ beta: Beta function
234
+ hyper: Generalized Hypergeometric function
235
+
236
+ References
237
+ ==========
238
+
239
+ .. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
240
+ .. [2] https://dlmf.nist.gov/8.17
241
+ .. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
242
+ .. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
243
+
244
+ """
245
+ nargs = 4
246
+ unbranched = True
247
+
248
+ def fdiff(self, argindex):
249
+ a, b, x1, x2 = self.args
250
+ if argindex == 3:
251
+ # Diff wrt x1
252
+ return -(1 - x1)**(b - 1)*x1**(a - 1)
253
+ elif argindex == 4:
254
+ # Diff wrt x2
255
+ return (1 - x2)**(b - 1)*x2**(a - 1)
256
+ else:
257
+ raise ArgumentIndexError(self, argindex)
258
+
259
+ def _eval_mpmath(self):
260
+ return betainc_mpmath_fix, self.args
261
+
262
+ def _eval_is_real(self):
263
+ if all(arg.is_real for arg in self.args):
264
+ return True
265
+
266
+ def _eval_conjugate(self):
267
+ return self.func(*map(conjugate, self.args))
268
+
269
+ def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
270
+ from sympy.integrals.integrals import Integral
271
+ t = Dummy(uniquely_named_symbol('t', [a, b, x1, x2]).name)
272
+ return Integral(t**(a - 1)*(1 - t)**(b - 1), (t, x1, x2))
273
+
274
+ def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
275
+ from sympy.functions.special.hyper import hyper
276
+ return (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
277
+
278
+ ###############################################################################
279
+ #################### REGULARIZED INCOMPLETE BETA FUNCTION #####################
280
+ ###############################################################################
281
+
282
+ class betainc_regularized(DefinedFunction):
283
+ r"""
284
+ The Generalized Regularized Incomplete Beta function is given by
285
+
286
+ .. math::
287
+ \mathrm{I}_{(x_1, x_2)}(a, b) = \frac{\mathrm{B}_{(x_1, x_2)}(a, b)}{\mathrm{B}(a, b)}
288
+
289
+ The Regularized Incomplete Beta function is a special case
290
+ of the Generalized Regularized Incomplete Beta function :
291
+
292
+ .. math:: \mathrm{I}_z (a, b) = \mathrm{I}_{(0, z)}(a, b)
293
+
294
+ The Regularized Incomplete Beta function is the cumulative distribution
295
+ function of the beta distribution.
296
+
297
+ Examples
298
+ ========
299
+
300
+ >>> from sympy import betainc_regularized, symbols, conjugate
301
+ >>> a, b, x, x1, x2 = symbols('a b x x1 x2')
302
+
303
+ The Generalized Regularized Incomplete Beta
304
+ function is given by:
305
+
306
+ >>> betainc_regularized(a, b, x1, x2)
307
+ betainc_regularized(a, b, x1, x2)
308
+
309
+ The Regularized Incomplete Beta function
310
+ can be obtained as follows:
311
+
312
+ >>> betainc_regularized(a, b, 0, x)
313
+ betainc_regularized(a, b, 0, x)
314
+
315
+ The Regularized Incomplete Beta function
316
+ obeys the mirror symmetry:
317
+
318
+ >>> conjugate(betainc_regularized(a, b, x1, x2))
319
+ betainc_regularized(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
320
+
321
+ We can numerically evaluate the Regularized Incomplete Beta function
322
+ to arbitrary precision for any complex numbers a, b, x1 and x2:
323
+
324
+ >>> from sympy import betainc_regularized, pi, E
325
+ >>> betainc_regularized(1, 2, 0, 0.25).evalf(10)
326
+ 0.4375000000
327
+ >>> betainc_regularized(pi, E, 0, 1).evalf(5)
328
+ 1.00000
329
+
330
+ The Generalized Regularized Incomplete Beta function can be
331
+ expressed in terms of the Generalized Hypergeometric function.
332
+
333
+ >>> from sympy import hyper
334
+ >>> betainc_regularized(a, b, x1, x2).rewrite(hyper)
335
+ (-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/(a*beta(a, b))
336
+
337
+ See Also
338
+ ========
339
+
340
+ beta: Beta function
341
+ hyper: Generalized Hypergeometric function
342
+
343
+ References
344
+ ==========
345
+
346
+ .. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
347
+ .. [2] https://dlmf.nist.gov/8.17
348
+ .. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
349
+ .. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
350
+
351
+ """
352
+ nargs = 4
353
+ unbranched = True
354
+
355
+ def __new__(cls, a, b, x1, x2):
356
+ return super().__new__(cls, a, b, x1, x2)
357
+
358
+ def _eval_mpmath(self):
359
+ return betainc_mpmath_fix, (*self.args, S(1))
360
+
361
+ def fdiff(self, argindex):
362
+ a, b, x1, x2 = self.args
363
+ if argindex == 3:
364
+ # Diff wrt x1
365
+ return -(1 - x1)**(b - 1)*x1**(a - 1) / beta(a, b)
366
+ elif argindex == 4:
367
+ # Diff wrt x2
368
+ return (1 - x2)**(b - 1)*x2**(a - 1) / beta(a, b)
369
+ else:
370
+ raise ArgumentIndexError(self, argindex)
371
+
372
+ def _eval_is_real(self):
373
+ if all(arg.is_real for arg in self.args):
374
+ return True
375
+
376
+ def _eval_conjugate(self):
377
+ return self.func(*map(conjugate, self.args))
378
+
379
+ def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
380
+ from sympy.integrals.integrals import Integral
381
+ t = Dummy(uniquely_named_symbol('t', [a, b, x1, x2]).name)
382
+ integrand = t**(a - 1)*(1 - t)**(b - 1)
383
+ expr = Integral(integrand, (t, x1, x2))
384
+ return expr / Integral(integrand, (t, 0, 1))
385
+
386
+ def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
387
+ from sympy.functions.special.hyper import hyper
388
+ expr = (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
389
+ return expr / beta(a, b)
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/bsplines.py ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import S, sympify
2
+ from sympy.core.symbol import (Dummy, symbols)
3
+ from sympy.functions import Piecewise, piecewise_fold
4
+ from sympy.logic.boolalg import And
5
+ from sympy.sets.sets import Interval
6
+
7
+ from functools import lru_cache
8
+
9
+
10
+ def _ivl(cond, x):
11
+ """return the interval corresponding to the condition
12
+
13
+ Conditions in spline's Piecewise give the range over
14
+ which an expression is valid like (lo <= x) & (x <= hi).
15
+ This function returns (lo, hi).
16
+ """
17
+ if isinstance(cond, And) and len(cond.args) == 2:
18
+ a, b = cond.args
19
+ if a.lts == x:
20
+ a, b = b, a
21
+ return a.lts, b.gts
22
+ raise TypeError('unexpected cond type: %s' % cond)
23
+
24
+
25
+ def _add_splines(c, b1, d, b2, x):
26
+ """Construct c*b1 + d*b2."""
27
+
28
+ if S.Zero in (b1, c):
29
+ rv = piecewise_fold(d * b2)
30
+ elif S.Zero in (b2, d):
31
+ rv = piecewise_fold(c * b1)
32
+ else:
33
+ new_args = []
34
+ # Just combining the Piecewise without any fancy optimization
35
+ p1 = piecewise_fold(c * b1)
36
+ p2 = piecewise_fold(d * b2)
37
+
38
+ # Search all Piecewise arguments except (0, True)
39
+ p2args = list(p2.args[:-1])
40
+
41
+ # This merging algorithm assumes the conditions in
42
+ # p1 and p2 are sorted
43
+ for arg in p1.args[:-1]:
44
+ expr = arg.expr
45
+ cond = arg.cond
46
+
47
+ lower = _ivl(cond, x)[0]
48
+
49
+ # Check p2 for matching conditions that can be merged
50
+ for i, arg2 in enumerate(p2args):
51
+ expr2 = arg2.expr
52
+ cond2 = arg2.cond
53
+
54
+ lower_2, upper_2 = _ivl(cond2, x)
55
+ if cond2 == cond:
56
+ # Conditions match, join expressions
57
+ expr += expr2
58
+ # Remove matching element
59
+ del p2args[i]
60
+ # No need to check the rest
61
+ break
62
+ elif lower_2 < lower and upper_2 <= lower:
63
+ # Check if arg2 condition smaller than arg1,
64
+ # add to new_args by itself (no match expected
65
+ # in p1)
66
+ new_args.append(arg2)
67
+ del p2args[i]
68
+ break
69
+
70
+ # Checked all, add expr and cond
71
+ new_args.append((expr, cond))
72
+
73
+ # Add remaining items from p2args
74
+ new_args.extend(p2args)
75
+
76
+ # Add final (0, True)
77
+ new_args.append((0, True))
78
+
79
+ rv = Piecewise(*new_args, evaluate=False)
80
+
81
+ return rv.expand()
82
+
83
+
84
+ @lru_cache(maxsize=128)
85
+ def bspline_basis(d, knots, n, x):
86
+ """
87
+ The $n$-th B-spline at $x$ of degree $d$ with knots.
88
+
89
+ Explanation
90
+ ===========
91
+
92
+ B-Splines are piecewise polynomials of degree $d$. They are defined on a
93
+ set of knots, which is a sequence of integers or floats.
94
+
95
+ Examples
96
+ ========
97
+
98
+ The 0th degree splines have a value of 1 on a single interval:
99
+
100
+ >>> from sympy import bspline_basis
101
+ >>> from sympy.abc import x
102
+ >>> d = 0
103
+ >>> knots = tuple(range(5))
104
+ >>> bspline_basis(d, knots, 0, x)
105
+ Piecewise((1, (x >= 0) & (x <= 1)), (0, True))
106
+
107
+ For a given ``(d, knots)`` there are ``len(knots)-d-1`` B-splines
108
+ defined, that are indexed by ``n`` (starting at 0).
109
+
110
+ Here is an example of a cubic B-spline:
111
+
112
+ >>> bspline_basis(3, tuple(range(5)), 0, x)
113
+ Piecewise((x**3/6, (x >= 0) & (x <= 1)),
114
+ (-x**3/2 + 2*x**2 - 2*x + 2/3,
115
+ (x >= 1) & (x <= 2)),
116
+ (x**3/2 - 4*x**2 + 10*x - 22/3,
117
+ (x >= 2) & (x <= 3)),
118
+ (-x**3/6 + 2*x**2 - 8*x + 32/3,
119
+ (x >= 3) & (x <= 4)),
120
+ (0, True))
121
+
122
+ By repeating knot points, you can introduce discontinuities in the
123
+ B-splines and their derivatives:
124
+
125
+ >>> d = 1
126
+ >>> knots = (0, 0, 2, 3, 4)
127
+ >>> bspline_basis(d, knots, 0, x)
128
+ Piecewise((1 - x/2, (x >= 0) & (x <= 2)), (0, True))
129
+
130
+ It is quite time consuming to construct and evaluate B-splines. If
131
+ you need to evaluate a B-spline many times, it is best to lambdify them
132
+ first:
133
+
134
+ >>> from sympy import lambdify
135
+ >>> d = 3
136
+ >>> knots = tuple(range(10))
137
+ >>> b0 = bspline_basis(d, knots, 0, x)
138
+ >>> f = lambdify(x, b0)
139
+ >>> y = f(0.5)
140
+
141
+ Parameters
142
+ ==========
143
+
144
+ d : integer
145
+ degree of bspline
146
+
147
+ knots : list of integer values
148
+ list of knots points of bspline
149
+
150
+ n : integer
151
+ $n$-th B-spline
152
+
153
+ x : symbol
154
+
155
+ See Also
156
+ ========
157
+
158
+ bspline_basis_set
159
+
160
+ References
161
+ ==========
162
+
163
+ .. [1] https://en.wikipedia.org/wiki/B-spline
164
+
165
+ """
166
+ # make sure x has no assumptions so conditions don't evaluate
167
+ xvar = x
168
+ x = Dummy()
169
+
170
+ knots = tuple(sympify(k) for k in knots)
171
+ d = int(d)
172
+ n = int(n)
173
+ n_knots = len(knots)
174
+ n_intervals = n_knots - 1
175
+ if n + d + 1 > n_intervals:
176
+ raise ValueError("n + d + 1 must not exceed len(knots) - 1")
177
+ if d == 0:
178
+ result = Piecewise(
179
+ (S.One, Interval(knots[n], knots[n + 1]).contains(x)), (0, True)
180
+ )
181
+ elif d > 0:
182
+ denom = knots[n + d + 1] - knots[n + 1]
183
+ if denom != S.Zero:
184
+ B = (knots[n + d + 1] - x) / denom
185
+ b2 = bspline_basis(d - 1, knots, n + 1, x)
186
+ else:
187
+ b2 = B = S.Zero
188
+
189
+ denom = knots[n + d] - knots[n]
190
+ if denom != S.Zero:
191
+ A = (x - knots[n]) / denom
192
+ b1 = bspline_basis(d - 1, knots, n, x)
193
+ else:
194
+ b1 = A = S.Zero
195
+
196
+ result = _add_splines(A, b1, B, b2, x)
197
+ else:
198
+ raise ValueError("degree must be non-negative: %r" % n)
199
+
200
+ # return result with user-given x
201
+ return result.xreplace({x: xvar})
202
+
203
+
204
+ def bspline_basis_set(d, knots, x):
205
+ """
206
+ Return the ``len(knots)-d-1`` B-splines at *x* of degree *d*
207
+ with *knots*.
208
+
209
+ Explanation
210
+ ===========
211
+
212
+ This function returns a list of piecewise polynomials that are the
213
+ ``len(knots)-d-1`` B-splines of degree *d* for the given knots.
214
+ This function calls ``bspline_basis(d, knots, n, x)`` for different
215
+ values of *n*.
216
+
217
+ Examples
218
+ ========
219
+
220
+ >>> from sympy import bspline_basis_set
221
+ >>> from sympy.abc import x
222
+ >>> d = 2
223
+ >>> knots = range(5)
224
+ >>> splines = bspline_basis_set(d, knots, x)
225
+ >>> splines
226
+ [Piecewise((x**2/2, (x >= 0) & (x <= 1)),
227
+ (-x**2 + 3*x - 3/2, (x >= 1) & (x <= 2)),
228
+ (x**2/2 - 3*x + 9/2, (x >= 2) & (x <= 3)),
229
+ (0, True)),
230
+ Piecewise((x**2/2 - x + 1/2, (x >= 1) & (x <= 2)),
231
+ (-x**2 + 5*x - 11/2, (x >= 2) & (x <= 3)),
232
+ (x**2/2 - 4*x + 8, (x >= 3) & (x <= 4)),
233
+ (0, True))]
234
+
235
+ Parameters
236
+ ==========
237
+
238
+ d : integer
239
+ degree of bspline
240
+
241
+ knots : list of integers
242
+ list of knots points of bspline
243
+
244
+ x : symbol
245
+
246
+ See Also
247
+ ========
248
+
249
+ bspline_basis
250
+
251
+ """
252
+ n_splines = len(knots) - d - 1
253
+ return [bspline_basis(d, tuple(knots), i, x) for i in range(n_splines)]
254
+
255
+
256
+ def interpolating_spline(d, x, X, Y):
257
+ """
258
+ Return spline of degree *d*, passing through the given *X*
259
+ and *Y* values.
260
+
261
+ Explanation
262
+ ===========
263
+
264
+ This function returns a piecewise function such that each part is
265
+ a polynomial of degree not greater than *d*. The value of *d*
266
+ must be 1 or greater and the values of *X* must be strictly
267
+ increasing.
268
+
269
+ Examples
270
+ ========
271
+
272
+ >>> from sympy import interpolating_spline
273
+ >>> from sympy.abc import x
274
+ >>> interpolating_spline(1, x, [1, 2, 4, 7], [3, 6, 5, 7])
275
+ Piecewise((3*x, (x >= 1) & (x <= 2)),
276
+ (7 - x/2, (x >= 2) & (x <= 4)),
277
+ (2*x/3 + 7/3, (x >= 4) & (x <= 7)))
278
+ >>> interpolating_spline(3, x, [-2, 0, 1, 3, 4], [4, 2, 1, 1, 3])
279
+ Piecewise((7*x**3/117 + 7*x**2/117 - 131*x/117 + 2, (x >= -2) & (x <= 1)),
280
+ (10*x**3/117 - 2*x**2/117 - 122*x/117 + 77/39, (x >= 1) & (x <= 4)))
281
+
282
+ Parameters
283
+ ==========
284
+
285
+ d : integer
286
+ Degree of Bspline strictly greater than equal to one
287
+
288
+ x : symbol
289
+
290
+ X : list of strictly increasing real values
291
+ list of X coordinates through which the spline passes
292
+
293
+ Y : list of real values
294
+ list of corresponding Y coordinates through which the spline passes
295
+
296
+ See Also
297
+ ========
298
+
299
+ bspline_basis_set, interpolating_poly
300
+
301
+ """
302
+ from sympy.solvers.solveset import linsolve
303
+ from sympy.matrices.dense import Matrix
304
+
305
+ # Input sanitization
306
+ d = sympify(d)
307
+ if not (d.is_Integer and d.is_positive):
308
+ raise ValueError("Spline degree must be a positive integer, not %s." % d)
309
+ if len(X) != len(Y):
310
+ raise ValueError("Number of X and Y coordinates must be the same.")
311
+ if len(X) < d + 1:
312
+ raise ValueError("Degree must be less than the number of control points.")
313
+ if not all(a < b for a, b in zip(X, X[1:])):
314
+ raise ValueError("The x-coordinates must be strictly increasing.")
315
+ X = [sympify(i) for i in X]
316
+
317
+ # Evaluating knots value
318
+ if d.is_odd:
319
+ j = (d + 1) // 2
320
+ interior_knots = X[j:-j]
321
+ else:
322
+ j = d // 2
323
+ interior_knots = [
324
+ (a + b)/2 for a, b in zip(X[j : -j - 1], X[j + 1 : -j])
325
+ ]
326
+
327
+ knots = [X[0]] * (d + 1) + list(interior_knots) + [X[-1]] * (d + 1)
328
+
329
+ basis = bspline_basis_set(d, knots, x)
330
+
331
+ A = [[b.subs(x, v) for b in basis] for v in X]
332
+
333
+ coeff = linsolve((Matrix(A), Matrix(Y)), symbols("c0:{}".format(len(X)), cls=Dummy))
334
+ coeff = list(coeff)[0]
335
+ intervals = {c for b in basis for (e, c) in b.args if c != True}
336
+
337
+ # Sorting the intervals
338
+ # ival contains the end-points of each interval
339
+ intervals = sorted(intervals, key=lambda c: _ivl(c, x))
340
+
341
+ basis_dicts = [{c: e for (e, c) in b.args} for b in basis]
342
+ spline = []
343
+ for i in intervals:
344
+ piece = sum(
345
+ [c * d.get(i, S.Zero) for (c, d) in zip(coeff, basis_dicts)], S.Zero
346
+ )
347
+ spline.append((piece, i))
348
+ return Piecewise(*spline)
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/delta_functions.py ADDED
@@ -0,0 +1,664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import S, diff
2
+ from sympy.core.function import DefinedFunction, ArgumentIndexError
3
+ from sympy.core.logic import fuzzy_not
4
+ from sympy.core.relational import Eq, Ne
5
+ from sympy.functions.elementary.complexes import im, sign
6
+ from sympy.functions.elementary.piecewise import Piecewise
7
+ from sympy.polys.polyerrors import PolynomialError
8
+ from sympy.polys.polyroots import roots
9
+ from sympy.utilities.misc import filldedent
10
+
11
+
12
+ ###############################################################################
13
+ ################################ DELTA FUNCTION ###############################
14
+ ###############################################################################
15
+
16
+
17
+ class DiracDelta(DefinedFunction):
18
+ r"""
19
+ The DiracDelta function and its derivatives.
20
+
21
+ Explanation
22
+ ===========
23
+
24
+ DiracDelta is not an ordinary function. It can be rigorously defined either
25
+ as a distribution or as a measure.
26
+
27
+ DiracDelta only makes sense in definite integrals, and in particular,
28
+ integrals of the form ``Integral(f(x)*DiracDelta(x - x0), (x, a, b))``,
29
+ where it equals ``f(x0)`` if ``a <= x0 <= b`` and ``0`` otherwise. Formally,
30
+ DiracDelta acts in some ways like a function that is ``0`` everywhere except
31
+ at ``0``, but in many ways it also does not. It can often be useful to treat
32
+ DiracDelta in formal ways, building up and manipulating expressions with
33
+ delta functions (which may eventually be integrated), but care must be taken
34
+ to not treat it as a real function. SymPy's ``oo`` is similar. It only
35
+ truly makes sense formally in certain contexts (such as integration limits),
36
+ but SymPy allows its use everywhere, and it tries to be consistent with
37
+ operations on it (like ``1/oo``), but it is easy to get into trouble and get
38
+ wrong results if ``oo`` is treated too much like a number. Similarly, if
39
+ DiracDelta is treated too much like a function, it is easy to get wrong or
40
+ nonsensical results.
41
+
42
+ DiracDelta function has the following properties:
43
+
44
+ 1) $\frac{d}{d x} \theta(x) = \delta(x)$
45
+ 2) $\int_{-\infty}^\infty \delta(x - a)f(x)\, dx = f(a)$ and $\int_{a-
46
+ \epsilon}^{a+\epsilon} \delta(x - a)f(x)\, dx = f(a)$
47
+ 3) $\delta(x) = 0$ for all $x \neq 0$
48
+ 4) $\delta(g(x)) = \sum_i \frac{\delta(x - x_i)}{\|g'(x_i)\|}$ where $x_i$
49
+ are the roots of $g$
50
+ 5) $\delta(-x) = \delta(x)$
51
+
52
+ Derivatives of ``k``-th order of DiracDelta have the following properties:
53
+
54
+ 6) $\delta(x, k) = 0$ for all $x \neq 0$
55
+ 7) $\delta(-x, k) = -\delta(x, k)$ for odd $k$
56
+ 8) $\delta(-x, k) = \delta(x, k)$ for even $k$
57
+
58
+ Examples
59
+ ========
60
+
61
+ >>> from sympy import DiracDelta, diff, pi
62
+ >>> from sympy.abc import x, y
63
+
64
+ >>> DiracDelta(x)
65
+ DiracDelta(x)
66
+ >>> DiracDelta(1)
67
+ 0
68
+ >>> DiracDelta(-1)
69
+ 0
70
+ >>> DiracDelta(pi)
71
+ 0
72
+ >>> DiracDelta(x - 4).subs(x, 4)
73
+ DiracDelta(0)
74
+ >>> diff(DiracDelta(x))
75
+ DiracDelta(x, 1)
76
+ >>> diff(DiracDelta(x - 1), x, 2)
77
+ DiracDelta(x - 1, 2)
78
+ >>> diff(DiracDelta(x**2 - 1), x, 2)
79
+ 2*(2*x**2*DiracDelta(x**2 - 1, 2) + DiracDelta(x**2 - 1, 1))
80
+ >>> DiracDelta(3*x).is_simple(x)
81
+ True
82
+ >>> DiracDelta(x**2).is_simple(x)
83
+ False
84
+ >>> DiracDelta((x**2 - 1)*y).expand(diracdelta=True, wrt=x)
85
+ DiracDelta(x - 1)/(2*Abs(y)) + DiracDelta(x + 1)/(2*Abs(y))
86
+
87
+ See Also
88
+ ========
89
+
90
+ Heaviside
91
+ sympy.simplify.simplify.simplify, is_simple
92
+ sympy.functions.special.tensor_functions.KroneckerDelta
93
+
94
+ References
95
+ ==========
96
+
97
+ .. [1] https://mathworld.wolfram.com/DeltaFunction.html
98
+
99
+ """
100
+
101
+ is_real = True
102
+
103
+ def fdiff(self, argindex=1):
104
+ """
105
+ Returns the first derivative of a DiracDelta Function.
106
+
107
+ Explanation
108
+ ===========
109
+
110
+ The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the
111
+ user-level function and ``fdiff()`` is an object method. ``fdiff()`` is
112
+ a convenience method available in the ``Function`` class. It returns
113
+ the derivative of the function without considering the chain rule.
114
+ ``diff(function, x)`` calls ``Function._eval_derivative`` which in turn
115
+ calls ``fdiff()`` internally to compute the derivative of the function.
116
+
117
+ Examples
118
+ ========
119
+
120
+ >>> from sympy import DiracDelta, diff
121
+ >>> from sympy.abc import x
122
+
123
+ >>> DiracDelta(x).fdiff()
124
+ DiracDelta(x, 1)
125
+
126
+ >>> DiracDelta(x, 1).fdiff()
127
+ DiracDelta(x, 2)
128
+
129
+ >>> DiracDelta(x**2 - 1).fdiff()
130
+ DiracDelta(x**2 - 1, 1)
131
+
132
+ >>> diff(DiracDelta(x, 1)).fdiff()
133
+ DiracDelta(x, 3)
134
+
135
+ Parameters
136
+ ==========
137
+
138
+ argindex : integer
139
+ degree of derivative
140
+
141
+ """
142
+ if argindex == 1:
143
+ #I didn't know if there is a better way to handle default arguments
144
+ k = 0
145
+ if len(self.args) > 1:
146
+ k = self.args[1]
147
+ return self.func(self.args[0], k + 1)
148
+ else:
149
+ raise ArgumentIndexError(self, argindex)
150
+
151
+ @classmethod
152
+ def eval(cls, arg, k=S.Zero):
153
+ """
154
+ Returns a simplified form or a value of DiracDelta depending on the
155
+ argument passed by the DiracDelta object.
156
+
157
+ Explanation
158
+ ===========
159
+
160
+ The ``eval()`` method is automatically called when the ``DiracDelta``
161
+ class is about to be instantiated and it returns either some simplified
162
+ instance or the unevaluated instance depending on the argument passed.
163
+ In other words, ``eval()`` method is not needed to be called explicitly,
164
+ it is being called and evaluated once the object is called.
165
+
166
+ Examples
167
+ ========
168
+
169
+ >>> from sympy import DiracDelta, S
170
+ >>> from sympy.abc import x
171
+
172
+ >>> DiracDelta(x)
173
+ DiracDelta(x)
174
+
175
+ >>> DiracDelta(-x, 1)
176
+ -DiracDelta(x, 1)
177
+
178
+ >>> DiracDelta(1)
179
+ 0
180
+
181
+ >>> DiracDelta(5, 1)
182
+ 0
183
+
184
+ >>> DiracDelta(0)
185
+ DiracDelta(0)
186
+
187
+ >>> DiracDelta(-1)
188
+ 0
189
+
190
+ >>> DiracDelta(S.NaN)
191
+ nan
192
+
193
+ >>> DiracDelta(x - 100).subs(x, 5)
194
+ 0
195
+
196
+ >>> DiracDelta(x - 100).subs(x, 100)
197
+ DiracDelta(0)
198
+
199
+ Parameters
200
+ ==========
201
+
202
+ k : integer
203
+ order of derivative
204
+
205
+ arg : argument passed to DiracDelta
206
+
207
+ """
208
+ if not k.is_Integer or k.is_negative:
209
+ raise ValueError("Error: the second argument of DiracDelta must be \
210
+ a non-negative integer, %s given instead." % (k,))
211
+ if arg is S.NaN:
212
+ return S.NaN
213
+ if arg.is_nonzero:
214
+ return S.Zero
215
+ if fuzzy_not(im(arg).is_zero):
216
+ raise ValueError(filldedent('''
217
+ Function defined only for Real Values.
218
+ Complex part: %s found in %s .''' % (
219
+ repr(im(arg)), repr(arg))))
220
+ c, nc = arg.args_cnc()
221
+ if c and c[0] is S.NegativeOne:
222
+ # keep this fast and simple instead of using
223
+ # could_extract_minus_sign
224
+ if k.is_odd:
225
+ return -cls(-arg, k)
226
+ elif k.is_even:
227
+ return cls(-arg, k) if k else cls(-arg)
228
+ elif k.is_zero:
229
+ return cls(arg, evaluate=False)
230
+
231
+ def _eval_expand_diracdelta(self, **hints):
232
+ """
233
+ Compute a simplified representation of the function using
234
+ property number 4. Pass ``wrt`` as a hint to expand the expression
235
+ with respect to a particular variable.
236
+
237
+ Explanation
238
+ ===========
239
+
240
+ ``wrt`` is:
241
+
242
+ - a variable with respect to which a DiracDelta expression will
243
+ get expanded.
244
+
245
+ Examples
246
+ ========
247
+
248
+ >>> from sympy import DiracDelta
249
+ >>> from sympy.abc import x, y
250
+
251
+ >>> DiracDelta(x*y).expand(diracdelta=True, wrt=x)
252
+ DiracDelta(x)/Abs(y)
253
+ >>> DiracDelta(x*y).expand(diracdelta=True, wrt=y)
254
+ DiracDelta(y)/Abs(x)
255
+
256
+ >>> DiracDelta(x**2 + x - 2).expand(diracdelta=True, wrt=x)
257
+ DiracDelta(x - 1)/3 + DiracDelta(x + 2)/3
258
+
259
+ See Also
260
+ ========
261
+
262
+ is_simple, Diracdelta
263
+
264
+ """
265
+ wrt = hints.get('wrt', None)
266
+ if wrt is None:
267
+ free = self.free_symbols
268
+ if len(free) == 1:
269
+ wrt = free.pop()
270
+ else:
271
+ raise TypeError(filldedent('''
272
+ When there is more than 1 free symbol or variable in the expression,
273
+ the 'wrt' keyword is required as a hint to expand when using the
274
+ DiracDelta hint.'''))
275
+
276
+ if not self.args[0].has(wrt) or (len(self.args) > 1 and self.args[1] != 0 ):
277
+ return self
278
+ try:
279
+ argroots = roots(self.args[0], wrt)
280
+ result = 0
281
+ valid = True
282
+ darg = abs(diff(self.args[0], wrt))
283
+ for r, m in argroots.items():
284
+ if r.is_real is not False and m == 1:
285
+ result += self.func(wrt - r)/darg.subs(wrt, r)
286
+ else:
287
+ # don't handle non-real and if m != 1 then
288
+ # a polynomial will have a zero in the derivative (darg)
289
+ # at r
290
+ valid = False
291
+ break
292
+ if valid:
293
+ return result
294
+ except PolynomialError:
295
+ pass
296
+ return self
297
+
298
+ def is_simple(self, x):
299
+ """
300
+ Tells whether the argument(args[0]) of DiracDelta is a linear
301
+ expression in *x*.
302
+
303
+ Examples
304
+ ========
305
+
306
+ >>> from sympy import DiracDelta, cos
307
+ >>> from sympy.abc import x, y
308
+
309
+ >>> DiracDelta(x*y).is_simple(x)
310
+ True
311
+ >>> DiracDelta(x*y).is_simple(y)
312
+ True
313
+
314
+ >>> DiracDelta(x**2 + x - 2).is_simple(x)
315
+ False
316
+
317
+ >>> DiracDelta(cos(x)).is_simple(x)
318
+ False
319
+
320
+ Parameters
321
+ ==========
322
+
323
+ x : can be a symbol
324
+
325
+ See Also
326
+ ========
327
+
328
+ sympy.simplify.simplify.simplify, DiracDelta
329
+
330
+ """
331
+ p = self.args[0].as_poly(x)
332
+ if p:
333
+ return p.degree() == 1
334
+ return False
335
+
336
+ def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
337
+ """
338
+ Represents DiracDelta in a piecewise form.
339
+
340
+ Examples
341
+ ========
342
+
343
+ >>> from sympy import DiracDelta, Piecewise, Symbol
344
+ >>> x = Symbol('x')
345
+
346
+ >>> DiracDelta(x).rewrite(Piecewise)
347
+ Piecewise((DiracDelta(0), Eq(x, 0)), (0, True))
348
+
349
+ >>> DiracDelta(x - 5).rewrite(Piecewise)
350
+ Piecewise((DiracDelta(0), Eq(x, 5)), (0, True))
351
+
352
+ >>> DiracDelta(x**2 - 5).rewrite(Piecewise)
353
+ Piecewise((DiracDelta(0), Eq(x**2, 5)), (0, True))
354
+
355
+ >>> DiracDelta(x - 5, 4).rewrite(Piecewise)
356
+ DiracDelta(x - 5, 4)
357
+
358
+ """
359
+ if len(args) == 1:
360
+ return Piecewise((DiracDelta(0), Eq(args[0], 0)), (0, True))
361
+
362
+ def _eval_rewrite_as_SingularityFunction(self, *args, **kwargs):
363
+ """
364
+ Returns the DiracDelta expression written in the form of Singularity
365
+ Functions.
366
+
367
+ """
368
+ from sympy.solvers import solve
369
+ from sympy.functions.special.singularity_functions import SingularityFunction
370
+ if self == DiracDelta(0):
371
+ return SingularityFunction(0, 0, -1)
372
+ if self == DiracDelta(0, 1):
373
+ return SingularityFunction(0, 0, -2)
374
+ free = self.free_symbols
375
+ if len(free) == 1:
376
+ x = (free.pop())
377
+ if len(args) == 1:
378
+ return SingularityFunction(x, solve(args[0], x)[0], -1)
379
+ return SingularityFunction(x, solve(args[0], x)[0], -args[1] - 1)
380
+ else:
381
+ # I don't know how to handle the case for DiracDelta expressions
382
+ # having arguments with more than one variable.
383
+ raise TypeError(filldedent('''
384
+ rewrite(SingularityFunction) does not support
385
+ arguments with more that one variable.'''))
386
+
387
+
388
+ ###############################################################################
389
+ ############################## HEAVISIDE FUNCTION #############################
390
+ ###############################################################################
391
+
392
+
393
+ class Heaviside(DefinedFunction):
394
+ r"""
395
+ Heaviside step function.
396
+
397
+ Explanation
398
+ ===========
399
+
400
+ The Heaviside step function has the following properties:
401
+
402
+ 1) $\frac{d}{d x} \theta(x) = \delta(x)$
403
+ 2) $\theta(x) = \begin{cases} 0 & \text{for}\: x < 0 \\ \frac{1}{2} &
404
+ \text{for}\: x = 0 \\1 & \text{for}\: x > 0 \end{cases}$
405
+ 3) $\frac{d}{d x} \max(x, 0) = \theta(x)$
406
+
407
+ Heaviside(x) is printed as $\theta(x)$ with the SymPy LaTeX printer.
408
+
409
+ The value at 0 is set differently in different fields. SymPy uses 1/2,
410
+ which is a convention from electronics and signal processing, and is
411
+ consistent with solving improper integrals by Fourier transform and
412
+ convolution.
413
+
414
+ To specify a different value of Heaviside at ``x=0``, a second argument
415
+ can be given. Using ``Heaviside(x, nan)`` gives an expression that will
416
+ evaluate to nan for x=0.
417
+
418
+ .. versionchanged:: 1.9 ``Heaviside(0)`` now returns 1/2 (before: undefined)
419
+
420
+ Examples
421
+ ========
422
+
423
+ >>> from sympy import Heaviside, nan
424
+ >>> from sympy.abc import x
425
+ >>> Heaviside(9)
426
+ 1
427
+ >>> Heaviside(-9)
428
+ 0
429
+ >>> Heaviside(0)
430
+ 1/2
431
+ >>> Heaviside(0, nan)
432
+ nan
433
+ >>> (Heaviside(x) + 1).replace(Heaviside(x), Heaviside(x, 1))
434
+ Heaviside(x, 1) + 1
435
+
436
+ See Also
437
+ ========
438
+
439
+ DiracDelta
440
+
441
+ References
442
+ ==========
443
+
444
+ .. [1] https://mathworld.wolfram.com/HeavisideStepFunction.html
445
+ .. [2] https://dlmf.nist.gov/1.16#iv
446
+
447
+ """
448
+
449
+ is_real = True
450
+
451
+ def fdiff(self, argindex=1):
452
+ """
453
+ Returns the first derivative of a Heaviside Function.
454
+
455
+ Examples
456
+ ========
457
+
458
+ >>> from sympy import Heaviside, diff
459
+ >>> from sympy.abc import x
460
+
461
+ >>> Heaviside(x).fdiff()
462
+ DiracDelta(x)
463
+
464
+ >>> Heaviside(x**2 - 1).fdiff()
465
+ DiracDelta(x**2 - 1)
466
+
467
+ >>> diff(Heaviside(x)).fdiff()
468
+ DiracDelta(x, 1)
469
+
470
+ Parameters
471
+ ==========
472
+
473
+ argindex : integer
474
+ order of derivative
475
+
476
+ """
477
+ if argindex == 1:
478
+ return DiracDelta(self.args[0])
479
+ else:
480
+ raise ArgumentIndexError(self, argindex)
481
+
482
+ def __new__(cls, arg, H0=S.Half, **options):
483
+ if isinstance(H0, Heaviside) and len(H0.args) == 1:
484
+ H0 = S.Half
485
+ return super(cls, cls).__new__(cls, arg, H0, **options)
486
+
487
+ @property
488
+ def pargs(self):
489
+ """Args without default S.Half"""
490
+ args = self.args
491
+ if args[1] is S.Half:
492
+ args = args[:1]
493
+ return args
494
+
495
+ @classmethod
496
+ def eval(cls, arg, H0=S.Half):
497
+ """
498
+ Returns a simplified form or a value of Heaviside depending on the
499
+ argument passed by the Heaviside object.
500
+
501
+ Explanation
502
+ ===========
503
+
504
+ The ``eval()`` method is automatically called when the ``Heaviside``
505
+ class is about to be instantiated and it returns either some simplified
506
+ instance or the unevaluated instance depending on the argument passed.
507
+ In other words, ``eval()`` method is not needed to be called explicitly,
508
+ it is being called and evaluated once the object is called.
509
+
510
+ Examples
511
+ ========
512
+
513
+ >>> from sympy import Heaviside, S
514
+ >>> from sympy.abc import x
515
+
516
+ >>> Heaviside(x)
517
+ Heaviside(x)
518
+
519
+ >>> Heaviside(19)
520
+ 1
521
+
522
+ >>> Heaviside(0)
523
+ 1/2
524
+
525
+ >>> Heaviside(0, 1)
526
+ 1
527
+
528
+ >>> Heaviside(-5)
529
+ 0
530
+
531
+ >>> Heaviside(S.NaN)
532
+ nan
533
+
534
+ >>> Heaviside(x - 100).subs(x, 5)
535
+ 0
536
+
537
+ >>> Heaviside(x - 100).subs(x, 105)
538
+ 1
539
+
540
+ Parameters
541
+ ==========
542
+
543
+ arg : argument passed by Heaviside object
544
+
545
+ H0 : value of Heaviside(0)
546
+
547
+ """
548
+ if arg.is_extended_negative:
549
+ return S.Zero
550
+ elif arg.is_extended_positive:
551
+ return S.One
552
+ elif arg.is_zero:
553
+ return H0
554
+ elif arg is S.NaN:
555
+ return S.NaN
556
+ elif fuzzy_not(im(arg).is_zero):
557
+ raise ValueError("Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)) )
558
+
559
+ def _eval_rewrite_as_Piecewise(self, arg, H0=None, **kwargs):
560
+ """
561
+ Represents Heaviside in a Piecewise form.
562
+
563
+ Examples
564
+ ========
565
+
566
+ >>> from sympy import Heaviside, Piecewise, Symbol, nan
567
+ >>> x = Symbol('x')
568
+
569
+ >>> Heaviside(x).rewrite(Piecewise)
570
+ Piecewise((0, x < 0), (1/2, Eq(x, 0)), (1, True))
571
+
572
+ >>> Heaviside(x,nan).rewrite(Piecewise)
573
+ Piecewise((0, x < 0), (nan, Eq(x, 0)), (1, True))
574
+
575
+ >>> Heaviside(x - 5).rewrite(Piecewise)
576
+ Piecewise((0, x < 5), (1/2, Eq(x, 5)), (1, True))
577
+
578
+ >>> Heaviside(x**2 - 1).rewrite(Piecewise)
579
+ Piecewise((0, x**2 < 1), (1/2, Eq(x**2, 1)), (1, True))
580
+
581
+ """
582
+ if H0 == 0:
583
+ return Piecewise((0, arg <= 0), (1, True))
584
+ if H0 == 1:
585
+ return Piecewise((0, arg < 0), (1, True))
586
+ return Piecewise((0, arg < 0), (H0, Eq(arg, 0)), (1, True))
587
+
588
+ def _eval_rewrite_as_sign(self, arg, H0=S.Half, **kwargs):
589
+ """
590
+ Represents the Heaviside function in the form of sign function.
591
+
592
+ Explanation
593
+ ===========
594
+
595
+ The value of Heaviside(0) must be 1/2 for rewriting as sign to be
596
+ strictly equivalent. For easier usage, we also allow this rewriting
597
+ when Heaviside(0) is undefined.
598
+
599
+ Examples
600
+ ========
601
+
602
+ >>> from sympy import Heaviside, Symbol, sign, nan
603
+ >>> x = Symbol('x', real=True)
604
+ >>> y = Symbol('y')
605
+
606
+ >>> Heaviside(x).rewrite(sign)
607
+ sign(x)/2 + 1/2
608
+
609
+ >>> Heaviside(x, 0).rewrite(sign)
610
+ Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (0, True))
611
+
612
+ >>> Heaviside(x, nan).rewrite(sign)
613
+ Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (nan, True))
614
+
615
+ >>> Heaviside(x - 2).rewrite(sign)
616
+ sign(x - 2)/2 + 1/2
617
+
618
+ >>> Heaviside(x**2 - 2*x + 1).rewrite(sign)
619
+ sign(x**2 - 2*x + 1)/2 + 1/2
620
+
621
+ >>> Heaviside(y).rewrite(sign)
622
+ Heaviside(y)
623
+
624
+ >>> Heaviside(y**2 - 2*y + 1).rewrite(sign)
625
+ Heaviside(y**2 - 2*y + 1)
626
+
627
+ See Also
628
+ ========
629
+
630
+ sign
631
+
632
+ """
633
+ if arg.is_extended_real:
634
+ pw1 = Piecewise(
635
+ ((sign(arg) + 1)/2, Ne(arg, 0)),
636
+ (Heaviside(0, H0=H0), True))
637
+ pw2 = Piecewise(
638
+ ((sign(arg) + 1)/2, Eq(Heaviside(0, H0=H0), S.Half)),
639
+ (pw1, True))
640
+ return pw2
641
+
642
+ def _eval_rewrite_as_SingularityFunction(self, args, H0=S.Half, **kwargs):
643
+ """
644
+ Returns the Heaviside expression written in the form of Singularity
645
+ Functions.
646
+
647
+ """
648
+ from sympy.solvers import solve
649
+ from sympy.functions.special.singularity_functions import SingularityFunction
650
+ if self == Heaviside(0):
651
+ return SingularityFunction(0, 0, 0)
652
+ free = self.free_symbols
653
+ if len(free) == 1:
654
+ x = (free.pop())
655
+ return SingularityFunction(x, solve(args, x)[0], 0)
656
+ # TODO
657
+ # ((x - 5)**3*Heaviside(x - 5)).rewrite(SingularityFunction) should output
658
+ # SingularityFunction(x, 5, 0) instead of (x - 5)**3*SingularityFunction(x, 5, 0)
659
+ else:
660
+ # I don't know how to handle the case for Heaviside expressions
661
+ # having arguments with more than one variable.
662
+ raise TypeError(filldedent('''
663
+ rewrite(SingularityFunction) does not
664
+ support arguments with more that one variable.'''))
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/elliptic_integrals.py ADDED
@@ -0,0 +1,445 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Elliptic Integrals. """
2
+
3
+ from sympy.core import S, pi, I, Rational
4
+ from sympy.core.function import DefinedFunction, ArgumentIndexError
5
+ from sympy.core.symbol import Dummy,uniquely_named_symbol
6
+ from sympy.functions.elementary.complexes import sign
7
+ from sympy.functions.elementary.hyperbolic import atanh
8
+ from sympy.functions.elementary.miscellaneous import sqrt
9
+ from sympy.functions.elementary.trigonometric import sin, tan
10
+ from sympy.functions.special.gamma_functions import gamma
11
+ from sympy.functions.special.hyper import hyper, meijerg
12
+
13
+ class elliptic_k(DefinedFunction):
14
+ r"""
15
+ The complete elliptic integral of the first kind, defined by
16
+
17
+ .. math:: K(m) = F\left(\tfrac{\pi}{2}\middle| m\right)
18
+
19
+ where $F\left(z\middle| m\right)$ is the Legendre incomplete
20
+ elliptic integral of the first kind.
21
+
22
+ Explanation
23
+ ===========
24
+
25
+ The function $K(m)$ is a single-valued function on the complex
26
+ plane with branch cut along the interval $(1, \infty)$.
27
+
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$.
32
+
33
+ Examples
34
+ ========
35
+
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)
44
+
45
+ See Also
46
+ ========
47
+
48
+ elliptic_f
49
+
50
+ References
51
+ ==========
52
+
53
+ .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
54
+ .. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticK
55
+
56
+ """
57
+
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
71
+
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))
75
+
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())
80
+
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))
84
+
85
+ def _eval_rewrite_as_hyper(self, m, **kwargs):
86
+ return pi*S.Half*hyper((S.Half, S.Half), (S.One,), m)
87
+
88
+ def _eval_rewrite_as_meijerg(self, m, **kwargs):
89
+ return meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -m)/2
90
+
91
+ def _eval_is_zero(self):
92
+ m = self.args[0]
93
+ if m.is_infinite:
94
+ return True
95
+
96
+ def _eval_rewrite_as_Integral(self, *args, **kwargs):
97
+ from sympy.integrals.integrals import Integral
98
+ t = Dummy(uniquely_named_symbol('t', args).name)
99
+ m = self.args[0]
100
+ return Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, pi/2))
101
+
102
+
103
+ class elliptic_f(DefinedFunction):
104
+ r"""
105
+ The Legendre incomplete elliptic integral of the first
106
+ kind, defined by
107
+
108
+ .. math:: F\left(z\middle| m\right) =
109
+ \int_0^z \frac{dt}{\sqrt{1 - m \sin^2 t}}
110
+
111
+ Explanation
112
+ ===========
113
+
114
+ This function reduces to a complete elliptic integral of
115
+ the first kind, $K(m)$, when $z = \pi/2$.
116
+
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$.
121
+
122
+ Examples
123
+ ========
124
+
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
131
+
132
+ See Also
133
+ ========
134
+
135
+ elliptic_k
136
+
137
+ References
138
+ ==========
139
+
140
+ .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
141
+ .. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticF
142
+
143
+ """
144
+
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)
158
+
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)
168
+
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())
173
+
174
+ def _eval_rewrite_as_Integral(self, *args, **kwargs):
175
+ from sympy.integrals.integrals import Integral
176
+ t = Dummy(uniquely_named_symbol('t', args).name)
177
+ z, m = self.args[0], self.args[1]
178
+ return Integral(1/(sqrt(1 - m*sin(t)**2)), (t, 0, z))
179
+
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
186
+
187
+
188
+ class elliptic_e(DefinedFunction):
189
+ r"""
190
+ Called with two arguments $z$ and $m$, evaluates the
191
+ incomplete elliptic integral of the second kind, defined by
192
+
193
+ .. math:: E\left(z\middle| m\right) = \int_0^z \sqrt{1 - m \sin^2 t} dt
194
+
195
+ Called with a single argument $m$, evaluates the Legendre complete
196
+ elliptic integral of the second kind
197
+
198
+ .. math:: E(m) = E\left(\tfrac{\pi}{2}\middle| m\right)
199
+
200
+ Explanation
201
+ ===========
202
+
203
+ The function $E(m)$ is a single-valued function on the complex
204
+ plane with branch cut along the interval $(1, \infty)$.
205
+
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$.
210
+
211
+ Examples
212
+ ========
213
+
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
226
+
227
+ References
228
+ ==========
229
+
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
233
+
234
+ """
235
+
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
262
+
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)
275
+
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())
285
+
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)
291
+
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)
296
+
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
302
+
303
+ def _eval_rewrite_as_Integral(self, *args, **kwargs):
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(uniquely_named_symbol('t', args).name)
307
+ return Integral(sqrt(1 - m*sin(t)**2), (t, 0, z))
308
+
309
+
310
+ class elliptic_pi(DefinedFunction):
311
+ r"""
312
+ Called with three arguments $n$, $z$ and $m$, evaluates the
313
+ Legendre incomplete elliptic integral of the third kind, defined by
314
+
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}}
317
+
318
+ Called with two arguments $n$ and $m$, evaluates the complete
319
+ elliptic integral of the third kind:
320
+
321
+ .. math:: \Pi\left(n\middle| m\right) =
322
+ \Pi\left(n; \tfrac{\pi}{2}\middle| m\right)
323
+
324
+ Explanation
325
+ ===========
326
+
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$.
331
+
332
+ Examples
333
+ ========
334
+
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
345
+
346
+ References
347
+ ==========
348
+
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
352
+
353
+ """
354
+
355
+ @classmethod
356
+ def eval(cls, n, m, z=None):
357
+ if z is not None:
358
+ z, m = 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
404
+
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())
414
+
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)
437
+
438
+ def _eval_rewrite_as_Integral(self, *args, **kwargs):
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(uniquely_named_symbol('t', args).name)
445
+ return Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, z))
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/error_functions.py ADDED
@@ -0,0 +1,2801 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ This module contains various functions that are special cases
2
+ of incomplete gamma functions. It should probably be renamed. """
3
+
4
+ from sympy.core import EulerGamma # Must be imported from core, not core.numbers
5
+ from sympy.core.add import Add
6
+ from sympy.core.cache import cacheit
7
+ from sympy.core.function import DefinedFunction, ArgumentIndexError, expand_mul
8
+ from sympy.core.logic import fuzzy_or
9
+ from sympy.core.numbers import I, pi, Rational, Integer
10
+ from sympy.core.relational import is_eq
11
+ from sympy.core.power import Pow
12
+ from sympy.core.singleton import S
13
+ from sympy.core.symbol import Dummy, uniquely_named_symbol
14
+ from sympy.core.sympify import sympify
15
+ from sympy.functions.combinatorial.factorials import factorial, factorial2, RisingFactorial
16
+ from sympy.functions.elementary.complexes import polar_lift, re, unpolarify
17
+ from sympy.functions.elementary.integers import ceiling, floor
18
+ from sympy.functions.elementary.miscellaneous import sqrt, root
19
+ from sympy.functions.elementary.exponential import exp, log, exp_polar
20
+ from sympy.functions.elementary.hyperbolic import cosh, sinh
21
+ from sympy.functions.elementary.trigonometric import cos, sin, sinc
22
+ from sympy.functions.special.hyper import hyper, meijerg
23
+
24
+ # TODO series expansions
25
+ # TODO see the "Note:" in Ei
26
+
27
+ # Helper function
28
+ def real_to_real_as_real_imag(self, deep=True, **hints):
29
+ if self.args[0].is_extended_real:
30
+ if deep:
31
+ hints['complex'] = False
32
+ return (self.expand(deep, **hints), S.Zero)
33
+ else:
34
+ return (self, S.Zero)
35
+ if deep:
36
+ x, y = self.args[0].expand(deep, **hints).as_real_imag()
37
+ else:
38
+ x, y = self.args[0].as_real_imag()
39
+ re = (self.func(x + I*y) + self.func(x - I*y))/2
40
+ im = (self.func(x + I*y) - self.func(x - I*y))/(2*I)
41
+ return (re, im)
42
+
43
+
44
+ ###############################################################################
45
+ ################################ ERROR FUNCTION ###############################
46
+ ###############################################################################
47
+
48
+
49
+ class erf(DefinedFunction):
50
+ r"""
51
+ The Gauss error function.
52
+
53
+ Explanation
54
+ ===========
55
+
56
+ This function is defined as:
57
+
58
+ .. math ::
59
+ \mathrm{erf}(x) = \frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2} \mathrm{d}t.
60
+
61
+ Examples
62
+ ========
63
+
64
+ >>> from sympy import I, oo, erf
65
+ >>> from sympy.abc import z
66
+
67
+ Several special values are known:
68
+
69
+ >>> erf(0)
70
+ 0
71
+ >>> erf(oo)
72
+ 1
73
+ >>> erf(-oo)
74
+ -1
75
+ >>> erf(I*oo)
76
+ oo*I
77
+ >>> erf(-I*oo)
78
+ -oo*I
79
+
80
+ In general one can pull out factors of -1 and $I$ from the argument:
81
+
82
+ >>> erf(-z)
83
+ -erf(z)
84
+
85
+ The error function obeys the mirror symmetry:
86
+
87
+ >>> from sympy import conjugate
88
+ >>> conjugate(erf(z))
89
+ erf(conjugate(z))
90
+
91
+ Differentiation with respect to $z$ is supported:
92
+
93
+ >>> from sympy import diff
94
+ >>> diff(erf(z), z)
95
+ 2*exp(-z**2)/sqrt(pi)
96
+
97
+ We can numerically evaluate the error function to arbitrary precision
98
+ on the whole complex plane:
99
+
100
+ >>> erf(4).evalf(30)
101
+ 0.999999984582742099719981147840
102
+
103
+ >>> erf(-4*I).evalf(30)
104
+ -1296959.73071763923152794095062*I
105
+
106
+ See Also
107
+ ========
108
+
109
+ erfc: Complementary error function.
110
+ erfi: Imaginary error function.
111
+ erf2: Two-argument error function.
112
+ erfinv: Inverse error function.
113
+ erfcinv: Inverse Complementary error function.
114
+ erf2inv: Inverse two-argument error function.
115
+
116
+ References
117
+ ==========
118
+
119
+ .. [1] https://en.wikipedia.org/wiki/Error_function
120
+ .. [2] https://dlmf.nist.gov/7
121
+ .. [3] https://mathworld.wolfram.com/Erf.html
122
+ .. [4] https://functions.wolfram.com/GammaBetaErf/Erf
123
+
124
+ """
125
+
126
+ unbranched = True
127
+
128
+ def fdiff(self, argindex=1):
129
+ if argindex == 1:
130
+ return 2*exp(-self.args[0]**2)/sqrt(pi)
131
+ else:
132
+ raise ArgumentIndexError(self, argindex)
133
+
134
+
135
+ def inverse(self, argindex=1):
136
+ """
137
+ Returns the inverse of this function.
138
+
139
+ """
140
+ return erfinv
141
+
142
+ @classmethod
143
+ def eval(cls, arg):
144
+ if arg.is_Number:
145
+ if arg is S.NaN:
146
+ return S.NaN
147
+ elif arg is S.Infinity:
148
+ return S.One
149
+ elif arg is S.NegativeInfinity:
150
+ return S.NegativeOne
151
+ elif arg.is_zero:
152
+ return S.Zero
153
+
154
+ if isinstance(arg, erfinv):
155
+ return arg.args[0]
156
+
157
+ if isinstance(arg, erfcinv):
158
+ return S.One - arg.args[0]
159
+
160
+ if arg.is_zero:
161
+ return S.Zero
162
+
163
+ # Only happens with unevaluated erf2inv
164
+ if isinstance(arg, erf2inv) and arg.args[0].is_zero:
165
+ return arg.args[1]
166
+
167
+ # Try to pull out factors of I
168
+ t = arg.extract_multiplicatively(I)
169
+ if t in (S.Infinity, S.NegativeInfinity):
170
+ return arg
171
+
172
+ # Try to pull out factors of -1
173
+ if arg.could_extract_minus_sign():
174
+ return -cls(-arg)
175
+
176
+ @staticmethod
177
+ @cacheit
178
+ def taylor_term(n, x, *previous_terms):
179
+ if n < 0 or n % 2 == 0:
180
+ return S.Zero
181
+ else:
182
+ x = sympify(x)
183
+ k = floor((n - 1)/S(2))
184
+ if len(previous_terms) > 2:
185
+ return -previous_terms[-2] * x**2 * (n - 2)/(n*k)
186
+ else:
187
+ return 2*S.NegativeOne**k * x**n/(n*factorial(k)*sqrt(pi))
188
+
189
+ def _eval_conjugate(self):
190
+ return self.func(self.args[0].conjugate())
191
+
192
+ def _eval_is_real(self):
193
+ if self.args[0].is_extended_real is True:
194
+ return True
195
+ # There are cases where erf(z) becomes a real number
196
+ # even if z is a complex number
197
+
198
+ def _eval_is_imaginary(self):
199
+ if self.args[0].is_imaginary is True:
200
+ return True
201
+
202
+ def _eval_is_finite(self):
203
+ z = self.args[0]
204
+ return fuzzy_or([z.is_finite, z.is_extended_real])
205
+
206
+ def _eval_is_zero(self):
207
+ if self.args[0].is_extended_real is True:
208
+ return self.args[0].is_zero
209
+
210
+ def _eval_is_positive(self):
211
+ if self.args[0].is_extended_real is True:
212
+ return self.args[0].is_extended_positive
213
+
214
+ def _eval_is_negative(self):
215
+ if self.args[0].is_extended_real is True:
216
+ return self.args[0].is_extended_negative
217
+
218
+ def _eval_rewrite_as_uppergamma(self, z, **kwargs):
219
+ from sympy.functions.special.gamma_functions import uppergamma
220
+ return sqrt(z**2)/z*(S.One - uppergamma(S.Half, z**2)/sqrt(pi))
221
+
222
+ def _eval_rewrite_as_fresnels(self, z, **kwargs):
223
+ arg = (S.One - I)*z/sqrt(pi)
224
+ return (S.One + I)*(fresnelc(arg) - I*fresnels(arg))
225
+
226
+ def _eval_rewrite_as_fresnelc(self, z, **kwargs):
227
+ arg = (S.One - I)*z/sqrt(pi)
228
+ return (S.One + I)*(fresnelc(arg) - I*fresnels(arg))
229
+
230
+ def _eval_rewrite_as_meijerg(self, z, **kwargs):
231
+ return z/sqrt(pi)*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2)
232
+
233
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
234
+ return 2*z/sqrt(pi)*hyper([S.Half], [3*S.Half], -z**2)
235
+
236
+ def _eval_rewrite_as_expint(self, z, **kwargs):
237
+ return sqrt(z**2)/z - z*expint(S.Half, z**2)/sqrt(pi)
238
+
239
+ def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs):
240
+ from sympy.series.limits import limit
241
+ if limitvar:
242
+ lim = limit(z, limitvar, S.Infinity)
243
+ if lim is S.NegativeInfinity:
244
+ return S.NegativeOne + _erfs(-z)*exp(-z**2)
245
+ return S.One - _erfs(z)*exp(-z**2)
246
+
247
+ def _eval_rewrite_as_erfc(self, z, **kwargs):
248
+ return S.One - erfc(z)
249
+
250
+ def _eval_rewrite_as_erfi(self, z, **kwargs):
251
+ return -I*erfi(I*z)
252
+
253
+ def _eval_as_leading_term(self, x, logx, cdir):
254
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
255
+ arg0 = arg.subs(x, 0)
256
+
257
+ if arg0 is S.ComplexInfinity:
258
+ arg0 = arg.limit(x, 0, dir='-' if cdir == -1 else '+')
259
+ if x in arg.free_symbols and arg0.is_zero:
260
+ return 2*arg/sqrt(pi)
261
+ else:
262
+ return self.func(arg0)
263
+
264
+ def _eval_aseries(self, n, args0, x, logx):
265
+ from sympy.series.order import Order
266
+ point = args0[0]
267
+
268
+ if point in [S.Infinity, S.NegativeInfinity]:
269
+ z = self.args[0]
270
+
271
+ try:
272
+ _, ex = z.leadterm(x)
273
+ except (ValueError, NotImplementedError):
274
+ return self
275
+
276
+ ex = -ex # as x->1/x for aseries
277
+ if ex.is_positive:
278
+ newn = ceiling(n/ex)
279
+ s = [S.NegativeOne**k * factorial2(2*k - 1) / (z**(2*k + 1) * 2**k)
280
+ for k in range(newn)] + [Order(1/z**newn, x)]
281
+ return S.One - (exp(-z**2)/sqrt(pi)) * Add(*s)
282
+
283
+ return super(erf, self)._eval_aseries(n, args0, x, logx)
284
+
285
+ as_real_imag = real_to_real_as_real_imag
286
+
287
+
288
+ class erfc(DefinedFunction):
289
+ r"""
290
+ Complementary Error Function.
291
+
292
+ Explanation
293
+ ===========
294
+
295
+ The function is defined as:
296
+
297
+ .. math ::
298
+ \mathrm{erfc}(x) = \frac{2}{\sqrt{\pi}} \int_x^\infty e^{-t^2} \mathrm{d}t
299
+
300
+ Examples
301
+ ========
302
+
303
+ >>> from sympy import I, oo, erfc
304
+ >>> from sympy.abc import z
305
+
306
+ Several special values are known:
307
+
308
+ >>> erfc(0)
309
+ 1
310
+ >>> erfc(oo)
311
+ 0
312
+ >>> erfc(-oo)
313
+ 2
314
+ >>> erfc(I*oo)
315
+ -oo*I
316
+ >>> erfc(-I*oo)
317
+ oo*I
318
+
319
+ The error function obeys the mirror symmetry:
320
+
321
+ >>> from sympy import conjugate
322
+ >>> conjugate(erfc(z))
323
+ erfc(conjugate(z))
324
+
325
+ Differentiation with respect to $z$ is supported:
326
+
327
+ >>> from sympy import diff
328
+ >>> diff(erfc(z), z)
329
+ -2*exp(-z**2)/sqrt(pi)
330
+
331
+ It also follows
332
+
333
+ >>> erfc(-z)
334
+ 2 - erfc(z)
335
+
336
+ We can numerically evaluate the complementary error function to arbitrary
337
+ precision on the whole complex plane:
338
+
339
+ >>> erfc(4).evalf(30)
340
+ 0.0000000154172579002800188521596734869
341
+
342
+ >>> erfc(4*I).evalf(30)
343
+ 1.0 - 1296959.73071763923152794095062*I
344
+
345
+ See Also
346
+ ========
347
+
348
+ erf: Gaussian error function.
349
+ erfi: Imaginary error function.
350
+ erf2: Two-argument error function.
351
+ erfinv: Inverse error function.
352
+ erfcinv: Inverse Complementary error function.
353
+ erf2inv: Inverse two-argument error function.
354
+
355
+ References
356
+ ==========
357
+
358
+ .. [1] https://en.wikipedia.org/wiki/Error_function
359
+ .. [2] https://dlmf.nist.gov/7
360
+ .. [3] https://mathworld.wolfram.com/Erfc.html
361
+ .. [4] https://functions.wolfram.com/GammaBetaErf/Erfc
362
+
363
+ """
364
+
365
+ unbranched = True
366
+
367
+ def fdiff(self, argindex=1):
368
+ if argindex == 1:
369
+ return -2*exp(-self.args[0]**2)/sqrt(pi)
370
+ else:
371
+ raise ArgumentIndexError(self, argindex)
372
+
373
+ def inverse(self, argindex=1):
374
+ """
375
+ Returns the inverse of this function.
376
+
377
+ """
378
+ return erfcinv
379
+
380
+ @classmethod
381
+ def eval(cls, arg):
382
+ if arg.is_Number:
383
+ if arg is S.NaN:
384
+ return S.NaN
385
+ elif arg is S.Infinity:
386
+ return S.Zero
387
+ elif arg.is_zero:
388
+ return S.One
389
+
390
+ if isinstance(arg, erfinv):
391
+ return S.One - arg.args[0]
392
+
393
+ if isinstance(arg, erfcinv):
394
+ return arg.args[0]
395
+
396
+ if arg.is_zero:
397
+ return S.One
398
+
399
+ # Try to pull out factors of I
400
+ t = arg.extract_multiplicatively(I)
401
+ if t in (S.Infinity, S.NegativeInfinity):
402
+ return -arg
403
+
404
+ # Try to pull out factors of -1
405
+ if arg.could_extract_minus_sign():
406
+ return 2 - cls(-arg)
407
+
408
+ @staticmethod
409
+ @cacheit
410
+ def taylor_term(n, x, *previous_terms):
411
+ if n == 0:
412
+ return S.One
413
+ elif n < 0 or n % 2 == 0:
414
+ return S.Zero
415
+ else:
416
+ x = sympify(x)
417
+ k = floor((n - 1)/S(2))
418
+ if len(previous_terms) > 2:
419
+ return -previous_terms[-2] * x**2 * (n - 2)/(n*k)
420
+ else:
421
+ return -2*S.NegativeOne**k * x**n/(n*factorial(k)*sqrt(pi))
422
+
423
+ def _eval_conjugate(self):
424
+ return self.func(self.args[0].conjugate())
425
+
426
+ def _eval_is_real(self):
427
+ if self.args[0].is_extended_real is True:
428
+ return True
429
+ if self.args[0].is_imaginary is True:
430
+ return False
431
+
432
+ def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs):
433
+ return self.rewrite(erf).rewrite("tractable", deep=True, limitvar=limitvar)
434
+
435
+ def _eval_rewrite_as_erf(self, z, **kwargs):
436
+ return S.One - erf(z)
437
+
438
+ def _eval_rewrite_as_erfi(self, z, **kwargs):
439
+ return S.One + I*erfi(I*z)
440
+
441
+ def _eval_rewrite_as_fresnels(self, z, **kwargs):
442
+ arg = (S.One - I)*z/sqrt(pi)
443
+ return S.One - (S.One + I)*(fresnelc(arg) - I*fresnels(arg))
444
+
445
+ def _eval_rewrite_as_fresnelc(self, z, **kwargs):
446
+ arg = (S.One-I)*z/sqrt(pi)
447
+ return S.One - (S.One + I)*(fresnelc(arg) - I*fresnels(arg))
448
+
449
+ def _eval_rewrite_as_meijerg(self, z, **kwargs):
450
+ return S.One - z/sqrt(pi)*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2)
451
+
452
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
453
+ return S.One - 2*z/sqrt(pi)*hyper([S.Half], [3*S.Half], -z**2)
454
+
455
+ def _eval_rewrite_as_uppergamma(self, z, **kwargs):
456
+ from sympy.functions.special.gamma_functions import uppergamma
457
+ return S.One - sqrt(z**2)/z*(S.One - uppergamma(S.Half, z**2)/sqrt(pi))
458
+
459
+ def _eval_rewrite_as_expint(self, z, **kwargs):
460
+ return S.One - sqrt(z**2)/z + z*expint(S.Half, z**2)/sqrt(pi)
461
+
462
+ def _eval_expand_func(self, **hints):
463
+ return self.rewrite(erf)
464
+
465
+ def _eval_as_leading_term(self, x, logx, cdir):
466
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
467
+ arg0 = arg.subs(x, 0)
468
+
469
+ if arg0 is S.ComplexInfinity:
470
+ arg0 = arg.limit(x, 0, dir='-' if cdir == -1 else '+')
471
+ if arg0.is_zero:
472
+ return S.One
473
+ else:
474
+ return self.func(arg0)
475
+
476
+ as_real_imag = real_to_real_as_real_imag
477
+
478
+ def _eval_aseries(self, n, args0, x, logx):
479
+ return S.One - erf(*self.args)._eval_aseries(n, args0, x, logx)
480
+
481
+
482
+ class erfi(DefinedFunction):
483
+ r"""
484
+ Imaginary error function.
485
+
486
+ Explanation
487
+ ===========
488
+
489
+ The function erfi is defined as:
490
+
491
+ .. math ::
492
+ \mathrm{erfi}(x) = \frac{2}{\sqrt{\pi}} \int_0^x e^{t^2} \mathrm{d}t
493
+
494
+ Examples
495
+ ========
496
+
497
+ >>> from sympy import I, oo, erfi
498
+ >>> from sympy.abc import z
499
+
500
+ Several special values are known:
501
+
502
+ >>> erfi(0)
503
+ 0
504
+ >>> erfi(oo)
505
+ oo
506
+ >>> erfi(-oo)
507
+ -oo
508
+ >>> erfi(I*oo)
509
+ I
510
+ >>> erfi(-I*oo)
511
+ -I
512
+
513
+ In general one can pull out factors of -1 and $I$ from the argument:
514
+
515
+ >>> erfi(-z)
516
+ -erfi(z)
517
+
518
+ >>> from sympy import conjugate
519
+ >>> conjugate(erfi(z))
520
+ erfi(conjugate(z))
521
+
522
+ Differentiation with respect to $z$ is supported:
523
+
524
+ >>> from sympy import diff
525
+ >>> diff(erfi(z), z)
526
+ 2*exp(z**2)/sqrt(pi)
527
+
528
+ We can numerically evaluate the imaginary error function to arbitrary
529
+ precision on the whole complex plane:
530
+
531
+ >>> erfi(2).evalf(30)
532
+ 18.5648024145755525987042919132
533
+
534
+ >>> erfi(-2*I).evalf(30)
535
+ -0.995322265018952734162069256367*I
536
+
537
+ See Also
538
+ ========
539
+
540
+ erf: Gaussian error function.
541
+ erfc: Complementary error function.
542
+ erf2: Two-argument error function.
543
+ erfinv: Inverse error function.
544
+ erfcinv: Inverse Complementary error function.
545
+ erf2inv: Inverse two-argument error function.
546
+
547
+ References
548
+ ==========
549
+
550
+ .. [1] https://en.wikipedia.org/wiki/Error_function
551
+ .. [2] https://mathworld.wolfram.com/Erfi.html
552
+ .. [3] https://functions.wolfram.com/GammaBetaErf/Erfi
553
+
554
+ """
555
+
556
+ unbranched = True
557
+
558
+ def fdiff(self, argindex=1):
559
+ if argindex == 1:
560
+ return 2*exp(self.args[0]**2)/sqrt(pi)
561
+ else:
562
+ raise ArgumentIndexError(self, argindex)
563
+
564
+ @classmethod
565
+ def eval(cls, z):
566
+ if z.is_Number:
567
+ if z is S.NaN:
568
+ return S.NaN
569
+ elif z.is_zero:
570
+ return S.Zero
571
+ elif z is S.Infinity:
572
+ return S.Infinity
573
+
574
+ if z.is_zero:
575
+ return S.Zero
576
+
577
+ # Try to pull out factors of -1
578
+ if z.could_extract_minus_sign():
579
+ return -cls(-z)
580
+
581
+ # Try to pull out factors of I
582
+ nz = z.extract_multiplicatively(I)
583
+ if nz is not None:
584
+ if nz is S.Infinity:
585
+ return I
586
+ if isinstance(nz, erfinv):
587
+ return I*nz.args[0]
588
+ if isinstance(nz, erfcinv):
589
+ return I*(S.One - nz.args[0])
590
+ # Only happens with unevaluated erf2inv
591
+ if isinstance(nz, erf2inv) and nz.args[0].is_zero:
592
+ return I*nz.args[1]
593
+
594
+ @staticmethod
595
+ @cacheit
596
+ def taylor_term(n, x, *previous_terms):
597
+ if n < 0 or n % 2 == 0:
598
+ return S.Zero
599
+ else:
600
+ x = sympify(x)
601
+ k = floor((n - 1)/S(2))
602
+ if len(previous_terms) > 2:
603
+ return previous_terms[-2] * x**2 * (n - 2)/(n*k)
604
+ else:
605
+ return 2 * x**n/(n*factorial(k)*sqrt(pi))
606
+
607
+ def _eval_conjugate(self):
608
+ return self.func(self.args[0].conjugate())
609
+
610
+ def _eval_is_extended_real(self):
611
+ return self.args[0].is_extended_real
612
+
613
+ def _eval_is_zero(self):
614
+ return self.args[0].is_zero
615
+
616
+ def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs):
617
+ return self.rewrite(erf).rewrite("tractable", deep=True, limitvar=limitvar)
618
+
619
+ def _eval_rewrite_as_erf(self, z, **kwargs):
620
+ return -I*erf(I*z)
621
+
622
+ def _eval_rewrite_as_erfc(self, z, **kwargs):
623
+ return I*erfc(I*z) - I
624
+
625
+ def _eval_rewrite_as_fresnels(self, z, **kwargs):
626
+ arg = (S.One + I)*z/sqrt(pi)
627
+ return (S.One - I)*(fresnelc(arg) - I*fresnels(arg))
628
+
629
+ def _eval_rewrite_as_fresnelc(self, z, **kwargs):
630
+ arg = (S.One + I)*z/sqrt(pi)
631
+ return (S.One - I)*(fresnelc(arg) - I*fresnels(arg))
632
+
633
+ def _eval_rewrite_as_meijerg(self, z, **kwargs):
634
+ return z/sqrt(pi)*meijerg([S.Half], [], [0], [Rational(-1, 2)], -z**2)
635
+
636
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
637
+ return 2*z/sqrt(pi)*hyper([S.Half], [3*S.Half], z**2)
638
+
639
+ def _eval_rewrite_as_uppergamma(self, z, **kwargs):
640
+ from sympy.functions.special.gamma_functions import uppergamma
641
+ return sqrt(-z**2)/z*(uppergamma(S.Half, -z**2)/sqrt(pi) - S.One)
642
+
643
+ def _eval_rewrite_as_expint(self, z, **kwargs):
644
+ return sqrt(-z**2)/z - z*expint(S.Half, -z**2)/sqrt(pi)
645
+
646
+ def _eval_expand_func(self, **hints):
647
+ return self.rewrite(erf)
648
+
649
+ as_real_imag = real_to_real_as_real_imag
650
+
651
+ def _eval_as_leading_term(self, x, logx, cdir):
652
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
653
+ arg0 = arg.subs(x, 0)
654
+
655
+ if x in arg.free_symbols and arg0.is_zero:
656
+ return 2*arg/sqrt(pi)
657
+ elif arg0.is_finite:
658
+ return self.func(arg0)
659
+ return self.func(arg)
660
+
661
+ def _eval_aseries(self, n, args0, x, logx):
662
+ from sympy.series.order import Order
663
+ point = args0[0]
664
+
665
+ if point is S.Infinity:
666
+ z = self.args[0]
667
+ s = [factorial2(2*k - 1) / (2**k * z**(2*k + 1))
668
+ for k in range(n)] + [Order(1/z**n, x)]
669
+ return -I + (exp(z**2)/sqrt(pi)) * Add(*s)
670
+
671
+ return super(erfi, self)._eval_aseries(n, args0, x, logx)
672
+
673
+
674
+ class erf2(DefinedFunction):
675
+ r"""
676
+ Two-argument error function.
677
+
678
+ Explanation
679
+ ===========
680
+
681
+ This function is defined as:
682
+
683
+ .. math ::
684
+ \mathrm{erf2}(x, y) = \frac{2}{\sqrt{\pi}} \int_x^y e^{-t^2} \mathrm{d}t
685
+
686
+ Examples
687
+ ========
688
+
689
+ >>> from sympy import oo, erf2
690
+ >>> from sympy.abc import x, y
691
+
692
+ Several special values are known:
693
+
694
+ >>> erf2(0, 0)
695
+ 0
696
+ >>> erf2(x, x)
697
+ 0
698
+ >>> erf2(x, oo)
699
+ 1 - erf(x)
700
+ >>> erf2(x, -oo)
701
+ -erf(x) - 1
702
+ >>> erf2(oo, y)
703
+ erf(y) - 1
704
+ >>> erf2(-oo, y)
705
+ erf(y) + 1
706
+
707
+ In general one can pull out factors of -1:
708
+
709
+ >>> erf2(-x, -y)
710
+ -erf2(x, y)
711
+
712
+ The error function obeys the mirror symmetry:
713
+
714
+ >>> from sympy import conjugate
715
+ >>> conjugate(erf2(x, y))
716
+ erf2(conjugate(x), conjugate(y))
717
+
718
+ Differentiation with respect to $x$, $y$ is supported:
719
+
720
+ >>> from sympy import diff
721
+ >>> diff(erf2(x, y), x)
722
+ -2*exp(-x**2)/sqrt(pi)
723
+ >>> diff(erf2(x, y), y)
724
+ 2*exp(-y**2)/sqrt(pi)
725
+
726
+ See Also
727
+ ========
728
+
729
+ erf: Gaussian error function.
730
+ erfc: Complementary error function.
731
+ erfi: Imaginary error function.
732
+ erfinv: Inverse error function.
733
+ erfcinv: Inverse Complementary error function.
734
+ erf2inv: Inverse two-argument error function.
735
+
736
+ References
737
+ ==========
738
+
739
+ .. [1] https://functions.wolfram.com/GammaBetaErf/Erf2/
740
+
741
+ """
742
+
743
+
744
+ def fdiff(self, argindex):
745
+ x, y = self.args
746
+ if argindex == 1:
747
+ return -2*exp(-x**2)/sqrt(pi)
748
+ elif argindex == 2:
749
+ return 2*exp(-y**2)/sqrt(pi)
750
+ else:
751
+ raise ArgumentIndexError(self, argindex)
752
+
753
+ @classmethod
754
+ def eval(cls, x, y):
755
+ chk = (S.Infinity, S.NegativeInfinity, S.Zero)
756
+ if x is S.NaN or y is S.NaN:
757
+ return S.NaN
758
+ elif x == y:
759
+ return S.Zero
760
+ elif x in chk or y in chk:
761
+ return erf(y) - erf(x)
762
+
763
+ if isinstance(y, erf2inv) and y.args[0] == x:
764
+ return y.args[1]
765
+
766
+ if x.is_zero or y.is_zero or x.is_extended_real and x.is_infinite or \
767
+ y.is_extended_real and y.is_infinite:
768
+ return erf(y) - erf(x)
769
+
770
+ #Try to pull out -1 factor
771
+ sign_x = x.could_extract_minus_sign()
772
+ sign_y = y.could_extract_minus_sign()
773
+ if (sign_x and sign_y):
774
+ return -cls(-x, -y)
775
+ elif (sign_x or sign_y):
776
+ return erf(y)-erf(x)
777
+
778
+ def _eval_conjugate(self):
779
+ return self.func(self.args[0].conjugate(), self.args[1].conjugate())
780
+
781
+ def _eval_is_extended_real(self):
782
+ return self.args[0].is_extended_real and self.args[1].is_extended_real
783
+
784
+ def _eval_rewrite_as_erf(self, x, y, **kwargs):
785
+ return erf(y) - erf(x)
786
+
787
+ def _eval_rewrite_as_erfc(self, x, y, **kwargs):
788
+ return erfc(x) - erfc(y)
789
+
790
+ def _eval_rewrite_as_erfi(self, x, y, **kwargs):
791
+ return I*(erfi(I*x)-erfi(I*y))
792
+
793
+ def _eval_rewrite_as_fresnels(self, x, y, **kwargs):
794
+ return erf(y).rewrite(fresnels) - erf(x).rewrite(fresnels)
795
+
796
+ def _eval_rewrite_as_fresnelc(self, x, y, **kwargs):
797
+ return erf(y).rewrite(fresnelc) - erf(x).rewrite(fresnelc)
798
+
799
+ def _eval_rewrite_as_meijerg(self, x, y, **kwargs):
800
+ return erf(y).rewrite(meijerg) - erf(x).rewrite(meijerg)
801
+
802
+ def _eval_rewrite_as_hyper(self, x, y, **kwargs):
803
+ return erf(y).rewrite(hyper) - erf(x).rewrite(hyper)
804
+
805
+ def _eval_rewrite_as_uppergamma(self, x, y, **kwargs):
806
+ from sympy.functions.special.gamma_functions import uppergamma
807
+ return (sqrt(y**2)/y*(S.One - uppergamma(S.Half, y**2)/sqrt(pi)) -
808
+ sqrt(x**2)/x*(S.One - uppergamma(S.Half, x**2)/sqrt(pi)))
809
+
810
+ def _eval_rewrite_as_expint(self, x, y, **kwargs):
811
+ return erf(y).rewrite(expint) - erf(x).rewrite(expint)
812
+
813
+ def _eval_expand_func(self, **hints):
814
+ return self.rewrite(erf)
815
+
816
+ def _eval_is_zero(self):
817
+ return is_eq(*self.args)
818
+
819
+ class erfinv(DefinedFunction):
820
+ r"""
821
+ Inverse Error Function. The erfinv function is defined as:
822
+
823
+ .. math ::
824
+ \mathrm{erf}(x) = y \quad \Rightarrow \quad \mathrm{erfinv}(y) = x
825
+
826
+ Examples
827
+ ========
828
+
829
+ >>> from sympy import erfinv
830
+ >>> from sympy.abc import x
831
+
832
+ Several special values are known:
833
+
834
+ >>> erfinv(0)
835
+ 0
836
+ >>> erfinv(1)
837
+ oo
838
+
839
+ Differentiation with respect to $x$ is supported:
840
+
841
+ >>> from sympy import diff
842
+ >>> diff(erfinv(x), x)
843
+ sqrt(pi)*exp(erfinv(x)**2)/2
844
+
845
+ We can numerically evaluate the inverse error function to arbitrary
846
+ precision on [-1, 1]:
847
+
848
+ >>> erfinv(0.2).evalf(30)
849
+ 0.179143454621291692285822705344
850
+
851
+ See Also
852
+ ========
853
+
854
+ erf: Gaussian error function.
855
+ erfc: Complementary error function.
856
+ erfi: Imaginary error function.
857
+ erf2: Two-argument error function.
858
+ erfcinv: Inverse Complementary error function.
859
+ erf2inv: Inverse two-argument error function.
860
+
861
+ References
862
+ ==========
863
+
864
+ .. [1] https://en.wikipedia.org/wiki/Error_function#Inverse_functions
865
+ .. [2] https://functions.wolfram.com/GammaBetaErf/InverseErf/
866
+
867
+ """
868
+
869
+
870
+ def fdiff(self, argindex =1):
871
+ if argindex == 1:
872
+ return sqrt(pi)*exp(self.func(self.args[0])**2)*S.Half
873
+ else :
874
+ raise ArgumentIndexError(self, argindex)
875
+
876
+ def inverse(self, argindex=1):
877
+ """
878
+ Returns the inverse of this function.
879
+
880
+ """
881
+ return erf
882
+
883
+ @classmethod
884
+ def eval(cls, z):
885
+ if z is S.NaN:
886
+ return S.NaN
887
+ elif z is S.NegativeOne:
888
+ return S.NegativeInfinity
889
+ elif z.is_zero:
890
+ return S.Zero
891
+ elif z is S.One:
892
+ return S.Infinity
893
+
894
+ if isinstance(z, erf) and z.args[0].is_extended_real:
895
+ return z.args[0]
896
+
897
+ if z.is_zero:
898
+ return S.Zero
899
+
900
+ # Try to pull out factors of -1
901
+ nz = z.extract_multiplicatively(-1)
902
+ if nz is not None and (isinstance(nz, erf) and (nz.args[0]).is_extended_real):
903
+ return -nz.args[0]
904
+
905
+ def _eval_rewrite_as_erfcinv(self, z, **kwargs):
906
+ return erfcinv(1-z)
907
+
908
+ def _eval_is_zero(self):
909
+ return self.args[0].is_zero
910
+
911
+
912
+ class erfcinv (DefinedFunction):
913
+ r"""
914
+ Inverse Complementary Error Function. The erfcinv function is defined as:
915
+
916
+ .. math ::
917
+ \mathrm{erfc}(x) = y \quad \Rightarrow \quad \mathrm{erfcinv}(y) = x
918
+
919
+ Examples
920
+ ========
921
+
922
+ >>> from sympy import erfcinv
923
+ >>> from sympy.abc import x
924
+
925
+ Several special values are known:
926
+
927
+ >>> erfcinv(1)
928
+ 0
929
+ >>> erfcinv(0)
930
+ oo
931
+
932
+ Differentiation with respect to $x$ is supported:
933
+
934
+ >>> from sympy import diff
935
+ >>> diff(erfcinv(x), x)
936
+ -sqrt(pi)*exp(erfcinv(x)**2)/2
937
+
938
+ See Also
939
+ ========
940
+
941
+ erf: Gaussian error function.
942
+ erfc: Complementary error function.
943
+ erfi: Imaginary error function.
944
+ erf2: Two-argument error function.
945
+ erfinv: Inverse error function.
946
+ erf2inv: Inverse two-argument error function.
947
+
948
+ References
949
+ ==========
950
+
951
+ .. [1] https://en.wikipedia.org/wiki/Error_function#Inverse_functions
952
+ .. [2] https://functions.wolfram.com/GammaBetaErf/InverseErfc/
953
+
954
+ """
955
+
956
+
957
+ def fdiff(self, argindex =1):
958
+ if argindex == 1:
959
+ return -sqrt(pi)*exp(self.func(self.args[0])**2)*S.Half
960
+ else:
961
+ raise ArgumentIndexError(self, argindex)
962
+
963
+ def inverse(self, argindex=1):
964
+ """
965
+ Returns the inverse of this function.
966
+
967
+ """
968
+ return erfc
969
+
970
+ @classmethod
971
+ def eval(cls, z):
972
+ if z is S.NaN:
973
+ return S.NaN
974
+ elif z.is_zero:
975
+ return S.Infinity
976
+ elif z is S.One:
977
+ return S.Zero
978
+ elif z == 2:
979
+ return S.NegativeInfinity
980
+
981
+ if z.is_zero:
982
+ return S.Infinity
983
+
984
+ def _eval_rewrite_as_erfinv(self, z, **kwargs):
985
+ return erfinv(1-z)
986
+
987
+ def _eval_is_zero(self):
988
+ return (self.args[0] - 1).is_zero
989
+
990
+ def _eval_is_infinite(self):
991
+ z = self.args[0]
992
+ return fuzzy_or([z.is_zero, is_eq(z, Integer(2))])
993
+
994
+
995
+ class erf2inv(DefinedFunction):
996
+ r"""
997
+ Two-argument Inverse error function. The erf2inv function is defined as:
998
+
999
+ .. math ::
1000
+ \mathrm{erf2}(x, w) = y \quad \Rightarrow \quad \mathrm{erf2inv}(x, y) = w
1001
+
1002
+ Examples
1003
+ ========
1004
+
1005
+ >>> from sympy import erf2inv, oo
1006
+ >>> from sympy.abc import x, y
1007
+
1008
+ Several special values are known:
1009
+
1010
+ >>> erf2inv(0, 0)
1011
+ 0
1012
+ >>> erf2inv(1, 0)
1013
+ 1
1014
+ >>> erf2inv(0, 1)
1015
+ oo
1016
+ >>> erf2inv(0, y)
1017
+ erfinv(y)
1018
+ >>> erf2inv(oo, y)
1019
+ erfcinv(-y)
1020
+
1021
+ Differentiation with respect to $x$ and $y$ is supported:
1022
+
1023
+ >>> from sympy import diff
1024
+ >>> diff(erf2inv(x, y), x)
1025
+ exp(-x**2 + erf2inv(x, y)**2)
1026
+ >>> diff(erf2inv(x, y), y)
1027
+ sqrt(pi)*exp(erf2inv(x, y)**2)/2
1028
+
1029
+ See Also
1030
+ ========
1031
+
1032
+ erf: Gaussian error function.
1033
+ erfc: Complementary error function.
1034
+ erfi: Imaginary error function.
1035
+ erf2: Two-argument error function.
1036
+ erfinv: Inverse error function.
1037
+ erfcinv: Inverse complementary error function.
1038
+
1039
+ References
1040
+ ==========
1041
+
1042
+ .. [1] https://functions.wolfram.com/GammaBetaErf/InverseErf2/
1043
+
1044
+ """
1045
+
1046
+
1047
+ def fdiff(self, argindex):
1048
+ x, y = self.args
1049
+ if argindex == 1:
1050
+ return exp(self.func(x,y)**2-x**2)
1051
+ elif argindex == 2:
1052
+ return sqrt(pi)*S.Half*exp(self.func(x,y)**2)
1053
+ else:
1054
+ raise ArgumentIndexError(self, argindex)
1055
+
1056
+ @classmethod
1057
+ def eval(cls, x, y):
1058
+ if x is S.NaN or y is S.NaN:
1059
+ return S.NaN
1060
+ elif x.is_zero and y.is_zero:
1061
+ return S.Zero
1062
+ elif x.is_zero and y is S.One:
1063
+ return S.Infinity
1064
+ elif x is S.One and y.is_zero:
1065
+ return S.One
1066
+ elif x.is_zero:
1067
+ return erfinv(y)
1068
+ elif x is S.Infinity:
1069
+ return erfcinv(-y)
1070
+ elif y.is_zero:
1071
+ return x
1072
+ elif y is S.Infinity:
1073
+ return erfinv(x)
1074
+
1075
+ if x.is_zero:
1076
+ if y.is_zero:
1077
+ return S.Zero
1078
+ else:
1079
+ return erfinv(y)
1080
+ if y.is_zero:
1081
+ return x
1082
+
1083
+ def _eval_is_zero(self):
1084
+ x, y = self.args
1085
+ if x.is_zero and y.is_zero:
1086
+ return True
1087
+
1088
+ ###############################################################################
1089
+ #################### EXPONENTIAL INTEGRALS ####################################
1090
+ ###############################################################################
1091
+
1092
+ class Ei(DefinedFunction):
1093
+ r"""
1094
+ The classical exponential integral.
1095
+
1096
+ Explanation
1097
+ ===========
1098
+
1099
+ For use in SymPy, this function is defined as
1100
+
1101
+ .. math:: \operatorname{Ei}(x) = \sum_{n=1}^\infty \frac{x^n}{n\, n!}
1102
+ + \log(x) + \gamma,
1103
+
1104
+ where $\gamma$ is the Euler-Mascheroni constant.
1105
+
1106
+ If $x$ is a polar number, this defines an analytic function on the
1107
+ Riemann surface of the logarithm. Otherwise this defines an analytic
1108
+ function in the cut plane $\mathbb{C} \setminus (-\infty, 0]$.
1109
+
1110
+ **Background**
1111
+
1112
+ The name exponential integral comes from the following statement:
1113
+
1114
+ .. math:: \operatorname{Ei}(x) = \int_{-\infty}^x \frac{e^t}{t} \mathrm{d}t
1115
+
1116
+ If the integral is interpreted as a Cauchy principal value, this statement
1117
+ holds for $x > 0$ and $\operatorname{Ei}(x)$ as defined above.
1118
+
1119
+ Examples
1120
+ ========
1121
+
1122
+ >>> from sympy import Ei, polar_lift, exp_polar, I, pi
1123
+ >>> from sympy.abc import x
1124
+
1125
+ >>> Ei(-1)
1126
+ Ei(-1)
1127
+
1128
+ This yields a real value:
1129
+
1130
+ >>> Ei(-1).n(chop=True)
1131
+ -0.219383934395520
1132
+
1133
+ On the other hand the analytic continuation is not real:
1134
+
1135
+ >>> Ei(polar_lift(-1)).n(chop=True)
1136
+ -0.21938393439552 + 3.14159265358979*I
1137
+
1138
+ The exponential integral has a logarithmic branch point at the origin:
1139
+
1140
+ >>> Ei(x*exp_polar(2*I*pi))
1141
+ Ei(x) + 2*I*pi
1142
+
1143
+ Differentiation is supported:
1144
+
1145
+ >>> Ei(x).diff(x)
1146
+ exp(x)/x
1147
+
1148
+ The exponential integral is related to many other special functions.
1149
+ For example:
1150
+
1151
+ >>> from sympy import expint, Shi
1152
+ >>> Ei(x).rewrite(expint)
1153
+ -expint(1, x*exp_polar(I*pi)) - I*pi
1154
+ >>> Ei(x).rewrite(Shi)
1155
+ Chi(x) + Shi(x)
1156
+
1157
+ See Also
1158
+ ========
1159
+
1160
+ expint: Generalised exponential integral.
1161
+ E1: Special case of the generalised exponential integral.
1162
+ li: Logarithmic integral.
1163
+ Li: Offset logarithmic integral.
1164
+ Si: Sine integral.
1165
+ Ci: Cosine integral.
1166
+ Shi: Hyperbolic sine integral.
1167
+ Chi: Hyperbolic cosine integral.
1168
+ uppergamma: Upper incomplete gamma function.
1169
+
1170
+ References
1171
+ ==========
1172
+
1173
+ .. [1] https://dlmf.nist.gov/6.6
1174
+ .. [2] https://en.wikipedia.org/wiki/Exponential_integral
1175
+ .. [3] Abramowitz & Stegun, section 5: https://web.archive.org/web/20201128173312/http://people.math.sfu.ca/~cbm/aands/page_228.htm
1176
+
1177
+ """
1178
+
1179
+
1180
+ @classmethod
1181
+ def eval(cls, z):
1182
+ if z.is_zero:
1183
+ return S.NegativeInfinity
1184
+ elif z is S.Infinity:
1185
+ return S.Infinity
1186
+ elif z is S.NegativeInfinity:
1187
+ return S.Zero
1188
+
1189
+ if z.is_zero:
1190
+ return S.NegativeInfinity
1191
+
1192
+ nz, n = z.extract_branch_factor()
1193
+ if n:
1194
+ return Ei(nz) + 2*I*pi*n
1195
+
1196
+ def fdiff(self, argindex=1):
1197
+ arg = unpolarify(self.args[0])
1198
+ if argindex == 1:
1199
+ return exp(arg)/arg
1200
+ else:
1201
+ raise ArgumentIndexError(self, argindex)
1202
+
1203
+ def _eval_evalf(self, prec):
1204
+ if (self.args[0]/polar_lift(-1)).is_positive:
1205
+ return super()._eval_evalf(prec) + (I*pi)._eval_evalf(prec)
1206
+ return super()._eval_evalf(prec)
1207
+
1208
+ def _eval_rewrite_as_uppergamma(self, z, **kwargs):
1209
+ from sympy.functions.special.gamma_functions import uppergamma
1210
+ # XXX this does not currently work usefully because uppergamma
1211
+ # immediately turns into expint
1212
+ return -uppergamma(0, polar_lift(-1)*z) - I*pi
1213
+
1214
+ def _eval_rewrite_as_expint(self, z, **kwargs):
1215
+ return -expint(1, polar_lift(-1)*z) - I*pi
1216
+
1217
+ def _eval_rewrite_as_li(self, z, **kwargs):
1218
+ if isinstance(z, log):
1219
+ return li(z.args[0])
1220
+ # TODO:
1221
+ # Actually it only holds that:
1222
+ # Ei(z) = li(exp(z))
1223
+ # for -pi < imag(z) <= pi
1224
+ return li(exp(z))
1225
+
1226
+ def _eval_rewrite_as_Si(self, z, **kwargs):
1227
+ if z.is_negative:
1228
+ return Shi(z) + Chi(z) - I*pi
1229
+ else:
1230
+ return Shi(z) + Chi(z)
1231
+ _eval_rewrite_as_Ci = _eval_rewrite_as_Si
1232
+ _eval_rewrite_as_Chi = _eval_rewrite_as_Si
1233
+ _eval_rewrite_as_Shi = _eval_rewrite_as_Si
1234
+
1235
+ def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs):
1236
+ return exp(z) * _eis(z)
1237
+
1238
+ def _eval_rewrite_as_Integral(self, z, **kwargs):
1239
+ from sympy.integrals.integrals import Integral
1240
+ t = Dummy(uniquely_named_symbol('t', [z]).name)
1241
+ return Integral(S.Exp1**t/t, (t, S.NegativeInfinity, z))
1242
+
1243
+ def _eval_as_leading_term(self, x, logx, cdir):
1244
+ from sympy import re
1245
+ x0 = self.args[0].limit(x, 0)
1246
+ arg = self.args[0].as_leading_term(x, cdir=cdir)
1247
+ cdir = arg.dir(x, cdir)
1248
+ if x0.is_zero:
1249
+ c, e = arg.as_coeff_exponent(x)
1250
+ logx = log(x) if logx is None else logx
1251
+ return log(c) + e*logx + EulerGamma - (
1252
+ I*pi if re(cdir).is_negative else S.Zero)
1253
+ return super()._eval_as_leading_term(x, logx=logx, cdir=cdir)
1254
+
1255
+ def _eval_nseries(self, x, n, logx, cdir=0):
1256
+ x0 = self.args[0].limit(x, 0)
1257
+ if x0.is_zero:
1258
+ f = self._eval_rewrite_as_Si(*self.args)
1259
+ return f._eval_nseries(x, n, logx)
1260
+ return super()._eval_nseries(x, n, logx)
1261
+
1262
+ def _eval_aseries(self, n, args0, x, logx):
1263
+ from sympy.series.order import Order
1264
+ point = args0[0]
1265
+
1266
+ if point in (S.Infinity, S.NegativeInfinity):
1267
+ z = self.args[0]
1268
+ s = [factorial(k) / (z)**k for k in range(n)] + \
1269
+ [Order(1/z**n, x)]
1270
+ return (exp(z)/z) * Add(*s)
1271
+
1272
+ return super(Ei, self)._eval_aseries(n, args0, x, logx)
1273
+
1274
+
1275
+ class expint(DefinedFunction):
1276
+ r"""
1277
+ Generalized exponential integral.
1278
+
1279
+ Explanation
1280
+ ===========
1281
+
1282
+ This function is defined as
1283
+
1284
+ .. math:: \operatorname{E}_\nu(z) = z^{\nu - 1} \Gamma(1 - \nu, z),
1285
+
1286
+ where $\Gamma(1 - \nu, z)$ is the upper incomplete gamma function
1287
+ (``uppergamma``).
1288
+
1289
+ Hence for $z$ with positive real part we have
1290
+
1291
+ .. math:: \operatorname{E}_\nu(z)
1292
+ = \int_1^\infty \frac{e^{-zt}}{t^\nu} \mathrm{d}t,
1293
+
1294
+ which explains the name.
1295
+
1296
+ The representation as an incomplete gamma function provides an analytic
1297
+ continuation for $\operatorname{E}_\nu(z)$. If $\nu$ is a
1298
+ non-positive integer, the exponential integral is thus an unbranched
1299
+ function of $z$, otherwise there is a branch point at the origin.
1300
+ Refer to the incomplete gamma function documentation for details of the
1301
+ branching behavior.
1302
+
1303
+ Examples
1304
+ ========
1305
+
1306
+ >>> from sympy import expint, S
1307
+ >>> from sympy.abc import nu, z
1308
+
1309
+ Differentiation is supported. Differentiation with respect to $z$ further
1310
+ explains the name: for integral orders, the exponential integral is an
1311
+ iterated integral of the exponential function.
1312
+
1313
+ >>> expint(nu, z).diff(z)
1314
+ -expint(nu - 1, z)
1315
+
1316
+ Differentiation with respect to $\nu$ has no classical expression:
1317
+
1318
+ >>> expint(nu, z).diff(nu)
1319
+ -z**(nu - 1)*meijerg(((), (1, 1)), ((0, 0, 1 - nu), ()), z)
1320
+
1321
+ At non-postive integer orders, the exponential integral reduces to the
1322
+ exponential function:
1323
+
1324
+ >>> expint(0, z)
1325
+ exp(-z)/z
1326
+ >>> expint(-1, z)
1327
+ exp(-z)/z + exp(-z)/z**2
1328
+
1329
+ At half-integers it reduces to error functions:
1330
+
1331
+ >>> expint(S(1)/2, z)
1332
+ sqrt(pi)*erfc(sqrt(z))/sqrt(z)
1333
+
1334
+ At positive integer orders it can be rewritten in terms of exponentials
1335
+ and ``expint(1, z)``. Use ``expand_func()`` to do this:
1336
+
1337
+ >>> from sympy import expand_func
1338
+ >>> expand_func(expint(5, z))
1339
+ z**4*expint(1, z)/24 + (-z**3 + z**2 - 2*z + 6)*exp(-z)/24
1340
+
1341
+ The generalised exponential integral is essentially equivalent to the
1342
+ incomplete gamma function:
1343
+
1344
+ >>> from sympy import uppergamma
1345
+ >>> expint(nu, z).rewrite(uppergamma)
1346
+ z**(nu - 1)*uppergamma(1 - nu, z)
1347
+
1348
+ As such it is branched at the origin:
1349
+
1350
+ >>> from sympy import exp_polar, pi, I
1351
+ >>> expint(4, z*exp_polar(2*pi*I))
1352
+ I*pi*z**3/3 + expint(4, z)
1353
+ >>> expint(nu, z*exp_polar(2*pi*I))
1354
+ z**(nu - 1)*(exp(2*I*pi*nu) - 1)*gamma(1 - nu) + expint(nu, z)
1355
+
1356
+ See Also
1357
+ ========
1358
+
1359
+ Ei: Another related function called exponential integral.
1360
+ E1: The classical case, returns expint(1, z).
1361
+ li: Logarithmic integral.
1362
+ Li: Offset logarithmic integral.
1363
+ Si: Sine integral.
1364
+ Ci: Cosine integral.
1365
+ Shi: Hyperbolic sine integral.
1366
+ Chi: Hyperbolic cosine integral.
1367
+ uppergamma
1368
+
1369
+ References
1370
+ ==========
1371
+
1372
+ .. [1] https://dlmf.nist.gov/8.19
1373
+ .. [2] https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/
1374
+ .. [3] https://en.wikipedia.org/wiki/Exponential_integral
1375
+
1376
+ """
1377
+
1378
+
1379
+ @classmethod
1380
+ def eval(cls, nu, z):
1381
+ from sympy.functions.special.gamma_functions import (gamma, uppergamma)
1382
+ nu2 = unpolarify(nu)
1383
+ if nu != nu2:
1384
+ return expint(nu2, z)
1385
+ if nu.is_Integer and nu <= 0 or (not nu.is_Integer and (2*nu).is_Integer):
1386
+ return unpolarify(expand_mul(z**(nu - 1)*uppergamma(1 - nu, z)))
1387
+
1388
+ # Extract branching information. This can be deduced from what is
1389
+ # explained in lowergamma.eval().
1390
+ z, n = z.extract_branch_factor()
1391
+ if n is S.Zero:
1392
+ return
1393
+ if nu.is_integer:
1394
+ if not nu > 0:
1395
+ return
1396
+ return expint(nu, z) \
1397
+ - 2*pi*I*n*S.NegativeOne**(nu - 1)/factorial(nu - 1)*unpolarify(z)**(nu - 1)
1398
+ else:
1399
+ return (exp(2*I*pi*nu*n) - 1)*z**(nu - 1)*gamma(1 - nu) + expint(nu, z)
1400
+
1401
+ def fdiff(self, argindex):
1402
+ nu, z = self.args
1403
+ if argindex == 1:
1404
+ return -z**(nu - 1)*meijerg([], [1, 1], [0, 0, 1 - nu], [], z)
1405
+ elif argindex == 2:
1406
+ return -expint(nu - 1, z)
1407
+ else:
1408
+ raise ArgumentIndexError(self, argindex)
1409
+
1410
+ def _eval_rewrite_as_uppergamma(self, nu, z, **kwargs):
1411
+ from sympy.functions.special.gamma_functions import uppergamma
1412
+ return z**(nu - 1)*uppergamma(1 - nu, z)
1413
+
1414
+ def _eval_rewrite_as_Ei(self, nu, z, **kwargs):
1415
+ if nu == 1:
1416
+ return -Ei(z*exp_polar(-I*pi)) - I*pi
1417
+ elif nu.is_Integer and nu > 1:
1418
+ # DLMF, 8.19.7
1419
+ x = -unpolarify(z)
1420
+ return x**(nu - 1)/factorial(nu - 1)*E1(z).rewrite(Ei) + \
1421
+ exp(x)/factorial(nu - 1) * \
1422
+ Add(*[factorial(nu - k - 2)*x**k for k in range(nu - 1)])
1423
+ else:
1424
+ return self
1425
+
1426
+ def _eval_expand_func(self, **hints):
1427
+ return self.rewrite(Ei).rewrite(expint, **hints)
1428
+
1429
+ def _eval_rewrite_as_Si(self, nu, z, **kwargs):
1430
+ if nu != 1:
1431
+ return self
1432
+ return Shi(z) - Chi(z)
1433
+ _eval_rewrite_as_Ci = _eval_rewrite_as_Si
1434
+ _eval_rewrite_as_Chi = _eval_rewrite_as_Si
1435
+ _eval_rewrite_as_Shi = _eval_rewrite_as_Si
1436
+
1437
+ def _eval_nseries(self, x, n, logx, cdir=0):
1438
+ if not self.args[0].has(x):
1439
+ nu = self.args[0]
1440
+ if nu == 1:
1441
+ f = self._eval_rewrite_as_Si(*self.args)
1442
+ return f._eval_nseries(x, n, logx)
1443
+ elif nu.is_Integer and nu > 1:
1444
+ f = self._eval_rewrite_as_Ei(*self.args)
1445
+ return f._eval_nseries(x, n, logx)
1446
+ return super()._eval_nseries(x, n, logx)
1447
+
1448
+ def _eval_aseries(self, n, args0, x, logx):
1449
+ from sympy.series.order import Order
1450
+ point = args0[1]
1451
+ nu = self.args[0]
1452
+
1453
+ if point is S.Infinity:
1454
+ z = self.args[1]
1455
+ s = [S.NegativeOne**k * RisingFactorial(nu, k) / z**k for k in range(n)] + [Order(1/z**n, x)]
1456
+ return (exp(-z)/z) * Add(*s)
1457
+
1458
+ return super(expint, self)._eval_aseries(n, args0, x, logx)
1459
+
1460
+ def _eval_rewrite_as_Integral(self, *args, **kwargs):
1461
+ from sympy.integrals.integrals import Integral
1462
+ n, x = self.args
1463
+ t = Dummy(uniquely_named_symbol('t', args).name)
1464
+ return Integral(t**-n * exp(-t*x), (t, 1, S.Infinity))
1465
+
1466
+
1467
+ def E1(z):
1468
+ """
1469
+ Classical case of the generalized exponential integral.
1470
+
1471
+ Explanation
1472
+ ===========
1473
+
1474
+ This is equivalent to ``expint(1, z)``.
1475
+
1476
+ Examples
1477
+ ========
1478
+
1479
+ >>> from sympy import E1
1480
+ >>> E1(0)
1481
+ expint(1, 0)
1482
+
1483
+ >>> E1(5)
1484
+ expint(1, 5)
1485
+
1486
+ See Also
1487
+ ========
1488
+
1489
+ Ei: Exponential integral.
1490
+ expint: Generalised exponential integral.
1491
+ li: Logarithmic integral.
1492
+ Li: Offset logarithmic integral.
1493
+ Si: Sine integral.
1494
+ Ci: Cosine integral.
1495
+ Shi: Hyperbolic sine integral.
1496
+ Chi: Hyperbolic cosine integral.
1497
+
1498
+ """
1499
+ return expint(1, z)
1500
+
1501
+
1502
+ class li(DefinedFunction):
1503
+ r"""
1504
+ The classical logarithmic integral.
1505
+
1506
+ Explanation
1507
+ ===========
1508
+
1509
+ For use in SymPy, this function is defined as
1510
+
1511
+ .. math:: \operatorname{li}(x) = \int_0^x \frac{1}{\log(t)} \mathrm{d}t \,.
1512
+
1513
+ Examples
1514
+ ========
1515
+
1516
+ >>> from sympy import I, oo, li
1517
+ >>> from sympy.abc import z
1518
+
1519
+ Several special values are known:
1520
+
1521
+ >>> li(0)
1522
+ 0
1523
+ >>> li(1)
1524
+ -oo
1525
+ >>> li(oo)
1526
+ oo
1527
+
1528
+ Differentiation with respect to $z$ is supported:
1529
+
1530
+ >>> from sympy import diff
1531
+ >>> diff(li(z), z)
1532
+ 1/log(z)
1533
+
1534
+ Defining the ``li`` function via an integral:
1535
+ >>> from sympy import integrate
1536
+ >>> integrate(li(z))
1537
+ z*li(z) - Ei(2*log(z))
1538
+
1539
+ >>> integrate(li(z),z)
1540
+ z*li(z) - Ei(2*log(z))
1541
+
1542
+
1543
+ The logarithmic integral can also be defined in terms of ``Ei``:
1544
+
1545
+ >>> from sympy import Ei
1546
+ >>> li(z).rewrite(Ei)
1547
+ Ei(log(z))
1548
+ >>> diff(li(z).rewrite(Ei), z)
1549
+ 1/log(z)
1550
+
1551
+ We can numerically evaluate the logarithmic integral to arbitrary precision
1552
+ on the whole complex plane (except the singular points):
1553
+
1554
+ >>> li(2).evalf(30)
1555
+ 1.04516378011749278484458888919
1556
+
1557
+ >>> li(2*I).evalf(30)
1558
+ 1.0652795784357498247001125598 + 3.08346052231061726610939702133*I
1559
+
1560
+ We can even compute Soldner's constant by the help of mpmath:
1561
+
1562
+ >>> from mpmath import findroot
1563
+ >>> findroot(li, 2)
1564
+ 1.45136923488338
1565
+
1566
+ Further transformations include rewriting ``li`` in terms of
1567
+ the trigonometric integrals ``Si``, ``Ci``, ``Shi`` and ``Chi``:
1568
+
1569
+ >>> from sympy import Si, Ci, Shi, Chi
1570
+ >>> li(z).rewrite(Si)
1571
+ -log(I*log(z)) - log(1/log(z))/2 + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z))
1572
+ >>> li(z).rewrite(Ci)
1573
+ -log(I*log(z)) - log(1/log(z))/2 + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z))
1574
+ >>> li(z).rewrite(Shi)
1575
+ -log(1/log(z))/2 + log(log(z))/2 + Chi(log(z)) - Shi(log(z))
1576
+ >>> li(z).rewrite(Chi)
1577
+ -log(1/log(z))/2 + log(log(z))/2 + Chi(log(z)) - Shi(log(z))
1578
+
1579
+ See Also
1580
+ ========
1581
+
1582
+ Li: Offset logarithmic integral.
1583
+ Ei: Exponential integral.
1584
+ expint: Generalised exponential integral.
1585
+ E1: Special case of the generalised exponential integral.
1586
+ Si: Sine integral.
1587
+ Ci: Cosine integral.
1588
+ Shi: Hyperbolic sine integral.
1589
+ Chi: Hyperbolic cosine integral.
1590
+
1591
+ References
1592
+ ==========
1593
+
1594
+ .. [1] https://en.wikipedia.org/wiki/Logarithmic_integral
1595
+ .. [2] https://mathworld.wolfram.com/LogarithmicIntegral.html
1596
+ .. [3] https://dlmf.nist.gov/6
1597
+ .. [4] https://mathworld.wolfram.com/SoldnersConstant.html
1598
+
1599
+ """
1600
+
1601
+
1602
+ @classmethod
1603
+ def eval(cls, z):
1604
+ if z.is_zero:
1605
+ return S.Zero
1606
+ elif z is S.One:
1607
+ return S.NegativeInfinity
1608
+ elif z is S.Infinity:
1609
+ return S.Infinity
1610
+ if z.is_zero:
1611
+ return S.Zero
1612
+
1613
+ def fdiff(self, argindex=1):
1614
+ arg = self.args[0]
1615
+ if argindex == 1:
1616
+ return S.One / log(arg)
1617
+ else:
1618
+ raise ArgumentIndexError(self, argindex)
1619
+
1620
+ def _eval_conjugate(self):
1621
+ z = self.args[0]
1622
+ # Exclude values on the branch cut (-oo, 0)
1623
+ if not z.is_extended_negative:
1624
+ return self.func(z.conjugate())
1625
+
1626
+ def _eval_rewrite_as_Li(self, z, **kwargs):
1627
+ return Li(z) + li(2)
1628
+
1629
+ def _eval_rewrite_as_Ei(self, z, **kwargs):
1630
+ return Ei(log(z))
1631
+
1632
+ def _eval_rewrite_as_uppergamma(self, z, **kwargs):
1633
+ from sympy.functions.special.gamma_functions import uppergamma
1634
+ return (-uppergamma(0, -log(z)) +
1635
+ S.Half*(log(log(z)) - log(S.One/log(z))) - log(-log(z)))
1636
+
1637
+ def _eval_rewrite_as_Si(self, z, **kwargs):
1638
+ return (Ci(I*log(z)) - I*Si(I*log(z)) -
1639
+ S.Half*(log(S.One/log(z)) - log(log(z))) - log(I*log(z)))
1640
+
1641
+ _eval_rewrite_as_Ci = _eval_rewrite_as_Si
1642
+
1643
+ def _eval_rewrite_as_Shi(self, z, **kwargs):
1644
+ return (Chi(log(z)) - Shi(log(z)) - S.Half*(log(S.One/log(z)) - log(log(z))))
1645
+
1646
+ _eval_rewrite_as_Chi = _eval_rewrite_as_Shi
1647
+
1648
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
1649
+ return (log(z)*hyper((1, 1), (2, 2), log(z)) +
1650
+ S.Half*(log(log(z)) - log(S.One/log(z))) + EulerGamma)
1651
+
1652
+ def _eval_rewrite_as_meijerg(self, z, **kwargs):
1653
+ return (-log(-log(z)) - S.Half*(log(S.One/log(z)) - log(log(z)))
1654
+ - meijerg(((), (1,)), ((0, 0), ()), -log(z)))
1655
+
1656
+ def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs):
1657
+ return z * _eis(log(z))
1658
+
1659
+ def _eval_nseries(self, x, n, logx, cdir=0):
1660
+ z = self.args[0]
1661
+ s = [(log(z))**k / (factorial(k) * k) for k in range(1, n)]
1662
+ return EulerGamma + log(log(z)) + Add(*s)
1663
+
1664
+ def _eval_is_zero(self):
1665
+ z = self.args[0]
1666
+ if z.is_zero:
1667
+ return True
1668
+
1669
+ class Li(DefinedFunction):
1670
+ r"""
1671
+ The offset logarithmic integral.
1672
+
1673
+ Explanation
1674
+ ===========
1675
+
1676
+ For use in SymPy, this function is defined as
1677
+
1678
+ .. math:: \operatorname{Li}(x) = \operatorname{li}(x) - \operatorname{li}(2)
1679
+
1680
+ Examples
1681
+ ========
1682
+
1683
+ >>> from sympy import Li
1684
+ >>> from sympy.abc import z
1685
+
1686
+ The following special value is known:
1687
+
1688
+ >>> Li(2)
1689
+ 0
1690
+
1691
+ Differentiation with respect to $z$ is supported:
1692
+
1693
+ >>> from sympy import diff
1694
+ >>> diff(Li(z), z)
1695
+ 1/log(z)
1696
+
1697
+ The shifted logarithmic integral can be written in terms of $li(z)$:
1698
+
1699
+ >>> from sympy import li
1700
+ >>> Li(z).rewrite(li)
1701
+ li(z) - li(2)
1702
+
1703
+ We can numerically evaluate the logarithmic integral to arbitrary precision
1704
+ on the whole complex plane (except the singular points):
1705
+
1706
+ >>> Li(2).evalf(30)
1707
+ 0
1708
+
1709
+ >>> Li(4).evalf(30)
1710
+ 1.92242131492155809316615998938
1711
+
1712
+ See Also
1713
+ ========
1714
+
1715
+ li: Logarithmic integral.
1716
+ Ei: Exponential integral.
1717
+ expint: Generalised exponential integral.
1718
+ E1: Special case of the generalised exponential integral.
1719
+ Si: Sine integral.
1720
+ Ci: Cosine integral.
1721
+ Shi: Hyperbolic sine integral.
1722
+ Chi: Hyperbolic cosine integral.
1723
+
1724
+ References
1725
+ ==========
1726
+
1727
+ .. [1] https://en.wikipedia.org/wiki/Logarithmic_integral
1728
+ .. [2] https://mathworld.wolfram.com/LogarithmicIntegral.html
1729
+ .. [3] https://dlmf.nist.gov/6
1730
+
1731
+ """
1732
+
1733
+
1734
+ @classmethod
1735
+ def eval(cls, z):
1736
+ if z is S.Infinity:
1737
+ return S.Infinity
1738
+ elif z == S(2):
1739
+ return S.Zero
1740
+
1741
+ def fdiff(self, argindex=1):
1742
+ arg = self.args[0]
1743
+ if argindex == 1:
1744
+ return S.One / log(arg)
1745
+ else:
1746
+ raise ArgumentIndexError(self, argindex)
1747
+
1748
+ def _eval_evalf(self, prec):
1749
+ return self.rewrite(li).evalf(prec)
1750
+
1751
+ def _eval_rewrite_as_li(self, z, **kwargs):
1752
+ return li(z) - li(2)
1753
+
1754
+ def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs):
1755
+ return self.rewrite(li).rewrite("tractable", deep=True)
1756
+
1757
+ def _eval_nseries(self, x, n, logx, cdir=0):
1758
+ f = self._eval_rewrite_as_li(*self.args)
1759
+ return f._eval_nseries(x, n, logx)
1760
+
1761
+ ###############################################################################
1762
+ #################### TRIGONOMETRIC INTEGRALS ##################################
1763
+ ###############################################################################
1764
+
1765
+ class TrigonometricIntegral(DefinedFunction):
1766
+ """ Base class for trigonometric integrals. """
1767
+
1768
+
1769
+ @classmethod
1770
+ def eval(cls, z):
1771
+ if z is S.Zero:
1772
+ return cls._atzero
1773
+ elif z is S.Infinity:
1774
+ return cls._atinf()
1775
+ elif z is S.NegativeInfinity:
1776
+ return cls._atneginf()
1777
+
1778
+ if z.is_zero:
1779
+ return cls._atzero
1780
+
1781
+ nz = z.extract_multiplicatively(polar_lift(I))
1782
+ if nz is None and cls._trigfunc(0) == 0:
1783
+ nz = z.extract_multiplicatively(I)
1784
+ if nz is not None:
1785
+ return cls._Ifactor(nz, 1)
1786
+ nz = z.extract_multiplicatively(polar_lift(-I))
1787
+ if nz is not None:
1788
+ return cls._Ifactor(nz, -1)
1789
+
1790
+ nz = z.extract_multiplicatively(polar_lift(-1))
1791
+ if nz is None and cls._trigfunc(0) == 0:
1792
+ nz = z.extract_multiplicatively(-1)
1793
+ if nz is not None:
1794
+ return cls._minusfactor(nz)
1795
+
1796
+ nz, n = z.extract_branch_factor()
1797
+ if n == 0 and nz == z:
1798
+ return
1799
+ return 2*pi*I*n*cls._trigfunc(0) + cls(nz)
1800
+
1801
+ def fdiff(self, argindex=1):
1802
+ arg = unpolarify(self.args[0])
1803
+ if argindex == 1:
1804
+ return self._trigfunc(arg)/arg
1805
+ else:
1806
+ raise ArgumentIndexError(self, argindex)
1807
+
1808
+ def _eval_rewrite_as_Ei(self, z, **kwargs):
1809
+ return self._eval_rewrite_as_expint(z).rewrite(Ei)
1810
+
1811
+ def _eval_rewrite_as_uppergamma(self, z, **kwargs):
1812
+ from sympy.functions.special.gamma_functions import uppergamma
1813
+ return self._eval_rewrite_as_expint(z).rewrite(uppergamma)
1814
+
1815
+ def _eval_nseries(self, x, n, logx, cdir=0):
1816
+ # NOTE this is fairly inefficient
1817
+ if self.args[0].subs(x, 0) != 0:
1818
+ return super()._eval_nseries(x, n, logx)
1819
+ baseseries = self._trigfunc(x)._eval_nseries(x, n, logx)
1820
+ if self._trigfunc(0) != 0:
1821
+ baseseries -= 1
1822
+ baseseries = baseseries.replace(Pow, lambda t, n: t**n/n, simultaneous=False)
1823
+ if self._trigfunc(0) != 0:
1824
+ baseseries += EulerGamma + log(x)
1825
+ return baseseries.subs(x, self.args[0])._eval_nseries(x, n, logx)
1826
+
1827
+
1828
+ class Si(TrigonometricIntegral):
1829
+ r"""
1830
+ Sine integral.
1831
+
1832
+ Explanation
1833
+ ===========
1834
+
1835
+ This function is defined by
1836
+
1837
+ .. math:: \operatorname{Si}(z) = \int_0^z \frac{\sin{t}}{t} \mathrm{d}t.
1838
+
1839
+ It is an entire function.
1840
+
1841
+ Examples
1842
+ ========
1843
+
1844
+ >>> from sympy import Si
1845
+ >>> from sympy.abc import z
1846
+
1847
+ The sine integral is an antiderivative of $sin(z)/z$:
1848
+
1849
+ >>> Si(z).diff(z)
1850
+ sin(z)/z
1851
+
1852
+ It is unbranched:
1853
+
1854
+ >>> from sympy import exp_polar, I, pi
1855
+ >>> Si(z*exp_polar(2*I*pi))
1856
+ Si(z)
1857
+
1858
+ Sine integral behaves much like ordinary sine under multiplication by ``I``:
1859
+
1860
+ >>> Si(I*z)
1861
+ I*Shi(z)
1862
+ >>> Si(-z)
1863
+ -Si(z)
1864
+
1865
+ It can also be expressed in terms of exponential integrals, but beware
1866
+ that the latter is branched:
1867
+
1868
+ >>> from sympy import expint
1869
+ >>> Si(z).rewrite(expint)
1870
+ -I*(-expint(1, z*exp_polar(-I*pi/2))/2 +
1871
+ expint(1, z*exp_polar(I*pi/2))/2) + pi/2
1872
+
1873
+ It can be rewritten in the form of sinc function (by definition):
1874
+
1875
+ >>> from sympy import sinc
1876
+ >>> Si(z).rewrite(sinc)
1877
+ Integral(sinc(_t), (_t, 0, z))
1878
+
1879
+ See Also
1880
+ ========
1881
+
1882
+ Ci: Cosine integral.
1883
+ Shi: Hyperbolic sine integral.
1884
+ Chi: Hyperbolic cosine integral.
1885
+ Ei: Exponential integral.
1886
+ expint: Generalised exponential integral.
1887
+ sinc: unnormalized sinc function
1888
+ E1: Special case of the generalised exponential integral.
1889
+ li: Logarithmic integral.
1890
+ Li: Offset logarithmic integral.
1891
+
1892
+ References
1893
+ ==========
1894
+
1895
+ .. [1] https://en.wikipedia.org/wiki/Trigonometric_integral
1896
+
1897
+ """
1898
+
1899
+ _trigfunc = sin
1900
+ _atzero = S.Zero
1901
+
1902
+ @classmethod
1903
+ def _atinf(cls):
1904
+ return pi*S.Half
1905
+
1906
+ @classmethod
1907
+ def _atneginf(cls):
1908
+ return -pi*S.Half
1909
+
1910
+ @classmethod
1911
+ def _minusfactor(cls, z):
1912
+ return -Si(z)
1913
+
1914
+ @classmethod
1915
+ def _Ifactor(cls, z, sign):
1916
+ return I*Shi(z)*sign
1917
+
1918
+ def _eval_rewrite_as_expint(self, z, **kwargs):
1919
+ # XXX should we polarify z?
1920
+ return pi/2 + (E1(polar_lift(I)*z) - E1(polar_lift(-I)*z))/2/I
1921
+
1922
+ def _eval_rewrite_as_Integral(self, z, **kwargs):
1923
+ from sympy.integrals.integrals import Integral
1924
+ t = Dummy(uniquely_named_symbol('t', [z]).name)
1925
+ return Integral(sinc(t), (t, 0, z))
1926
+
1927
+ _eval_rewrite_as_sinc = _eval_rewrite_as_Integral
1928
+
1929
+ def _eval_as_leading_term(self, x, logx, cdir):
1930
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
1931
+ arg0 = arg.subs(x, 0)
1932
+
1933
+ if arg0 is S.NaN:
1934
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
1935
+ if arg0.is_zero:
1936
+ return arg
1937
+ elif not arg0.is_infinite:
1938
+ return self.func(arg0)
1939
+ else:
1940
+ return self
1941
+
1942
+ def _eval_aseries(self, n, args0, x, logx):
1943
+ from sympy.series.order import Order
1944
+ point = args0[0]
1945
+
1946
+ # Expansion at oo
1947
+ if point is S.Infinity:
1948
+ z = self.args[0]
1949
+ p = [S.NegativeOne**k * factorial(2*k) / z**(2*k + 1)
1950
+ for k in range(n//2 + 1)] + [Order(1/z**n, x)]
1951
+ q = [S.NegativeOne**k * factorial(2*k + 1) / z**(2*(k + 1))
1952
+ for k in range(n//2)] + [Order(1/z**n, x)]
1953
+ return pi/2 - cos(z)*Add(*p) - sin(z)*Add(*q)
1954
+
1955
+ # All other points are not handled
1956
+ return super(Si, self)._eval_aseries(n, args0, x, logx)
1957
+
1958
+ def _eval_is_zero(self):
1959
+ z = self.args[0]
1960
+ if z.is_zero:
1961
+ return True
1962
+
1963
+
1964
+ class Ci(TrigonometricIntegral):
1965
+ r"""
1966
+ Cosine integral.
1967
+
1968
+ Explanation
1969
+ ===========
1970
+
1971
+ This function is defined for positive $x$ by
1972
+
1973
+ .. math:: \operatorname{Ci}(x) = \gamma + \log{x}
1974
+ + \int_0^x \frac{\cos{t} - 1}{t} \mathrm{d}t
1975
+ = -\int_x^\infty \frac{\cos{t}}{t} \mathrm{d}t,
1976
+
1977
+ where $\gamma$ is the Euler-Mascheroni constant.
1978
+
1979
+ We have
1980
+
1981
+ .. math:: \operatorname{Ci}(z) =
1982
+ -\frac{\operatorname{E}_1\left(e^{i\pi/2} z\right)
1983
+ + \operatorname{E}_1\left(e^{-i \pi/2} z\right)}{2}
1984
+
1985
+ which holds for all polar $z$ and thus provides an analytic
1986
+ continuation to the Riemann surface of the logarithm.
1987
+
1988
+ The formula also holds as stated
1989
+ for $z \in \mathbb{C}$ with $\Re(z) > 0$.
1990
+ By lifting to the principal branch, we obtain an analytic function on the
1991
+ cut complex plane.
1992
+
1993
+ Examples
1994
+ ========
1995
+
1996
+ >>> from sympy import Ci
1997
+ >>> from sympy.abc import z
1998
+
1999
+ The cosine integral is a primitive of $\cos(z)/z$:
2000
+
2001
+ >>> Ci(z).diff(z)
2002
+ cos(z)/z
2003
+
2004
+ It has a logarithmic branch point at the origin:
2005
+
2006
+ >>> from sympy import exp_polar, I, pi
2007
+ >>> Ci(z*exp_polar(2*I*pi))
2008
+ Ci(z) + 2*I*pi
2009
+
2010
+ The cosine integral behaves somewhat like ordinary $\cos$ under
2011
+ multiplication by $i$:
2012
+
2013
+ >>> from sympy import polar_lift
2014
+ >>> Ci(polar_lift(I)*z)
2015
+ Chi(z) + I*pi/2
2016
+ >>> Ci(polar_lift(-1)*z)
2017
+ Ci(z) + I*pi
2018
+
2019
+ It can also be expressed in terms of exponential integrals:
2020
+
2021
+ >>> from sympy import expint
2022
+ >>> Ci(z).rewrite(expint)
2023
+ -expint(1, z*exp_polar(-I*pi/2))/2 - expint(1, z*exp_polar(I*pi/2))/2
2024
+
2025
+ See Also
2026
+ ========
2027
+
2028
+ Si: Sine integral.
2029
+ Shi: Hyperbolic sine integral.
2030
+ Chi: Hyperbolic cosine integral.
2031
+ Ei: Exponential integral.
2032
+ expint: Generalised exponential integral.
2033
+ E1: Special case of the generalised exponential integral.
2034
+ li: Logarithmic integral.
2035
+ Li: Offset logarithmic integral.
2036
+
2037
+ References
2038
+ ==========
2039
+
2040
+ .. [1] https://en.wikipedia.org/wiki/Trigonometric_integral
2041
+
2042
+ """
2043
+
2044
+ _trigfunc = cos
2045
+ _atzero = S.ComplexInfinity
2046
+
2047
+ @classmethod
2048
+ def _atinf(cls):
2049
+ return S.Zero
2050
+
2051
+ @classmethod
2052
+ def _atneginf(cls):
2053
+ return I*pi
2054
+
2055
+ @classmethod
2056
+ def _minusfactor(cls, z):
2057
+ return Ci(z) + I*pi
2058
+
2059
+ @classmethod
2060
+ def _Ifactor(cls, z, sign):
2061
+ return Chi(z) + I*pi/2*sign
2062
+
2063
+ def _eval_rewrite_as_expint(self, z, **kwargs):
2064
+ return -(E1(polar_lift(I)*z) + E1(polar_lift(-I)*z))/2
2065
+
2066
+ def _eval_rewrite_as_Integral(self, z, **kwargs):
2067
+ from sympy.integrals.integrals import Integral
2068
+ t = Dummy(uniquely_named_symbol('t', [z]).name)
2069
+ return S.EulerGamma + log(z) - Integral((1-cos(t))/t, (t, 0, z))
2070
+
2071
+ def _eval_as_leading_term(self, x, logx, cdir):
2072
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
2073
+ arg0 = arg.subs(x, 0)
2074
+
2075
+ if arg0 is S.NaN:
2076
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
2077
+ if arg0.is_zero:
2078
+ c, e = arg.as_coeff_exponent(x)
2079
+ logx = log(x) if logx is None else logx
2080
+ return log(c) + e*logx + EulerGamma
2081
+ elif arg0.is_finite:
2082
+ return self.func(arg0)
2083
+ else:
2084
+ return self
2085
+
2086
+ def _eval_aseries(self, n, args0, x, logx):
2087
+ from sympy.series.order import Order
2088
+ point = args0[0]
2089
+
2090
+ if point in (S.Infinity, S.NegativeInfinity):
2091
+ z = self.args[0]
2092
+ p = [S.NegativeOne**k * factorial(2*k) / z**(2*k + 1)
2093
+ for k in range(n//2 + 1)] + [Order(1/z**n, x)]
2094
+ q = [S.NegativeOne**k * factorial(2*k + 1) / z**(2*(k + 1))
2095
+ for k in range(n//2)] + [Order(1/z**n, x)]
2096
+ result = sin(z)*(Add(*p)) - cos(z)*(Add(*q))
2097
+
2098
+ if point is S.NegativeInfinity:
2099
+ result += I*pi
2100
+ return result
2101
+
2102
+ return super(Ci, self)._eval_aseries(n, args0, x, logx)
2103
+
2104
+ class Shi(TrigonometricIntegral):
2105
+ r"""
2106
+ Sinh integral.
2107
+
2108
+ Explanation
2109
+ ===========
2110
+
2111
+ This function is defined by
2112
+
2113
+ .. math:: \operatorname{Shi}(z) = \int_0^z \frac{\sinh{t}}{t} \mathrm{d}t.
2114
+
2115
+ It is an entire function.
2116
+
2117
+ Examples
2118
+ ========
2119
+
2120
+ >>> from sympy import Shi
2121
+ >>> from sympy.abc import z
2122
+
2123
+ The Sinh integral is a primitive of $\sinh(z)/z$:
2124
+
2125
+ >>> Shi(z).diff(z)
2126
+ sinh(z)/z
2127
+
2128
+ It is unbranched:
2129
+
2130
+ >>> from sympy import exp_polar, I, pi
2131
+ >>> Shi(z*exp_polar(2*I*pi))
2132
+ Shi(z)
2133
+
2134
+ The $\sinh$ integral behaves much like ordinary $\sinh$ under
2135
+ multiplication by $i$:
2136
+
2137
+ >>> Shi(I*z)
2138
+ I*Si(z)
2139
+ >>> Shi(-z)
2140
+ -Shi(z)
2141
+
2142
+ It can also be expressed in terms of exponential integrals, but beware
2143
+ that the latter is branched:
2144
+
2145
+ >>> from sympy import expint
2146
+ >>> Shi(z).rewrite(expint)
2147
+ expint(1, z)/2 - expint(1, z*exp_polar(I*pi))/2 - I*pi/2
2148
+
2149
+ See Also
2150
+ ========
2151
+
2152
+ Si: Sine integral.
2153
+ Ci: Cosine integral.
2154
+ Chi: Hyperbolic cosine integral.
2155
+ Ei: Exponential integral.
2156
+ expint: Generalised exponential integral.
2157
+ E1: Special case of the generalised exponential integral.
2158
+ li: Logarithmic integral.
2159
+ Li: Offset logarithmic integral.
2160
+
2161
+ References
2162
+ ==========
2163
+
2164
+ .. [1] https://en.wikipedia.org/wiki/Trigonometric_integral
2165
+
2166
+ """
2167
+
2168
+ _trigfunc = sinh
2169
+ _atzero = S.Zero
2170
+
2171
+ @classmethod
2172
+ def _atinf(cls):
2173
+ return S.Infinity
2174
+
2175
+ @classmethod
2176
+ def _atneginf(cls):
2177
+ return S.NegativeInfinity
2178
+
2179
+ @classmethod
2180
+ def _minusfactor(cls, z):
2181
+ return -Shi(z)
2182
+
2183
+ @classmethod
2184
+ def _Ifactor(cls, z, sign):
2185
+ return I*Si(z)*sign
2186
+
2187
+ def _eval_rewrite_as_expint(self, z, **kwargs):
2188
+ # XXX should we polarify z?
2189
+ return (E1(z) - E1(exp_polar(I*pi)*z))/2 - I*pi/2
2190
+
2191
+ def _eval_is_zero(self):
2192
+ z = self.args[0]
2193
+ if z.is_zero:
2194
+ return True
2195
+
2196
+ def _eval_as_leading_term(self, x, logx, cdir):
2197
+ arg = self.args[0].as_leading_term(x)
2198
+ arg0 = arg.subs(x, 0)
2199
+
2200
+ if arg0 is S.NaN:
2201
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
2202
+ if arg0.is_zero:
2203
+ return arg
2204
+ elif not arg0.is_infinite:
2205
+ return self.func(arg0)
2206
+ else:
2207
+ return self
2208
+
2209
+
2210
+ class Chi(TrigonometricIntegral):
2211
+ r"""
2212
+ Cosh integral.
2213
+
2214
+ Explanation
2215
+ ===========
2216
+
2217
+ This function is defined for positive $x$ by
2218
+
2219
+ .. math:: \operatorname{Chi}(x) = \gamma + \log{x}
2220
+ + \int_0^x \frac{\cosh{t} - 1}{t} \mathrm{d}t,
2221
+
2222
+ where $\gamma$ is the Euler-Mascheroni constant.
2223
+
2224
+ We have
2225
+
2226
+ .. math:: \operatorname{Chi}(z) = \operatorname{Ci}\left(e^{i \pi/2}z\right)
2227
+ - i\frac{\pi}{2},
2228
+
2229
+ which holds for all polar $z$ and thus provides an analytic
2230
+ continuation to the Riemann surface of the logarithm.
2231
+ By lifting to the principal branch we obtain an analytic function on the
2232
+ cut complex plane.
2233
+
2234
+ Examples
2235
+ ========
2236
+
2237
+ >>> from sympy import Chi
2238
+ >>> from sympy.abc import z
2239
+
2240
+ The $\cosh$ integral is a primitive of $\cosh(z)/z$:
2241
+
2242
+ >>> Chi(z).diff(z)
2243
+ cosh(z)/z
2244
+
2245
+ It has a logarithmic branch point at the origin:
2246
+
2247
+ >>> from sympy import exp_polar, I, pi
2248
+ >>> Chi(z*exp_polar(2*I*pi))
2249
+ Chi(z) + 2*I*pi
2250
+
2251
+ The $\cosh$ integral behaves somewhat like ordinary $\cosh$ under
2252
+ multiplication by $i$:
2253
+
2254
+ >>> from sympy import polar_lift
2255
+ >>> Chi(polar_lift(I)*z)
2256
+ Ci(z) + I*pi/2
2257
+ >>> Chi(polar_lift(-1)*z)
2258
+ Chi(z) + I*pi
2259
+
2260
+ It can also be expressed in terms of exponential integrals:
2261
+
2262
+ >>> from sympy import expint
2263
+ >>> Chi(z).rewrite(expint)
2264
+ -expint(1, z)/2 - expint(1, z*exp_polar(I*pi))/2 - I*pi/2
2265
+
2266
+ See Also
2267
+ ========
2268
+
2269
+ Si: Sine integral.
2270
+ Ci: Cosine integral.
2271
+ Shi: Hyperbolic sine integral.
2272
+ Ei: Exponential integral.
2273
+ expint: Generalised exponential integral.
2274
+ E1: Special case of the generalised exponential integral.
2275
+ li: Logarithmic integral.
2276
+ Li: Offset logarithmic integral.
2277
+
2278
+ References
2279
+ ==========
2280
+
2281
+ .. [1] https://en.wikipedia.org/wiki/Trigonometric_integral
2282
+
2283
+ """
2284
+
2285
+ _trigfunc = cosh
2286
+ _atzero = S.ComplexInfinity
2287
+
2288
+ @classmethod
2289
+ def _atinf(cls):
2290
+ return S.Infinity
2291
+
2292
+ @classmethod
2293
+ def _atneginf(cls):
2294
+ return S.Infinity
2295
+
2296
+ @classmethod
2297
+ def _minusfactor(cls, z):
2298
+ return Chi(z) + I*pi
2299
+
2300
+ @classmethod
2301
+ def _Ifactor(cls, z, sign):
2302
+ return Ci(z) + I*pi/2*sign
2303
+
2304
+ def _eval_rewrite_as_expint(self, z, **kwargs):
2305
+ return -I*pi/2 - (E1(z) + E1(exp_polar(I*pi)*z))/2
2306
+
2307
+ def _eval_as_leading_term(self, x, logx, cdir):
2308
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
2309
+ arg0 = arg.subs(x, 0)
2310
+
2311
+ if arg0 is S.NaN:
2312
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
2313
+ if arg0.is_zero:
2314
+ c, e = arg.as_coeff_exponent(x)
2315
+ logx = log(x) if logx is None else logx
2316
+ return log(c) + e*logx + EulerGamma
2317
+ elif arg0.is_finite:
2318
+ return self.func(arg0)
2319
+ else:
2320
+ return self
2321
+
2322
+
2323
+ ###############################################################################
2324
+ #################### FRESNEL INTEGRALS ########################################
2325
+ ###############################################################################
2326
+
2327
+ class FresnelIntegral(DefinedFunction):
2328
+ """ Base class for the Fresnel integrals."""
2329
+
2330
+ unbranched = True
2331
+
2332
+ @classmethod
2333
+ def eval(cls, z):
2334
+ # Values at positive infinities signs
2335
+ # if any were extracted automatically
2336
+ if z is S.Infinity:
2337
+ return S.Half
2338
+
2339
+ # Value at zero
2340
+ if z.is_zero:
2341
+ return S.Zero
2342
+
2343
+ # Try to pull out factors of -1 and I
2344
+ prefact = S.One
2345
+ newarg = z
2346
+ changed = False
2347
+
2348
+ nz = newarg.extract_multiplicatively(-1)
2349
+ if nz is not None:
2350
+ prefact = -prefact
2351
+ newarg = nz
2352
+ changed = True
2353
+
2354
+ nz = newarg.extract_multiplicatively(I)
2355
+ if nz is not None:
2356
+ prefact = cls._sign*I*prefact
2357
+ newarg = nz
2358
+ changed = True
2359
+
2360
+ if changed:
2361
+ return prefact*cls(newarg)
2362
+
2363
+ def fdiff(self, argindex=1):
2364
+ if argindex == 1:
2365
+ return self._trigfunc(S.Half*pi*self.args[0]**2)
2366
+ else:
2367
+ raise ArgumentIndexError(self, argindex)
2368
+
2369
+ def _eval_is_extended_real(self):
2370
+ return self.args[0].is_extended_real
2371
+
2372
+ _eval_is_finite = _eval_is_extended_real
2373
+
2374
+ def _eval_is_zero(self):
2375
+ return self.args[0].is_zero
2376
+
2377
+ def _eval_conjugate(self):
2378
+ return self.func(self.args[0].conjugate())
2379
+
2380
+ as_real_imag = real_to_real_as_real_imag
2381
+
2382
+
2383
+ class fresnels(FresnelIntegral):
2384
+ r"""
2385
+ Fresnel integral S.
2386
+
2387
+ Explanation
2388
+ ===========
2389
+
2390
+ This function is defined by
2391
+
2392
+ .. math:: \operatorname{S}(z) = \int_0^z \sin{\frac{\pi}{2} t^2} \mathrm{d}t.
2393
+
2394
+ It is an entire function.
2395
+
2396
+ Examples
2397
+ ========
2398
+
2399
+ >>> from sympy import I, oo, fresnels
2400
+ >>> from sympy.abc import z
2401
+
2402
+ Several special values are known:
2403
+
2404
+ >>> fresnels(0)
2405
+ 0
2406
+ >>> fresnels(oo)
2407
+ 1/2
2408
+ >>> fresnels(-oo)
2409
+ -1/2
2410
+ >>> fresnels(I*oo)
2411
+ -I/2
2412
+ >>> fresnels(-I*oo)
2413
+ I/2
2414
+
2415
+ In general one can pull out factors of -1 and $i$ from the argument:
2416
+
2417
+ >>> fresnels(-z)
2418
+ -fresnels(z)
2419
+ >>> fresnels(I*z)
2420
+ -I*fresnels(z)
2421
+
2422
+ The Fresnel S integral obeys the mirror symmetry
2423
+ $\overline{S(z)} = S(\bar{z})$:
2424
+
2425
+ >>> from sympy import conjugate
2426
+ >>> conjugate(fresnels(z))
2427
+ fresnels(conjugate(z))
2428
+
2429
+ Differentiation with respect to $z$ is supported:
2430
+
2431
+ >>> from sympy import diff
2432
+ >>> diff(fresnels(z), z)
2433
+ sin(pi*z**2/2)
2434
+
2435
+ Defining the Fresnel functions via an integral:
2436
+
2437
+ >>> from sympy import integrate, pi, sin, expand_func
2438
+ >>> integrate(sin(pi*z**2/2), z)
2439
+ 3*fresnels(z)*gamma(3/4)/(4*gamma(7/4))
2440
+ >>> expand_func(integrate(sin(pi*z**2/2), z))
2441
+ fresnels(z)
2442
+
2443
+ We can numerically evaluate the Fresnel integral to arbitrary precision
2444
+ on the whole complex plane:
2445
+
2446
+ >>> fresnels(2).evalf(30)
2447
+ 0.343415678363698242195300815958
2448
+
2449
+ >>> fresnels(-2*I).evalf(30)
2450
+ 0.343415678363698242195300815958*I
2451
+
2452
+ See Also
2453
+ ========
2454
+
2455
+ fresnelc: Fresnel cosine integral.
2456
+
2457
+ References
2458
+ ==========
2459
+
2460
+ .. [1] https://en.wikipedia.org/wiki/Fresnel_integral
2461
+ .. [2] https://dlmf.nist.gov/7
2462
+ .. [3] https://mathworld.wolfram.com/FresnelIntegrals.html
2463
+ .. [4] https://functions.wolfram.com/GammaBetaErf/FresnelS
2464
+ .. [5] The converging factors for the fresnel integrals
2465
+ by John W. Wrench Jr. and Vicki Alley
2466
+
2467
+ """
2468
+ _trigfunc = sin
2469
+ _sign = -S.One
2470
+
2471
+ @staticmethod
2472
+ @cacheit
2473
+ def taylor_term(n, x, *previous_terms):
2474
+ if n < 0:
2475
+ return S.Zero
2476
+ else:
2477
+ x = sympify(x)
2478
+ if len(previous_terms) > 1:
2479
+ p = previous_terms[-1]
2480
+ return (-pi**2*x**4*(4*n - 1)/(8*n*(2*n + 1)*(4*n + 3))) * p
2481
+ else:
2482
+ return x**3 * (-x**4)**n * (S(2)**(-2*n - 1)*pi**(2*n + 1)) / ((4*n + 3)*factorial(2*n + 1))
2483
+
2484
+ def _eval_rewrite_as_erf(self, z, **kwargs):
2485
+ return (S.One + I)/4 * (erf((S.One + I)/2*sqrt(pi)*z) - I*erf((S.One - I)/2*sqrt(pi)*z))
2486
+
2487
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
2488
+ return pi*z**3/6 * hyper([Rational(3, 4)], [Rational(3, 2), Rational(7, 4)], -pi**2*z**4/16)
2489
+
2490
+ def _eval_rewrite_as_meijerg(self, z, **kwargs):
2491
+ return (pi*z**Rational(9, 4) / (sqrt(2)*(z**2)**Rational(3, 4)*(-z)**Rational(3, 4))
2492
+ * meijerg([], [1], [Rational(3, 4)], [Rational(1, 4), 0], -pi**2*z**4/16))
2493
+
2494
+ def _eval_rewrite_as_Integral(self, z, **kwargs):
2495
+ from sympy.integrals.integrals import Integral
2496
+ t = Dummy(uniquely_named_symbol('t', [z]).name)
2497
+ return Integral(sin(pi*t**2/2), (t, 0, z))
2498
+
2499
+ def _eval_as_leading_term(self, x, logx, cdir):
2500
+ from sympy.series.order import Order
2501
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
2502
+ arg0 = arg.subs(x, 0)
2503
+
2504
+ if arg0 is S.ComplexInfinity:
2505
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
2506
+ if arg0.is_zero:
2507
+ return pi*arg**3/6
2508
+ elif arg0 in [S.Infinity, S.NegativeInfinity]:
2509
+ s = 1 if arg0 is S.Infinity else -1
2510
+ return s*S.Half + Order(x, x)
2511
+ else:
2512
+ return self.func(arg0)
2513
+
2514
+ def _eval_aseries(self, n, args0, x, logx):
2515
+ from sympy.series.order import Order
2516
+ point = args0[0]
2517
+
2518
+ # Expansion at oo and -oo
2519
+ if point in [S.Infinity, -S.Infinity]:
2520
+ z = self.args[0]
2521
+
2522
+ # expansion of S(x) = S1(x*sqrt(pi/2)), see reference[5] page 1-8
2523
+ # as only real infinities are dealt with, sin and cos are O(1)
2524
+ p = [S.NegativeOne**k * factorial(4*k + 1) /
2525
+ (2**(2*k + 2) * z**(4*k + 3) * 2**(2*k)*factorial(2*k))
2526
+ for k in range(0, n) if 4*k + 3 < n]
2527
+ q = [1/(2*z)] + [S.NegativeOne**k * factorial(4*k - 1) /
2528
+ (2**(2*k + 1) * z**(4*k + 1) * 2**(2*k - 1)*factorial(2*k - 1))
2529
+ for k in range(1, n) if 4*k + 1 < n]
2530
+
2531
+ p = [-sqrt(2/pi)*t for t in p]
2532
+ q = [-sqrt(2/pi)*t for t in q]
2533
+ s = 1 if point is S.Infinity else -1
2534
+ # The expansion at oo is 1/2 + some odd powers of z
2535
+ # To get the expansion at -oo, replace z by -z and flip the sign
2536
+ # The result -1/2 + the same odd powers of z as before.
2537
+ return s*S.Half + (sin(z**2)*Add(*p) + cos(z**2)*Add(*q)
2538
+ ).subs(x, sqrt(2/pi)*x) + Order(1/z**n, x)
2539
+
2540
+ # All other points are not handled
2541
+ return super()._eval_aseries(n, args0, x, logx)
2542
+
2543
+
2544
+ class fresnelc(FresnelIntegral):
2545
+ r"""
2546
+ Fresnel integral C.
2547
+
2548
+ Explanation
2549
+ ===========
2550
+
2551
+ This function is defined by
2552
+
2553
+ .. math:: \operatorname{C}(z) = \int_0^z \cos{\frac{\pi}{2} t^2} \mathrm{d}t.
2554
+
2555
+ It is an entire function.
2556
+
2557
+ Examples
2558
+ ========
2559
+
2560
+ >>> from sympy import I, oo, fresnelc
2561
+ >>> from sympy.abc import z
2562
+
2563
+ Several special values are known:
2564
+
2565
+ >>> fresnelc(0)
2566
+ 0
2567
+ >>> fresnelc(oo)
2568
+ 1/2
2569
+ >>> fresnelc(-oo)
2570
+ -1/2
2571
+ >>> fresnelc(I*oo)
2572
+ I/2
2573
+ >>> fresnelc(-I*oo)
2574
+ -I/2
2575
+
2576
+ In general one can pull out factors of -1 and $i$ from the argument:
2577
+
2578
+ >>> fresnelc(-z)
2579
+ -fresnelc(z)
2580
+ >>> fresnelc(I*z)
2581
+ I*fresnelc(z)
2582
+
2583
+ The Fresnel C integral obeys the mirror symmetry
2584
+ $\overline{C(z)} = C(\bar{z})$:
2585
+
2586
+ >>> from sympy import conjugate
2587
+ >>> conjugate(fresnelc(z))
2588
+ fresnelc(conjugate(z))
2589
+
2590
+ Differentiation with respect to $z$ is supported:
2591
+
2592
+ >>> from sympy import diff
2593
+ >>> diff(fresnelc(z), z)
2594
+ cos(pi*z**2/2)
2595
+
2596
+ Defining the Fresnel functions via an integral:
2597
+
2598
+ >>> from sympy import integrate, pi, cos, expand_func
2599
+ >>> integrate(cos(pi*z**2/2), z)
2600
+ fresnelc(z)*gamma(1/4)/(4*gamma(5/4))
2601
+ >>> expand_func(integrate(cos(pi*z**2/2), z))
2602
+ fresnelc(z)
2603
+
2604
+ We can numerically evaluate the Fresnel integral to arbitrary precision
2605
+ on the whole complex plane:
2606
+
2607
+ >>> fresnelc(2).evalf(30)
2608
+ 0.488253406075340754500223503357
2609
+
2610
+ >>> fresnelc(-2*I).evalf(30)
2611
+ -0.488253406075340754500223503357*I
2612
+
2613
+ See Also
2614
+ ========
2615
+
2616
+ fresnels: Fresnel sine integral.
2617
+
2618
+ References
2619
+ ==========
2620
+
2621
+ .. [1] https://en.wikipedia.org/wiki/Fresnel_integral
2622
+ .. [2] https://dlmf.nist.gov/7
2623
+ .. [3] https://mathworld.wolfram.com/FresnelIntegrals.html
2624
+ .. [4] https://functions.wolfram.com/GammaBetaErf/FresnelC
2625
+ .. [5] The converging factors for the fresnel integrals
2626
+ by John W. Wrench Jr. and Vicki Alley
2627
+
2628
+ """
2629
+ _trigfunc = cos
2630
+ _sign = S.One
2631
+
2632
+ @staticmethod
2633
+ @cacheit
2634
+ def taylor_term(n, x, *previous_terms):
2635
+ if n < 0:
2636
+ return S.Zero
2637
+ else:
2638
+ x = sympify(x)
2639
+ if len(previous_terms) > 1:
2640
+ p = previous_terms[-1]
2641
+ return (-pi**2*x**4*(4*n - 3)/(8*n*(2*n - 1)*(4*n + 1))) * p
2642
+ else:
2643
+ return x * (-x**4)**n * (S(2)**(-2*n)*pi**(2*n)) / ((4*n + 1)*factorial(2*n))
2644
+
2645
+ def _eval_rewrite_as_erf(self, z, **kwargs):
2646
+ return (S.One - I)/4 * (erf((S.One + I)/2*sqrt(pi)*z) + I*erf((S.One - I)/2*sqrt(pi)*z))
2647
+
2648
+ def _eval_rewrite_as_hyper(self, z, **kwargs):
2649
+ return z * hyper([Rational(1, 4)], [S.Half, Rational(5, 4)], -pi**2*z**4/16)
2650
+
2651
+ def _eval_rewrite_as_meijerg(self, z, **kwargs):
2652
+ return (pi*z**Rational(3, 4) / (sqrt(2)*root(z**2, 4)*root(-z, 4))
2653
+ * meijerg([], [1], [Rational(1, 4)], [Rational(3, 4), 0], -pi**2*z**4/16))
2654
+
2655
+ def _eval_rewrite_as_Integral(self, z, **kwargs):
2656
+ from sympy.integrals.integrals import Integral
2657
+ t = Dummy(uniquely_named_symbol('t', [z]).name)
2658
+ return Integral(cos(pi*t**2/2), (t, 0, z))
2659
+
2660
+ def _eval_as_leading_term(self, x, logx, cdir):
2661
+ from sympy.series.order import Order
2662
+ arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir)
2663
+ arg0 = arg.subs(x, 0)
2664
+
2665
+ if arg0 is S.ComplexInfinity:
2666
+ arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
2667
+ if arg0.is_zero:
2668
+ return arg
2669
+ elif arg0 in [S.Infinity, S.NegativeInfinity]:
2670
+ s = 1 if arg0 is S.Infinity else -1
2671
+ return s*S.Half + Order(x, x)
2672
+ else:
2673
+ return self.func(arg0)
2674
+
2675
+ def _eval_aseries(self, n, args0, x, logx):
2676
+ from sympy.series.order import Order
2677
+ point = args0[0]
2678
+
2679
+ # Expansion at oo
2680
+ if point in [S.Infinity, -S.Infinity]:
2681
+ z = self.args[0]
2682
+
2683
+ # expansion of C(x) = C1(x*sqrt(pi/2)), see reference[5] page 1-8
2684
+ # as only real infinities are dealt with, sin and cos are O(1)
2685
+ p = [S.NegativeOne**k * factorial(4*k + 1) /
2686
+ (2**(2*k + 2) * z**(4*k + 3) * 2**(2*k)*factorial(2*k))
2687
+ for k in range(n) if 4*k + 3 < n]
2688
+ q = [1/(2*z)] + [S.NegativeOne**k * factorial(4*k - 1) /
2689
+ (2**(2*k + 1) * z**(4*k + 1) * 2**(2*k - 1)*factorial(2*k - 1))
2690
+ for k in range(1, n) if 4*k + 1 < n]
2691
+
2692
+ p = [-sqrt(2/pi)*t for t in p]
2693
+ q = [ sqrt(2/pi)*t for t in q]
2694
+ s = 1 if point is S.Infinity else -1
2695
+ # The expansion at oo is 1/2 + some odd powers of z
2696
+ # To get the expansion at -oo, replace z by -z and flip the sign
2697
+ # The result -1/2 + the same odd powers of z as before.
2698
+ return s*S.Half + (cos(z**2)*Add(*p) + sin(z**2)*Add(*q)
2699
+ ).subs(x, sqrt(2/pi)*x) + Order(1/z**n, x)
2700
+
2701
+ # All other points are not handled
2702
+ return super()._eval_aseries(n, args0, x, logx)
2703
+
2704
+
2705
+ ###############################################################################
2706
+ #################### HELPER FUNCTIONS #########################################
2707
+ ###############################################################################
2708
+
2709
+
2710
+ class _erfs(DefinedFunction):
2711
+ """
2712
+ Helper function to make the $\\mathrm{erf}(z)$ function
2713
+ tractable for the Gruntz algorithm.
2714
+
2715
+ """
2716
+ @classmethod
2717
+ def eval(cls, arg):
2718
+ if arg.is_zero:
2719
+ return S.One
2720
+
2721
+ def _eval_aseries(self, n, args0, x, logx):
2722
+ from sympy.series.order import Order
2723
+ point = args0[0]
2724
+
2725
+ # Expansion at oo
2726
+ if point is S.Infinity:
2727
+ z = self.args[0]
2728
+ l = [1/sqrt(pi) * factorial(2*k)*(-S(
2729
+ 4))**(-k)/factorial(k) * (1/z)**(2*k + 1) for k in range(n)]
2730
+ o = Order(1/z**(2*n + 1), x)
2731
+ # It is very inefficient to first add the order and then do the nseries
2732
+ return (Add(*l))._eval_nseries(x, n, logx) + o
2733
+
2734
+ # Expansion at I*oo
2735
+ t = point.extract_multiplicatively(I)
2736
+ if t is S.Infinity:
2737
+ z = self.args[0]
2738
+ # TODO: is the series really correct?
2739
+ l = [1/sqrt(pi) * factorial(2*k)*(-S(
2740
+ 4))**(-k)/factorial(k) * (1/z)**(2*k + 1) for k in range(n)]
2741
+ o = Order(1/z**(2*n + 1), x)
2742
+ # It is very inefficient to first add the order and then do the nseries
2743
+ return (Add(*l))._eval_nseries(x, n, logx) + o
2744
+
2745
+ # All other points are not handled
2746
+ return super()._eval_aseries(n, args0, x, logx)
2747
+
2748
+ def fdiff(self, argindex=1):
2749
+ if argindex == 1:
2750
+ z = self.args[0]
2751
+ return -2/sqrt(pi) + 2*z*_erfs(z)
2752
+ else:
2753
+ raise ArgumentIndexError(self, argindex)
2754
+
2755
+ def _eval_rewrite_as_intractable(self, z, **kwargs):
2756
+ return (S.One - erf(z))*exp(z**2)
2757
+
2758
+
2759
+ class _eis(DefinedFunction):
2760
+ """
2761
+ Helper function to make the $\\mathrm{Ei}(z)$ and $\\mathrm{li}(z)$
2762
+ functions tractable for the Gruntz algorithm.
2763
+
2764
+ """
2765
+
2766
+
2767
+ def _eval_aseries(self, n, args0, x, logx):
2768
+ from sympy.series.order import Order
2769
+ if args0[0] not in (S.Infinity, S.NegativeInfinity):
2770
+ return super()._eval_aseries(n, args0, x, logx)
2771
+
2772
+ z = self.args[0]
2773
+ l = [factorial(k) * (1/z)**(k + 1) for k in range(n)]
2774
+ o = Order(1/z**(n + 1), x)
2775
+ # It is very inefficient to first add the order and then do the nseries
2776
+ return (Add(*l))._eval_nseries(x, n, logx) + o
2777
+
2778
+
2779
+ def fdiff(self, argindex=1):
2780
+ if argindex == 1:
2781
+ z = self.args[0]
2782
+ return S.One / z - _eis(z)
2783
+ else:
2784
+ raise ArgumentIndexError(self, argindex)
2785
+
2786
+ def _eval_rewrite_as_intractable(self, z, **kwargs):
2787
+ return exp(-z)*Ei(z)
2788
+
2789
+ def _eval_as_leading_term(self, x, logx, cdir):
2790
+ x0 = self.args[0].limit(x, 0)
2791
+ if x0.is_zero:
2792
+ f = self._eval_rewrite_as_intractable(*self.args)
2793
+ return f._eval_as_leading_term(x, logx=logx, cdir=cdir)
2794
+ return super()._eval_as_leading_term(x, logx=logx, cdir=cdir)
2795
+
2796
+ def _eval_nseries(self, x, n, logx, cdir=0):
2797
+ x0 = self.args[0].limit(x, 0)
2798
+ if x0.is_zero:
2799
+ f = self._eval_rewrite_as_intractable(*self.args)
2800
+ return f._eval_nseries(x, n, logx)
2801
+ return super()._eval_nseries(x, n, logx)
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/gamma_functions.py ADDED
@@ -0,0 +1,1344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from math import prod
2
+
3
+ from sympy.core import Add, S, Dummy, expand_func
4
+ from sympy.core.expr import Expr
5
+ from sympy.core.function import DefinedFunction, ArgumentIndexError, PoleError
6
+ from sympy.core.logic import fuzzy_and, fuzzy_not
7
+ from sympy.core.numbers import Rational, pi, oo, I
8
+ from sympy.core.power import Pow
9
+ from sympy.functions.special.zeta_functions import zeta
10
+ from sympy.functions.special.error_functions import erf, erfc, Ei
11
+ from sympy.functions.elementary.complexes import re, unpolarify
12
+ from sympy.functions.elementary.exponential import exp, log
13
+ from sympy.functions.elementary.integers import ceiling, floor
14
+ from sympy.functions.elementary.miscellaneous import sqrt
15
+ from sympy.functions.elementary.trigonometric import sin, cos, cot
16
+ from sympy.functions.combinatorial.numbers import bernoulli, harmonic
17
+ from sympy.functions.combinatorial.factorials import factorial, rf, RisingFactorial
18
+ from sympy.utilities.misc import as_int
19
+
20
+ from mpmath import mp, workprec
21
+ from mpmath.libmp.libmpf import prec_to_dps
22
+
23
+ def intlike(n):
24
+ try:
25
+ as_int(n, strict=False)
26
+ return True
27
+ except ValueError:
28
+ return False
29
+
30
+ ###############################################################################
31
+ ############################ COMPLETE GAMMA FUNCTION ##########################
32
+ ###############################################################################
33
+
34
+ class gamma(DefinedFunction):
35
+ r"""
36
+ The gamma function
37
+
38
+ .. math::
39
+ \Gamma(x) := \int^{\infty}_{0} t^{x-1} e^{-t} \mathrm{d}t.
40
+
41
+ Explanation
42
+ ===========
43
+
44
+ The ``gamma`` function implements the function which passes through the
45
+ values of the factorial function (i.e., $\Gamma(n) = (n - 1)!$ when n is
46
+ an integer). More generally, $\Gamma(z)$ is defined in the whole complex
47
+ plane except at the negative integers where there are simple poles.
48
+
49
+ Examples
50
+ ========
51
+
52
+ >>> from sympy import S, I, pi, gamma
53
+ >>> from sympy.abc import x
54
+
55
+ Several special values are known:
56
+
57
+ >>> gamma(1)
58
+ 1
59
+ >>> gamma(4)
60
+ 6
61
+ >>> gamma(S(3)/2)
62
+ sqrt(pi)/2
63
+
64
+ The ``gamma`` function obeys the mirror symmetry:
65
+
66
+ >>> from sympy import conjugate
67
+ >>> conjugate(gamma(x))
68
+ gamma(conjugate(x))
69
+
70
+ Differentiation with respect to $x$ is supported:
71
+
72
+ >>> from sympy import diff
73
+ >>> diff(gamma(x), x)
74
+ gamma(x)*polygamma(0, x)
75
+
76
+ Series expansion is also supported:
77
+
78
+ >>> from sympy import series
79
+ >>> series(gamma(x), x, 0, 3)
80
+ 1/x - EulerGamma + x*(EulerGamma**2/2 + pi**2/12) + x**2*(-EulerGamma*pi**2/12 - zeta(3)/3 - EulerGamma**3/6) + O(x**3)
81
+
82
+ We can numerically evaluate the ``gamma`` function to arbitrary precision
83
+ on the whole complex plane:
84
+
85
+ >>> gamma(pi).evalf(40)
86
+ 2.288037795340032417959588909060233922890
87
+ >>> gamma(1+I).evalf(20)
88
+ 0.49801566811835604271 - 0.15494982830181068512*I
89
+
90
+ See Also
91
+ ========
92
+
93
+ lowergamma: Lower incomplete gamma function.
94
+ uppergamma: Upper incomplete gamma function.
95
+ polygamma: Polygamma function.
96
+ loggamma: Log Gamma function.
97
+ digamma: Digamma function.
98
+ trigamma: Trigamma function.
99
+ sympy.functions.special.beta_functions.beta: Euler Beta function.
100
+
101
+ References
102
+ ==========
103
+
104
+ .. [1] https://en.wikipedia.org/wiki/Gamma_function
105
+ .. [2] https://dlmf.nist.gov/5
106
+ .. [3] https://mathworld.wolfram.com/GammaFunction.html
107
+ .. [4] https://functions.wolfram.com/GammaBetaErf/Gamma/
108
+
109
+ """
110
+
111
+ unbranched = True
112
+ _singularities = (S.ComplexInfinity,)
113
+
114
+ def fdiff(self, argindex=1):
115
+ if argindex == 1:
116
+ return self.func(self.args[0])*polygamma(0, self.args[0])
117
+ else:
118
+ raise ArgumentIndexError(self, argindex)
119
+
120
+ @classmethod
121
+ def eval(cls, arg):
122
+ if arg.is_Number:
123
+ if arg is S.NaN:
124
+ return S.NaN
125
+ elif arg is oo:
126
+ return oo
127
+ elif intlike(arg):
128
+ if arg.is_positive:
129
+ return factorial(arg - 1)
130
+ else:
131
+ return S.ComplexInfinity
132
+ elif arg.is_Rational:
133
+ if arg.q == 2:
134
+ n = abs(arg.p) // arg.q
135
+
136
+ if arg.is_positive:
137
+ k, coeff = n, S.One
138
+ else:
139
+ n = k = n + 1
140
+
141
+ if n & 1 == 0:
142
+ coeff = S.One
143
+ else:
144
+ coeff = S.NegativeOne
145
+
146
+ coeff *= prod(range(3, 2*k, 2))
147
+
148
+ if arg.is_positive:
149
+ return coeff*sqrt(pi) / 2**n
150
+ else:
151
+ return 2**n*sqrt(pi) / coeff
152
+
153
+ def _eval_expand_func(self, **hints):
154
+ arg = self.args[0]
155
+ if arg.is_Rational:
156
+ if abs(arg.p) > arg.q:
157
+ x = Dummy('x')
158
+ n = arg.p // arg.q
159
+ p = arg.p - n*arg.q
160
+ return self.func(x + n)._eval_expand_func().subs(x, Rational(p, arg.q))
161
+
162
+ if arg.is_Add:
163
+ coeff, tail = arg.as_coeff_add()
164
+ if coeff and coeff.q != 1:
165
+ intpart = floor(coeff)
166
+ tail = (coeff - intpart,) + tail
167
+ coeff = intpart
168
+ tail = arg._new_rawargs(*tail, reeval=False)
169
+ return self.func(tail)*RisingFactorial(tail, coeff)
170
+
171
+ return self.func(*self.args)
172
+
173
+ def _eval_conjugate(self):
174
+ return self.func(self.args[0].conjugate())
175
+
176
+ def _eval_is_real(self):
177
+ x = self.args[0]
178
+ if x.is_nonpositive and x.is_integer:
179
+ return False
180
+ if intlike(x) and x <= 0:
181
+ return False
182
+ if x.is_positive or x.is_noninteger:
183
+ return True
184
+
185
+ def _eval_is_positive(self):
186
+ x = self.args[0]
187
+ if x.is_positive:
188
+ return True
189
+ elif x.is_noninteger:
190
+ return floor(x).is_even
191
+
192
+ def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs):
193
+ return exp(loggamma(z))
194
+
195
+ def _eval_rewrite_as_factorial(self, z, **kwargs):
196
+ return factorial(z - 1)
197
+
198
+ def _eval_nseries(self, x, n, logx, cdir=0):
199
+ x0 = self.args[0].limit(x, 0)
200
+ if not (x0.is_Integer and x0 <= 0):
201
+ return super()._eval_nseries(x, n, logx)
202
+ t = self.args[0] - x0
203
+ return (self.func(t + 1)/rf(self.args[0], -x0 + 1))._eval_nseries(x, n, logx)
204
+
205
+ def _eval_as_leading_term(self, x, logx, cdir):
206
+ arg = self.args[0]
207
+ x0 = arg.subs(x, 0)
208
+
209
+ if x0.is_integer and x0.is_nonpositive:
210
+ n = -x0
211
+ res = S.NegativeOne**n/self.func(n + 1)
212
+ return res/(arg + n).as_leading_term(x)
213
+ elif not x0.is_infinite:
214
+ return self.func(x0)
215
+ raise PoleError()
216
+
217
+
218
+ ###############################################################################
219
+ ################## LOWER and UPPER INCOMPLETE GAMMA FUNCTIONS #################
220
+ ###############################################################################
221
+
222
+ class lowergamma(DefinedFunction):
223
+ r"""
224
+ The lower incomplete gamma function.
225
+
226
+ Explanation
227
+ ===========
228
+
229
+ It can be defined as the meromorphic continuation of
230
+
231
+ .. math::
232
+ \gamma(s, x) := \int_0^x t^{s-1} e^{-t} \mathrm{d}t = \Gamma(s) - \Gamma(s, x).
233
+
234
+ This can be shown to be the same as
235
+
236
+ .. math::
237
+ \gamma(s, x) = \frac{x^s}{s} {}_1F_1\left({s \atop s+1} \middle| -x\right),
238
+
239
+ where ${}_1F_1$ is the (confluent) hypergeometric function.
240
+
241
+ Examples
242
+ ========
243
+
244
+ >>> from sympy import lowergamma, S
245
+ >>> from sympy.abc import s, x
246
+ >>> lowergamma(s, x)
247
+ lowergamma(s, x)
248
+ >>> lowergamma(3, x)
249
+ -2*(x**2/2 + x + 1)*exp(-x) + 2
250
+ >>> lowergamma(-S(1)/2, x)
251
+ -2*sqrt(pi)*erf(sqrt(x)) - 2*exp(-x)/sqrt(x)
252
+
253
+ See Also
254
+ ========
255
+
256
+ gamma: Gamma function.
257
+ uppergamma: Upper incomplete gamma function.
258
+ polygamma: Polygamma function.
259
+ loggamma: Log Gamma function.
260
+ digamma: Digamma function.
261
+ trigamma: Trigamma function.
262
+ sympy.functions.special.beta_functions.beta: Euler Beta function.
263
+
264
+ References
265
+ ==========
266
+
267
+ .. [1] https://en.wikipedia.org/wiki/Incomplete_gamma_function#Lower_incomplete_gamma_function
268
+ .. [2] Abramowitz, Milton; Stegun, Irene A., eds. (1965), Chapter 6,
269
+ Section 5, Handbook of Mathematical Functions with Formulas, Graphs,
270
+ and Mathematical Tables
271
+ .. [3] https://dlmf.nist.gov/8
272
+ .. [4] https://functions.wolfram.com/GammaBetaErf/Gamma2/
273
+ .. [5] https://functions.wolfram.com/GammaBetaErf/Gamma3/
274
+
275
+ """
276
+
277
+
278
+ def fdiff(self, argindex=2):
279
+ from sympy.functions.special.hyper import meijerg
280
+ if argindex == 2:
281
+ a, z = self.args
282
+ return exp(-unpolarify(z))*z**(a - 1)
283
+ elif argindex == 1:
284
+ a, z = self.args
285
+ return gamma(a)*digamma(a) - log(z)*uppergamma(a, z) \
286
+ - meijerg([], [1, 1], [0, 0, a], [], z)
287
+
288
+ else:
289
+ raise ArgumentIndexError(self, argindex)
290
+
291
+ @classmethod
292
+ def eval(cls, a, x):
293
+ # For lack of a better place, we use this one to extract branching
294
+ # information. The following can be
295
+ # found in the literature (c/f references given above), albeit scattered:
296
+ # 1) For fixed x != 0, lowergamma(s, x) is an entire function of s
297
+ # 2) For fixed positive integers s, lowergamma(s, x) is an entire
298
+ # function of x.
299
+ # 3) For fixed non-positive integers s,
300
+ # lowergamma(s, exp(I*2*pi*n)*x) =
301
+ # 2*pi*I*n*(-1)**(-s)/factorial(-s) + lowergamma(s, x)
302
+ # (this follows from lowergamma(s, x).diff(x) = x**(s-1)*exp(-x)).
303
+ # 4) For fixed non-integral s,
304
+ # lowergamma(s, x) = x**s*gamma(s)*lowergamma_unbranched(s, x),
305
+ # where lowergamma_unbranched(s, x) is an entire function (in fact
306
+ # of both s and x), i.e.
307
+ # lowergamma(s, exp(2*I*pi*n)*x) = exp(2*pi*I*n*a)*lowergamma(a, x)
308
+ if x is S.Zero:
309
+ return S.Zero
310
+ nx, n = x.extract_branch_factor()
311
+ if a.is_integer and a.is_positive:
312
+ nx = unpolarify(x)
313
+ if nx != x:
314
+ return lowergamma(a, nx)
315
+ elif a.is_integer and a.is_nonpositive:
316
+ if n != 0:
317
+ return 2*pi*I*n*S.NegativeOne**(-a)/factorial(-a) + lowergamma(a, nx)
318
+ elif n != 0:
319
+ return exp(2*pi*I*n*a)*lowergamma(a, nx)
320
+
321
+ # Special values.
322
+ if a.is_Number:
323
+ if a is S.One:
324
+ return S.One - exp(-x)
325
+ elif a is S.Half:
326
+ return sqrt(pi)*erf(sqrt(x))
327
+ elif a.is_Integer or (2*a).is_Integer:
328
+ b = a - 1
329
+ if b.is_positive:
330
+ if a.is_integer:
331
+ return factorial(b) - exp(-x) * factorial(b) * Add(*[x ** k / factorial(k) for k in range(a)])
332
+ else:
333
+ return gamma(a)*(lowergamma(S.Half, x)/sqrt(pi) - exp(-x)*Add(*[x**(k - S.Half)/gamma(S.Half + k) for k in range(1, a + S.Half)]))
334
+
335
+ if not a.is_Integer:
336
+ return S.NegativeOne**(S.Half - a)*pi*erf(sqrt(x))/gamma(1 - a) + exp(-x)*Add(*[x**(k + a - 1)*gamma(a)/gamma(a + k) for k in range(1, Rational(3, 2) - a)])
337
+
338
+ if x.is_zero:
339
+ return S.Zero
340
+
341
+ def _eval_evalf(self, prec):
342
+ if all(x.is_number for x in self.args):
343
+ a = self.args[0]._to_mpmath(prec)
344
+ z = self.args[1]._to_mpmath(prec)
345
+ with workprec(prec):
346
+ res = mp.gammainc(a, 0, z)
347
+ return Expr._from_mpmath(res, prec)
348
+ else:
349
+ return self
350
+
351
+ def _eval_conjugate(self):
352
+ x = self.args[1]
353
+ if x not in (S.Zero, S.NegativeInfinity):
354
+ return self.func(self.args[0].conjugate(), x.conjugate())
355
+
356
+ def _eval_is_meromorphic(self, x, a):
357
+ # By https://en.wikipedia.org/wiki/Incomplete_gamma_function#Holomorphic_extension,
358
+ # lowergamma(s, z) = z**s*gamma(s)*gammastar(s, z),
359
+ # where gammastar(s, z) is holomorphic for all s and z.
360
+ # Hence the singularities of lowergamma are z = 0 (branch
361
+ # point) and nonpositive integer values of s (poles of gamma(s)).
362
+ s, z = self.args
363
+ args_merom = fuzzy_and([z._eval_is_meromorphic(x, a),
364
+ s._eval_is_meromorphic(x, a)])
365
+ if not args_merom:
366
+ return args_merom
367
+ z0 = z.subs(x, a)
368
+ if s.is_integer:
369
+ return fuzzy_and([s.is_positive, z0.is_finite])
370
+ s0 = s.subs(x, a)
371
+ return fuzzy_and([s0.is_finite, z0.is_finite, fuzzy_not(z0.is_zero)])
372
+
373
+ def _eval_aseries(self, n, args0, x, logx):
374
+ from sympy.series.order import O
375
+ s, z = self.args
376
+ if args0[0] is oo and not z.has(x):
377
+ coeff = z**s*exp(-z)
378
+ sum_expr = sum(z**k/rf(s, k + 1) for k in range(n - 1))
379
+ o = O(z**s*s**(-n))
380
+ return coeff*sum_expr + o
381
+ return super()._eval_aseries(n, args0, x, logx)
382
+
383
+ def _eval_rewrite_as_uppergamma(self, s, x, **kwargs):
384
+ return gamma(s) - uppergamma(s, x)
385
+
386
+ def _eval_rewrite_as_expint(self, s, x, **kwargs):
387
+ from sympy.functions.special.error_functions import expint
388
+ if s.is_integer and s.is_nonpositive:
389
+ return self
390
+ return self.rewrite(uppergamma).rewrite(expint)
391
+
392
+ def _eval_is_zero(self):
393
+ x = self.args[1]
394
+ if x.is_zero:
395
+ return True
396
+
397
+
398
+ class uppergamma(DefinedFunction):
399
+ r"""
400
+ The upper incomplete gamma function.
401
+
402
+ Explanation
403
+ ===========
404
+
405
+ It can be defined as the meromorphic continuation of
406
+
407
+ .. math::
408
+ \Gamma(s, x) := \int_x^\infty t^{s-1} e^{-t} \mathrm{d}t = \Gamma(s) - \gamma(s, x).
409
+
410
+ where $\gamma(s, x)$ is the lower incomplete gamma function,
411
+ :class:`lowergamma`. This can be shown to be the same as
412
+
413
+ .. math::
414
+ \Gamma(s, x) = \Gamma(s) - \frac{x^s}{s} {}_1F_1\left({s \atop s+1} \middle| -x\right),
415
+
416
+ where ${}_1F_1$ is the (confluent) hypergeometric function.
417
+
418
+ The upper incomplete gamma function is also essentially equivalent to the
419
+ generalized exponential integral:
420
+
421
+ .. math::
422
+ \operatorname{E}_{n}(x) = \int_{1}^{\infty}{\frac{e^{-xt}}{t^n} \, dt} = x^{n-1}\Gamma(1-n,x).
423
+
424
+ Examples
425
+ ========
426
+
427
+ >>> from sympy import uppergamma, S
428
+ >>> from sympy.abc import s, x
429
+ >>> uppergamma(s, x)
430
+ uppergamma(s, x)
431
+ >>> uppergamma(3, x)
432
+ 2*(x**2/2 + x + 1)*exp(-x)
433
+ >>> uppergamma(-S(1)/2, x)
434
+ -2*sqrt(pi)*erfc(sqrt(x)) + 2*exp(-x)/sqrt(x)
435
+ >>> uppergamma(-2, x)
436
+ expint(3, x)/x**2
437
+
438
+ See Also
439
+ ========
440
+
441
+ gamma: Gamma function.
442
+ lowergamma: Lower incomplete gamma function.
443
+ polygamma: Polygamma function.
444
+ loggamma: Log Gamma function.
445
+ digamma: Digamma function.
446
+ trigamma: Trigamma function.
447
+ sympy.functions.special.beta_functions.beta: Euler Beta function.
448
+
449
+ References
450
+ ==========
451
+
452
+ .. [1] https://en.wikipedia.org/wiki/Incomplete_gamma_function#Upper_incomplete_gamma_function
453
+ .. [2] Abramowitz, Milton; Stegun, Irene A., eds. (1965), Chapter 6,
454
+ Section 5, Handbook of Mathematical Functions with Formulas, Graphs,
455
+ and Mathematical Tables
456
+ .. [3] https://dlmf.nist.gov/8
457
+ .. [4] https://functions.wolfram.com/GammaBetaErf/Gamma2/
458
+ .. [5] https://functions.wolfram.com/GammaBetaErf/Gamma3/
459
+ .. [6] https://en.wikipedia.org/wiki/Exponential_integral#Relation_with_other_functions
460
+
461
+ """
462
+
463
+
464
+ def fdiff(self, argindex=2):
465
+ from sympy.functions.special.hyper import meijerg
466
+ if argindex == 2:
467
+ a, z = self.args
468
+ return -exp(-unpolarify(z))*z**(a - 1)
469
+ elif argindex == 1:
470
+ a, z = self.args
471
+ return uppergamma(a, z)*log(z) + meijerg([], [1, 1], [0, 0, a], [], z)
472
+ else:
473
+ raise ArgumentIndexError(self, argindex)
474
+
475
+ def _eval_evalf(self, prec):
476
+ if all(x.is_number for x in self.args):
477
+ a = self.args[0]._to_mpmath(prec)
478
+ z = self.args[1]._to_mpmath(prec)
479
+ with workprec(prec):
480
+ res = mp.gammainc(a, z, mp.inf)
481
+ return Expr._from_mpmath(res, prec)
482
+ return self
483
+
484
+ @classmethod
485
+ def eval(cls, a, z):
486
+ from sympy.functions.special.error_functions import expint
487
+ if z.is_Number:
488
+ if z is S.NaN:
489
+ return S.NaN
490
+ elif z is oo:
491
+ return S.Zero
492
+ elif z.is_zero:
493
+ if re(a).is_positive:
494
+ return gamma(a)
495
+
496
+ # We extract branching information here. C/f lowergamma.
497
+ nx, n = z.extract_branch_factor()
498
+ if a.is_integer and a.is_positive:
499
+ nx = unpolarify(z)
500
+ if z != nx:
501
+ return uppergamma(a, nx)
502
+ elif a.is_integer and a.is_nonpositive:
503
+ if n != 0:
504
+ return -2*pi*I*n*S.NegativeOne**(-a)/factorial(-a) + uppergamma(a, nx)
505
+ elif n != 0:
506
+ return gamma(a)*(1 - exp(2*pi*I*n*a)) + exp(2*pi*I*n*a)*uppergamma(a, nx)
507
+
508
+ # Special values.
509
+ if a.is_Number:
510
+ if a is S.Zero and z.is_positive:
511
+ return -Ei(-z)
512
+ elif a is S.One:
513
+ return exp(-z)
514
+ elif a is S.Half:
515
+ return sqrt(pi)*erfc(sqrt(z))
516
+ elif a.is_Integer or (2*a).is_Integer:
517
+ b = a - 1
518
+ if b.is_positive:
519
+ if a.is_integer:
520
+ return exp(-z) * factorial(b) * Add(*[z**k / factorial(k)
521
+ for k in range(a)])
522
+ else:
523
+ return (gamma(a) * erfc(sqrt(z)) +
524
+ S.NegativeOne**(a - S(3)/2) * exp(-z) * sqrt(z)
525
+ * Add(*[gamma(-S.Half - k) * (-z)**k / gamma(1-a)
526
+ for k in range(a - S.Half)]))
527
+ elif b.is_Integer:
528
+ return expint(-b, z)*unpolarify(z)**(b + 1)
529
+
530
+ if not a.is_Integer:
531
+ return (S.NegativeOne**(S.Half - a) * pi*erfc(sqrt(z))/gamma(1-a)
532
+ - z**a * exp(-z) * Add(*[z**k * gamma(a) / gamma(a+k+1)
533
+ for k in range(S.Half - a)]))
534
+
535
+ if a.is_zero and z.is_positive:
536
+ return -Ei(-z)
537
+
538
+ if z.is_zero and re(a).is_positive:
539
+ return gamma(a)
540
+
541
+ def _eval_conjugate(self):
542
+ z = self.args[1]
543
+ if z not in (S.Zero, S.NegativeInfinity):
544
+ return self.func(self.args[0].conjugate(), z.conjugate())
545
+
546
+ def _eval_is_meromorphic(self, x, a):
547
+ return lowergamma._eval_is_meromorphic(self, x, a)
548
+
549
+ def _eval_rewrite_as_lowergamma(self, s, x, **kwargs):
550
+ return gamma(s) - lowergamma(s, x)
551
+
552
+ def _eval_rewrite_as_tractable(self, s, x, **kwargs):
553
+ return exp(loggamma(s)) - lowergamma(s, x)
554
+
555
+ def _eval_rewrite_as_expint(self, s, x, **kwargs):
556
+ from sympy.functions.special.error_functions import expint
557
+ return expint(1 - s, x)*x**s
558
+
559
+
560
+ ###############################################################################
561
+ ###################### POLYGAMMA and LOGGAMMA FUNCTIONS #######################
562
+ ###############################################################################
563
+
564
+ class polygamma(DefinedFunction):
565
+ r"""
566
+ The function ``polygamma(n, z)`` returns ``log(gamma(z)).diff(n + 1)``.
567
+
568
+ Explanation
569
+ ===========
570
+
571
+ It is a meromorphic function on $\mathbb{C}$ and defined as the $(n+1)$-th
572
+ derivative of the logarithm of the gamma function:
573
+
574
+ .. math::
575
+ \psi^{(n)} (z) := \frac{\mathrm{d}^{n+1}}{\mathrm{d} z^{n+1}} \log\Gamma(z).
576
+
577
+ For `n` not a nonnegative integer the generalization by Espinosa and Moll [5]_
578
+ is used:
579
+
580
+ .. math:: \psi(s,z) = \frac{\zeta'(s+1, z) + (\gamma + \psi(-s)) \zeta(s+1, z)}
581
+ {\Gamma(-s)}
582
+
583
+ Examples
584
+ ========
585
+
586
+ Several special values are known:
587
+
588
+ >>> from sympy import S, polygamma
589
+ >>> polygamma(0, 1)
590
+ -EulerGamma
591
+ >>> polygamma(0, 1/S(2))
592
+ -2*log(2) - EulerGamma
593
+ >>> polygamma(0, 1/S(3))
594
+ -log(3) - sqrt(3)*pi/6 - EulerGamma - log(sqrt(3))
595
+ >>> polygamma(0, 1/S(4))
596
+ -pi/2 - log(4) - log(2) - EulerGamma
597
+ >>> polygamma(0, 2)
598
+ 1 - EulerGamma
599
+ >>> polygamma(0, 23)
600
+ 19093197/5173168 - EulerGamma
601
+
602
+ >>> from sympy import oo, I
603
+ >>> polygamma(0, oo)
604
+ oo
605
+ >>> polygamma(0, -oo)
606
+ oo
607
+ >>> polygamma(0, I*oo)
608
+ oo
609
+ >>> polygamma(0, -I*oo)
610
+ oo
611
+
612
+ Differentiation with respect to $x$ is supported:
613
+
614
+ >>> from sympy import Symbol, diff
615
+ >>> x = Symbol("x")
616
+ >>> diff(polygamma(0, x), x)
617
+ polygamma(1, x)
618
+ >>> diff(polygamma(0, x), x, 2)
619
+ polygamma(2, x)
620
+ >>> diff(polygamma(0, x), x, 3)
621
+ polygamma(3, x)
622
+ >>> diff(polygamma(1, x), x)
623
+ polygamma(2, x)
624
+ >>> diff(polygamma(1, x), x, 2)
625
+ polygamma(3, x)
626
+ >>> diff(polygamma(2, x), x)
627
+ polygamma(3, x)
628
+ >>> diff(polygamma(2, x), x, 2)
629
+ polygamma(4, x)
630
+
631
+ >>> n = Symbol("n")
632
+ >>> diff(polygamma(n, x), x)
633
+ polygamma(n + 1, x)
634
+ >>> diff(polygamma(n, x), x, 2)
635
+ polygamma(n + 2, x)
636
+
637
+ We can rewrite ``polygamma`` functions in terms of harmonic numbers:
638
+
639
+ >>> from sympy import harmonic
640
+ >>> polygamma(0, x).rewrite(harmonic)
641
+ harmonic(x - 1) - EulerGamma
642
+ >>> polygamma(2, x).rewrite(harmonic)
643
+ 2*harmonic(x - 1, 3) - 2*zeta(3)
644
+ >>> ni = Symbol("n", integer=True)
645
+ >>> polygamma(ni, x).rewrite(harmonic)
646
+ (-1)**(n + 1)*(-harmonic(x - 1, n + 1) + zeta(n + 1))*factorial(n)
647
+
648
+ See Also
649
+ ========
650
+
651
+ gamma: Gamma function.
652
+ lowergamma: Lower incomplete gamma function.
653
+ uppergamma: Upper incomplete gamma function.
654
+ loggamma: Log Gamma function.
655
+ digamma: Digamma function.
656
+ trigamma: Trigamma function.
657
+ sympy.functions.special.beta_functions.beta: Euler Beta function.
658
+
659
+ References
660
+ ==========
661
+
662
+ .. [1] https://en.wikipedia.org/wiki/Polygamma_function
663
+ .. [2] https://mathworld.wolfram.com/PolygammaFunction.html
664
+ .. [3] https://functions.wolfram.com/GammaBetaErf/PolyGamma/
665
+ .. [4] https://functions.wolfram.com/GammaBetaErf/PolyGamma2/
666
+ .. [5] O. Espinosa and V. Moll, "A generalized polygamma function",
667
+ *Integral Transforms and Special Functions* (2004), 101-115.
668
+
669
+ """
670
+
671
+ @classmethod
672
+ def eval(cls, n, z):
673
+ if n is S.NaN or z is S.NaN:
674
+ return S.NaN
675
+ elif z is oo:
676
+ return oo if n.is_zero else S.Zero
677
+ elif z.is_Integer and z.is_nonpositive:
678
+ return S.ComplexInfinity
679
+ elif n is S.NegativeOne:
680
+ return loggamma(z) - log(2*pi) / 2
681
+ elif n.is_zero:
682
+ if z is -oo or z.extract_multiplicatively(I) in (oo, -oo):
683
+ return oo
684
+ elif z.is_Integer:
685
+ return harmonic(z-1) - S.EulerGamma
686
+ elif z.is_Rational:
687
+ # TODO n == 1 also can do some rational z
688
+ p, q = z.as_numer_denom()
689
+ # only expand for small denominators to avoid creating long expressions
690
+ if q <= 6:
691
+ return expand_func(polygamma(S.Zero, z, evaluate=False))
692
+ elif n.is_integer and n.is_nonnegative:
693
+ nz = unpolarify(z)
694
+ if z != nz:
695
+ return polygamma(n, nz)
696
+ if z.is_Integer:
697
+ return S.NegativeOne**(n+1) * factorial(n) * zeta(n+1, z)
698
+ elif z is S.Half:
699
+ return S.NegativeOne**(n+1) * factorial(n) * (2**(n+1)-1) * zeta(n+1)
700
+
701
+ def _eval_is_real(self):
702
+ if self.args[0].is_positive and self.args[1].is_positive:
703
+ return True
704
+
705
+ def _eval_is_complex(self):
706
+ z = self.args[1]
707
+ is_negative_integer = fuzzy_and([z.is_negative, z.is_integer])
708
+ return fuzzy_and([z.is_complex, fuzzy_not(is_negative_integer)])
709
+
710
+ def _eval_is_positive(self):
711
+ n, z = self.args
712
+ if n.is_positive:
713
+ if n.is_odd and z.is_real:
714
+ return True
715
+ if n.is_even and z.is_positive:
716
+ return False
717
+
718
+ def _eval_is_negative(self):
719
+ n, z = self.args
720
+ if n.is_positive:
721
+ if n.is_even and z.is_positive:
722
+ return True
723
+ if n.is_odd and z.is_real:
724
+ return False
725
+
726
+ def _eval_expand_func(self, **hints):
727
+ n, z = self.args
728
+
729
+ if n.is_Integer and n.is_nonnegative:
730
+ if z.is_Add:
731
+ coeff = z.args[0]
732
+ if coeff.is_Integer:
733
+ e = -(n + 1)
734
+ if coeff > 0:
735
+ tail = Add(*[Pow(
736
+ z - i, e) for i in range(1, int(coeff) + 1)])
737
+ else:
738
+ tail = -Add(*[Pow(
739
+ z + i, e) for i in range(int(-coeff))])
740
+ return polygamma(n, z - coeff) + S.NegativeOne**n*factorial(n)*tail
741
+
742
+ elif z.is_Mul:
743
+ coeff, z = z.as_two_terms()
744
+ if coeff.is_Integer and coeff.is_positive:
745
+ tail = [polygamma(n, z + Rational(
746
+ i, coeff)) for i in range(int(coeff))]
747
+ if n == 0:
748
+ return Add(*tail)/coeff + log(coeff)
749
+ else:
750
+ return Add(*tail)/coeff**(n + 1)
751
+ z *= coeff
752
+
753
+ if n == 0 and z.is_Rational:
754
+ p, q = z.as_numer_denom()
755
+
756
+ # Reference:
757
+ # Values of the polygamma functions at rational arguments, J. Choi, 2007
758
+ part_1 = -S.EulerGamma - pi * cot(p * pi / q) / 2 - log(q) + Add(
759
+ *[cos(2 * k * pi * p / q) * log(2 * sin(k * pi / q)) for k in range(1, q)])
760
+
761
+ if z > 0:
762
+ n = floor(z)
763
+ z0 = z - n
764
+ return part_1 + Add(*[1 / (z0 + k) for k in range(n)])
765
+ elif z < 0:
766
+ n = floor(1 - z)
767
+ z0 = z + n
768
+ return part_1 - Add(*[1 / (z0 - 1 - k) for k in range(n)])
769
+
770
+ if n == -1:
771
+ return loggamma(z) - log(2*pi) / 2
772
+ if n.is_integer is False or n.is_nonnegative is False:
773
+ s = Dummy("s")
774
+ dzt = zeta(s, z).diff(s).subs(s, n+1)
775
+ return (dzt + (S.EulerGamma + digamma(-n)) * zeta(n+1, z)) / gamma(-n)
776
+
777
+ return polygamma(n, z)
778
+
779
+ def _eval_rewrite_as_zeta(self, n, z, **kwargs):
780
+ if n.is_integer and n.is_positive:
781
+ return S.NegativeOne**(n + 1)*factorial(n)*zeta(n + 1, z)
782
+
783
+ def _eval_rewrite_as_harmonic(self, n, z, **kwargs):
784
+ if n.is_integer:
785
+ if n.is_zero:
786
+ return harmonic(z - 1) - S.EulerGamma
787
+ else:
788
+ return S.NegativeOne**(n+1) * factorial(n) * (zeta(n+1) - harmonic(z-1, n+1))
789
+
790
+ def _eval_as_leading_term(self, x, logx, cdir):
791
+ from sympy.series.order import Order
792
+ n, z = [a.as_leading_term(x) for a in self.args]
793
+ o = Order(z, x)
794
+ if n == 0 and o.contains(1/x):
795
+ logx = log(x) if logx is None else logx
796
+ return o.getn() * logx
797
+ else:
798
+ return self.func(n, z)
799
+
800
+ def fdiff(self, argindex=2):
801
+ if argindex == 2:
802
+ n, z = self.args[:2]
803
+ return polygamma(n + 1, z)
804
+ else:
805
+ raise ArgumentIndexError(self, argindex)
806
+
807
+ def _eval_aseries(self, n, args0, x, logx):
808
+ from sympy.series.order import Order
809
+ if args0[1] != oo or not \
810
+ (self.args[0].is_Integer and self.args[0].is_nonnegative):
811
+ return super()._eval_aseries(n, args0, x, logx)
812
+ z = self.args[1]
813
+ N = self.args[0]
814
+
815
+ if N == 0:
816
+ # digamma function series
817
+ # Abramowitz & Stegun, p. 259, 6.3.18
818
+ r = log(z) - 1/(2*z)
819
+ o = None
820
+ if n < 2:
821
+ o = Order(1/z, x)
822
+ else:
823
+ m = ceiling((n + 1)//2)
824
+ l = [bernoulli(2*k) / (2*k*z**(2*k)) for k in range(1, m)]
825
+ r -= Add(*l)
826
+ o = Order(1/z**n, x)
827
+ return r._eval_nseries(x, n, logx) + o
828
+ else:
829
+ # proper polygamma function
830
+ # Abramowitz & Stegun, p. 260, 6.4.10
831
+ # We return terms to order higher than O(x**n) on purpose
832
+ # -- otherwise we would not be able to return any terms for
833
+ # quite a long time!
834
+ fac = gamma(N)
835
+ e0 = fac + N*fac/(2*z)
836
+ m = ceiling((n + 1)//2)
837
+ for k in range(1, m):
838
+ fac = fac*(2*k + N - 1)*(2*k + N - 2) / ((2*k)*(2*k - 1))
839
+ e0 += bernoulli(2*k)*fac/z**(2*k)
840
+ o = Order(1/z**(2*m), x)
841
+ if n == 0:
842
+ o = Order(1/z, x)
843
+ elif n == 1:
844
+ o = Order(1/z**2, x)
845
+ r = e0._eval_nseries(z, n, logx) + o
846
+ return (-1 * (-1/z)**N * r)._eval_nseries(x, n, logx)
847
+
848
+ def _eval_evalf(self, prec):
849
+ if not all(i.is_number for i in self.args):
850
+ return
851
+ s = self.args[0]._to_mpmath(prec+12)
852
+ z = self.args[1]._to_mpmath(prec+12)
853
+ if mp.isint(z) and z <= 0:
854
+ return S.ComplexInfinity
855
+ with workprec(prec+12):
856
+ if mp.isint(s) and s >= 0:
857
+ res = mp.polygamma(s, z)
858
+ else:
859
+ zt = mp.zeta(s+1, z)
860
+ dzt = mp.zeta(s+1, z, 1)
861
+ res = (dzt + (mp.euler + mp.digamma(-s)) * zt) * mp.rgamma(-s)
862
+ return Expr._from_mpmath(res, prec)
863
+
864
+
865
+ class loggamma(DefinedFunction):
866
+ r"""
867
+ The ``loggamma`` function implements the logarithm of the
868
+ gamma function (i.e., $\log\Gamma(x)$).
869
+
870
+ Examples
871
+ ========
872
+
873
+ Several special values are known. For numerical integral
874
+ arguments we have:
875
+
876
+ >>> from sympy import loggamma
877
+ >>> loggamma(-2)
878
+ oo
879
+ >>> loggamma(0)
880
+ oo
881
+ >>> loggamma(1)
882
+ 0
883
+ >>> loggamma(2)
884
+ 0
885
+ >>> loggamma(3)
886
+ log(2)
887
+
888
+ And for symbolic values:
889
+
890
+ >>> from sympy import Symbol
891
+ >>> n = Symbol("n", integer=True, positive=True)
892
+ >>> loggamma(n)
893
+ log(gamma(n))
894
+ >>> loggamma(-n)
895
+ oo
896
+
897
+ For half-integral values:
898
+
899
+ >>> from sympy import S
900
+ >>> loggamma(S(5)/2)
901
+ log(3*sqrt(pi)/4)
902
+ >>> loggamma(n/2)
903
+ log(2**(1 - n)*sqrt(pi)*gamma(n)/gamma(n/2 + 1/2))
904
+
905
+ And general rational arguments:
906
+
907
+ >>> from sympy import expand_func
908
+ >>> L = loggamma(S(16)/3)
909
+ >>> expand_func(L).doit()
910
+ -5*log(3) + loggamma(1/3) + log(4) + log(7) + log(10) + log(13)
911
+ >>> L = loggamma(S(19)/4)
912
+ >>> expand_func(L).doit()
913
+ -4*log(4) + loggamma(3/4) + log(3) + log(7) + log(11) + log(15)
914
+ >>> L = loggamma(S(23)/7)
915
+ >>> expand_func(L).doit()
916
+ -3*log(7) + log(2) + loggamma(2/7) + log(9) + log(16)
917
+
918
+ The ``loggamma`` function has the following limits towards infinity:
919
+
920
+ >>> from sympy import oo
921
+ >>> loggamma(oo)
922
+ oo
923
+ >>> loggamma(-oo)
924
+ zoo
925
+
926
+ The ``loggamma`` function obeys the mirror symmetry
927
+ if $x \in \mathbb{C} \setminus \{-\infty, 0\}$:
928
+
929
+ >>> from sympy.abc import x
930
+ >>> from sympy import conjugate
931
+ >>> conjugate(loggamma(x))
932
+ loggamma(conjugate(x))
933
+
934
+ Differentiation with respect to $x$ is supported:
935
+
936
+ >>> from sympy import diff
937
+ >>> diff(loggamma(x), x)
938
+ polygamma(0, x)
939
+
940
+ Series expansion is also supported:
941
+
942
+ >>> from sympy import series
943
+ >>> series(loggamma(x), x, 0, 4).cancel()
944
+ -log(x) - EulerGamma*x + pi**2*x**2/12 - x**3*zeta(3)/3 + O(x**4)
945
+
946
+ We can numerically evaluate the ``loggamma`` function
947
+ to arbitrary precision on the whole complex plane:
948
+
949
+ >>> from sympy import I
950
+ >>> loggamma(5).evalf(30)
951
+ 3.17805383034794561964694160130
952
+ >>> loggamma(I).evalf(20)
953
+ -0.65092319930185633889 - 1.8724366472624298171*I
954
+
955
+ See Also
956
+ ========
957
+
958
+ gamma: Gamma function.
959
+ lowergamma: Lower incomplete gamma function.
960
+ uppergamma: Upper incomplete gamma function.
961
+ polygamma: Polygamma function.
962
+ digamma: Digamma function.
963
+ trigamma: Trigamma function.
964
+ sympy.functions.special.beta_functions.beta: Euler Beta function.
965
+
966
+ References
967
+ ==========
968
+
969
+ .. [1] https://en.wikipedia.org/wiki/Gamma_function
970
+ .. [2] https://dlmf.nist.gov/5
971
+ .. [3] https://mathworld.wolfram.com/LogGammaFunction.html
972
+ .. [4] https://functions.wolfram.com/GammaBetaErf/LogGamma/
973
+
974
+ """
975
+ @classmethod
976
+ def eval(cls, z):
977
+ if z.is_integer:
978
+ if z.is_nonpositive:
979
+ return oo
980
+ elif z.is_positive:
981
+ return log(gamma(z))
982
+ elif z.is_rational:
983
+ p, q = z.as_numer_denom()
984
+ # Half-integral values:
985
+ if p.is_positive and q == 2:
986
+ return log(sqrt(pi) * 2**(1 - p) * gamma(p) / gamma((p + 1)*S.Half))
987
+
988
+ if z is oo:
989
+ return oo
990
+ elif abs(z) is oo:
991
+ return S.ComplexInfinity
992
+ if z is S.NaN:
993
+ return S.NaN
994
+
995
+ def _eval_expand_func(self, **hints):
996
+ from sympy.concrete.summations import Sum
997
+ z = self.args[0]
998
+
999
+ if z.is_Rational:
1000
+ p, q = z.as_numer_denom()
1001
+ # General rational arguments (u + p/q)
1002
+ # Split z as n + p/q with p < q
1003
+ n = p // q
1004
+ p = p - n*q
1005
+ if p.is_positive and q.is_positive and p < q:
1006
+ k = Dummy("k")
1007
+ if n.is_positive:
1008
+ return loggamma(p / q) - n*log(q) + Sum(log((k - 1)*q + p), (k, 1, n))
1009
+ elif n.is_negative:
1010
+ return loggamma(p / q) - n*log(q) + pi*I*n - Sum(log(k*q - p), (k, 1, -n))
1011
+ elif n.is_zero:
1012
+ return loggamma(p / q)
1013
+
1014
+ return self
1015
+
1016
+ def _eval_nseries(self, x, n, logx=None, cdir=0):
1017
+ x0 = self.args[0].limit(x, 0)
1018
+ if x0.is_zero:
1019
+ f = self._eval_rewrite_as_intractable(*self.args)
1020
+ return f._eval_nseries(x, n, logx)
1021
+ return super()._eval_nseries(x, n, logx)
1022
+
1023
+ def _eval_aseries(self, n, args0, x, logx):
1024
+ from sympy.series.order import Order
1025
+ if args0[0] != oo:
1026
+ return super()._eval_aseries(n, args0, x, logx)
1027
+ z = self.args[0]
1028
+ r = log(z)*(z - S.Half) - z + log(2*pi)/2
1029
+ l = [bernoulli(2*k) / (2*k*(2*k - 1)*z**(2*k - 1)) for k in range(1, n)]
1030
+ o = None
1031
+ if n == 0:
1032
+ o = Order(1, x)
1033
+ else:
1034
+ o = Order(1/z**n, x)
1035
+ # It is very inefficient to first add the order and then do the nseries
1036
+ return (r + Add(*l))._eval_nseries(x, n, logx) + o
1037
+
1038
+ def _eval_rewrite_as_intractable(self, z, **kwargs):
1039
+ return log(gamma(z))
1040
+
1041
+ def _eval_is_real(self):
1042
+ z = self.args[0]
1043
+ if z.is_positive:
1044
+ return True
1045
+ elif z.is_nonpositive:
1046
+ return False
1047
+
1048
+ def _eval_conjugate(self):
1049
+ z = self.args[0]
1050
+ if z not in (S.Zero, S.NegativeInfinity):
1051
+ return self.func(z.conjugate())
1052
+
1053
+ def fdiff(self, argindex=1):
1054
+ if argindex == 1:
1055
+ return polygamma(0, self.args[0])
1056
+ else:
1057
+ raise ArgumentIndexError(self, argindex)
1058
+
1059
+
1060
+ class digamma(DefinedFunction):
1061
+ r"""
1062
+ The ``digamma`` function is the first derivative of the ``loggamma``
1063
+ function
1064
+
1065
+ .. math::
1066
+ \psi(x) := \frac{\mathrm{d}}{\mathrm{d} z} \log\Gamma(z)
1067
+ = \frac{\Gamma'(z)}{\Gamma(z) }.
1068
+
1069
+ In this case, ``digamma(z) = polygamma(0, z)``.
1070
+
1071
+ Examples
1072
+ ========
1073
+
1074
+ >>> from sympy import digamma
1075
+ >>> digamma(0)
1076
+ zoo
1077
+ >>> from sympy import Symbol
1078
+ >>> z = Symbol('z')
1079
+ >>> digamma(z)
1080
+ polygamma(0, z)
1081
+
1082
+ To retain ``digamma`` as it is:
1083
+
1084
+ >>> digamma(0, evaluate=False)
1085
+ digamma(0)
1086
+ >>> digamma(z, evaluate=False)
1087
+ digamma(z)
1088
+
1089
+ See Also
1090
+ ========
1091
+
1092
+ gamma: Gamma function.
1093
+ lowergamma: Lower incomplete gamma function.
1094
+ uppergamma: Upper incomplete gamma function.
1095
+ polygamma: Polygamma function.
1096
+ loggamma: Log Gamma function.
1097
+ trigamma: Trigamma function.
1098
+ sympy.functions.special.beta_functions.beta: Euler Beta function.
1099
+
1100
+ References
1101
+ ==========
1102
+
1103
+ .. [1] https://en.wikipedia.org/wiki/Digamma_function
1104
+ .. [2] https://mathworld.wolfram.com/DigammaFunction.html
1105
+ .. [3] https://functions.wolfram.com/GammaBetaErf/PolyGamma2/
1106
+
1107
+ """
1108
+ def _eval_evalf(self, prec):
1109
+ z = self.args[0]
1110
+ nprec = prec_to_dps(prec)
1111
+ return polygamma(0, z).evalf(n=nprec)
1112
+
1113
+ def fdiff(self, argindex=1):
1114
+ z = self.args[0]
1115
+ return polygamma(0, z).fdiff()
1116
+
1117
+ def _eval_is_real(self):
1118
+ z = self.args[0]
1119
+ return polygamma(0, z).is_real
1120
+
1121
+ def _eval_is_positive(self):
1122
+ z = self.args[0]
1123
+ return polygamma(0, z).is_positive
1124
+
1125
+ def _eval_is_negative(self):
1126
+ z = self.args[0]
1127
+ return polygamma(0, z).is_negative
1128
+
1129
+ def _eval_aseries(self, n, args0, x, logx):
1130
+ as_polygamma = self.rewrite(polygamma)
1131
+ args0 = [S.Zero,] + args0
1132
+ return as_polygamma._eval_aseries(n, args0, x, logx)
1133
+
1134
+ @classmethod
1135
+ def eval(cls, z):
1136
+ return polygamma(0, z)
1137
+
1138
+ def _eval_expand_func(self, **hints):
1139
+ z = self.args[0]
1140
+ return polygamma(0, z).expand(func=True)
1141
+
1142
+ def _eval_rewrite_as_harmonic(self, z, **kwargs):
1143
+ return harmonic(z - 1) - S.EulerGamma
1144
+
1145
+ def _eval_rewrite_as_polygamma(self, z, **kwargs):
1146
+ return polygamma(0, z)
1147
+
1148
+ def _eval_as_leading_term(self, x, logx, cdir):
1149
+ z = self.args[0]
1150
+ return polygamma(0, z).as_leading_term(x)
1151
+
1152
+
1153
+
1154
+ class trigamma(DefinedFunction):
1155
+ r"""
1156
+ The ``trigamma`` function is the second derivative of the ``loggamma``
1157
+ function
1158
+
1159
+ .. math::
1160
+ \psi^{(1)}(z) := \frac{\mathrm{d}^{2}}{\mathrm{d} z^{2}} \log\Gamma(z).
1161
+
1162
+ In this case, ``trigamma(z) = polygamma(1, z)``.
1163
+
1164
+ Examples
1165
+ ========
1166
+
1167
+ >>> from sympy import trigamma
1168
+ >>> trigamma(0)
1169
+ zoo
1170
+ >>> from sympy import Symbol
1171
+ >>> z = Symbol('z')
1172
+ >>> trigamma(z)
1173
+ polygamma(1, z)
1174
+
1175
+ To retain ``trigamma`` as it is:
1176
+
1177
+ >>> trigamma(0, evaluate=False)
1178
+ trigamma(0)
1179
+ >>> trigamma(z, evaluate=False)
1180
+ trigamma(z)
1181
+
1182
+
1183
+ See Also
1184
+ ========
1185
+
1186
+ gamma: Gamma function.
1187
+ lowergamma: Lower incomplete gamma function.
1188
+ uppergamma: Upper incomplete gamma function.
1189
+ polygamma: Polygamma function.
1190
+ loggamma: Log Gamma function.
1191
+ digamma: Digamma function.
1192
+ sympy.functions.special.beta_functions.beta: Euler Beta function.
1193
+
1194
+ References
1195
+ ==========
1196
+
1197
+ .. [1] https://en.wikipedia.org/wiki/Trigamma_function
1198
+ .. [2] https://mathworld.wolfram.com/TrigammaFunction.html
1199
+ .. [3] https://functions.wolfram.com/GammaBetaErf/PolyGamma2/
1200
+
1201
+ """
1202
+ def _eval_evalf(self, prec):
1203
+ z = self.args[0]
1204
+ nprec = prec_to_dps(prec)
1205
+ return polygamma(1, z).evalf(n=nprec)
1206
+
1207
+ def fdiff(self, argindex=1):
1208
+ z = self.args[0]
1209
+ return polygamma(1, z).fdiff()
1210
+
1211
+ def _eval_is_real(self):
1212
+ z = self.args[0]
1213
+ return polygamma(1, z).is_real
1214
+
1215
+ def _eval_is_positive(self):
1216
+ z = self.args[0]
1217
+ return polygamma(1, z).is_positive
1218
+
1219
+ def _eval_is_negative(self):
1220
+ z = self.args[0]
1221
+ return polygamma(1, z).is_negative
1222
+
1223
+ def _eval_aseries(self, n, args0, x, logx):
1224
+ as_polygamma = self.rewrite(polygamma)
1225
+ args0 = [S.One,] + args0
1226
+ return as_polygamma._eval_aseries(n, args0, x, logx)
1227
+
1228
+ @classmethod
1229
+ def eval(cls, z):
1230
+ return polygamma(1, z)
1231
+
1232
+ def _eval_expand_func(self, **hints):
1233
+ z = self.args[0]
1234
+ return polygamma(1, z).expand(func=True)
1235
+
1236
+ def _eval_rewrite_as_zeta(self, z, **kwargs):
1237
+ return zeta(2, z)
1238
+
1239
+ def _eval_rewrite_as_polygamma(self, z, **kwargs):
1240
+ return polygamma(1, z)
1241
+
1242
+ def _eval_rewrite_as_harmonic(self, z, **kwargs):
1243
+ return -harmonic(z - 1, 2) + pi**2 / 6
1244
+
1245
+ def _eval_as_leading_term(self, x, logx, cdir):
1246
+ z = self.args[0]
1247
+ return polygamma(1, z).as_leading_term(x)
1248
+
1249
+
1250
+ ###############################################################################
1251
+ ##################### COMPLETE MULTIVARIATE GAMMA FUNCTION ####################
1252
+ ###############################################################################
1253
+
1254
+
1255
+ class multigamma(DefinedFunction):
1256
+ r"""
1257
+ The multivariate gamma function is a generalization of the gamma function
1258
+
1259
+ .. math::
1260
+ \Gamma_p(z) = \pi^{p(p-1)/4}\prod_{k=1}^p \Gamma[z + (1 - k)/2].
1261
+
1262
+ In a special case, ``multigamma(x, 1) = gamma(x)``.
1263
+
1264
+ Examples
1265
+ ========
1266
+
1267
+ >>> from sympy import S, multigamma
1268
+ >>> from sympy import Symbol
1269
+ >>> x = Symbol('x')
1270
+ >>> p = Symbol('p', positive=True, integer=True)
1271
+
1272
+ >>> multigamma(x, p)
1273
+ pi**(p*(p - 1)/4)*Product(gamma(-_k/2 + x + 1/2), (_k, 1, p))
1274
+
1275
+ Several special values are known:
1276
+
1277
+ >>> multigamma(1, 1)
1278
+ 1
1279
+ >>> multigamma(4, 1)
1280
+ 6
1281
+ >>> multigamma(S(3)/2, 1)
1282
+ sqrt(pi)/2
1283
+
1284
+ Writing ``multigamma`` in terms of the ``gamma`` function:
1285
+
1286
+ >>> multigamma(x, 1)
1287
+ gamma(x)
1288
+
1289
+ >>> multigamma(x, 2)
1290
+ sqrt(pi)*gamma(x)*gamma(x - 1/2)
1291
+
1292
+ >>> multigamma(x, 3)
1293
+ pi**(3/2)*gamma(x)*gamma(x - 1)*gamma(x - 1/2)
1294
+
1295
+ Parameters
1296
+ ==========
1297
+
1298
+ p : order or dimension of the multivariate gamma function
1299
+
1300
+ See Also
1301
+ ========
1302
+
1303
+ gamma, lowergamma, uppergamma, polygamma, loggamma, digamma, trigamma,
1304
+ sympy.functions.special.beta_functions.beta
1305
+
1306
+ References
1307
+ ==========
1308
+
1309
+ .. [1] https://en.wikipedia.org/wiki/Multivariate_gamma_function
1310
+
1311
+ """
1312
+ unbranched = True
1313
+
1314
+ def fdiff(self, argindex=2):
1315
+ from sympy.concrete.summations import Sum
1316
+ if argindex == 2:
1317
+ x, p = self.args
1318
+ k = Dummy("k")
1319
+ return self.func(x, p)*Sum(polygamma(0, x + (1 - k)/2), (k, 1, p))
1320
+ else:
1321
+ raise ArgumentIndexError(self, argindex)
1322
+
1323
+ @classmethod
1324
+ def eval(cls, x, p):
1325
+ from sympy.concrete.products import Product
1326
+ if p.is_positive is False or p.is_integer is False:
1327
+ raise ValueError('Order parameter p must be positive integer.')
1328
+ k = Dummy("k")
1329
+ return (pi**(p*(p - 1)/4)*Product(gamma(x + (1 - k)/2),
1330
+ (k, 1, p))).doit()
1331
+
1332
+ def _eval_conjugate(self):
1333
+ x, p = self.args
1334
+ return self.func(x.conjugate(), p)
1335
+
1336
+ def _eval_is_real(self):
1337
+ x, p = self.args
1338
+ y = 2*x
1339
+ if y.is_integer and (y <= (p - 1)) is True:
1340
+ return False
1341
+ if intlike(y) and (y <= (p - 1)):
1342
+ return False
1343
+ if y > (p - 1) or y.is_noninteger:
1344
+ return True
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/hyper.py ADDED
@@ -0,0 +1,1185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Hypergeometric and Meijer G-functions"""
2
+ from collections import Counter
3
+
4
+ from sympy.core import S, Mod
5
+ from sympy.core.add import Add
6
+ from sympy.core.expr import Expr
7
+ from sympy.core.function import DefinedFunction, Derivative, ArgumentIndexError
8
+
9
+ from sympy.core.containers import Tuple
10
+ from sympy.core.mul import Mul
11
+ from sympy.core.numbers import I, pi, oo, zoo
12
+ from sympy.core.parameters import global_parameters
13
+ from sympy.core.relational import Ne
14
+ from sympy.core.sorting import default_sort_key
15
+ from sympy.core.symbol import Dummy
16
+
17
+ from sympy.external.gmpy import lcm
18
+ from sympy.functions import (sqrt, exp, log, sin, cos, asin, atan,
19
+ sinh, cosh, asinh, acosh, atanh, acoth)
20
+ from sympy.functions import factorial, RisingFactorial
21
+ from sympy.functions.elementary.complexes import Abs, re, unpolarify
22
+ from sympy.functions.elementary.exponential import exp_polar
23
+ from sympy.functions.elementary.integers import ceiling
24
+ from sympy.functions.elementary.piecewise import Piecewise
25
+ from sympy.logic.boolalg import (And, Or)
26
+ from sympy import ordered
27
+
28
+
29
+ class TupleArg(Tuple):
30
+
31
+ # This method is only needed because hyper._eval_as_leading_term falls back
32
+ # (via super()) on using Function._eval_as_leading_term, which in turn
33
+ # calls as_leading_term on the args of the hyper. Ideally hyper should just
34
+ # have an _eval_as_leading_term method that handles all cases and this
35
+ # method should be removed because leading terms of tuples don't make
36
+ # sense.
37
+ def as_leading_term(self, *x, logx=None, cdir=0):
38
+ return TupleArg(*[f.as_leading_term(*x, logx=logx, cdir=cdir) for f in self.args])
39
+
40
+ def limit(self, x, xlim, dir='+'):
41
+ """ Compute limit x->xlim.
42
+ """
43
+ from sympy.series.limits import limit
44
+ return TupleArg(*[limit(f, x, xlim, dir) for f in self.args])
45
+
46
+
47
+ # TODO should __new__ accept **options?
48
+ # TODO should constructors should check if parameters are sensible?
49
+
50
+
51
+ def _prep_tuple(v):
52
+ """
53
+ Turn an iterable argument *v* into a tuple and unpolarify, since both
54
+ hypergeometric and meijer g-functions are unbranched in their parameters.
55
+
56
+ Examples
57
+ ========
58
+
59
+ >>> from sympy.functions.special.hyper import _prep_tuple
60
+ >>> _prep_tuple([1, 2, 3])
61
+ (1, 2, 3)
62
+ >>> _prep_tuple((4, 5))
63
+ (4, 5)
64
+ >>> _prep_tuple((7, 8, 9))
65
+ (7, 8, 9)
66
+
67
+ """
68
+ return TupleArg(*[unpolarify(x) for x in v])
69
+
70
+
71
+ class TupleParametersBase(DefinedFunction):
72
+ """ Base class that takes care of differentiation, when some of
73
+ the arguments are actually tuples. """
74
+ # This is not deduced automatically since there are Tuples as arguments.
75
+ is_commutative = True
76
+
77
+ def _eval_derivative(self, s):
78
+ try:
79
+ res = 0
80
+ if self.args[0].has(s) or self.args[1].has(s):
81
+ for i, p in enumerate(self._diffargs):
82
+ m = self._diffargs[i].diff(s)
83
+ if m != 0:
84
+ res += self.fdiff((1, i))*m
85
+ return res + self.fdiff(3)*self.args[2].diff(s)
86
+ except (ArgumentIndexError, NotImplementedError):
87
+ return Derivative(self, s)
88
+
89
+
90
+ class hyper(TupleParametersBase):
91
+ r"""
92
+ The generalized hypergeometric function is defined by a series where
93
+ the ratios of successive terms are a rational function of the summation
94
+ index. When convergent, it is continued analytically to the largest
95
+ possible domain.
96
+
97
+ Explanation
98
+ ===========
99
+
100
+ The hypergeometric function depends on two vectors of parameters, called
101
+ the numerator parameters $a_p$, and the denominator parameters
102
+ $b_q$. It also has an argument $z$. The series definition is
103
+
104
+ .. math ::
105
+ {}_pF_q\left(\begin{matrix} a_1, \cdots, a_p \\ b_1, \cdots, b_q \end{matrix}
106
+ \middle| z \right)
107
+ = \sum_{n=0}^\infty \frac{(a_1)_n \cdots (a_p)_n}{(b_1)_n \cdots (b_q)_n}
108
+ \frac{z^n}{n!},
109
+
110
+ where $(a)_n = (a)(a+1)\cdots(a+n-1)$ denotes the rising factorial.
111
+
112
+ If one of the $b_q$ is a non-positive integer then the series is
113
+ undefined unless one of the $a_p$ is a larger (i.e., smaller in
114
+ magnitude) non-positive integer. If none of the $b_q$ is a
115
+ non-positive integer and one of the $a_p$ is a non-positive
116
+ integer, then the series reduces to a polynomial. To simplify the
117
+ following discussion, we assume that none of the $a_p$ or
118
+ $b_q$ is a non-positive integer. For more details, see the
119
+ references.
120
+
121
+ The series converges for all $z$ if $p \le q$, and thus
122
+ defines an entire single-valued function in this case. If $p =
123
+ q+1$ the series converges for $|z| < 1$, and can be continued
124
+ analytically into a half-plane. If $p > q+1$ the series is
125
+ divergent for all $z$.
126
+
127
+ Please note the hypergeometric function constructor currently does *not*
128
+ check if the parameters actually yield a well-defined function.
129
+
130
+ Examples
131
+ ========
132
+
133
+ The parameters $a_p$ and $b_q$ can be passed as arbitrary
134
+ iterables, for example:
135
+
136
+ >>> from sympy import hyper
137
+ >>> from sympy.abc import x, n, a
138
+ >>> h = hyper((1, 2, 3), [3, 4], x); h
139
+ hyper((1, 2), (4,), x)
140
+ >>> hyper((3, 1, 2), [3, 4], x, evaluate=False) # don't remove duplicates
141
+ hyper((1, 2, 3), (3, 4), x)
142
+
143
+ There is also pretty printing (it looks better using Unicode):
144
+
145
+ >>> from sympy import pprint
146
+ >>> pprint(h, use_unicode=False)
147
+ _
148
+ |_ /1, 2 | \
149
+ | | | x|
150
+ 2 1 \ 4 | /
151
+
152
+ The parameters must always be iterables, even if they are vectors of
153
+ length one or zero:
154
+
155
+ >>> hyper((1, ), [], x)
156
+ hyper((1,), (), x)
157
+
158
+ But of course they may be variables (but if they depend on $x$ then you
159
+ should not expect much implemented functionality):
160
+
161
+ >>> hyper((n, a), (n**2,), x)
162
+ hyper((a, n), (n**2,), x)
163
+
164
+ The hypergeometric function generalizes many named special functions.
165
+ The function ``hyperexpand()`` tries to express a hypergeometric function
166
+ using named special functions. For example:
167
+
168
+ >>> from sympy import hyperexpand
169
+ >>> hyperexpand(hyper([], [], x))
170
+ exp(x)
171
+
172
+ You can also use ``expand_func()``:
173
+
174
+ >>> from sympy import expand_func
175
+ >>> expand_func(x*hyper([1, 1], [2], -x))
176
+ log(x + 1)
177
+
178
+ More examples:
179
+
180
+ >>> from sympy import S
181
+ >>> hyperexpand(hyper([], [S(1)/2], -x**2/4))
182
+ cos(x)
183
+ >>> hyperexpand(x*hyper([S(1)/2, S(1)/2], [S(3)/2], x**2))
184
+ asin(x)
185
+
186
+ We can also sometimes ``hyperexpand()`` parametric functions:
187
+
188
+ >>> from sympy.abc import a
189
+ >>> hyperexpand(hyper([-a], [], x))
190
+ (1 - x)**a
191
+
192
+ See Also
193
+ ========
194
+
195
+ sympy.simplify.hyperexpand
196
+ gamma
197
+ meijerg
198
+
199
+ References
200
+ ==========
201
+
202
+ .. [1] Luke, Y. L. (1969), The Special Functions and Their Approximations,
203
+ Volume 1
204
+ .. [2] https://en.wikipedia.org/wiki/Generalized_hypergeometric_function
205
+
206
+ """
207
+
208
+
209
+ def __new__(cls, ap, bq, z, **kwargs):
210
+ # TODO should we check convergence conditions?
211
+ if kwargs.pop('evaluate', global_parameters.evaluate):
212
+ ca = Counter(Tuple(*ap))
213
+ cb = Counter(Tuple(*bq))
214
+ common = ca & cb
215
+ arg = ap, bq = [], []
216
+ for i, c in enumerate((ca, cb)):
217
+ c -= common
218
+ for k in ordered(c):
219
+ arg[i].extend([k]*c[k])
220
+ else:
221
+ ap = list(ordered(ap))
222
+ bq = list(ordered(bq))
223
+ return super().__new__(cls, _prep_tuple(ap), _prep_tuple(bq), z, **kwargs)
224
+
225
+ @classmethod
226
+ def eval(cls, ap, bq, z):
227
+ if len(ap) <= len(bq) or (len(ap) == len(bq) + 1 and (Abs(z) <= 1) == True):
228
+ nz = unpolarify(z)
229
+ if z != nz:
230
+ return hyper(ap, bq, nz)
231
+
232
+ def fdiff(self, argindex=3):
233
+ if argindex != 3:
234
+ raise ArgumentIndexError(self, argindex)
235
+ nap = Tuple(*[a + 1 for a in self.ap])
236
+ nbq = Tuple(*[b + 1 for b in self.bq])
237
+ fac = Mul(*self.ap)/Mul(*self.bq)
238
+ return fac*hyper(nap, nbq, self.argument)
239
+
240
+ def _eval_expand_func(self, **hints):
241
+ from sympy.functions.special.gamma_functions import gamma
242
+ from sympy.simplify.hyperexpand import hyperexpand
243
+ if len(self.ap) == 2 and len(self.bq) == 1 and self.argument == 1:
244
+ a, b = self.ap
245
+ c = self.bq[0]
246
+ return gamma(c)*gamma(c - a - b)/gamma(c - a)/gamma(c - b)
247
+ return hyperexpand(self)
248
+
249
+ def _eval_rewrite_as_Sum(self, ap, bq, z, **kwargs):
250
+ from sympy.concrete.summations import Sum
251
+ n = Dummy("n", integer=True)
252
+ rfap = [RisingFactorial(a, n) for a in ap]
253
+ rfbq = [RisingFactorial(b, n) for b in bq]
254
+ coeff = Mul(*rfap) / Mul(*rfbq)
255
+ return Piecewise((Sum(coeff * z**n / factorial(n), (n, 0, oo)),
256
+ self.convergence_statement), (self, True))
257
+
258
+ def _eval_as_leading_term(self, x, logx, cdir):
259
+ arg = self.args[2]
260
+ x0 = arg.subs(x, 0)
261
+ if x0 is S.NaN:
262
+ x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
263
+
264
+ if x0 is S.Zero:
265
+ return S.One
266
+ return super()._eval_as_leading_term(x, logx=logx, cdir=cdir)
267
+
268
+ def _eval_nseries(self, x, n, logx, cdir=0):
269
+
270
+ from sympy.series.order import Order
271
+
272
+ arg = self.args[2]
273
+ x0 = arg.limit(x, 0)
274
+ ap = self.args[0]
275
+ bq = self.args[1]
276
+
277
+ if not (arg == x and x0 == 0):
278
+ # It would be better to do something with arg.nseries here, rather
279
+ # than falling back on Function._eval_nseries. The code below
280
+ # though is not sufficient if arg is something like x/(x+1).
281
+ from sympy.simplify.hyperexpand import hyperexpand
282
+ return hyperexpand(super()._eval_nseries(x, n, logx))
283
+
284
+ terms = []
285
+
286
+ for i in range(n):
287
+ num = Mul(*[RisingFactorial(a, i) for a in ap])
288
+ den = Mul(*[RisingFactorial(b, i) for b in bq])
289
+ terms.append(((num/den) * (arg**i)) / factorial(i))
290
+
291
+ return (Add(*terms) + Order(x**n,x))
292
+
293
+ @property
294
+ def argument(self):
295
+ """ Argument of the hypergeometric function. """
296
+ return self.args[2]
297
+
298
+ @property
299
+ def ap(self):
300
+ """ Numerator parameters of the hypergeometric function. """
301
+ return Tuple(*self.args[0])
302
+
303
+ @property
304
+ def bq(self):
305
+ """ Denominator parameters of the hypergeometric function. """
306
+ return Tuple(*self.args[1])
307
+
308
+ @property
309
+ def _diffargs(self):
310
+ return self.ap + self.bq
311
+
312
+ @property
313
+ def eta(self):
314
+ """ A quantity related to the convergence of the series. """
315
+ return sum(self.ap) - sum(self.bq)
316
+
317
+ @property
318
+ def radius_of_convergence(self):
319
+ """
320
+ Compute the radius of convergence of the defining series.
321
+
322
+ Explanation
323
+ ===========
324
+
325
+ Note that even if this is not ``oo``, the function may still be
326
+ evaluated outside of the radius of convergence by analytic
327
+ continuation. But if this is zero, then the function is not actually
328
+ defined anywhere else.
329
+
330
+ Examples
331
+ ========
332
+
333
+ >>> from sympy import hyper
334
+ >>> from sympy.abc import z
335
+ >>> hyper((1, 2), [3], z).radius_of_convergence
336
+ 1
337
+ >>> hyper((1, 2, 3), [4], z).radius_of_convergence
338
+ 0
339
+ >>> hyper((1, 2), (3, 4), z).radius_of_convergence
340
+ oo
341
+
342
+ """
343
+ if any(a.is_integer and (a <= 0) == True for a in self.ap + self.bq):
344
+ aints = [a for a in self.ap if a.is_Integer and (a <= 0) == True]
345
+ bints = [a for a in self.bq if a.is_Integer and (a <= 0) == True]
346
+ if len(aints) < len(bints):
347
+ return S.Zero
348
+ popped = False
349
+ for b in bints:
350
+ cancelled = False
351
+ while aints:
352
+ a = aints.pop()
353
+ if a >= b:
354
+ cancelled = True
355
+ break
356
+ popped = True
357
+ if not cancelled:
358
+ return S.Zero
359
+ if aints or popped:
360
+ # There are still non-positive numerator parameters.
361
+ # This is a polynomial.
362
+ return oo
363
+ if len(self.ap) == len(self.bq) + 1:
364
+ return S.One
365
+ elif len(self.ap) <= len(self.bq):
366
+ return oo
367
+ else:
368
+ return S.Zero
369
+
370
+ @property
371
+ def convergence_statement(self):
372
+ """ Return a condition on z under which the series converges. """
373
+ R = self.radius_of_convergence
374
+ if R == 0:
375
+ return False
376
+ if R == oo:
377
+ return True
378
+ # The special functions and their approximations, page 44
379
+ e = self.eta
380
+ z = self.argument
381
+ c1 = And(re(e) < 0, abs(z) <= 1)
382
+ c2 = And(0 <= re(e), re(e) < 1, abs(z) <= 1, Ne(z, 1))
383
+ c3 = And(re(e) >= 1, abs(z) < 1)
384
+ return Or(c1, c2, c3)
385
+
386
+ def _eval_simplify(self, **kwargs):
387
+ from sympy.simplify.hyperexpand import hyperexpand
388
+ return hyperexpand(self)
389
+
390
+
391
+ class meijerg(TupleParametersBase):
392
+ r"""
393
+ The Meijer G-function is defined by a Mellin-Barnes type integral that
394
+ resembles an inverse Mellin transform. It generalizes the hypergeometric
395
+ functions.
396
+
397
+ Explanation
398
+ ===========
399
+
400
+ The Meijer G-function depends on four sets of parameters. There are
401
+ "*numerator parameters*"
402
+ $a_1, \ldots, a_n$ and $a_{n+1}, \ldots, a_p$, and there are
403
+ "*denominator parameters*"
404
+ $b_1, \ldots, b_m$ and $b_{m+1}, \ldots, b_q$.
405
+ Confusingly, it is traditionally denoted as follows (note the position
406
+ of $m$, $n$, $p$, $q$, and how they relate to the lengths of the four
407
+ parameter vectors):
408
+
409
+ .. math ::
410
+ G_{p,q}^{m,n} \left(\begin{matrix}a_1, \cdots, a_n & a_{n+1}, \cdots, a_p \\
411
+ b_1, \cdots, b_m & b_{m+1}, \cdots, b_q
412
+ \end{matrix} \middle| z \right).
413
+
414
+ However, in SymPy the four parameter vectors are always available
415
+ separately (see examples), so that there is no need to keep track of the
416
+ decorating sub- and super-scripts on the G symbol.
417
+
418
+ The G function is defined as the following integral:
419
+
420
+ .. math ::
421
+ \frac{1}{2 \pi i} \int_L \frac{\prod_{j=1}^m \Gamma(b_j - s)
422
+ \prod_{j=1}^n \Gamma(1 - a_j + s)}{\prod_{j=m+1}^q \Gamma(1- b_j +s)
423
+ \prod_{j=n+1}^p \Gamma(a_j - s)} z^s \mathrm{d}s,
424
+
425
+ where $\Gamma(z)$ is the gamma function. There are three possible
426
+ contours which we will not describe in detail here (see the references).
427
+ If the integral converges along more than one of them, the definitions
428
+ agree. The contours all separate the poles of $\Gamma(1-a_j+s)$
429
+ from the poles of $\Gamma(b_k-s)$, so in particular the G function
430
+ is undefined if $a_j - b_k \in \mathbb{Z}_{>0}$ for some
431
+ $j \le n$ and $k \le m$.
432
+
433
+ The conditions under which one of the contours yields a convergent integral
434
+ are complicated and we do not state them here, see the references.
435
+
436
+ Please note currently the Meijer G-function constructor does *not* check any
437
+ convergence conditions.
438
+
439
+ Examples
440
+ ========
441
+
442
+ You can pass the parameters either as four separate vectors:
443
+
444
+ >>> from sympy import meijerg, Tuple, pprint
445
+ >>> from sympy.abc import x, a
446
+ >>> pprint(meijerg((1, 2), (a, 4), (5,), [], x), use_unicode=False)
447
+ __1, 2 /1, 2 4, a | \
448
+ /__ | | x|
449
+ \_|4, 1 \ 5 | /
450
+
451
+ Or as two nested vectors:
452
+
453
+ >>> pprint(meijerg([(1, 2), (3, 4)], ([5], Tuple()), x), use_unicode=False)
454
+ __1, 2 /1, 2 3, 4 | \
455
+ /__ | | x|
456
+ \_|4, 1 \ 5 | /
457
+
458
+ As with the hypergeometric function, the parameters may be passed as
459
+ arbitrary iterables. Vectors of length zero and one also have to be
460
+ passed as iterables. The parameters need not be constants, but if they
461
+ depend on the argument then not much implemented functionality should be
462
+ expected.
463
+
464
+ All the subvectors of parameters are available:
465
+
466
+ >>> from sympy import pprint
467
+ >>> g = meijerg([1], [2], [3], [4], x)
468
+ >>> pprint(g, use_unicode=False)
469
+ __1, 1 /1 2 | \
470
+ /__ | | x|
471
+ \_|2, 2 \3 4 | /
472
+ >>> g.an
473
+ (1,)
474
+ >>> g.ap
475
+ (1, 2)
476
+ >>> g.aother
477
+ (2,)
478
+ >>> g.bm
479
+ (3,)
480
+ >>> g.bq
481
+ (3, 4)
482
+ >>> g.bother
483
+ (4,)
484
+
485
+ The Meijer G-function generalizes the hypergeometric functions.
486
+ In some cases it can be expressed in terms of hypergeometric functions,
487
+ using Slater's theorem. For example:
488
+
489
+ >>> from sympy import hyperexpand
490
+ >>> from sympy.abc import a, b, c
491
+ >>> hyperexpand(meijerg([a], [], [c], [b], x), allow_hyper=True)
492
+ x**c*gamma(-a + c + 1)*hyper((-a + c + 1,),
493
+ (-b + c + 1,), -x)/gamma(-b + c + 1)
494
+
495
+ Thus the Meijer G-function also subsumes many named functions as special
496
+ cases. You can use ``expand_func()`` or ``hyperexpand()`` to (try to)
497
+ rewrite a Meijer G-function in terms of named special functions. For
498
+ example:
499
+
500
+ >>> from sympy import expand_func, S
501
+ >>> expand_func(meijerg([[],[]], [[0],[]], -x))
502
+ exp(x)
503
+ >>> hyperexpand(meijerg([[],[]], [[S(1)/2],[0]], (x/2)**2))
504
+ sin(x)/sqrt(pi)
505
+
506
+ See Also
507
+ ========
508
+
509
+ hyper
510
+ sympy.simplify.hyperexpand
511
+
512
+ References
513
+ ==========
514
+
515
+ .. [1] Luke, Y. L. (1969), The Special Functions and Their Approximations,
516
+ Volume 1
517
+ .. [2] https://en.wikipedia.org/wiki/Meijer_G-function
518
+
519
+ """
520
+
521
+
522
+ def __new__(cls, *args, **kwargs):
523
+ if len(args) == 5:
524
+ args = [(args[0], args[1]), (args[2], args[3]), args[4]]
525
+ if len(args) != 3:
526
+ raise TypeError("args must be either as, as', bs, bs', z or "
527
+ "as, bs, z")
528
+
529
+ def tr(p):
530
+ if len(p) != 2:
531
+ raise TypeError("wrong argument")
532
+ p = [list(ordered(i)) for i in p]
533
+ return TupleArg(_prep_tuple(p[0]), _prep_tuple(p[1]))
534
+
535
+ arg0, arg1 = tr(args[0]), tr(args[1])
536
+ if Tuple(arg0, arg1).has(oo, zoo, -oo):
537
+ raise ValueError("G-function parameters must be finite")
538
+ if any((a - b).is_Integer and a - b > 0
539
+ for a in arg0[0] for b in arg1[0]):
540
+ raise ValueError("no parameter a1, ..., an may differ from "
541
+ "any b1, ..., bm by a positive integer")
542
+
543
+ # TODO should we check convergence conditions?
544
+ return super().__new__(cls, arg0, arg1, args[2], **kwargs)
545
+
546
+ def fdiff(self, argindex=3):
547
+ if argindex != 3:
548
+ return self._diff_wrt_parameter(argindex[1])
549
+ if len(self.an) >= 1:
550
+ a = list(self.an)
551
+ a[0] -= 1
552
+ G = meijerg(a, self.aother, self.bm, self.bother, self.argument)
553
+ return 1/self.argument * ((self.an[0] - 1)*self + G)
554
+ elif len(self.bm) >= 1:
555
+ b = list(self.bm)
556
+ b[0] += 1
557
+ G = meijerg(self.an, self.aother, b, self.bother, self.argument)
558
+ return 1/self.argument * (self.bm[0]*self - G)
559
+ else:
560
+ return S.Zero
561
+
562
+ def _diff_wrt_parameter(self, idx):
563
+ # Differentiation wrt a parameter can only be done in very special
564
+ # cases. In particular, if we want to differentiate with respect to
565
+ # `a`, all other gamma factors have to reduce to rational functions.
566
+ #
567
+ # Let MT denote mellin transform. Suppose T(-s) is the gamma factor
568
+ # appearing in the definition of G. Then
569
+ #
570
+ # MT(log(z)G(z)) = d/ds T(s) = d/da T(s) + ...
571
+ #
572
+ # Thus d/da G(z) = log(z)G(z) - ...
573
+ # The ... can be evaluated as a G function under the above conditions,
574
+ # the formula being most easily derived by using
575
+ #
576
+ # d Gamma(s + n) Gamma(s + n) / 1 1 1 \
577
+ # -- ------------ = ------------ | - + ---- + ... + --------- |
578
+ # ds Gamma(s) Gamma(s) \ s s + 1 s + n - 1 /
579
+ #
580
+ # which follows from the difference equation of the digamma function.
581
+ # (There is a similar equation for -n instead of +n).
582
+
583
+ # We first figure out how to pair the parameters.
584
+ an = list(self.an)
585
+ ap = list(self.aother)
586
+ bm = list(self.bm)
587
+ bq = list(self.bother)
588
+ if idx < len(an):
589
+ an.pop(idx)
590
+ else:
591
+ idx -= len(an)
592
+ if idx < len(ap):
593
+ ap.pop(idx)
594
+ else:
595
+ idx -= len(ap)
596
+ if idx < len(bm):
597
+ bm.pop(idx)
598
+ else:
599
+ bq.pop(idx - len(bm))
600
+ pairs1 = []
601
+ pairs2 = []
602
+ for l1, l2, pairs in [(an, bq, pairs1), (ap, bm, pairs2)]:
603
+ while l1:
604
+ x = l1.pop()
605
+ found = None
606
+ for i, y in enumerate(l2):
607
+ if not Mod((x - y).simplify(), 1):
608
+ found = i
609
+ break
610
+ if found is None:
611
+ raise NotImplementedError('Derivative not expressible '
612
+ 'as G-function?')
613
+ y = l2[i]
614
+ l2.pop(i)
615
+ pairs.append((x, y))
616
+
617
+ # Now build the result.
618
+ res = log(self.argument)*self
619
+
620
+ for a, b in pairs1:
621
+ sign = 1
622
+ n = a - b
623
+ base = b
624
+ if n < 0:
625
+ sign = -1
626
+ n = b - a
627
+ base = a
628
+ for k in range(n):
629
+ res -= sign*meijerg(self.an + (base + k + 1,), self.aother,
630
+ self.bm, self.bother + (base + k + 0,),
631
+ self.argument)
632
+
633
+ for a, b in pairs2:
634
+ sign = 1
635
+ n = b - a
636
+ base = a
637
+ if n < 0:
638
+ sign = -1
639
+ n = a - b
640
+ base = b
641
+ for k in range(n):
642
+ res -= sign*meijerg(self.an, self.aother + (base + k + 1,),
643
+ self.bm + (base + k + 0,), self.bother,
644
+ self.argument)
645
+
646
+ return res
647
+
648
+ def get_period(self):
649
+ """
650
+ Return a number $P$ such that $G(x*exp(I*P)) == G(x)$.
651
+
652
+ Examples
653
+ ========
654
+
655
+ >>> from sympy import meijerg, pi, S
656
+ >>> from sympy.abc import z
657
+
658
+ >>> meijerg([1], [], [], [], z).get_period()
659
+ 2*pi
660
+ >>> meijerg([pi], [], [], [], z).get_period()
661
+ oo
662
+ >>> meijerg([1, 2], [], [], [], z).get_period()
663
+ oo
664
+ >>> meijerg([1,1], [2], [1, S(1)/2, S(1)/3], [1], z).get_period()
665
+ 12*pi
666
+
667
+ """
668
+ # This follows from slater's theorem.
669
+ def compute(l):
670
+ # first check that no two differ by an integer
671
+ for i, b in enumerate(l):
672
+ if not b.is_Rational:
673
+ return oo
674
+ for j in range(i + 1, len(l)):
675
+ if not Mod((b - l[j]).simplify(), 1):
676
+ return oo
677
+ return lcm(*(x.q for x in l))
678
+ beta = compute(self.bm)
679
+ alpha = compute(self.an)
680
+ p, q = len(self.ap), len(self.bq)
681
+ if p == q:
682
+ if oo in (alpha, beta):
683
+ return oo
684
+ return 2*pi*lcm(alpha, beta)
685
+ elif p < q:
686
+ return 2*pi*beta
687
+ else:
688
+ return 2*pi*alpha
689
+
690
+ def _eval_expand_func(self, **hints):
691
+ from sympy.simplify.hyperexpand import hyperexpand
692
+ return hyperexpand(self)
693
+
694
+ def _eval_evalf(self, prec):
695
+ # The default code is insufficient for polar arguments.
696
+ # mpmath provides an optional argument "r", which evaluates
697
+ # G(z**(1/r)). I am not sure what its intended use is, but we hijack it
698
+ # here in the following way: to evaluate at a number z of |argument|
699
+ # less than (say) n*pi, we put r=1/n, compute z' = root(z, n)
700
+ # (carefully so as not to loose the branch information), and evaluate
701
+ # G(z'**(1/r)) = G(z'**n) = G(z).
702
+ import mpmath
703
+ znum = self.argument._eval_evalf(prec)
704
+ if znum.has(exp_polar):
705
+ znum, branch = znum.as_coeff_mul(exp_polar)
706
+ if len(branch) != 1:
707
+ return
708
+ branch = branch[0].args[0]/I
709
+ else:
710
+ branch = S.Zero
711
+ n = ceiling(abs(branch/pi)) + 1
712
+ znum = znum**(S.One/n)*exp(I*branch / n)
713
+
714
+ # Convert all args to mpf or mpc
715
+ try:
716
+ [z, r, ap, bq] = [arg._to_mpmath(prec)
717
+ for arg in [znum, 1/n, self.args[0], self.args[1]]]
718
+ except ValueError:
719
+ return
720
+
721
+ with mpmath.workprec(prec):
722
+ v = mpmath.meijerg(ap, bq, z, r)
723
+
724
+ return Expr._from_mpmath(v, prec)
725
+
726
+ def _eval_as_leading_term(self, x, logx, cdir):
727
+ from sympy.simplify.hyperexpand import hyperexpand
728
+ return hyperexpand(self).as_leading_term(x, logx=logx, cdir=cdir)
729
+
730
+ def integrand(self, s):
731
+ """ Get the defining integrand D(s). """
732
+ from sympy.functions.special.gamma_functions import gamma
733
+ return self.argument**s \
734
+ * Mul(*(gamma(b - s) for b in self.bm)) \
735
+ * Mul(*(gamma(1 - a + s) for a in self.an)) \
736
+ / Mul(*(gamma(1 - b + s) for b in self.bother)) \
737
+ / Mul(*(gamma(a - s) for a in self.aother))
738
+
739
+ @property
740
+ def argument(self):
741
+ """ Argument of the Meijer G-function. """
742
+ return self.args[2]
743
+
744
+ @property
745
+ def an(self):
746
+ """ First set of numerator parameters. """
747
+ return Tuple(*self.args[0][0])
748
+
749
+ @property
750
+ def ap(self):
751
+ """ Combined numerator parameters. """
752
+ return Tuple(*(self.args[0][0] + self.args[0][1]))
753
+
754
+ @property
755
+ def aother(self):
756
+ """ Second set of numerator parameters. """
757
+ return Tuple(*self.args[0][1])
758
+
759
+ @property
760
+ def bm(self):
761
+ """ First set of denominator parameters. """
762
+ return Tuple(*self.args[1][0])
763
+
764
+ @property
765
+ def bq(self):
766
+ """ Combined denominator parameters. """
767
+ return Tuple(*(self.args[1][0] + self.args[1][1]))
768
+
769
+ @property
770
+ def bother(self):
771
+ """ Second set of denominator parameters. """
772
+ return Tuple(*self.args[1][1])
773
+
774
+ @property
775
+ def _diffargs(self):
776
+ return self.ap + self.bq
777
+
778
+ @property
779
+ def nu(self):
780
+ """ A quantity related to the convergence region of the integral,
781
+ c.f. references. """
782
+ return sum(self.bq) - sum(self.ap)
783
+
784
+ @property
785
+ def delta(self):
786
+ """ A quantity related to the convergence region of the integral,
787
+ c.f. references. """
788
+ return len(self.bm) + len(self.an) - S(len(self.ap) + len(self.bq))/2
789
+
790
+ @property
791
+ def is_number(self):
792
+ """ Returns true if expression has numeric data only. """
793
+ return not self.free_symbols
794
+
795
+
796
+ class HyperRep(DefinedFunction):
797
+ """
798
+ A base class for "hyper representation functions".
799
+
800
+ This is used exclusively in ``hyperexpand()``, but fits more logically here.
801
+
802
+ pFq is branched at 1 if p == q+1. For use with slater-expansion, we want
803
+ define an "analytic continuation" to all polar numbers, which is
804
+ continuous on circles and on the ray t*exp_polar(I*pi). Moreover, we want
805
+ a "nice" expression for the various cases.
806
+
807
+ This base class contains the core logic, concrete derived classes only
808
+ supply the actual functions.
809
+
810
+ """
811
+
812
+
813
+ @classmethod
814
+ def eval(cls, *args):
815
+ newargs = tuple(map(unpolarify, args[:-1])) + args[-1:]
816
+ if args != newargs:
817
+ return cls(*newargs)
818
+
819
+ @classmethod
820
+ def _expr_small(cls, x):
821
+ """ An expression for F(x) which holds for |x| < 1. """
822
+ raise NotImplementedError
823
+
824
+ @classmethod
825
+ def _expr_small_minus(cls, x):
826
+ """ An expression for F(-x) which holds for |x| < 1. """
827
+ raise NotImplementedError
828
+
829
+ @classmethod
830
+ def _expr_big(cls, x, n):
831
+ """ An expression for F(exp_polar(2*I*pi*n)*x), |x| > 1. """
832
+ raise NotImplementedError
833
+
834
+ @classmethod
835
+ def _expr_big_minus(cls, x, n):
836
+ """ An expression for F(exp_polar(2*I*pi*n + pi*I)*x), |x| > 1. """
837
+ raise NotImplementedError
838
+
839
+ def _eval_rewrite_as_nonrep(self, *args, **kwargs):
840
+ x, n = self.args[-1].extract_branch_factor(allow_half=True)
841
+ minus = False
842
+ newargs = self.args[:-1] + (x,)
843
+ if not n.is_Integer:
844
+ minus = True
845
+ n -= S.Half
846
+ newerargs = newargs + (n,)
847
+ if minus:
848
+ small = self._expr_small_minus(*newargs)
849
+ big = self._expr_big_minus(*newerargs)
850
+ else:
851
+ small = self._expr_small(*newargs)
852
+ big = self._expr_big(*newerargs)
853
+
854
+ if big == small:
855
+ return small
856
+ return Piecewise((big, abs(x) > 1), (small, True))
857
+
858
+ def _eval_rewrite_as_nonrepsmall(self, *args, **kwargs):
859
+ x, n = self.args[-1].extract_branch_factor(allow_half=True)
860
+ args = self.args[:-1] + (x,)
861
+ if not n.is_Integer:
862
+ return self._expr_small_minus(*args)
863
+ return self._expr_small(*args)
864
+
865
+
866
+ class HyperRep_power1(HyperRep):
867
+ """ Return a representative for hyper([-a], [], z) == (1 - z)**a. """
868
+
869
+ @classmethod
870
+ def _expr_small(cls, a, x):
871
+ return (1 - x)**a
872
+
873
+ @classmethod
874
+ def _expr_small_minus(cls, a, x):
875
+ return (1 + x)**a
876
+
877
+ @classmethod
878
+ def _expr_big(cls, a, x, n):
879
+ if a.is_integer:
880
+ return cls._expr_small(a, x)
881
+ return (x - 1)**a*exp((2*n - 1)*pi*I*a)
882
+
883
+ @classmethod
884
+ def _expr_big_minus(cls, a, x, n):
885
+ if a.is_integer:
886
+ return cls._expr_small_minus(a, x)
887
+ return (1 + x)**a*exp(2*n*pi*I*a)
888
+
889
+
890
+ class HyperRep_power2(HyperRep):
891
+ """ Return a representative for hyper([a, a - 1/2], [2*a], z). """
892
+
893
+ @classmethod
894
+ def _expr_small(cls, a, x):
895
+ return 2**(2*a - 1)*(1 + sqrt(1 - x))**(1 - 2*a)
896
+
897
+ @classmethod
898
+ def _expr_small_minus(cls, a, x):
899
+ return 2**(2*a - 1)*(1 + sqrt(1 + x))**(1 - 2*a)
900
+
901
+ @classmethod
902
+ def _expr_big(cls, a, x, n):
903
+ sgn = -1
904
+ if n.is_odd:
905
+ sgn = 1
906
+ n -= 1
907
+ return 2**(2*a - 1)*(1 + sgn*I*sqrt(x - 1))**(1 - 2*a) \
908
+ *exp(-2*n*pi*I*a)
909
+
910
+ @classmethod
911
+ def _expr_big_minus(cls, a, x, n):
912
+ sgn = 1
913
+ if n.is_odd:
914
+ sgn = -1
915
+ return sgn*2**(2*a - 1)*(sqrt(1 + x) + sgn)**(1 - 2*a)*exp(-2*pi*I*a*n)
916
+
917
+
918
+ class HyperRep_log1(HyperRep):
919
+ """ Represent -z*hyper([1, 1], [2], z) == log(1 - z). """
920
+ @classmethod
921
+ def _expr_small(cls, x):
922
+ return log(1 - x)
923
+
924
+ @classmethod
925
+ def _expr_small_minus(cls, x):
926
+ return log(1 + x)
927
+
928
+ @classmethod
929
+ def _expr_big(cls, x, n):
930
+ return log(x - 1) + (2*n - 1)*pi*I
931
+
932
+ @classmethod
933
+ def _expr_big_minus(cls, x, n):
934
+ return log(1 + x) + 2*n*pi*I
935
+
936
+
937
+ class HyperRep_atanh(HyperRep):
938
+ """ Represent hyper([1/2, 1], [3/2], z) == atanh(sqrt(z))/sqrt(z). """
939
+ @classmethod
940
+ def _expr_small(cls, x):
941
+ return atanh(sqrt(x))/sqrt(x)
942
+
943
+ def _expr_small_minus(cls, x):
944
+ return atan(sqrt(x))/sqrt(x)
945
+
946
+ def _expr_big(cls, x, n):
947
+ if n.is_even:
948
+ return (acoth(sqrt(x)) + I*pi/2)/sqrt(x)
949
+ else:
950
+ return (acoth(sqrt(x)) - I*pi/2)/sqrt(x)
951
+
952
+ def _expr_big_minus(cls, x, n):
953
+ if n.is_even:
954
+ return atan(sqrt(x))/sqrt(x)
955
+ else:
956
+ return (atan(sqrt(x)) - pi)/sqrt(x)
957
+
958
+
959
+ class HyperRep_asin1(HyperRep):
960
+ """ Represent hyper([1/2, 1/2], [3/2], z) == asin(sqrt(z))/sqrt(z). """
961
+ @classmethod
962
+ def _expr_small(cls, z):
963
+ return asin(sqrt(z))/sqrt(z)
964
+
965
+ @classmethod
966
+ def _expr_small_minus(cls, z):
967
+ return asinh(sqrt(z))/sqrt(z)
968
+
969
+ @classmethod
970
+ def _expr_big(cls, z, n):
971
+ return S.NegativeOne**n*((S.Half - n)*pi/sqrt(z) + I*acosh(sqrt(z))/sqrt(z))
972
+
973
+ @classmethod
974
+ def _expr_big_minus(cls, z, n):
975
+ return S.NegativeOne**n*(asinh(sqrt(z))/sqrt(z) + n*pi*I/sqrt(z))
976
+
977
+
978
+ class HyperRep_asin2(HyperRep):
979
+ """ Represent hyper([1, 1], [3/2], z) == asin(sqrt(z))/sqrt(z)/sqrt(1-z). """
980
+ # TODO this can be nicer
981
+ @classmethod
982
+ def _expr_small(cls, z):
983
+ return HyperRep_asin1._expr_small(z) \
984
+ /HyperRep_power1._expr_small(S.Half, z)
985
+
986
+ @classmethod
987
+ def _expr_small_minus(cls, z):
988
+ return HyperRep_asin1._expr_small_minus(z) \
989
+ /HyperRep_power1._expr_small_minus(S.Half, z)
990
+
991
+ @classmethod
992
+ def _expr_big(cls, z, n):
993
+ return HyperRep_asin1._expr_big(z, n) \
994
+ /HyperRep_power1._expr_big(S.Half, z, n)
995
+
996
+ @classmethod
997
+ def _expr_big_minus(cls, z, n):
998
+ return HyperRep_asin1._expr_big_minus(z, n) \
999
+ /HyperRep_power1._expr_big_minus(S.Half, z, n)
1000
+
1001
+
1002
+ class HyperRep_sqrts1(HyperRep):
1003
+ """ Return a representative for hyper([-a, 1/2 - a], [1/2], z). """
1004
+
1005
+ @classmethod
1006
+ def _expr_small(cls, a, z):
1007
+ return ((1 - sqrt(z))**(2*a) + (1 + sqrt(z))**(2*a))/2
1008
+
1009
+ @classmethod
1010
+ def _expr_small_minus(cls, a, z):
1011
+ return (1 + z)**a*cos(2*a*atan(sqrt(z)))
1012
+
1013
+ @classmethod
1014
+ def _expr_big(cls, a, z, n):
1015
+ if n.is_even:
1016
+ return ((sqrt(z) + 1)**(2*a)*exp(2*pi*I*n*a) +
1017
+ (sqrt(z) - 1)**(2*a)*exp(2*pi*I*(n - 1)*a))/2
1018
+ else:
1019
+ n -= 1
1020
+ return ((sqrt(z) - 1)**(2*a)*exp(2*pi*I*a*(n + 1)) +
1021
+ (sqrt(z) + 1)**(2*a)*exp(2*pi*I*a*n))/2
1022
+
1023
+ @classmethod
1024
+ def _expr_big_minus(cls, a, z, n):
1025
+ if n.is_even:
1026
+ return (1 + z)**a*exp(2*pi*I*n*a)*cos(2*a*atan(sqrt(z)))
1027
+ else:
1028
+ return (1 + z)**a*exp(2*pi*I*n*a)*cos(2*a*atan(sqrt(z)) - 2*pi*a)
1029
+
1030
+
1031
+ class HyperRep_sqrts2(HyperRep):
1032
+ """ Return a representative for
1033
+ sqrt(z)/2*[(1-sqrt(z))**2a - (1 + sqrt(z))**2a]
1034
+ == -2*z/(2*a+1) d/dz hyper([-a - 1/2, -a], [1/2], z)"""
1035
+
1036
+ @classmethod
1037
+ def _expr_small(cls, a, z):
1038
+ return sqrt(z)*((1 - sqrt(z))**(2*a) - (1 + sqrt(z))**(2*a))/2
1039
+
1040
+ @classmethod
1041
+ def _expr_small_minus(cls, a, z):
1042
+ return sqrt(z)*(1 + z)**a*sin(2*a*atan(sqrt(z)))
1043
+
1044
+ @classmethod
1045
+ def _expr_big(cls, a, z, n):
1046
+ if n.is_even:
1047
+ return sqrt(z)/2*((sqrt(z) - 1)**(2*a)*exp(2*pi*I*a*(n - 1)) -
1048
+ (sqrt(z) + 1)**(2*a)*exp(2*pi*I*a*n))
1049
+ else:
1050
+ n -= 1
1051
+ return sqrt(z)/2*((sqrt(z) - 1)**(2*a)*exp(2*pi*I*a*(n + 1)) -
1052
+ (sqrt(z) + 1)**(2*a)*exp(2*pi*I*a*n))
1053
+
1054
+ def _expr_big_minus(cls, a, z, n):
1055
+ if n.is_even:
1056
+ return (1 + z)**a*exp(2*pi*I*n*a)*sqrt(z)*sin(2*a*atan(sqrt(z)))
1057
+ else:
1058
+ return (1 + z)**a*exp(2*pi*I*n*a)*sqrt(z) \
1059
+ *sin(2*a*atan(sqrt(z)) - 2*pi*a)
1060
+
1061
+
1062
+ class HyperRep_log2(HyperRep):
1063
+ """ Represent log(1/2 + sqrt(1 - z)/2) == -z/4*hyper([3/2, 1, 1], [2, 2], z) """
1064
+
1065
+ @classmethod
1066
+ def _expr_small(cls, z):
1067
+ return log(S.Half + sqrt(1 - z)/2)
1068
+
1069
+ @classmethod
1070
+ def _expr_small_minus(cls, z):
1071
+ return log(S.Half + sqrt(1 + z)/2)
1072
+
1073
+ @classmethod
1074
+ def _expr_big(cls, z, n):
1075
+ if n.is_even:
1076
+ return (n - S.Half)*pi*I + log(sqrt(z)/2) + I*asin(1/sqrt(z))
1077
+ else:
1078
+ return (n - S.Half)*pi*I + log(sqrt(z)/2) - I*asin(1/sqrt(z))
1079
+
1080
+ def _expr_big_minus(cls, z, n):
1081
+ if n.is_even:
1082
+ return pi*I*n + log(S.Half + sqrt(1 + z)/2)
1083
+ else:
1084
+ return pi*I*n + log(sqrt(1 + z)/2 - S.Half)
1085
+
1086
+
1087
+ class HyperRep_cosasin(HyperRep):
1088
+ """ Represent hyper([a, -a], [1/2], z) == cos(2*a*asin(sqrt(z))). """
1089
+ # Note there are many alternative expressions, e.g. as powers of a sum of
1090
+ # square roots.
1091
+
1092
+ @classmethod
1093
+ def _expr_small(cls, a, z):
1094
+ return cos(2*a*asin(sqrt(z)))
1095
+
1096
+ @classmethod
1097
+ def _expr_small_minus(cls, a, z):
1098
+ return cosh(2*a*asinh(sqrt(z)))
1099
+
1100
+ @classmethod
1101
+ def _expr_big(cls, a, z, n):
1102
+ return cosh(2*a*acosh(sqrt(z)) + a*pi*I*(2*n - 1))
1103
+
1104
+ @classmethod
1105
+ def _expr_big_minus(cls, a, z, n):
1106
+ return cosh(2*a*asinh(sqrt(z)) + 2*a*pi*I*n)
1107
+
1108
+
1109
+ class HyperRep_sinasin(HyperRep):
1110
+ """ Represent 2*a*z*hyper([1 - a, 1 + a], [3/2], z)
1111
+ == sqrt(z)/sqrt(1-z)*sin(2*a*asin(sqrt(z))) """
1112
+
1113
+ @classmethod
1114
+ def _expr_small(cls, a, z):
1115
+ return sqrt(z)/sqrt(1 - z)*sin(2*a*asin(sqrt(z)))
1116
+
1117
+ @classmethod
1118
+ def _expr_small_minus(cls, a, z):
1119
+ return -sqrt(z)/sqrt(1 + z)*sinh(2*a*asinh(sqrt(z)))
1120
+
1121
+ @classmethod
1122
+ def _expr_big(cls, a, z, n):
1123
+ return -1/sqrt(1 - 1/z)*sinh(2*a*acosh(sqrt(z)) + a*pi*I*(2*n - 1))
1124
+
1125
+ @classmethod
1126
+ def _expr_big_minus(cls, a, z, n):
1127
+ return -1/sqrt(1 + 1/z)*sinh(2*a*asinh(sqrt(z)) + 2*a*pi*I*n)
1128
+
1129
+ class appellf1(DefinedFunction):
1130
+ r"""
1131
+ This is the Appell hypergeometric function of two variables as:
1132
+
1133
+ .. math ::
1134
+ F_1(a,b_1,b_2,c,x,y) = \sum_{m=0}^{\infty} \sum_{n=0}^{\infty}
1135
+ \frac{(a)_{m+n} (b_1)_m (b_2)_n}{(c)_{m+n}}
1136
+ \frac{x^m y^n}{m! n!}.
1137
+
1138
+ Examples
1139
+ ========
1140
+
1141
+ >>> from sympy import appellf1, symbols
1142
+ >>> x, y, a, b1, b2, c = symbols('x y a b1 b2 c')
1143
+ >>> appellf1(2., 1., 6., 4., 5., 6.)
1144
+ 0.0063339426292673
1145
+ >>> appellf1(12., 12., 6., 4., 0.5, 0.12)
1146
+ 172870711.659936
1147
+ >>> appellf1(40, 2, 6, 4, 15, 60)
1148
+ appellf1(40, 2, 6, 4, 15, 60)
1149
+ >>> appellf1(20., 12., 10., 3., 0.5, 0.12)
1150
+ 15605338197184.4
1151
+ >>> appellf1(40, 2, 6, 4, x, y)
1152
+ appellf1(40, 2, 6, 4, x, y)
1153
+ >>> appellf1(a, b1, b2, c, x, y)
1154
+ appellf1(a, b1, b2, c, x, y)
1155
+
1156
+ References
1157
+ ==========
1158
+
1159
+ .. [1] https://en.wikipedia.org/wiki/Appell_series
1160
+ .. [2] https://functions.wolfram.com/HypergeometricFunctions/AppellF1/
1161
+
1162
+ """
1163
+
1164
+ @classmethod
1165
+ def eval(cls, a, b1, b2, c, x, y):
1166
+ if default_sort_key(b1) > default_sort_key(b2):
1167
+ b1, b2 = b2, b1
1168
+ x, y = y, x
1169
+ return cls(a, b1, b2, c, x, y)
1170
+ elif b1 == b2 and default_sort_key(x) > default_sort_key(y):
1171
+ x, y = y, x
1172
+ return cls(a, b1, b2, c, x, y)
1173
+ if x == 0 and y == 0:
1174
+ return S.One
1175
+
1176
+ def fdiff(self, argindex=5):
1177
+ a, b1, b2, c, x, y = self.args
1178
+ if argindex == 5:
1179
+ return (a*b1/c)*appellf1(a + 1, b1 + 1, b2, c + 1, x, y)
1180
+ elif argindex == 6:
1181
+ return (a*b2/c)*appellf1(a + 1, b1, b2 + 1, c + 1, x, y)
1182
+ elif argindex in (1, 2, 3, 4):
1183
+ return Derivative(self, self.args[argindex-1])
1184
+ else:
1185
+ raise ArgumentIndexError(self, argindex)
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/mathieu_functions.py ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ This module contains the Mathieu functions.
2
+ """
3
+
4
+ from sympy.core.function import DefinedFunction, ArgumentIndexError
5
+ from sympy.functions.elementary.miscellaneous import sqrt
6
+ from sympy.functions.elementary.trigonometric import sin, cos
7
+
8
+
9
+ class MathieuBase(DefinedFunction):
10
+ """
11
+ Abstract base class for Mathieu functions.
12
+
13
+ This class is meant to reduce code duplication.
14
+
15
+ """
16
+
17
+ unbranched = True
18
+
19
+ def _eval_conjugate(self):
20
+ a, q, z = self.args
21
+ return self.func(a.conjugate(), q.conjugate(), z.conjugate())
22
+
23
+
24
+ class mathieus(MathieuBase):
25
+ r"""
26
+ The Mathieu Sine function $S(a,q,z)$.
27
+
28
+ Explanation
29
+ ===========
30
+
31
+ This function is one solution of the Mathieu differential equation:
32
+
33
+ .. math ::
34
+ y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
35
+
36
+ The other solution is the Mathieu Cosine function.
37
+
38
+ Examples
39
+ ========
40
+
41
+ >>> from sympy import diff, mathieus
42
+ >>> from sympy.abc import a, q, z
43
+
44
+ >>> mathieus(a, q, z)
45
+ mathieus(a, q, z)
46
+
47
+ >>> mathieus(a, 0, z)
48
+ sin(sqrt(a)*z)
49
+
50
+ >>> diff(mathieus(a, q, z), z)
51
+ mathieusprime(a, q, z)
52
+
53
+ See Also
54
+ ========
55
+
56
+ mathieuc: Mathieu cosine function.
57
+ mathieusprime: Derivative of Mathieu sine function.
58
+ mathieucprime: Derivative of Mathieu cosine function.
59
+
60
+ References
61
+ ==========
62
+
63
+ .. [1] https://en.wikipedia.org/wiki/Mathieu_function
64
+ .. [2] https://dlmf.nist.gov/28
65
+ .. [3] https://mathworld.wolfram.com/MathieuFunction.html
66
+ .. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuS/
67
+
68
+ """
69
+
70
+ def fdiff(self, argindex=1):
71
+ if argindex == 3:
72
+ a, q, z = self.args
73
+ return mathieusprime(a, q, z)
74
+ else:
75
+ raise ArgumentIndexError(self, argindex)
76
+
77
+ @classmethod
78
+ def eval(cls, a, q, z):
79
+ if q.is_Number and q.is_zero:
80
+ return sin(sqrt(a)*z)
81
+ # Try to pull out factors of -1
82
+ if z.could_extract_minus_sign():
83
+ return -cls(a, q, -z)
84
+
85
+
86
+ class mathieuc(MathieuBase):
87
+ r"""
88
+ The Mathieu Cosine function $C(a,q,z)$.
89
+
90
+ Explanation
91
+ ===========
92
+
93
+ This function is one solution of the Mathieu differential equation:
94
+
95
+ .. math ::
96
+ y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
97
+
98
+ The other solution is the Mathieu Sine function.
99
+
100
+ Examples
101
+ ========
102
+
103
+ >>> from sympy import diff, mathieuc
104
+ >>> from sympy.abc import a, q, z
105
+
106
+ >>> mathieuc(a, q, z)
107
+ mathieuc(a, q, z)
108
+
109
+ >>> mathieuc(a, 0, z)
110
+ cos(sqrt(a)*z)
111
+
112
+ >>> diff(mathieuc(a, q, z), z)
113
+ mathieucprime(a, q, z)
114
+
115
+ See Also
116
+ ========
117
+
118
+ mathieus: Mathieu sine function
119
+ mathieusprime: Derivative of Mathieu sine function
120
+ mathieucprime: Derivative of Mathieu cosine function
121
+
122
+ References
123
+ ==========
124
+
125
+ .. [1] https://en.wikipedia.org/wiki/Mathieu_function
126
+ .. [2] https://dlmf.nist.gov/28
127
+ .. [3] https://mathworld.wolfram.com/MathieuFunction.html
128
+ .. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuC/
129
+
130
+ """
131
+
132
+ def fdiff(self, argindex=1):
133
+ if argindex == 3:
134
+ a, q, z = self.args
135
+ return mathieucprime(a, q, z)
136
+ else:
137
+ raise ArgumentIndexError(self, argindex)
138
+
139
+ @classmethod
140
+ def eval(cls, a, q, z):
141
+ if q.is_Number and q.is_zero:
142
+ return cos(sqrt(a)*z)
143
+ # Try to pull out factors of -1
144
+ if z.could_extract_minus_sign():
145
+ return cls(a, q, -z)
146
+
147
+
148
+ class mathieusprime(MathieuBase):
149
+ r"""
150
+ The derivative $S^{\prime}(a,q,z)$ of the Mathieu Sine function.
151
+
152
+ Explanation
153
+ ===========
154
+
155
+ This function is one solution of the Mathieu differential equation:
156
+
157
+ .. math ::
158
+ y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
159
+
160
+ The other solution is the Mathieu Cosine function.
161
+
162
+ Examples
163
+ ========
164
+
165
+ >>> from sympy import diff, mathieusprime
166
+ >>> from sympy.abc import a, q, z
167
+
168
+ >>> mathieusprime(a, q, z)
169
+ mathieusprime(a, q, z)
170
+
171
+ >>> mathieusprime(a, 0, z)
172
+ sqrt(a)*cos(sqrt(a)*z)
173
+
174
+ >>> diff(mathieusprime(a, q, z), z)
175
+ (-a + 2*q*cos(2*z))*mathieus(a, q, z)
176
+
177
+ See Also
178
+ ========
179
+
180
+ mathieus: Mathieu sine function
181
+ mathieuc: Mathieu cosine function
182
+ mathieucprime: Derivative of Mathieu cosine function
183
+
184
+ References
185
+ ==========
186
+
187
+ .. [1] https://en.wikipedia.org/wiki/Mathieu_function
188
+ .. [2] https://dlmf.nist.gov/28
189
+ .. [3] https://mathworld.wolfram.com/MathieuFunction.html
190
+ .. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuSPrime/
191
+
192
+ """
193
+
194
+ def fdiff(self, argindex=1):
195
+ if argindex == 3:
196
+ a, q, z = self.args
197
+ return (2*q*cos(2*z) - a)*mathieus(a, q, z)
198
+ else:
199
+ raise ArgumentIndexError(self, argindex)
200
+
201
+ @classmethod
202
+ def eval(cls, a, q, z):
203
+ if q.is_Number and q.is_zero:
204
+ return sqrt(a)*cos(sqrt(a)*z)
205
+ # Try to pull out factors of -1
206
+ if z.could_extract_minus_sign():
207
+ return cls(a, q, -z)
208
+
209
+
210
+ class mathieucprime(MathieuBase):
211
+ r"""
212
+ The derivative $C^{\prime}(a,q,z)$ of the Mathieu Cosine function.
213
+
214
+ Explanation
215
+ ===========
216
+
217
+ This function is one solution of the Mathieu differential equation:
218
+
219
+ .. math ::
220
+ y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
221
+
222
+ The other solution is the Mathieu Sine function.
223
+
224
+ Examples
225
+ ========
226
+
227
+ >>> from sympy import diff, mathieucprime
228
+ >>> from sympy.abc import a, q, z
229
+
230
+ >>> mathieucprime(a, q, z)
231
+ mathieucprime(a, q, z)
232
+
233
+ >>> mathieucprime(a, 0, z)
234
+ -sqrt(a)*sin(sqrt(a)*z)
235
+
236
+ >>> diff(mathieucprime(a, q, z), z)
237
+ (-a + 2*q*cos(2*z))*mathieuc(a, q, z)
238
+
239
+ See Also
240
+ ========
241
+
242
+ mathieus: Mathieu sine function
243
+ mathieuc: Mathieu cosine function
244
+ mathieusprime: Derivative of Mathieu sine function
245
+
246
+ References
247
+ ==========
248
+
249
+ .. [1] https://en.wikipedia.org/wiki/Mathieu_function
250
+ .. [2] https://dlmf.nist.gov/28
251
+ .. [3] https://mathworld.wolfram.com/MathieuFunction.html
252
+ .. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuCPrime/
253
+
254
+ """
255
+
256
+ def fdiff(self, argindex=1):
257
+ if argindex == 3:
258
+ a, q, z = self.args
259
+ return (2*q*cos(2*z) - a)*mathieuc(a, q, z)
260
+ else:
261
+ raise ArgumentIndexError(self, argindex)
262
+
263
+ @classmethod
264
+ def eval(cls, a, q, z):
265
+ if q.is_Number and q.is_zero:
266
+ return -sqrt(a)*sin(sqrt(a)*z)
267
+ # Try to pull out factors of -1
268
+ if z.could_extract_minus_sign():
269
+ return -cls(a, q, -z)
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/polynomials.py ADDED
@@ -0,0 +1,1447 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module mainly implements special orthogonal polynomials.
3
+
4
+ See also functions.combinatorial.numbers which contains some
5
+ combinatorial polynomials.
6
+
7
+ """
8
+
9
+ from sympy.core import Rational
10
+ from sympy.core.function import DefinedFunction, ArgumentIndexError
11
+ from sympy.core.singleton import S
12
+ from sympy.core.symbol import Dummy
13
+ from sympy.functions.combinatorial.factorials import binomial, factorial, RisingFactorial
14
+ from sympy.functions.elementary.complexes import re
15
+ from sympy.functions.elementary.exponential import exp
16
+ from sympy.functions.elementary.integers import floor
17
+ from sympy.functions.elementary.miscellaneous import sqrt
18
+ from sympy.functions.elementary.trigonometric import cos, sec
19
+ from sympy.functions.special.gamma_functions import gamma
20
+ from sympy.functions.special.hyper import hyper
21
+ from sympy.polys.orthopolys import (chebyshevt_poly, chebyshevu_poly,
22
+ gegenbauer_poly, hermite_poly, hermite_prob_poly,
23
+ jacobi_poly, laguerre_poly, legendre_poly)
24
+
25
+ _x = Dummy('x')
26
+
27
+
28
+ class OrthogonalPolynomial(DefinedFunction):
29
+ """Base class for orthogonal polynomials.
30
+ """
31
+
32
+ @classmethod
33
+ def _eval_at_order(cls, n, x):
34
+ if n.is_integer and n >= 0:
35
+ return cls._ortho_poly(int(n), _x).subs(_x, x)
36
+
37
+ def _eval_conjugate(self):
38
+ return self.func(self.args[0], self.args[1].conjugate())
39
+
40
+ #----------------------------------------------------------------------------
41
+ # Jacobi polynomials
42
+ #
43
+
44
+
45
+ class jacobi(OrthogonalPolynomial):
46
+ r"""
47
+ Jacobi polynomial $P_n^{\left(\alpha, \beta\right)}(x)$.
48
+
49
+ Explanation
50
+ ===========
51
+
52
+ ``jacobi(n, alpha, beta, x)`` gives the $n$th Jacobi polynomial
53
+ in $x$, $P_n^{\left(\alpha, \beta\right)}(x)$.
54
+
55
+ The Jacobi polynomials are orthogonal on $[-1, 1]$ with respect
56
+ to the weight $\left(1-x\right)^\alpha \left(1+x\right)^\beta$.
57
+
58
+ Examples
59
+ ========
60
+
61
+ >>> from sympy import jacobi, S, conjugate, diff
62
+ >>> from sympy.abc import a, b, n, x
63
+
64
+ >>> jacobi(0, a, b, x)
65
+ 1
66
+ >>> jacobi(1, a, b, x)
67
+ a/2 - b/2 + x*(a/2 + b/2 + 1)
68
+ >>> jacobi(2, a, b, x)
69
+ a**2/8 - a*b/4 - a/8 + b**2/8 - b/8 + x**2*(a**2/8 + a*b/4 + 7*a/8 + b**2/8 + 7*b/8 + 3/2) + x*(a**2/4 + 3*a/4 - b**2/4 - 3*b/4) - 1/2
70
+
71
+ >>> jacobi(n, a, b, x)
72
+ jacobi(n, a, b, x)
73
+
74
+ >>> jacobi(n, a, a, x)
75
+ RisingFactorial(a + 1, n)*gegenbauer(n,
76
+ a + 1/2, x)/RisingFactorial(2*a + 1, n)
77
+
78
+ >>> jacobi(n, 0, 0, x)
79
+ legendre(n, x)
80
+
81
+ >>> jacobi(n, S(1)/2, S(1)/2, x)
82
+ RisingFactorial(3/2, n)*chebyshevu(n, x)/factorial(n + 1)
83
+
84
+ >>> jacobi(n, -S(1)/2, -S(1)/2, x)
85
+ RisingFactorial(1/2, n)*chebyshevt(n, x)/factorial(n)
86
+
87
+ >>> jacobi(n, a, b, -x)
88
+ (-1)**n*jacobi(n, b, a, x)
89
+
90
+ >>> jacobi(n, a, b, 0)
91
+ gamma(a + n + 1)*hyper((-n, -b - n), (a + 1,), -1)/(2**n*factorial(n)*gamma(a + 1))
92
+ >>> jacobi(n, a, b, 1)
93
+ RisingFactorial(a + 1, n)/factorial(n)
94
+
95
+ >>> conjugate(jacobi(n, a, b, x))
96
+ jacobi(n, conjugate(a), conjugate(b), conjugate(x))
97
+
98
+ >>> diff(jacobi(n,a,b,x), x)
99
+ (a/2 + b/2 + n/2 + 1/2)*jacobi(n - 1, a + 1, b + 1, x)
100
+
101
+ See Also
102
+ ========
103
+
104
+ gegenbauer,
105
+ chebyshevt_root, chebyshevu, chebyshevu_root,
106
+ legendre, assoc_legendre,
107
+ hermite, hermite_prob,
108
+ laguerre, assoc_laguerre,
109
+ sympy.polys.orthopolys.jacobi_poly,
110
+ sympy.polys.orthopolys.gegenbauer_poly
111
+ sympy.polys.orthopolys.chebyshevt_poly
112
+ sympy.polys.orthopolys.chebyshevu_poly
113
+ sympy.polys.orthopolys.hermite_poly
114
+ sympy.polys.orthopolys.legendre_poly
115
+ sympy.polys.orthopolys.laguerre_poly
116
+
117
+ References
118
+ ==========
119
+
120
+ .. [1] https://en.wikipedia.org/wiki/Jacobi_polynomials
121
+ .. [2] https://mathworld.wolfram.com/JacobiPolynomial.html
122
+ .. [3] https://functions.wolfram.com/Polynomials/JacobiP/
123
+
124
+ """
125
+
126
+ @classmethod
127
+ def eval(cls, n, a, b, x):
128
+ # Simplify to other polynomials
129
+ # P^{a, a}_n(x)
130
+ if a == b:
131
+ if a == Rational(-1, 2):
132
+ return RisingFactorial(S.Half, n) / factorial(n) * chebyshevt(n, x)
133
+ elif a.is_zero:
134
+ return legendre(n, x)
135
+ elif a == S.Half:
136
+ return RisingFactorial(3*S.Half, n) / factorial(n + 1) * chebyshevu(n, x)
137
+ else:
138
+ return RisingFactorial(a + 1, n) / RisingFactorial(2*a + 1, n) * gegenbauer(n, a + S.Half, x)
139
+ elif b == -a:
140
+ # P^{a, -a}_n(x)
141
+ return gamma(n + a + 1) / gamma(n + 1) * (1 + x)**(a/2) / (1 - x)**(a/2) * assoc_legendre(n, -a, x)
142
+
143
+ if not n.is_Number:
144
+ # Symbolic result P^{a,b}_n(x)
145
+ # P^{a,b}_n(-x) ---> (-1)**n * P^{b,a}_n(-x)
146
+ if x.could_extract_minus_sign():
147
+ return S.NegativeOne**n * jacobi(n, b, a, -x)
148
+ # We can evaluate for some special values of x
149
+ if x.is_zero:
150
+ return (2**(-n) * gamma(a + n + 1) / (gamma(a + 1) * factorial(n)) *
151
+ hyper([-b - n, -n], [a + 1], -1))
152
+ if x == S.One:
153
+ return RisingFactorial(a + 1, n) / factorial(n)
154
+ elif x is S.Infinity:
155
+ if n.is_positive:
156
+ # Make sure a+b+2*n \notin Z
157
+ if (a + b + 2*n).is_integer:
158
+ raise ValueError("Error. a + b + 2*n should not be an integer.")
159
+ return RisingFactorial(a + b + n + 1, n) * S.Infinity
160
+ else:
161
+ # n is a given fixed integer, evaluate into polynomial
162
+ return jacobi_poly(n, a, b, x)
163
+
164
+ def fdiff(self, argindex=4):
165
+ from sympy.concrete.summations import Sum
166
+ if argindex == 1:
167
+ # Diff wrt n
168
+ raise ArgumentIndexError(self, argindex)
169
+ elif argindex == 2:
170
+ # Diff wrt a
171
+ n, a, b, x = self.args
172
+ k = Dummy("k")
173
+ f1 = 1 / (a + b + n + k + 1)
174
+ f2 = ((a + b + 2*k + 1) * RisingFactorial(b + k + 1, n - k) /
175
+ ((n - k) * RisingFactorial(a + b + k + 1, n - k)))
176
+ return Sum(f1 * (jacobi(n, a, b, x) + f2*jacobi(k, a, b, x)), (k, 0, n - 1))
177
+ elif argindex == 3:
178
+ # Diff wrt b
179
+ n, a, b, x = self.args
180
+ k = Dummy("k")
181
+ f1 = 1 / (a + b + n + k + 1)
182
+ f2 = (-1)**(n - k) * ((a + b + 2*k + 1) * RisingFactorial(a + k + 1, n - k) /
183
+ ((n - k) * RisingFactorial(a + b + k + 1, n - k)))
184
+ return Sum(f1 * (jacobi(n, a, b, x) + f2*jacobi(k, a, b, x)), (k, 0, n - 1))
185
+ elif argindex == 4:
186
+ # Diff wrt x
187
+ n, a, b, x = self.args
188
+ return S.Half * (a + b + n + 1) * jacobi(n - 1, a + 1, b + 1, x)
189
+ else:
190
+ raise ArgumentIndexError(self, argindex)
191
+
192
+ def _eval_rewrite_as_Sum(self, n, a, b, x, **kwargs):
193
+ from sympy.concrete.summations import Sum
194
+ # Make sure n \in N
195
+ if n.is_negative or n.is_integer is False:
196
+ raise ValueError("Error: n should be a non-negative integer.")
197
+ k = Dummy("k")
198
+ kern = (RisingFactorial(-n, k) * RisingFactorial(a + b + n + 1, k) * RisingFactorial(a + k + 1, n - k) /
199
+ factorial(k) * ((1 - x)/2)**k)
200
+ return 1 / factorial(n) * Sum(kern, (k, 0, n))
201
+
202
+ def _eval_rewrite_as_polynomial(self, n, a, b, x, **kwargs):
203
+ # This function is just kept for backwards compatibility
204
+ # but should not be used
205
+ return self._eval_rewrite_as_Sum(n, a, b, x, **kwargs)
206
+
207
+ def _eval_conjugate(self):
208
+ n, a, b, x = self.args
209
+ return self.func(n, a.conjugate(), b.conjugate(), x.conjugate())
210
+
211
+
212
+ def jacobi_normalized(n, a, b, x):
213
+ r"""
214
+ Jacobi polynomial $P_n^{\left(\alpha, \beta\right)}(x)$.
215
+
216
+ Explanation
217
+ ===========
218
+
219
+ ``jacobi_normalized(n, alpha, beta, x)`` gives the $n$th
220
+ Jacobi polynomial in $x$, $P_n^{\left(\alpha, \beta\right)}(x)$.
221
+
222
+ The Jacobi polynomials are orthogonal on $[-1, 1]$ with respect
223
+ to the weight $\left(1-x\right)^\alpha \left(1+x\right)^\beta$.
224
+
225
+ This functions returns the polynomials normilzed:
226
+
227
+ .. math::
228
+
229
+ \int_{-1}^{1}
230
+ P_m^{\left(\alpha, \beta\right)}(x)
231
+ P_n^{\left(\alpha, \beta\right)}(x)
232
+ (1-x)^{\alpha} (1+x)^{\beta} \mathrm{d}x
233
+ = \delta_{m,n}
234
+
235
+ Examples
236
+ ========
237
+
238
+ >>> from sympy import jacobi_normalized
239
+ >>> from sympy.abc import n,a,b,x
240
+
241
+ >>> jacobi_normalized(n, a, b, x)
242
+ jacobi(n, a, b, x)/sqrt(2**(a + b + 1)*gamma(a + n + 1)*gamma(b + n + 1)/((a + b + 2*n + 1)*factorial(n)*gamma(a + b + n + 1)))
243
+
244
+ Parameters
245
+ ==========
246
+
247
+ n : integer degree of polynomial
248
+
249
+ a : alpha value
250
+
251
+ b : beta value
252
+
253
+ x : symbol
254
+
255
+ See Also
256
+ ========
257
+
258
+ gegenbauer,
259
+ chebyshevt_root, chebyshevu, chebyshevu_root,
260
+ legendre, assoc_legendre,
261
+ hermite, hermite_prob,
262
+ laguerre, assoc_laguerre,
263
+ sympy.polys.orthopolys.jacobi_poly,
264
+ sympy.polys.orthopolys.gegenbauer_poly
265
+ sympy.polys.orthopolys.chebyshevt_poly
266
+ sympy.polys.orthopolys.chebyshevu_poly
267
+ sympy.polys.orthopolys.hermite_poly
268
+ sympy.polys.orthopolys.legendre_poly
269
+ sympy.polys.orthopolys.laguerre_poly
270
+
271
+ References
272
+ ==========
273
+
274
+ .. [1] https://en.wikipedia.org/wiki/Jacobi_polynomials
275
+ .. [2] https://mathworld.wolfram.com/JacobiPolynomial.html
276
+ .. [3] https://functions.wolfram.com/Polynomials/JacobiP/
277
+
278
+ """
279
+ nfactor = (S(2)**(a + b + 1) * (gamma(n + a + 1) * gamma(n + b + 1))
280
+ / (2*n + a + b + 1) / (factorial(n) * gamma(n + a + b + 1)))
281
+
282
+ return jacobi(n, a, b, x) / sqrt(nfactor)
283
+
284
+
285
+ #----------------------------------------------------------------------------
286
+ # Gegenbauer polynomials
287
+ #
288
+
289
+
290
+ class gegenbauer(OrthogonalPolynomial):
291
+ r"""
292
+ Gegenbauer polynomial $C_n^{\left(\alpha\right)}(x)$.
293
+
294
+ Explanation
295
+ ===========
296
+
297
+ ``gegenbauer(n, alpha, x)`` gives the $n$th Gegenbauer polynomial
298
+ in $x$, $C_n^{\left(\alpha\right)}(x)$.
299
+
300
+ The Gegenbauer polynomials are orthogonal on $[-1, 1]$ with
301
+ respect to the weight $\left(1-x^2\right)^{\alpha-\frac{1}{2}}$.
302
+
303
+ Examples
304
+ ========
305
+
306
+ >>> from sympy import gegenbauer, conjugate, diff
307
+ >>> from sympy.abc import n,a,x
308
+ >>> gegenbauer(0, a, x)
309
+ 1
310
+ >>> gegenbauer(1, a, x)
311
+ 2*a*x
312
+ >>> gegenbauer(2, a, x)
313
+ -a + x**2*(2*a**2 + 2*a)
314
+ >>> gegenbauer(3, a, x)
315
+ x**3*(4*a**3/3 + 4*a**2 + 8*a/3) + x*(-2*a**2 - 2*a)
316
+
317
+ >>> gegenbauer(n, a, x)
318
+ gegenbauer(n, a, x)
319
+ >>> gegenbauer(n, a, -x)
320
+ (-1)**n*gegenbauer(n, a, x)
321
+
322
+ >>> gegenbauer(n, a, 0)
323
+ 2**n*sqrt(pi)*gamma(a + n/2)/(gamma(a)*gamma(1/2 - n/2)*gamma(n + 1))
324
+ >>> gegenbauer(n, a, 1)
325
+ gamma(2*a + n)/(gamma(2*a)*gamma(n + 1))
326
+
327
+ >>> conjugate(gegenbauer(n, a, x))
328
+ gegenbauer(n, conjugate(a), conjugate(x))
329
+
330
+ >>> diff(gegenbauer(n, a, x), x)
331
+ 2*a*gegenbauer(n - 1, a + 1, x)
332
+
333
+ See Also
334
+ ========
335
+
336
+ jacobi,
337
+ chebyshevt_root, chebyshevu, chebyshevu_root,
338
+ legendre, assoc_legendre,
339
+ hermite, hermite_prob,
340
+ laguerre, assoc_laguerre,
341
+ sympy.polys.orthopolys.jacobi_poly
342
+ sympy.polys.orthopolys.gegenbauer_poly
343
+ sympy.polys.orthopolys.chebyshevt_poly
344
+ sympy.polys.orthopolys.chebyshevu_poly
345
+ sympy.polys.orthopolys.hermite_poly
346
+ sympy.polys.orthopolys.hermite_prob_poly
347
+ sympy.polys.orthopolys.legendre_poly
348
+ sympy.polys.orthopolys.laguerre_poly
349
+
350
+ References
351
+ ==========
352
+
353
+ .. [1] https://en.wikipedia.org/wiki/Gegenbauer_polynomials
354
+ .. [2] https://mathworld.wolfram.com/GegenbauerPolynomial.html
355
+ .. [3] https://functions.wolfram.com/Polynomials/GegenbauerC3/
356
+
357
+ """
358
+
359
+ @classmethod
360
+ def eval(cls, n, a, x):
361
+ # For negative n the polynomials vanish
362
+ # See https://functions.wolfram.com/Polynomials/GegenbauerC3/03/01/03/0012/
363
+ if n.is_negative:
364
+ return S.Zero
365
+
366
+ # Some special values for fixed a
367
+ if a == S.Half:
368
+ return legendre(n, x)
369
+ elif a == S.One:
370
+ return chebyshevu(n, x)
371
+ elif a == S.NegativeOne:
372
+ return S.Zero
373
+
374
+ if not n.is_Number:
375
+ # Handle this before the general sign extraction rule
376
+ if x == S.NegativeOne:
377
+ if (re(a) > S.Half) == True:
378
+ return S.ComplexInfinity
379
+ else:
380
+ return (cos(S.Pi*(a+n)) * sec(S.Pi*a) * gamma(2*a+n) /
381
+ (gamma(2*a) * gamma(n+1)))
382
+
383
+ # Symbolic result C^a_n(x)
384
+ # C^a_n(-x) ---> (-1)**n * C^a_n(x)
385
+ if x.could_extract_minus_sign():
386
+ return S.NegativeOne**n * gegenbauer(n, a, -x)
387
+ # We can evaluate for some special values of x
388
+ if x.is_zero:
389
+ return (2**n * sqrt(S.Pi) * gamma(a + S.Half*n) /
390
+ (gamma((1 - n)/2) * gamma(n + 1) * gamma(a)) )
391
+ if x == S.One:
392
+ return gamma(2*a + n) / (gamma(2*a) * gamma(n + 1))
393
+ elif x is S.Infinity:
394
+ if n.is_positive:
395
+ return RisingFactorial(a, n) * S.Infinity
396
+ else:
397
+ # n is a given fixed integer, evaluate into polynomial
398
+ return gegenbauer_poly(n, a, x)
399
+
400
+ def fdiff(self, argindex=3):
401
+ from sympy.concrete.summations import Sum
402
+ if argindex == 1:
403
+ # Diff wrt n
404
+ raise ArgumentIndexError(self, argindex)
405
+ elif argindex == 2:
406
+ # Diff wrt a
407
+ n, a, x = self.args
408
+ k = Dummy("k")
409
+ factor1 = 2 * (1 + (-1)**(n - k)) * (k + a) / ((k +
410
+ n + 2*a) * (n - k))
411
+ factor2 = 2*(k + 1) / ((k + 2*a) * (2*k + 2*a + 1)) + \
412
+ 2 / (k + n + 2*a)
413
+ kern = factor1*gegenbauer(k, a, x) + factor2*gegenbauer(n, a, x)
414
+ return Sum(kern, (k, 0, n - 1))
415
+ elif argindex == 3:
416
+ # Diff wrt x
417
+ n, a, x = self.args
418
+ return 2*a*gegenbauer(n - 1, a + 1, x)
419
+ else:
420
+ raise ArgumentIndexError(self, argindex)
421
+
422
+ def _eval_rewrite_as_Sum(self, n, a, x, **kwargs):
423
+ from sympy.concrete.summations import Sum
424
+ k = Dummy("k")
425
+ kern = ((-1)**k * RisingFactorial(a, n - k) * (2*x)**(n - 2*k) /
426
+ (factorial(k) * factorial(n - 2*k)))
427
+ return Sum(kern, (k, 0, floor(n/2)))
428
+
429
+ def _eval_rewrite_as_polynomial(self, n, a, x, **kwargs):
430
+ # This function is just kept for backwards compatibility
431
+ # but should not be used
432
+ return self._eval_rewrite_as_Sum(n, a, x, **kwargs)
433
+
434
+ def _eval_conjugate(self):
435
+ n, a, x = self.args
436
+ return self.func(n, a.conjugate(), x.conjugate())
437
+
438
+ #----------------------------------------------------------------------------
439
+ # Chebyshev polynomials of first and second kind
440
+ #
441
+
442
+
443
+ class chebyshevt(OrthogonalPolynomial):
444
+ r"""
445
+ Chebyshev polynomial of the first kind, $T_n(x)$.
446
+
447
+ Explanation
448
+ ===========
449
+
450
+ ``chebyshevt(n, x)`` gives the $n$th Chebyshev polynomial (of the first
451
+ kind) in $x$, $T_n(x)$.
452
+
453
+ The Chebyshev polynomials of the first kind are orthogonal on
454
+ $[-1, 1]$ with respect to the weight $\frac{1}{\sqrt{1-x^2}}$.
455
+
456
+ Examples
457
+ ========
458
+
459
+ >>> from sympy import chebyshevt, diff
460
+ >>> from sympy.abc import n,x
461
+ >>> chebyshevt(0, x)
462
+ 1
463
+ >>> chebyshevt(1, x)
464
+ x
465
+ >>> chebyshevt(2, x)
466
+ 2*x**2 - 1
467
+
468
+ >>> chebyshevt(n, x)
469
+ chebyshevt(n, x)
470
+ >>> chebyshevt(n, -x)
471
+ (-1)**n*chebyshevt(n, x)
472
+ >>> chebyshevt(-n, x)
473
+ chebyshevt(n, x)
474
+
475
+ >>> chebyshevt(n, 0)
476
+ cos(pi*n/2)
477
+ >>> chebyshevt(n, -1)
478
+ (-1)**n
479
+
480
+ >>> diff(chebyshevt(n, x), x)
481
+ n*chebyshevu(n - 1, x)
482
+
483
+ See Also
484
+ ========
485
+
486
+ jacobi, gegenbauer,
487
+ chebyshevt_root, chebyshevu, chebyshevu_root,
488
+ legendre, assoc_legendre,
489
+ hermite, hermite_prob,
490
+ laguerre, assoc_laguerre,
491
+ sympy.polys.orthopolys.jacobi_poly
492
+ sympy.polys.orthopolys.gegenbauer_poly
493
+ sympy.polys.orthopolys.chebyshevt_poly
494
+ sympy.polys.orthopolys.chebyshevu_poly
495
+ sympy.polys.orthopolys.hermite_poly
496
+ sympy.polys.orthopolys.hermite_prob_poly
497
+ sympy.polys.orthopolys.legendre_poly
498
+ sympy.polys.orthopolys.laguerre_poly
499
+
500
+ References
501
+ ==========
502
+
503
+ .. [1] https://en.wikipedia.org/wiki/Chebyshev_polynomial
504
+ .. [2] https://mathworld.wolfram.com/ChebyshevPolynomialoftheFirstKind.html
505
+ .. [3] https://mathworld.wolfram.com/ChebyshevPolynomialoftheSecondKind.html
506
+ .. [4] https://functions.wolfram.com/Polynomials/ChebyshevT/
507
+ .. [5] https://functions.wolfram.com/Polynomials/ChebyshevU/
508
+
509
+ """
510
+
511
+ _ortho_poly = staticmethod(chebyshevt_poly)
512
+
513
+ @classmethod
514
+ def eval(cls, n, x):
515
+ if not n.is_Number:
516
+ # Symbolic result T_n(x)
517
+ # T_n(-x) ---> (-1)**n * T_n(x)
518
+ if x.could_extract_minus_sign():
519
+ return S.NegativeOne**n * chebyshevt(n, -x)
520
+ # T_{-n}(x) ---> T_n(x)
521
+ if n.could_extract_minus_sign():
522
+ return chebyshevt(-n, x)
523
+ # We can evaluate for some special values of x
524
+ if x.is_zero:
525
+ return cos(S.Half * S.Pi * n)
526
+ if x == S.One:
527
+ return S.One
528
+ elif x is S.Infinity:
529
+ return S.Infinity
530
+ else:
531
+ # n is a given fixed integer, evaluate into polynomial
532
+ if n.is_negative:
533
+ # T_{-n}(x) == T_n(x)
534
+ return cls._eval_at_order(-n, x)
535
+ else:
536
+ return cls._eval_at_order(n, x)
537
+
538
+ def fdiff(self, argindex=2):
539
+ if argindex == 1:
540
+ # Diff wrt n
541
+ raise ArgumentIndexError(self, argindex)
542
+ elif argindex == 2:
543
+ # Diff wrt x
544
+ n, x = self.args
545
+ return n * chebyshevu(n - 1, x)
546
+ else:
547
+ raise ArgumentIndexError(self, argindex)
548
+
549
+ def _eval_rewrite_as_Sum(self, n, x, **kwargs):
550
+ from sympy.concrete.summations import Sum
551
+ k = Dummy("k")
552
+ kern = binomial(n, 2*k) * (x**2 - 1)**k * x**(n - 2*k)
553
+ return Sum(kern, (k, 0, floor(n/2)))
554
+
555
+ def _eval_rewrite_as_polynomial(self, n, x, **kwargs):
556
+ # This function is just kept for backwards compatibility
557
+ # but should not be used
558
+ return self._eval_rewrite_as_Sum(n, x, **kwargs)
559
+
560
+
561
+ class chebyshevu(OrthogonalPolynomial):
562
+ r"""
563
+ Chebyshev polynomial of the second kind, $U_n(x)$.
564
+
565
+ Explanation
566
+ ===========
567
+
568
+ ``chebyshevu(n, x)`` gives the $n$th Chebyshev polynomial of the second
569
+ kind in x, $U_n(x)$.
570
+
571
+ The Chebyshev polynomials of the second kind are orthogonal on
572
+ $[-1, 1]$ with respect to the weight $\sqrt{1-x^2}$.
573
+
574
+ Examples
575
+ ========
576
+
577
+ >>> from sympy import chebyshevu, diff
578
+ >>> from sympy.abc import n,x
579
+ >>> chebyshevu(0, x)
580
+ 1
581
+ >>> chebyshevu(1, x)
582
+ 2*x
583
+ >>> chebyshevu(2, x)
584
+ 4*x**2 - 1
585
+
586
+ >>> chebyshevu(n, x)
587
+ chebyshevu(n, x)
588
+ >>> chebyshevu(n, -x)
589
+ (-1)**n*chebyshevu(n, x)
590
+ >>> chebyshevu(-n, x)
591
+ -chebyshevu(n - 2, x)
592
+
593
+ >>> chebyshevu(n, 0)
594
+ cos(pi*n/2)
595
+ >>> chebyshevu(n, 1)
596
+ n + 1
597
+
598
+ >>> diff(chebyshevu(n, x), x)
599
+ (-x*chebyshevu(n, x) + (n + 1)*chebyshevt(n + 1, x))/(x**2 - 1)
600
+
601
+ See Also
602
+ ========
603
+
604
+ jacobi, gegenbauer,
605
+ chebyshevt, chebyshevt_root, chebyshevu_root,
606
+ legendre, assoc_legendre,
607
+ hermite, hermite_prob,
608
+ laguerre, assoc_laguerre,
609
+ sympy.polys.orthopolys.jacobi_poly
610
+ sympy.polys.orthopolys.gegenbauer_poly
611
+ sympy.polys.orthopolys.chebyshevt_poly
612
+ sympy.polys.orthopolys.chebyshevu_poly
613
+ sympy.polys.orthopolys.hermite_poly
614
+ sympy.polys.orthopolys.hermite_prob_poly
615
+ sympy.polys.orthopolys.legendre_poly
616
+ sympy.polys.orthopolys.laguerre_poly
617
+
618
+ References
619
+ ==========
620
+
621
+ .. [1] https://en.wikipedia.org/wiki/Chebyshev_polynomial
622
+ .. [2] https://mathworld.wolfram.com/ChebyshevPolynomialoftheFirstKind.html
623
+ .. [3] https://mathworld.wolfram.com/ChebyshevPolynomialoftheSecondKind.html
624
+ .. [4] https://functions.wolfram.com/Polynomials/ChebyshevT/
625
+ .. [5] https://functions.wolfram.com/Polynomials/ChebyshevU/
626
+
627
+ """
628
+
629
+ _ortho_poly = staticmethod(chebyshevu_poly)
630
+
631
+ @classmethod
632
+ def eval(cls, n, x):
633
+ if not n.is_Number:
634
+ # Symbolic result U_n(x)
635
+ # U_n(-x) ---> (-1)**n * U_n(x)
636
+ if x.could_extract_minus_sign():
637
+ return S.NegativeOne**n * chebyshevu(n, -x)
638
+ # U_{-n}(x) ---> -U_{n-2}(x)
639
+ if n.could_extract_minus_sign():
640
+ if n == S.NegativeOne:
641
+ # n can not be -1 here
642
+ return S.Zero
643
+ elif not (-n - 2).could_extract_minus_sign():
644
+ return -chebyshevu(-n - 2, x)
645
+ # We can evaluate for some special values of x
646
+ if x.is_zero:
647
+ return cos(S.Half * S.Pi * n)
648
+ if x == S.One:
649
+ return S.One + n
650
+ elif x is S.Infinity:
651
+ return S.Infinity
652
+ else:
653
+ # n is a given fixed integer, evaluate into polynomial
654
+ if n.is_negative:
655
+ # U_{-n}(x) ---> -U_{n-2}(x)
656
+ if n == S.NegativeOne:
657
+ return S.Zero
658
+ else:
659
+ return -cls._eval_at_order(-n - 2, x)
660
+ else:
661
+ return cls._eval_at_order(n, x)
662
+
663
+ def fdiff(self, argindex=2):
664
+ if argindex == 1:
665
+ # Diff wrt n
666
+ raise ArgumentIndexError(self, argindex)
667
+ elif argindex == 2:
668
+ # Diff wrt x
669
+ n, x = self.args
670
+ return ((n + 1) * chebyshevt(n + 1, x) - x * chebyshevu(n, x)) / (x**2 - 1)
671
+ else:
672
+ raise ArgumentIndexError(self, argindex)
673
+
674
+ def _eval_rewrite_as_Sum(self, n, x, **kwargs):
675
+ from sympy.concrete.summations import Sum
676
+ k = Dummy("k")
677
+ kern = S.NegativeOne**k * factorial(
678
+ n - k) * (2*x)**(n - 2*k) / (factorial(k) * factorial(n - 2*k))
679
+ return Sum(kern, (k, 0, floor(n/2)))
680
+
681
+ def _eval_rewrite_as_polynomial(self, n, x, **kwargs):
682
+ # This function is just kept for backwards compatibility
683
+ # but should not be used
684
+ return self._eval_rewrite_as_Sum(n, x, **kwargs)
685
+
686
+
687
+ class chebyshevt_root(DefinedFunction):
688
+ r"""
689
+ ``chebyshev_root(n, k)`` returns the $k$th root (indexed from zero) of
690
+ the $n$th Chebyshev polynomial of the first kind; that is, if
691
+ $0 \le k < n$, ``chebyshevt(n, chebyshevt_root(n, k)) == 0``.
692
+
693
+ Examples
694
+ ========
695
+
696
+ >>> from sympy import chebyshevt, chebyshevt_root
697
+ >>> chebyshevt_root(3, 2)
698
+ -sqrt(3)/2
699
+ >>> chebyshevt(3, chebyshevt_root(3, 2))
700
+ 0
701
+
702
+ See Also
703
+ ========
704
+
705
+ jacobi, gegenbauer,
706
+ chebyshevt, chebyshevu, chebyshevu_root,
707
+ legendre, assoc_legendre,
708
+ hermite, hermite_prob,
709
+ laguerre, assoc_laguerre,
710
+ sympy.polys.orthopolys.jacobi_poly
711
+ sympy.polys.orthopolys.gegenbauer_poly
712
+ sympy.polys.orthopolys.chebyshevt_poly
713
+ sympy.polys.orthopolys.chebyshevu_poly
714
+ sympy.polys.orthopolys.hermite_poly
715
+ sympy.polys.orthopolys.hermite_prob_poly
716
+ sympy.polys.orthopolys.legendre_poly
717
+ sympy.polys.orthopolys.laguerre_poly
718
+ """
719
+
720
+ @classmethod
721
+ def eval(cls, n, k):
722
+ if not ((0 <= k) and (k < n)):
723
+ raise ValueError("must have 0 <= k < n, "
724
+ "got k = %s and n = %s" % (k, n))
725
+ return cos(S.Pi*(2*k + 1)/(2*n))
726
+
727
+
728
+ class chebyshevu_root(DefinedFunction):
729
+ r"""
730
+ ``chebyshevu_root(n, k)`` returns the $k$th root (indexed from zero) of the
731
+ $n$th Chebyshev polynomial of the second kind; that is, if $0 \le k < n$,
732
+ ``chebyshevu(n, chebyshevu_root(n, k)) == 0``.
733
+
734
+ Examples
735
+ ========
736
+
737
+ >>> from sympy import chebyshevu, chebyshevu_root
738
+ >>> chebyshevu_root(3, 2)
739
+ -sqrt(2)/2
740
+ >>> chebyshevu(3, chebyshevu_root(3, 2))
741
+ 0
742
+
743
+ See Also
744
+ ========
745
+
746
+ chebyshevt, chebyshevt_root, chebyshevu,
747
+ legendre, assoc_legendre,
748
+ hermite, hermite_prob,
749
+ laguerre, assoc_laguerre,
750
+ sympy.polys.orthopolys.jacobi_poly
751
+ sympy.polys.orthopolys.gegenbauer_poly
752
+ sympy.polys.orthopolys.chebyshevt_poly
753
+ sympy.polys.orthopolys.chebyshevu_poly
754
+ sympy.polys.orthopolys.hermite_poly
755
+ sympy.polys.orthopolys.hermite_prob_poly
756
+ sympy.polys.orthopolys.legendre_poly
757
+ sympy.polys.orthopolys.laguerre_poly
758
+ """
759
+
760
+
761
+ @classmethod
762
+ def eval(cls, n, k):
763
+ if not ((0 <= k) and (k < n)):
764
+ raise ValueError("must have 0 <= k < n, "
765
+ "got k = %s and n = %s" % (k, n))
766
+ return cos(S.Pi*(k + 1)/(n + 1))
767
+
768
+ #----------------------------------------------------------------------------
769
+ # Legendre polynomials and Associated Legendre polynomials
770
+ #
771
+
772
+
773
+ class legendre(OrthogonalPolynomial):
774
+ r"""
775
+ ``legendre(n, x)`` gives the $n$th Legendre polynomial of $x$, $P_n(x)$
776
+
777
+ Explanation
778
+ ===========
779
+
780
+ The Legendre polynomials are orthogonal on $[-1, 1]$ with respect to
781
+ the constant weight 1. They satisfy $P_n(1) = 1$ for all $n$; further,
782
+ $P_n$ is odd for odd $n$ and even for even $n$.
783
+
784
+ Examples
785
+ ========
786
+
787
+ >>> from sympy import legendre, diff
788
+ >>> from sympy.abc import x, n
789
+ >>> legendre(0, x)
790
+ 1
791
+ >>> legendre(1, x)
792
+ x
793
+ >>> legendre(2, x)
794
+ 3*x**2/2 - 1/2
795
+ >>> legendre(n, x)
796
+ legendre(n, x)
797
+ >>> diff(legendre(n,x), x)
798
+ n*(x*legendre(n, x) - legendre(n - 1, x))/(x**2 - 1)
799
+
800
+ See Also
801
+ ========
802
+
803
+ jacobi, gegenbauer,
804
+ chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root,
805
+ assoc_legendre,
806
+ hermite, hermite_prob,
807
+ laguerre, assoc_laguerre,
808
+ sympy.polys.orthopolys.jacobi_poly
809
+ sympy.polys.orthopolys.gegenbauer_poly
810
+ sympy.polys.orthopolys.chebyshevt_poly
811
+ sympy.polys.orthopolys.chebyshevu_poly
812
+ sympy.polys.orthopolys.hermite_poly
813
+ sympy.polys.orthopolys.hermite_prob_poly
814
+ sympy.polys.orthopolys.legendre_poly
815
+ sympy.polys.orthopolys.laguerre_poly
816
+
817
+ References
818
+ ==========
819
+
820
+ .. [1] https://en.wikipedia.org/wiki/Legendre_polynomial
821
+ .. [2] https://mathworld.wolfram.com/LegendrePolynomial.html
822
+ .. [3] https://functions.wolfram.com/Polynomials/LegendreP/
823
+ .. [4] https://functions.wolfram.com/Polynomials/LegendreP2/
824
+
825
+ """
826
+
827
+ _ortho_poly = staticmethod(legendre_poly)
828
+
829
+ @classmethod
830
+ def eval(cls, n, x):
831
+ if not n.is_Number:
832
+ # Symbolic result L_n(x)
833
+ # L_n(-x) ---> (-1)**n * L_n(x)
834
+ if x.could_extract_minus_sign():
835
+ return S.NegativeOne**n * legendre(n, -x)
836
+ # L_{-n}(x) ---> L_{n-1}(x)
837
+ if n.could_extract_minus_sign() and not(-n - 1).could_extract_minus_sign():
838
+ return legendre(-n - S.One, x)
839
+ # We can evaluate for some special values of x
840
+ if x.is_zero:
841
+ return sqrt(S.Pi)/(gamma(S.Half - n/2)*gamma(S.One + n/2))
842
+ elif x == S.One:
843
+ return S.One
844
+ elif x is S.Infinity:
845
+ return S.Infinity
846
+ else:
847
+ # n is a given fixed integer, evaluate into polynomial;
848
+ # L_{-n}(x) ---> L_{n-1}(x)
849
+ if n.is_negative:
850
+ n = -n - S.One
851
+ return cls._eval_at_order(n, x)
852
+
853
+ def fdiff(self, argindex=2):
854
+ if argindex == 1:
855
+ # Diff wrt n
856
+ raise ArgumentIndexError(self, argindex)
857
+ elif argindex == 2:
858
+ # Diff wrt x
859
+ # Find better formula, this is unsuitable for x = +/-1
860
+ # https://www.autodiff.org/ad16/Oral/Buecker_Legendre.pdf says
861
+ # at x = 1:
862
+ # n*(n + 1)/2 , m = 0
863
+ # oo , m = 1
864
+ # -(n-1)*n*(n+1)*(n+2)/4 , m = 2
865
+ # 0 , m = 3, 4, ..., n
866
+ #
867
+ # at x = -1
868
+ # (-1)**(n+1)*n*(n + 1)/2 , m = 0
869
+ # (-1)**n*oo , m = 1
870
+ # (-1)**n*(n-1)*n*(n+1)*(n+2)/4 , m = 2
871
+ # 0 , m = 3, 4, ..., n
872
+ n, x = self.args
873
+ return n/(x**2 - 1)*(x*legendre(n, x) - legendre(n - 1, x))
874
+ else:
875
+ raise ArgumentIndexError(self, argindex)
876
+
877
+ def _eval_rewrite_as_Sum(self, n, x, **kwargs):
878
+ from sympy.concrete.summations import Sum
879
+ k = Dummy("k")
880
+ kern = S.NegativeOne**k*binomial(n, k)**2*((1 + x)/2)**(n - k)*((1 - x)/2)**k
881
+ return Sum(kern, (k, 0, n))
882
+
883
+ def _eval_rewrite_as_polynomial(self, n, x, **kwargs):
884
+ # This function is just kept for backwards compatibility
885
+ # but should not be used
886
+ return self._eval_rewrite_as_Sum(n, x, **kwargs)
887
+
888
+
889
+ class assoc_legendre(DefinedFunction):
890
+ r"""
891
+ ``assoc_legendre(n, m, x)`` gives $P_n^m(x)$, where $n$ and $m$ are
892
+ the degree and order or an expression which is related to the nth
893
+ order Legendre polynomial, $P_n(x)$ in the following manner:
894
+
895
+ .. math::
896
+ P_n^m(x) = (-1)^m (1 - x^2)^{\frac{m}{2}}
897
+ \frac{\mathrm{d}^m P_n(x)}{\mathrm{d} x^m}
898
+
899
+ Explanation
900
+ ===========
901
+
902
+ Associated Legendre polynomials are orthogonal on $[-1, 1]$ with:
903
+
904
+ - weight $= 1$ for the same $m$ and different $n$.
905
+ - weight $= \frac{1}{1-x^2}$ for the same $n$ and different $m$.
906
+
907
+ Examples
908
+ ========
909
+
910
+ >>> from sympy import assoc_legendre
911
+ >>> from sympy.abc import x, m, n
912
+ >>> assoc_legendre(0,0, x)
913
+ 1
914
+ >>> assoc_legendre(1,0, x)
915
+ x
916
+ >>> assoc_legendre(1,1, x)
917
+ -sqrt(1 - x**2)
918
+ >>> assoc_legendre(n,m,x)
919
+ assoc_legendre(n, m, x)
920
+
921
+ See Also
922
+ ========
923
+
924
+ jacobi, gegenbauer,
925
+ chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root,
926
+ legendre,
927
+ hermite, hermite_prob,
928
+ laguerre, assoc_laguerre,
929
+ sympy.polys.orthopolys.jacobi_poly
930
+ sympy.polys.orthopolys.gegenbauer_poly
931
+ sympy.polys.orthopolys.chebyshevt_poly
932
+ sympy.polys.orthopolys.chebyshevu_poly
933
+ sympy.polys.orthopolys.hermite_poly
934
+ sympy.polys.orthopolys.hermite_prob_poly
935
+ sympy.polys.orthopolys.legendre_poly
936
+ sympy.polys.orthopolys.laguerre_poly
937
+
938
+ References
939
+ ==========
940
+
941
+ .. [1] https://en.wikipedia.org/wiki/Associated_Legendre_polynomials
942
+ .. [2] https://mathworld.wolfram.com/LegendrePolynomial.html
943
+ .. [3] https://functions.wolfram.com/Polynomials/LegendreP/
944
+ .. [4] https://functions.wolfram.com/Polynomials/LegendreP2/
945
+
946
+ """
947
+
948
+ @classmethod
949
+ def _eval_at_order(cls, n, m):
950
+ P = legendre_poly(n, _x, polys=True).diff((_x, m))
951
+ return S.NegativeOne**m * (1 - _x**2)**Rational(m, 2) * P.as_expr()
952
+
953
+ @classmethod
954
+ def eval(cls, n, m, x):
955
+ if m.could_extract_minus_sign():
956
+ # P^{-m}_n ---> F * P^m_n
957
+ return S.NegativeOne**(-m) * (factorial(m + n)/factorial(n - m)) * assoc_legendre(n, -m, x)
958
+ if m == 0:
959
+ # P^0_n ---> L_n
960
+ return legendre(n, x)
961
+ if x == 0:
962
+ return 2**m*sqrt(S.Pi) / (gamma((1 - m - n)/2)*gamma(1 - (m - n)/2))
963
+ if n.is_Number and m.is_Number and n.is_integer and m.is_integer:
964
+ if n.is_negative:
965
+ raise ValueError("%s : 1st index must be nonnegative integer (got %r)" % (cls, n))
966
+ if abs(m) > n:
967
+ raise ValueError("%s : abs('2nd index') must be <= '1st index' (got %r, %r)" % (cls, n, m))
968
+ return cls._eval_at_order(int(n), abs(int(m))).subs(_x, x)
969
+
970
+ def fdiff(self, argindex=3):
971
+ if argindex == 1:
972
+ # Diff wrt n
973
+ raise ArgumentIndexError(self, argindex)
974
+ elif argindex == 2:
975
+ # Diff wrt m
976
+ raise ArgumentIndexError(self, argindex)
977
+ elif argindex == 3:
978
+ # Diff wrt x
979
+ # Find better formula, this is unsuitable for x = 1
980
+ n, m, x = self.args
981
+ return 1/(x**2 - 1)*(x*n*assoc_legendre(n, m, x) - (m + n)*assoc_legendre(n - 1, m, x))
982
+ else:
983
+ raise ArgumentIndexError(self, argindex)
984
+
985
+ def _eval_rewrite_as_Sum(self, n, m, x, **kwargs):
986
+ from sympy.concrete.summations import Sum
987
+ k = Dummy("k")
988
+ kern = factorial(2*n - 2*k)/(2**n*factorial(n - k)*factorial(
989
+ k)*factorial(n - 2*k - m))*S.NegativeOne**k*x**(n - m - 2*k)
990
+ return (1 - x**2)**(m/2) * Sum(kern, (k, 0, floor((n - m)*S.Half)))
991
+
992
+ def _eval_rewrite_as_polynomial(self, n, m, x, **kwargs):
993
+ # This function is just kept for backwards compatibility
994
+ # but should not be used
995
+ return self._eval_rewrite_as_Sum(n, m, x, **kwargs)
996
+
997
+ def _eval_conjugate(self):
998
+ n, m, x = self.args
999
+ return self.func(n, m.conjugate(), x.conjugate())
1000
+
1001
+ #----------------------------------------------------------------------------
1002
+ # Hermite polynomials
1003
+ #
1004
+
1005
+
1006
+ class hermite(OrthogonalPolynomial):
1007
+ r"""
1008
+ ``hermite(n, x)`` gives the $n$th Hermite polynomial in $x$, $H_n(x)$.
1009
+
1010
+ Explanation
1011
+ ===========
1012
+
1013
+ The Hermite polynomials are orthogonal on $(-\infty, \infty)$
1014
+ with respect to the weight $\exp\left(-x^2\right)$.
1015
+
1016
+ Examples
1017
+ ========
1018
+
1019
+ >>> from sympy import hermite, diff
1020
+ >>> from sympy.abc import x, n
1021
+ >>> hermite(0, x)
1022
+ 1
1023
+ >>> hermite(1, x)
1024
+ 2*x
1025
+ >>> hermite(2, x)
1026
+ 4*x**2 - 2
1027
+ >>> hermite(n, x)
1028
+ hermite(n, x)
1029
+ >>> diff(hermite(n,x), x)
1030
+ 2*n*hermite(n - 1, x)
1031
+ >>> hermite(n, -x)
1032
+ (-1)**n*hermite(n, x)
1033
+
1034
+ See Also
1035
+ ========
1036
+
1037
+ jacobi, gegenbauer,
1038
+ chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root,
1039
+ legendre, assoc_legendre,
1040
+ hermite_prob,
1041
+ laguerre, assoc_laguerre,
1042
+ sympy.polys.orthopolys.jacobi_poly
1043
+ sympy.polys.orthopolys.gegenbauer_poly
1044
+ sympy.polys.orthopolys.chebyshevt_poly
1045
+ sympy.polys.orthopolys.chebyshevu_poly
1046
+ sympy.polys.orthopolys.hermite_poly
1047
+ sympy.polys.orthopolys.hermite_prob_poly
1048
+ sympy.polys.orthopolys.legendre_poly
1049
+ sympy.polys.orthopolys.laguerre_poly
1050
+
1051
+ References
1052
+ ==========
1053
+
1054
+ .. [1] https://en.wikipedia.org/wiki/Hermite_polynomial
1055
+ .. [2] https://mathworld.wolfram.com/HermitePolynomial.html
1056
+ .. [3] https://functions.wolfram.com/Polynomials/HermiteH/
1057
+
1058
+ """
1059
+
1060
+ _ortho_poly = staticmethod(hermite_poly)
1061
+
1062
+ @classmethod
1063
+ def eval(cls, n, x):
1064
+ if not n.is_Number:
1065
+ # Symbolic result H_n(x)
1066
+ # H_n(-x) ---> (-1)**n * H_n(x)
1067
+ if x.could_extract_minus_sign():
1068
+ return S.NegativeOne**n * hermite(n, -x)
1069
+ # We can evaluate for some special values of x
1070
+ if x.is_zero:
1071
+ return 2**n * sqrt(S.Pi) / gamma((S.One - n)/2)
1072
+ elif x is S.Infinity:
1073
+ return S.Infinity
1074
+ else:
1075
+ # n is a given fixed integer, evaluate into polynomial
1076
+ if n.is_negative:
1077
+ raise ValueError(
1078
+ "The index n must be nonnegative integer (got %r)" % n)
1079
+ else:
1080
+ return cls._eval_at_order(n, x)
1081
+
1082
+ def fdiff(self, argindex=2):
1083
+ if argindex == 1:
1084
+ # Diff wrt n
1085
+ raise ArgumentIndexError(self, argindex)
1086
+ elif argindex == 2:
1087
+ # Diff wrt x
1088
+ n, x = self.args
1089
+ return 2*n*hermite(n - 1, x)
1090
+ else:
1091
+ raise ArgumentIndexError(self, argindex)
1092
+
1093
+ def _eval_rewrite_as_Sum(self, n, x, **kwargs):
1094
+ from sympy.concrete.summations import Sum
1095
+ k = Dummy("k")
1096
+ kern = S.NegativeOne**k / (factorial(k)*factorial(n - 2*k)) * (2*x)**(n - 2*k)
1097
+ return factorial(n)*Sum(kern, (k, 0, floor(n/2)))
1098
+
1099
+ def _eval_rewrite_as_polynomial(self, n, x, **kwargs):
1100
+ # This function is just kept for backwards compatibility
1101
+ # but should not be used
1102
+ return self._eval_rewrite_as_Sum(n, x, **kwargs)
1103
+
1104
+ def _eval_rewrite_as_hermite_prob(self, n, x, **kwargs):
1105
+ return sqrt(2)**n * hermite_prob(n, x*sqrt(2))
1106
+
1107
+
1108
+ class hermite_prob(OrthogonalPolynomial):
1109
+ r"""
1110
+ ``hermite_prob(n, x)`` gives the $n$th probabilist's Hermite polynomial
1111
+ in $x$, $He_n(x)$.
1112
+
1113
+ Explanation
1114
+ ===========
1115
+
1116
+ The probabilist's Hermite polynomials are orthogonal on $(-\infty, \infty)$
1117
+ with respect to the weight $\exp\left(-\frac{x^2}{2}\right)$. They are monic
1118
+ polynomials, related to the plain Hermite polynomials (:py:class:`~.hermite`) by
1119
+
1120
+ .. math :: He_n(x) = 2^{-n/2} H_n(x/\sqrt{2})
1121
+
1122
+ Examples
1123
+ ========
1124
+
1125
+ >>> from sympy import hermite_prob, diff, I
1126
+ >>> from sympy.abc import x, n
1127
+ >>> hermite_prob(1, x)
1128
+ x
1129
+ >>> hermite_prob(5, x)
1130
+ x**5 - 10*x**3 + 15*x
1131
+ >>> diff(hermite_prob(n,x), x)
1132
+ n*hermite_prob(n - 1, x)
1133
+ >>> hermite_prob(n, -x)
1134
+ (-1)**n*hermite_prob(n, x)
1135
+
1136
+ The sum of absolute values of coefficients of $He_n(x)$ is the number of
1137
+ matchings in the complete graph $K_n$ or telephone number, A000085 in the OEIS:
1138
+
1139
+ >>> [hermite_prob(n,I) / I**n for n in range(11)]
1140
+ [1, 1, 2, 4, 10, 26, 76, 232, 764, 2620, 9496]
1141
+
1142
+ See Also
1143
+ ========
1144
+
1145
+ jacobi, gegenbauer,
1146
+ chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root,
1147
+ legendre, assoc_legendre,
1148
+ hermite,
1149
+ laguerre, assoc_laguerre,
1150
+ sympy.polys.orthopolys.jacobi_poly
1151
+ sympy.polys.orthopolys.gegenbauer_poly
1152
+ sympy.polys.orthopolys.chebyshevt_poly
1153
+ sympy.polys.orthopolys.chebyshevu_poly
1154
+ sympy.polys.orthopolys.hermite_poly
1155
+ sympy.polys.orthopolys.hermite_prob_poly
1156
+ sympy.polys.orthopolys.legendre_poly
1157
+ sympy.polys.orthopolys.laguerre_poly
1158
+
1159
+ References
1160
+ ==========
1161
+
1162
+ .. [1] https://en.wikipedia.org/wiki/Hermite_polynomial
1163
+ .. [2] https://mathworld.wolfram.com/HermitePolynomial.html
1164
+ """
1165
+
1166
+ _ortho_poly = staticmethod(hermite_prob_poly)
1167
+
1168
+ @classmethod
1169
+ def eval(cls, n, x):
1170
+ if not n.is_Number:
1171
+ if x.could_extract_minus_sign():
1172
+ return S.NegativeOne**n * hermite_prob(n, -x)
1173
+ if x.is_zero:
1174
+ return sqrt(S.Pi) / gamma((S.One-n) / 2)
1175
+ elif x is S.Infinity:
1176
+ return S.Infinity
1177
+ else:
1178
+ if n.is_negative:
1179
+ ValueError("n must be a nonnegative integer, not %r" % n)
1180
+ else:
1181
+ return cls._eval_at_order(n, x)
1182
+
1183
+ def fdiff(self, argindex=2):
1184
+ if argindex == 2:
1185
+ n, x = self.args
1186
+ return n*hermite_prob(n-1, x)
1187
+ else:
1188
+ raise ArgumentIndexError(self, argindex)
1189
+
1190
+ def _eval_rewrite_as_Sum(self, n, x, **kwargs):
1191
+ from sympy.concrete.summations import Sum
1192
+ k = Dummy("k")
1193
+ kern = (-S.Half)**k * x**(n-2*k) / (factorial(k) * factorial(n-2*k))
1194
+ return factorial(n)*Sum(kern, (k, 0, floor(n/2)))
1195
+
1196
+ def _eval_rewrite_as_polynomial(self, n, x, **kwargs):
1197
+ # This function is just kept for backwards compatibility
1198
+ # but should not be used
1199
+ return self._eval_rewrite_as_Sum(n, x, **kwargs)
1200
+
1201
+ def _eval_rewrite_as_hermite(self, n, x, **kwargs):
1202
+ return sqrt(2)**(-n) * hermite(n, x/sqrt(2))
1203
+
1204
+
1205
+ #----------------------------------------------------------------------------
1206
+ # Laguerre polynomials
1207
+ #
1208
+
1209
+
1210
+ class laguerre(OrthogonalPolynomial):
1211
+ r"""
1212
+ Returns the $n$th Laguerre polynomial in $x$, $L_n(x)$.
1213
+
1214
+ Examples
1215
+ ========
1216
+
1217
+ >>> from sympy import laguerre, diff
1218
+ >>> from sympy.abc import x, n
1219
+ >>> laguerre(0, x)
1220
+ 1
1221
+ >>> laguerre(1, x)
1222
+ 1 - x
1223
+ >>> laguerre(2, x)
1224
+ x**2/2 - 2*x + 1
1225
+ >>> laguerre(3, x)
1226
+ -x**3/6 + 3*x**2/2 - 3*x + 1
1227
+
1228
+ >>> laguerre(n, x)
1229
+ laguerre(n, x)
1230
+
1231
+ >>> diff(laguerre(n, x), x)
1232
+ -assoc_laguerre(n - 1, 1, x)
1233
+
1234
+ Parameters
1235
+ ==========
1236
+
1237
+ n : int
1238
+ Degree of Laguerre polynomial. Must be `n \ge 0`.
1239
+
1240
+ See Also
1241
+ ========
1242
+
1243
+ jacobi, gegenbauer,
1244
+ chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root,
1245
+ legendre, assoc_legendre,
1246
+ hermite, hermite_prob,
1247
+ assoc_laguerre,
1248
+ sympy.polys.orthopolys.jacobi_poly
1249
+ sympy.polys.orthopolys.gegenbauer_poly
1250
+ sympy.polys.orthopolys.chebyshevt_poly
1251
+ sympy.polys.orthopolys.chebyshevu_poly
1252
+ sympy.polys.orthopolys.hermite_poly
1253
+ sympy.polys.orthopolys.hermite_prob_poly
1254
+ sympy.polys.orthopolys.legendre_poly
1255
+ sympy.polys.orthopolys.laguerre_poly
1256
+
1257
+ References
1258
+ ==========
1259
+
1260
+ .. [1] https://en.wikipedia.org/wiki/Laguerre_polynomial
1261
+ .. [2] https://mathworld.wolfram.com/LaguerrePolynomial.html
1262
+ .. [3] https://functions.wolfram.com/Polynomials/LaguerreL/
1263
+ .. [4] https://functions.wolfram.com/Polynomials/LaguerreL3/
1264
+
1265
+ """
1266
+
1267
+ _ortho_poly = staticmethod(laguerre_poly)
1268
+
1269
+ @classmethod
1270
+ def eval(cls, n, x):
1271
+ if n.is_integer is False:
1272
+ raise ValueError("Error: n should be an integer.")
1273
+ if not n.is_Number:
1274
+ # Symbolic result L_n(x)
1275
+ # L_{n}(-x) ---> exp(-x) * L_{-n-1}(x)
1276
+ # L_{-n}(x) ---> exp(x) * L_{n-1}(-x)
1277
+ if n.could_extract_minus_sign() and not(-n - 1).could_extract_minus_sign():
1278
+ return exp(x)*laguerre(-n - 1, -x)
1279
+ # We can evaluate for some special values of x
1280
+ if x.is_zero:
1281
+ return S.One
1282
+ elif x is S.NegativeInfinity:
1283
+ return S.Infinity
1284
+ elif x is S.Infinity:
1285
+ return S.NegativeOne**n * S.Infinity
1286
+ else:
1287
+ if n.is_negative:
1288
+ return exp(x)*laguerre(-n - 1, -x)
1289
+ else:
1290
+ return cls._eval_at_order(n, x)
1291
+
1292
+ def fdiff(self, argindex=2):
1293
+ if argindex == 1:
1294
+ # Diff wrt n
1295
+ raise ArgumentIndexError(self, argindex)
1296
+ elif argindex == 2:
1297
+ # Diff wrt x
1298
+ n, x = self.args
1299
+ return -assoc_laguerre(n - 1, 1, x)
1300
+ else:
1301
+ raise ArgumentIndexError(self, argindex)
1302
+
1303
+ def _eval_rewrite_as_Sum(self, n, x, **kwargs):
1304
+ from sympy.concrete.summations import Sum
1305
+ # Make sure n \in N_0
1306
+ if n.is_negative:
1307
+ return exp(x) * self._eval_rewrite_as_Sum(-n - 1, -x, **kwargs)
1308
+ if n.is_integer is False:
1309
+ raise ValueError("Error: n should be an integer.")
1310
+ k = Dummy("k")
1311
+ kern = RisingFactorial(-n, k) / factorial(k)**2 * x**k
1312
+ return Sum(kern, (k, 0, n))
1313
+
1314
+ def _eval_rewrite_as_polynomial(self, n, x, **kwargs):
1315
+ # This function is just kept for backwards compatibility
1316
+ # but should not be used
1317
+ return self._eval_rewrite_as_Sum(n, x, **kwargs)
1318
+
1319
+
1320
+ class assoc_laguerre(OrthogonalPolynomial):
1321
+ r"""
1322
+ Returns the $n$th generalized Laguerre polynomial in $x$, $L_n(x)$.
1323
+
1324
+ Examples
1325
+ ========
1326
+
1327
+ >>> from sympy import assoc_laguerre, diff
1328
+ >>> from sympy.abc import x, n, a
1329
+ >>> assoc_laguerre(0, a, x)
1330
+ 1
1331
+ >>> assoc_laguerre(1, a, x)
1332
+ a - x + 1
1333
+ >>> assoc_laguerre(2, a, x)
1334
+ a**2/2 + 3*a/2 + x**2/2 + x*(-a - 2) + 1
1335
+ >>> assoc_laguerre(3, a, x)
1336
+ a**3/6 + a**2 + 11*a/6 - x**3/6 + x**2*(a/2 + 3/2) +
1337
+ x*(-a**2/2 - 5*a/2 - 3) + 1
1338
+
1339
+ >>> assoc_laguerre(n, a, 0)
1340
+ binomial(a + n, a)
1341
+
1342
+ >>> assoc_laguerre(n, a, x)
1343
+ assoc_laguerre(n, a, x)
1344
+
1345
+ >>> assoc_laguerre(n, 0, x)
1346
+ laguerre(n, x)
1347
+
1348
+ >>> diff(assoc_laguerre(n, a, x), x)
1349
+ -assoc_laguerre(n - 1, a + 1, x)
1350
+
1351
+ >>> diff(assoc_laguerre(n, a, x), a)
1352
+ Sum(assoc_laguerre(_k, a, x)/(-a + n), (_k, 0, n - 1))
1353
+
1354
+ Parameters
1355
+ ==========
1356
+
1357
+ n : int
1358
+ Degree of Laguerre polynomial. Must be `n \ge 0`.
1359
+
1360
+ alpha : Expr
1361
+ Arbitrary expression. For ``alpha=0`` regular Laguerre
1362
+ polynomials will be generated.
1363
+
1364
+ See Also
1365
+ ========
1366
+
1367
+ jacobi, gegenbauer,
1368
+ chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root,
1369
+ legendre, assoc_legendre,
1370
+ hermite, hermite_prob,
1371
+ laguerre,
1372
+ sympy.polys.orthopolys.jacobi_poly
1373
+ sympy.polys.orthopolys.gegenbauer_poly
1374
+ sympy.polys.orthopolys.chebyshevt_poly
1375
+ sympy.polys.orthopolys.chebyshevu_poly
1376
+ sympy.polys.orthopolys.hermite_poly
1377
+ sympy.polys.orthopolys.hermite_prob_poly
1378
+ sympy.polys.orthopolys.legendre_poly
1379
+ sympy.polys.orthopolys.laguerre_poly
1380
+
1381
+ References
1382
+ ==========
1383
+
1384
+ .. [1] https://en.wikipedia.org/wiki/Laguerre_polynomial#Generalized_Laguerre_polynomials
1385
+ .. [2] https://mathworld.wolfram.com/AssociatedLaguerrePolynomial.html
1386
+ .. [3] https://functions.wolfram.com/Polynomials/LaguerreL/
1387
+ .. [4] https://functions.wolfram.com/Polynomials/LaguerreL3/
1388
+
1389
+ """
1390
+
1391
+ @classmethod
1392
+ def eval(cls, n, alpha, x):
1393
+ # L_{n}^{0}(x) ---> L_{n}(x)
1394
+ if alpha.is_zero:
1395
+ return laguerre(n, x)
1396
+
1397
+ if not n.is_Number:
1398
+ # We can evaluate for some special values of x
1399
+ if x.is_zero:
1400
+ return binomial(n + alpha, alpha)
1401
+ elif x is S.Infinity and n > 0:
1402
+ return S.NegativeOne**n * S.Infinity
1403
+ elif x is S.NegativeInfinity and n > 0:
1404
+ return S.Infinity
1405
+ else:
1406
+ # n is a given fixed integer, evaluate into polynomial
1407
+ if n.is_negative:
1408
+ raise ValueError(
1409
+ "The index n must be nonnegative integer (got %r)" % n)
1410
+ else:
1411
+ return laguerre_poly(n, x, alpha)
1412
+
1413
+ def fdiff(self, argindex=3):
1414
+ from sympy.concrete.summations import Sum
1415
+ if argindex == 1:
1416
+ # Diff wrt n
1417
+ raise ArgumentIndexError(self, argindex)
1418
+ elif argindex == 2:
1419
+ # Diff wrt alpha
1420
+ n, alpha, x = self.args
1421
+ k = Dummy("k")
1422
+ return Sum(assoc_laguerre(k, alpha, x) / (n - alpha), (k, 0, n - 1))
1423
+ elif argindex == 3:
1424
+ # Diff wrt x
1425
+ n, alpha, x = self.args
1426
+ return -assoc_laguerre(n - 1, alpha + 1, x)
1427
+ else:
1428
+ raise ArgumentIndexError(self, argindex)
1429
+
1430
+ def _eval_rewrite_as_Sum(self, n, alpha, x, **kwargs):
1431
+ from sympy.concrete.summations import Sum
1432
+ # Make sure n \in N_0
1433
+ if n.is_negative or n.is_integer is False:
1434
+ raise ValueError("Error: n should be a non-negative integer.")
1435
+ k = Dummy("k")
1436
+ kern = RisingFactorial(
1437
+ -n, k) / (gamma(k + alpha + 1) * factorial(k)) * x**k
1438
+ return gamma(n + alpha + 1) / factorial(n) * Sum(kern, (k, 0, n))
1439
+
1440
+ def _eval_rewrite_as_polynomial(self, n, alpha, x, **kwargs):
1441
+ # This function is just kept for backwards compatibility
1442
+ # but should not be used
1443
+ return self._eval_rewrite_as_Sum(n, alpha, x, **kwargs)
1444
+
1445
+ def _eval_conjugate(self):
1446
+ n, alpha, x = self.args
1447
+ return self.func(n, alpha.conjugate(), x.conjugate())
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/singularity_functions.py ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import S, oo, diff
2
+ from sympy.core.function import DefinedFunction, ArgumentIndexError
3
+ from sympy.core.logic import fuzzy_not
4
+ from sympy.core.relational import Eq
5
+ from sympy.functions.elementary.complexes import im
6
+ from sympy.functions.elementary.piecewise import Piecewise
7
+ from sympy.functions.special.delta_functions import Heaviside
8
+
9
+ ###############################################################################
10
+ ############################# SINGULARITY FUNCTION ############################
11
+ ###############################################################################
12
+
13
+
14
+ class SingularityFunction(DefinedFunction):
15
+ r"""
16
+ Singularity functions are a class of discontinuous functions.
17
+
18
+ Explanation
19
+ ===========
20
+
21
+ Singularity functions take a variable, an offset, and an exponent as
22
+ arguments. These functions are represented using Macaulay brackets as:
23
+
24
+ SingularityFunction(x, a, n) := <x - a>^n
25
+
26
+ The singularity function will automatically evaluate to
27
+ ``Derivative(DiracDelta(x - a), x, -n - 1)`` if ``n < 0``
28
+ and ``(x - a)**n*Heaviside(x - a, 1)`` if ``n >= 0``.
29
+
30
+ Examples
31
+ ========
32
+
33
+ >>> from sympy import SingularityFunction, diff, Piecewise, DiracDelta, Heaviside, Symbol
34
+ >>> from sympy.abc import x, a, n
35
+ >>> SingularityFunction(x, a, n)
36
+ SingularityFunction(x, a, n)
37
+ >>> y = Symbol('y', positive=True)
38
+ >>> n = Symbol('n', nonnegative=True)
39
+ >>> SingularityFunction(y, -10, n)
40
+ (y + 10)**n
41
+ >>> y = Symbol('y', negative=True)
42
+ >>> SingularityFunction(y, 10, n)
43
+ 0
44
+ >>> SingularityFunction(x, 4, -1).subs(x, 4)
45
+ oo
46
+ >>> SingularityFunction(x, 10, -2).subs(x, 10)
47
+ oo
48
+ >>> SingularityFunction(4, 1, 5)
49
+ 243
50
+ >>> diff(SingularityFunction(x, 1, 5) + SingularityFunction(x, 1, 4), x)
51
+ 4*SingularityFunction(x, 1, 3) + 5*SingularityFunction(x, 1, 4)
52
+ >>> diff(SingularityFunction(x, 4, 0), x, 2)
53
+ SingularityFunction(x, 4, -2)
54
+ >>> SingularityFunction(x, 4, 5).rewrite(Piecewise)
55
+ Piecewise(((x - 4)**5, x >= 4), (0, True))
56
+ >>> expr = SingularityFunction(x, a, n)
57
+ >>> y = Symbol('y', positive=True)
58
+ >>> n = Symbol('n', nonnegative=True)
59
+ >>> expr.subs({x: y, a: -10, n: n})
60
+ (y + 10)**n
61
+
62
+ The methods ``rewrite(DiracDelta)``, ``rewrite(Heaviside)``, and
63
+ ``rewrite('HeavisideDiracDelta')`` returns the same output. One can use any
64
+ of these methods according to their choice.
65
+
66
+ >>> expr = SingularityFunction(x, 4, 5) + SingularityFunction(x, -3, -1) - SingularityFunction(x, 0, -2)
67
+ >>> expr.rewrite(Heaviside)
68
+ (x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
69
+ >>> expr.rewrite(DiracDelta)
70
+ (x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
71
+ >>> expr.rewrite('HeavisideDiracDelta')
72
+ (x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
73
+
74
+ See Also
75
+ ========
76
+
77
+ DiracDelta, Heaviside
78
+
79
+ References
80
+ ==========
81
+
82
+ .. [1] https://en.wikipedia.org/wiki/Singularity_function
83
+
84
+ """
85
+
86
+ is_real = True
87
+
88
+ def fdiff(self, argindex=1):
89
+ """
90
+ Returns the first derivative of a DiracDelta Function.
91
+
92
+ Explanation
93
+ ===========
94
+
95
+ The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the
96
+ user-level function and ``fdiff()`` is an object method. ``fdiff()`` is
97
+ a convenience method available in the ``Function`` class. It returns
98
+ the derivative of the function without considering the chain rule.
99
+ ``diff(function, x)`` calls ``Function._eval_derivative`` which in turn
100
+ calls ``fdiff()`` internally to compute the derivative of the function.
101
+
102
+ """
103
+
104
+ if argindex == 1:
105
+ x, a, n = self.args
106
+ if n in (S.Zero, S.NegativeOne, S(-2), S(-3)):
107
+ return self.func(x, a, n-1)
108
+ elif n.is_positive:
109
+ return n*self.func(x, a, n-1)
110
+ else:
111
+ raise ArgumentIndexError(self, argindex)
112
+
113
+ @classmethod
114
+ def eval(cls, variable, offset, exponent):
115
+ """
116
+ Returns a simplified form or a value of Singularity Function depending
117
+ on the argument passed by the object.
118
+
119
+ Explanation
120
+ ===========
121
+
122
+ The ``eval()`` method is automatically called when the
123
+ ``SingularityFunction`` class is about to be instantiated and it
124
+ returns either some simplified instance or the unevaluated instance
125
+ depending on the argument passed. In other words, ``eval()`` method is
126
+ not needed to be called explicitly, it is being called and evaluated
127
+ once the object is called.
128
+
129
+ Examples
130
+ ========
131
+
132
+ >>> from sympy import SingularityFunction, Symbol, nan
133
+ >>> from sympy.abc import x, a, n
134
+ >>> SingularityFunction(x, a, n)
135
+ SingularityFunction(x, a, n)
136
+ >>> SingularityFunction(5, 3, 2)
137
+ 4
138
+ >>> SingularityFunction(x, a, nan)
139
+ nan
140
+ >>> SingularityFunction(x, 3, 0).subs(x, 3)
141
+ 1
142
+ >>> SingularityFunction(4, 1, 5)
143
+ 243
144
+ >>> x = Symbol('x', positive = True)
145
+ >>> a = Symbol('a', negative = True)
146
+ >>> n = Symbol('n', nonnegative = True)
147
+ >>> SingularityFunction(x, a, n)
148
+ (-a + x)**n
149
+ >>> x = Symbol('x', negative = True)
150
+ >>> a = Symbol('a', positive = True)
151
+ >>> SingularityFunction(x, a, n)
152
+ 0
153
+
154
+ """
155
+
156
+ x = variable
157
+ a = offset
158
+ n = exponent
159
+ shift = (x - a)
160
+
161
+ if fuzzy_not(im(shift).is_zero):
162
+ raise ValueError("Singularity Functions are defined only for Real Numbers.")
163
+ if fuzzy_not(im(n).is_zero):
164
+ raise ValueError("Singularity Functions are not defined for imaginary exponents.")
165
+ if shift is S.NaN or n is S.NaN:
166
+ return S.NaN
167
+ if (n + 4).is_negative:
168
+ raise ValueError("Singularity Functions are not defined for exponents less than -4.")
169
+ if shift.is_extended_negative:
170
+ return S.Zero
171
+ if n.is_nonnegative:
172
+ if shift.is_zero: # use literal 0 in case of Symbol('z', zero=True)
173
+ return S.Zero**n
174
+ if shift.is_extended_nonnegative:
175
+ return shift**n
176
+ if n in (S.NegativeOne, -2, -3, -4):
177
+ if shift.is_negative or shift.is_extended_positive:
178
+ return S.Zero
179
+ if shift.is_zero:
180
+ return oo
181
+
182
+ def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
183
+ '''
184
+ Converts a Singularity Function expression into its Piecewise form.
185
+
186
+ '''
187
+ x, a, n = self.args
188
+
189
+ if n in (S.NegativeOne, S(-2), S(-3), S(-4)):
190
+ return Piecewise((oo, Eq(x - a, 0)), (0, True))
191
+ elif n.is_nonnegative:
192
+ return Piecewise(((x - a)**n, x - a >= 0), (0, True))
193
+
194
+ def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
195
+ '''
196
+ Rewrites a Singularity Function expression using Heavisides and DiracDeltas.
197
+
198
+ '''
199
+ x, a, n = self.args
200
+
201
+ if n == -4:
202
+ return diff(Heaviside(x - a), x.free_symbols.pop(), 4)
203
+ if n == -3:
204
+ return diff(Heaviside(x - a), x.free_symbols.pop(), 3)
205
+ if n == -2:
206
+ return diff(Heaviside(x - a), x.free_symbols.pop(), 2)
207
+ if n == -1:
208
+ return diff(Heaviside(x - a), x.free_symbols.pop(), 1)
209
+ if n.is_nonnegative:
210
+ return (x - a)**n*Heaviside(x - a, 1)
211
+
212
+ def _eval_as_leading_term(self, x, logx, cdir):
213
+ z, a, n = self.args
214
+ shift = (z - a).subs(x, 0)
215
+ if n < 0:
216
+ return S.Zero
217
+ elif n.is_zero and shift.is_zero:
218
+ return S.Zero if cdir == -1 else S.One
219
+ elif shift.is_positive:
220
+ return shift**n
221
+ return S.Zero
222
+
223
+ def _eval_nseries(self, x, n, logx=None, cdir=0):
224
+ z, a, n = self.args
225
+ shift = (z - a).subs(x, 0)
226
+ if n < 0:
227
+ return S.Zero
228
+ elif n.is_zero and shift.is_zero:
229
+ return S.Zero if cdir == -1 else S.One
230
+ elif shift.is_positive:
231
+ return ((z - a)**n)._eval_nseries(x, n, logx=logx, cdir=cdir)
232
+ return S.Zero
233
+
234
+ _eval_rewrite_as_DiracDelta = _eval_rewrite_as_Heaviside
235
+ _eval_rewrite_as_HeavisideDiracDelta = _eval_rewrite_as_Heaviside
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/spherical_harmonics.py ADDED
@@ -0,0 +1,334 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.expr import Expr
2
+ from sympy.core.function import DefinedFunction, ArgumentIndexError
3
+ from sympy.core.numbers import I, pi
4
+ from sympy.core.singleton import S
5
+ from sympy.core.symbol import Dummy
6
+ from sympy.functions import assoc_legendre
7
+ from sympy.functions.combinatorial.factorials import factorial
8
+ from sympy.functions.elementary.complexes import Abs, conjugate
9
+ from sympy.functions.elementary.exponential import exp
10
+ from sympy.functions.elementary.miscellaneous import sqrt
11
+ from sympy.functions.elementary.trigonometric import sin, cos, cot
12
+
13
+ _x = Dummy("x")
14
+
15
+ class Ynm(DefinedFunction):
16
+ r"""
17
+ Spherical harmonics defined as
18
+
19
+ .. math::
20
+ Y_n^m(\theta, \varphi) := \sqrt{\frac{(2n+1)(n-m)!}{4\pi(n+m)!}}
21
+ \exp(i m \varphi)
22
+ \mathrm{P}_n^m\left(\cos(\theta)\right)
23
+
24
+ Explanation
25
+ ===========
26
+
27
+ ``Ynm()`` gives the spherical harmonic function of order $n$ and $m$
28
+ in $\theta$ and $\varphi$, $Y_n^m(\theta, \varphi)$. The four
29
+ parameters are as follows: $n \geq 0$ an integer and $m$ an integer
30
+ such that $-n \leq m \leq n$ holds. The two angles are real-valued
31
+ with $\theta \in [0, \pi]$ and $\varphi \in [0, 2\pi]$.
32
+
33
+ Examples
34
+ ========
35
+
36
+ >>> from sympy import Ynm, Symbol, simplify
37
+ >>> from sympy.abc import n,m
38
+ >>> theta = Symbol("theta")
39
+ >>> phi = Symbol("phi")
40
+
41
+ >>> Ynm(n, m, theta, phi)
42
+ Ynm(n, m, theta, phi)
43
+
44
+ Several symmetries are known, for the order:
45
+
46
+ >>> Ynm(n, -m, theta, phi)
47
+ (-1)**m*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
48
+
49
+ As well as for the angles:
50
+
51
+ >>> Ynm(n, m, -theta, phi)
52
+ Ynm(n, m, theta, phi)
53
+
54
+ >>> Ynm(n, m, theta, -phi)
55
+ exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
56
+
57
+ For specific integers $n$ and $m$ we can evaluate the harmonics
58
+ to more useful expressions:
59
+
60
+ >>> simplify(Ynm(0, 0, theta, phi).expand(func=True))
61
+ 1/(2*sqrt(pi))
62
+
63
+ >>> simplify(Ynm(1, -1, theta, phi).expand(func=True))
64
+ sqrt(6)*exp(-I*phi)*sin(theta)/(4*sqrt(pi))
65
+
66
+ >>> simplify(Ynm(1, 0, theta, phi).expand(func=True))
67
+ sqrt(3)*cos(theta)/(2*sqrt(pi))
68
+
69
+ >>> simplify(Ynm(1, 1, theta, phi).expand(func=True))
70
+ -sqrt(6)*exp(I*phi)*sin(theta)/(4*sqrt(pi))
71
+
72
+ >>> simplify(Ynm(2, -2, theta, phi).expand(func=True))
73
+ sqrt(30)*exp(-2*I*phi)*sin(theta)**2/(8*sqrt(pi))
74
+
75
+ >>> simplify(Ynm(2, -1, theta, phi).expand(func=True))
76
+ sqrt(30)*exp(-I*phi)*sin(2*theta)/(8*sqrt(pi))
77
+
78
+ >>> simplify(Ynm(2, 0, theta, phi).expand(func=True))
79
+ sqrt(5)*(3*cos(theta)**2 - 1)/(4*sqrt(pi))
80
+
81
+ >>> simplify(Ynm(2, 1, theta, phi).expand(func=True))
82
+ -sqrt(30)*exp(I*phi)*sin(2*theta)/(8*sqrt(pi))
83
+
84
+ >>> simplify(Ynm(2, 2, theta, phi).expand(func=True))
85
+ sqrt(30)*exp(2*I*phi)*sin(theta)**2/(8*sqrt(pi))
86
+
87
+ We can differentiate the functions with respect
88
+ to both angles:
89
+
90
+ >>> from sympy import Ynm, Symbol, diff
91
+ >>> from sympy.abc import n,m
92
+ >>> theta = Symbol("theta")
93
+ >>> phi = Symbol("phi")
94
+
95
+ >>> diff(Ynm(n, m, theta, phi), theta)
96
+ m*cot(theta)*Ynm(n, m, theta, phi) + sqrt((-m + n)*(m + n + 1))*exp(-I*phi)*Ynm(n, m + 1, theta, phi)
97
+
98
+ >>> diff(Ynm(n, m, theta, phi), phi)
99
+ I*m*Ynm(n, m, theta, phi)
100
+
101
+ Further we can compute the complex conjugation:
102
+
103
+ >>> from sympy import Ynm, Symbol, conjugate
104
+ >>> from sympy.abc import n,m
105
+ >>> theta = Symbol("theta")
106
+ >>> phi = Symbol("phi")
107
+
108
+ >>> conjugate(Ynm(n, m, theta, phi))
109
+ (-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
110
+
111
+ To get back the well known expressions in spherical
112
+ coordinates, we use full expansion:
113
+
114
+ >>> from sympy import Ynm, Symbol, expand_func
115
+ >>> from sympy.abc import n,m
116
+ >>> theta = Symbol("theta")
117
+ >>> phi = Symbol("phi")
118
+
119
+ >>> expand_func(Ynm(n, m, theta, phi))
120
+ sqrt((2*n + 1)*factorial(-m + n)/factorial(m + n))*exp(I*m*phi)*assoc_legendre(n, m, cos(theta))/(2*sqrt(pi))
121
+
122
+ See Also
123
+ ========
124
+
125
+ Ynm_c, Znm
126
+
127
+ References
128
+ ==========
129
+
130
+ .. [1] https://en.wikipedia.org/wiki/Spherical_harmonics
131
+ .. [2] https://mathworld.wolfram.com/SphericalHarmonic.html
132
+ .. [3] https://functions.wolfram.com/Polynomials/SphericalHarmonicY/
133
+ .. [4] https://dlmf.nist.gov/14.30
134
+
135
+ """
136
+
137
+ @classmethod
138
+ def eval(cls, n, m, theta, phi):
139
+ # Handle negative index m and arguments theta, phi
140
+ if m.could_extract_minus_sign():
141
+ m = -m
142
+ return S.NegativeOne**m * exp(-2*I*m*phi) * Ynm(n, m, theta, phi)
143
+ if theta.could_extract_minus_sign():
144
+ theta = -theta
145
+ return Ynm(n, m, theta, phi)
146
+ if phi.could_extract_minus_sign():
147
+ phi = -phi
148
+ return exp(-2*I*m*phi) * Ynm(n, m, theta, phi)
149
+
150
+ # TODO Add more simplififcation here
151
+
152
+ def _eval_expand_func(self, **hints):
153
+ n, m, theta, phi = self.args
154
+ rv = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) *
155
+ exp(I*m*phi) * assoc_legendre(n, m, cos(theta)))
156
+ # We can do this because of the range of theta
157
+ return rv.subs(sqrt(-cos(theta)**2 + 1), sin(theta))
158
+
159
+ def fdiff(self, argindex=4):
160
+ if argindex == 1:
161
+ # Diff wrt n
162
+ raise ArgumentIndexError(self, argindex)
163
+ elif argindex == 2:
164
+ # Diff wrt m
165
+ raise ArgumentIndexError(self, argindex)
166
+ elif argindex == 3:
167
+ # Diff wrt theta
168
+ n, m, theta, phi = self.args
169
+ return (m * cot(theta) * Ynm(n, m, theta, phi) +
170
+ sqrt((n - m)*(n + m + 1)) * exp(-I*phi) * Ynm(n, m + 1, theta, phi))
171
+ elif argindex == 4:
172
+ # Diff wrt phi
173
+ n, m, theta, phi = self.args
174
+ return I * m * Ynm(n, m, theta, phi)
175
+ else:
176
+ raise ArgumentIndexError(self, argindex)
177
+
178
+ def _eval_rewrite_as_polynomial(self, n, m, theta, phi, **kwargs):
179
+ # TODO: Make sure n \in N
180
+ # TODO: Assert |m| <= n ortherwise we should return 0
181
+ return self.expand(func=True)
182
+
183
+ def _eval_rewrite_as_sin(self, n, m, theta, phi, **kwargs):
184
+ return self.rewrite(cos)
185
+
186
+ def _eval_rewrite_as_cos(self, n, m, theta, phi, **kwargs):
187
+ # This method can be expensive due to extensive use of simplification!
188
+ from sympy.simplify import simplify, trigsimp
189
+ # TODO: Make sure n \in N
190
+ # TODO: Assert |m| <= n ortherwise we should return 0
191
+ term = simplify(self.expand(func=True))
192
+ # We can do this because of the range of theta
193
+ term = term.xreplace({Abs(sin(theta)):sin(theta)})
194
+ return simplify(trigsimp(term))
195
+
196
+ def _eval_conjugate(self):
197
+ # TODO: Make sure theta \in R and phi \in R
198
+ n, m, theta, phi = self.args
199
+ return S.NegativeOne**m * self.func(n, -m, theta, phi)
200
+
201
+ def as_real_imag(self, deep=True, **hints):
202
+ # TODO: Handle deep and hints
203
+ n, m, theta, phi = self.args
204
+ re = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) *
205
+ cos(m*phi) * assoc_legendre(n, m, cos(theta)))
206
+ im = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) *
207
+ sin(m*phi) * assoc_legendre(n, m, cos(theta)))
208
+ return (re, im)
209
+
210
+ def _eval_evalf(self, prec):
211
+ # Note: works without this function by just calling
212
+ # mpmath for Legendre polynomials. But using
213
+ # the dedicated function directly is cleaner.
214
+ from mpmath import mp, workprec
215
+ n = self.args[0]._to_mpmath(prec)
216
+ m = self.args[1]._to_mpmath(prec)
217
+ theta = self.args[2]._to_mpmath(prec)
218
+ phi = self.args[3]._to_mpmath(prec)
219
+ with workprec(prec):
220
+ res = mp.spherharm(n, m, theta, phi)
221
+ return Expr._from_mpmath(res, prec)
222
+
223
+
224
+ def Ynm_c(n, m, theta, phi):
225
+ r"""
226
+ Conjugate spherical harmonics defined as
227
+
228
+ .. math::
229
+ \overline{Y_n^m(\theta, \varphi)} := (-1)^m Y_n^{-m}(\theta, \varphi).
230
+
231
+ Examples
232
+ ========
233
+
234
+ >>> from sympy import Ynm_c, Symbol, simplify
235
+ >>> from sympy.abc import n,m
236
+ >>> theta = Symbol("theta")
237
+ >>> phi = Symbol("phi")
238
+ >>> Ynm_c(n, m, theta, phi)
239
+ (-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
240
+ >>> Ynm_c(n, m, -theta, phi)
241
+ (-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
242
+
243
+ For specific integers $n$ and $m$ we can evaluate the harmonics
244
+ to more useful expressions:
245
+
246
+ >>> simplify(Ynm_c(0, 0, theta, phi).expand(func=True))
247
+ 1/(2*sqrt(pi))
248
+ >>> simplify(Ynm_c(1, -1, theta, phi).expand(func=True))
249
+ sqrt(6)*exp(I*(-phi + 2*conjugate(phi)))*sin(theta)/(4*sqrt(pi))
250
+
251
+ See Also
252
+ ========
253
+
254
+ Ynm, Znm
255
+
256
+ References
257
+ ==========
258
+
259
+ .. [1] https://en.wikipedia.org/wiki/Spherical_harmonics
260
+ .. [2] https://mathworld.wolfram.com/SphericalHarmonic.html
261
+ .. [3] https://functions.wolfram.com/Polynomials/SphericalHarmonicY/
262
+
263
+ """
264
+ return conjugate(Ynm(n, m, theta, phi))
265
+
266
+
267
+ class Znm(DefinedFunction):
268
+ r"""
269
+ Real spherical harmonics defined as
270
+
271
+ .. math::
272
+
273
+ Z_n^m(\theta, \varphi) :=
274
+ \begin{cases}
275
+ \frac{Y_n^m(\theta, \varphi) + \overline{Y_n^m(\theta, \varphi)}}{\sqrt{2}} &\quad m > 0 \\
276
+ Y_n^m(\theta, \varphi) &\quad m = 0 \\
277
+ \frac{Y_n^m(\theta, \varphi) - \overline{Y_n^m(\theta, \varphi)}}{i \sqrt{2}} &\quad m < 0 \\
278
+ \end{cases}
279
+
280
+ which gives in simplified form
281
+
282
+ .. math::
283
+
284
+ Z_n^m(\theta, \varphi) =
285
+ \begin{cases}
286
+ \frac{Y_n^m(\theta, \varphi) + (-1)^m Y_n^{-m}(\theta, \varphi)}{\sqrt{2}} &\quad m > 0 \\
287
+ Y_n^m(\theta, \varphi) &\quad m = 0 \\
288
+ \frac{Y_n^m(\theta, \varphi) - (-1)^m Y_n^{-m}(\theta, \varphi)}{i \sqrt{2}} &\quad m < 0 \\
289
+ \end{cases}
290
+
291
+ Examples
292
+ ========
293
+
294
+ >>> from sympy import Znm, Symbol, simplify
295
+ >>> from sympy.abc import n, m
296
+ >>> theta = Symbol("theta")
297
+ >>> phi = Symbol("phi")
298
+ >>> Znm(n, m, theta, phi)
299
+ Znm(n, m, theta, phi)
300
+
301
+ For specific integers n and m we can evaluate the harmonics
302
+ to more useful expressions:
303
+
304
+ >>> simplify(Znm(0, 0, theta, phi).expand(func=True))
305
+ 1/(2*sqrt(pi))
306
+ >>> simplify(Znm(1, 1, theta, phi).expand(func=True))
307
+ -sqrt(3)*sin(theta)*cos(phi)/(2*sqrt(pi))
308
+ >>> simplify(Znm(2, 1, theta, phi).expand(func=True))
309
+ -sqrt(15)*sin(2*theta)*cos(phi)/(4*sqrt(pi))
310
+
311
+ See Also
312
+ ========
313
+
314
+ Ynm, Ynm_c
315
+
316
+ References
317
+ ==========
318
+
319
+ .. [1] https://en.wikipedia.org/wiki/Spherical_harmonics
320
+ .. [2] https://mathworld.wolfram.com/SphericalHarmonic.html
321
+ .. [3] https://functions.wolfram.com/Polynomials/SphericalHarmonicY/
322
+
323
+ """
324
+
325
+ @classmethod
326
+ def eval(cls, n, m, theta, phi):
327
+ if m.is_positive:
328
+ zz = (Ynm(n, m, theta, phi) + Ynm_c(n, m, theta, phi)) / sqrt(2)
329
+ return zz
330
+ elif m.is_zero:
331
+ return Ynm(n, m, theta, phi)
332
+ elif m.is_negative:
333
+ zz = (Ynm(n, m, theta, phi) - Ynm_c(n, m, theta, phi)) / (sqrt(2)*I)
334
+ return zz
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/tensor_functions.py ADDED
@@ -0,0 +1,474 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from math import prod
2
+
3
+ from sympy.core import S, Integer
4
+ from sympy.core.function import DefinedFunction
5
+ from sympy.core.logic import fuzzy_not
6
+ from sympy.core.relational import Ne
7
+ from sympy.core.sorting import default_sort_key
8
+ from sympy.external.gmpy import SYMPY_INTS
9
+ from sympy.functions.combinatorial.factorials import factorial
10
+ from sympy.functions.elementary.piecewise import Piecewise
11
+ from sympy.utilities.iterables import has_dups
12
+
13
+ ###############################################################################
14
+ ###################### Kronecker Delta, Levi-Civita etc. ######################
15
+ ###############################################################################
16
+
17
+
18
+ def Eijk(*args, **kwargs):
19
+ """
20
+ Represent the Levi-Civita symbol.
21
+
22
+ This is a compatibility wrapper to ``LeviCivita()``.
23
+
24
+ See Also
25
+ ========
26
+
27
+ LeviCivita
28
+
29
+ """
30
+ return LeviCivita(*args, **kwargs)
31
+
32
+
33
+ def eval_levicivita(*args):
34
+ """Evaluate Levi-Civita symbol."""
35
+ n = len(args)
36
+ return prod(
37
+ prod(args[j] - args[i] for j in range(i + 1, n))
38
+ / factorial(i) for i in range(n))
39
+ # converting factorial(i) to int is slightly faster
40
+
41
+
42
+ class LeviCivita(DefinedFunction):
43
+ """
44
+ Represent the Levi-Civita symbol.
45
+
46
+ Explanation
47
+ ===========
48
+
49
+ For even permutations of indices it returns 1, for odd permutations -1, and
50
+ for everything else (a repeated index) it returns 0.
51
+
52
+ Thus it represents an alternating pseudotensor.
53
+
54
+ Examples
55
+ ========
56
+
57
+ >>> from sympy import LeviCivita
58
+ >>> from sympy.abc import i, j, k
59
+ >>> LeviCivita(1, 2, 3)
60
+ 1
61
+ >>> LeviCivita(1, 3, 2)
62
+ -1
63
+ >>> LeviCivita(1, 2, 2)
64
+ 0
65
+ >>> LeviCivita(i, j, k)
66
+ LeviCivita(i, j, k)
67
+ >>> LeviCivita(i, j, i)
68
+ 0
69
+
70
+ See Also
71
+ ========
72
+
73
+ Eijk
74
+
75
+ """
76
+
77
+ is_integer = True
78
+
79
+ @classmethod
80
+ def eval(cls, *args):
81
+ if all(isinstance(a, (SYMPY_INTS, Integer)) for a in args):
82
+ return eval_levicivita(*args)
83
+ if has_dups(args):
84
+ return S.Zero
85
+
86
+ def doit(self, **hints):
87
+ return eval_levicivita(*self.args)
88
+
89
+
90
+ class KroneckerDelta(DefinedFunction):
91
+ """
92
+ The discrete, or Kronecker, delta function.
93
+
94
+ Explanation
95
+ ===========
96
+
97
+ A function that takes in two integers $i$ and $j$. It returns $0$ if $i$
98
+ and $j$ are not equal, or it returns $1$ if $i$ and $j$ are equal.
99
+
100
+ Examples
101
+ ========
102
+
103
+ An example with integer indices:
104
+
105
+ >>> from sympy import KroneckerDelta
106
+ >>> KroneckerDelta(1, 2)
107
+ 0
108
+ >>> KroneckerDelta(3, 3)
109
+ 1
110
+
111
+ Symbolic indices:
112
+
113
+ >>> from sympy.abc import i, j, k
114
+ >>> KroneckerDelta(i, j)
115
+ KroneckerDelta(i, j)
116
+ >>> KroneckerDelta(i, i)
117
+ 1
118
+ >>> KroneckerDelta(i, i + 1)
119
+ 0
120
+ >>> KroneckerDelta(i, i + 1 + k)
121
+ KroneckerDelta(i, i + k + 1)
122
+
123
+ Parameters
124
+ ==========
125
+
126
+ i : Number, Symbol
127
+ The first index of the delta function.
128
+ j : Number, Symbol
129
+ The second index of the delta function.
130
+
131
+ See Also
132
+ ========
133
+
134
+ eval
135
+ DiracDelta
136
+
137
+ References
138
+ ==========
139
+
140
+ .. [1] https://en.wikipedia.org/wiki/Kronecker_delta
141
+
142
+ """
143
+
144
+ is_integer = True
145
+
146
+ @classmethod
147
+ def eval(cls, i, j, delta_range=None):
148
+ """
149
+ Evaluates the discrete delta function.
150
+
151
+ Examples
152
+ ========
153
+
154
+ >>> from sympy import KroneckerDelta
155
+ >>> from sympy.abc import i, j, k
156
+
157
+ >>> KroneckerDelta(i, j)
158
+ KroneckerDelta(i, j)
159
+ >>> KroneckerDelta(i, i)
160
+ 1
161
+ >>> KroneckerDelta(i, i + 1)
162
+ 0
163
+ >>> KroneckerDelta(i, i + 1 + k)
164
+ KroneckerDelta(i, i + k + 1)
165
+
166
+ # indirect doctest
167
+
168
+ """
169
+
170
+ if delta_range is not None:
171
+ dinf, dsup = delta_range
172
+ if (dinf - i > 0) == True:
173
+ return S.Zero
174
+ if (dinf - j > 0) == True:
175
+ return S.Zero
176
+ if (dsup - i < 0) == True:
177
+ return S.Zero
178
+ if (dsup - j < 0) == True:
179
+ return S.Zero
180
+
181
+ diff = i - j
182
+ if diff.is_zero:
183
+ return S.One
184
+ elif fuzzy_not(diff.is_zero):
185
+ return S.Zero
186
+
187
+ if i.assumptions0.get("below_fermi") and \
188
+ j.assumptions0.get("above_fermi"):
189
+ return S.Zero
190
+ if j.assumptions0.get("below_fermi") and \
191
+ i.assumptions0.get("above_fermi"):
192
+ return S.Zero
193
+ # to make KroneckerDelta canonical
194
+ # following lines will check if inputs are in order
195
+ # if not, will return KroneckerDelta with correct order
196
+ if default_sort_key(j) < default_sort_key(i):
197
+ if delta_range:
198
+ return cls(j, i, delta_range)
199
+ else:
200
+ return cls(j, i)
201
+
202
+ @property
203
+ def delta_range(self):
204
+ if len(self.args) > 2:
205
+ return self.args[2]
206
+
207
+ def _eval_power(self, expt):
208
+ if expt.is_positive:
209
+ return self
210
+ if expt.is_negative and expt is not S.NegativeOne:
211
+ return 1/self
212
+
213
+ @property
214
+ def is_above_fermi(self):
215
+ """
216
+ True if Delta can be non-zero above fermi.
217
+
218
+ Examples
219
+ ========
220
+
221
+ >>> from sympy import KroneckerDelta, Symbol
222
+ >>> a = Symbol('a', above_fermi=True)
223
+ >>> i = Symbol('i', below_fermi=True)
224
+ >>> p = Symbol('p')
225
+ >>> q = Symbol('q')
226
+ >>> KroneckerDelta(p, a).is_above_fermi
227
+ True
228
+ >>> KroneckerDelta(p, i).is_above_fermi
229
+ False
230
+ >>> KroneckerDelta(p, q).is_above_fermi
231
+ True
232
+
233
+ See Also
234
+ ========
235
+
236
+ is_below_fermi, is_only_below_fermi, is_only_above_fermi
237
+
238
+ """
239
+ if self.args[0].assumptions0.get("below_fermi"):
240
+ return False
241
+ if self.args[1].assumptions0.get("below_fermi"):
242
+ return False
243
+ return True
244
+
245
+ @property
246
+ def is_below_fermi(self):
247
+ """
248
+ True if Delta can be non-zero below fermi.
249
+
250
+ Examples
251
+ ========
252
+
253
+ >>> from sympy import KroneckerDelta, Symbol
254
+ >>> a = Symbol('a', above_fermi=True)
255
+ >>> i = Symbol('i', below_fermi=True)
256
+ >>> p = Symbol('p')
257
+ >>> q = Symbol('q')
258
+ >>> KroneckerDelta(p, a).is_below_fermi
259
+ False
260
+ >>> KroneckerDelta(p, i).is_below_fermi
261
+ True
262
+ >>> KroneckerDelta(p, q).is_below_fermi
263
+ True
264
+
265
+ See Also
266
+ ========
267
+
268
+ is_above_fermi, is_only_above_fermi, is_only_below_fermi
269
+
270
+ """
271
+ if self.args[0].assumptions0.get("above_fermi"):
272
+ return False
273
+ if self.args[1].assumptions0.get("above_fermi"):
274
+ return False
275
+ return True
276
+
277
+ @property
278
+ def is_only_above_fermi(self):
279
+ """
280
+ True if Delta is restricted to above fermi.
281
+
282
+ Examples
283
+ ========
284
+
285
+ >>> from sympy import KroneckerDelta, Symbol
286
+ >>> a = Symbol('a', above_fermi=True)
287
+ >>> i = Symbol('i', below_fermi=True)
288
+ >>> p = Symbol('p')
289
+ >>> q = Symbol('q')
290
+ >>> KroneckerDelta(p, a).is_only_above_fermi
291
+ True
292
+ >>> KroneckerDelta(p, q).is_only_above_fermi
293
+ False
294
+ >>> KroneckerDelta(p, i).is_only_above_fermi
295
+ False
296
+
297
+ See Also
298
+ ========
299
+
300
+ is_above_fermi, is_below_fermi, is_only_below_fermi
301
+
302
+ """
303
+ return ( self.args[0].assumptions0.get("above_fermi")
304
+ or
305
+ self.args[1].assumptions0.get("above_fermi")
306
+ ) or False
307
+
308
+ @property
309
+ def is_only_below_fermi(self):
310
+ """
311
+ True if Delta is restricted to below fermi.
312
+
313
+ Examples
314
+ ========
315
+
316
+ >>> from sympy import KroneckerDelta, Symbol
317
+ >>> a = Symbol('a', above_fermi=True)
318
+ >>> i = Symbol('i', below_fermi=True)
319
+ >>> p = Symbol('p')
320
+ >>> q = Symbol('q')
321
+ >>> KroneckerDelta(p, i).is_only_below_fermi
322
+ True
323
+ >>> KroneckerDelta(p, q).is_only_below_fermi
324
+ False
325
+ >>> KroneckerDelta(p, a).is_only_below_fermi
326
+ False
327
+
328
+ See Also
329
+ ========
330
+
331
+ is_above_fermi, is_below_fermi, is_only_above_fermi
332
+
333
+ """
334
+ return ( self.args[0].assumptions0.get("below_fermi")
335
+ or
336
+ self.args[1].assumptions0.get("below_fermi")
337
+ ) or False
338
+
339
+ @property
340
+ def indices_contain_equal_information(self):
341
+ """
342
+ Returns True if indices are either both above or below fermi.
343
+
344
+ Examples
345
+ ========
346
+
347
+ >>> from sympy import KroneckerDelta, Symbol
348
+ >>> a = Symbol('a', above_fermi=True)
349
+ >>> i = Symbol('i', below_fermi=True)
350
+ >>> p = Symbol('p')
351
+ >>> q = Symbol('q')
352
+ >>> KroneckerDelta(p, q).indices_contain_equal_information
353
+ True
354
+ >>> KroneckerDelta(p, q+1).indices_contain_equal_information
355
+ True
356
+ >>> KroneckerDelta(i, p).indices_contain_equal_information
357
+ False
358
+
359
+ """
360
+ if (self.args[0].assumptions0.get("below_fermi") and
361
+ self.args[1].assumptions0.get("below_fermi")):
362
+ return True
363
+ if (self.args[0].assumptions0.get("above_fermi")
364
+ and self.args[1].assumptions0.get("above_fermi")):
365
+ return True
366
+
367
+ # if both indices are general we are True, else false
368
+ return self.is_below_fermi and self.is_above_fermi
369
+
370
+ @property
371
+ def preferred_index(self):
372
+ """
373
+ Returns the index which is preferred to keep in the final expression.
374
+
375
+ Explanation
376
+ ===========
377
+
378
+ The preferred index is the index with more information regarding fermi
379
+ level. If indices contain the same information, 'a' is preferred before
380
+ 'b'.
381
+
382
+ Examples
383
+ ========
384
+
385
+ >>> from sympy import KroneckerDelta, Symbol
386
+ >>> a = Symbol('a', above_fermi=True)
387
+ >>> i = Symbol('i', below_fermi=True)
388
+ >>> j = Symbol('j', below_fermi=True)
389
+ >>> p = Symbol('p')
390
+ >>> KroneckerDelta(p, i).preferred_index
391
+ i
392
+ >>> KroneckerDelta(p, a).preferred_index
393
+ a
394
+ >>> KroneckerDelta(i, j).preferred_index
395
+ i
396
+
397
+ See Also
398
+ ========
399
+
400
+ killable_index
401
+
402
+ """
403
+ if self._get_preferred_index():
404
+ return self.args[1]
405
+ else:
406
+ return self.args[0]
407
+
408
+ @property
409
+ def killable_index(self):
410
+ """
411
+ Returns the index which is preferred to substitute in the final
412
+ expression.
413
+
414
+ Explanation
415
+ ===========
416
+
417
+ The index to substitute is the index with less information regarding
418
+ fermi level. If indices contain the same information, 'a' is preferred
419
+ before 'b'.
420
+
421
+ Examples
422
+ ========
423
+
424
+ >>> from sympy import KroneckerDelta, Symbol
425
+ >>> a = Symbol('a', above_fermi=True)
426
+ >>> i = Symbol('i', below_fermi=True)
427
+ >>> j = Symbol('j', below_fermi=True)
428
+ >>> p = Symbol('p')
429
+ >>> KroneckerDelta(p, i).killable_index
430
+ p
431
+ >>> KroneckerDelta(p, a).killable_index
432
+ p
433
+ >>> KroneckerDelta(i, j).killable_index
434
+ j
435
+
436
+ See Also
437
+ ========
438
+
439
+ preferred_index
440
+
441
+ """
442
+ if self._get_preferred_index():
443
+ return self.args[0]
444
+ else:
445
+ return self.args[1]
446
+
447
+ def _get_preferred_index(self):
448
+ """
449
+ Returns the index which is preferred to keep in the final expression.
450
+
451
+ The preferred index is the index with more information regarding fermi
452
+ level. If indices contain the same information, index 0 is returned.
453
+
454
+ """
455
+ if not self.is_above_fermi:
456
+ if self.args[0].assumptions0.get("below_fermi"):
457
+ return 0
458
+ else:
459
+ return 1
460
+ elif not self.is_below_fermi:
461
+ if self.args[0].assumptions0.get("above_fermi"):
462
+ return 0
463
+ else:
464
+ return 1
465
+ else:
466
+ return 0
467
+
468
+ @property
469
+ def indices(self):
470
+ return self.args[0:2]
471
+
472
+ def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
473
+ i, j = args
474
+ return Piecewise((0, Ne(i, j)), (1, True))
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/functions/special/zeta_functions.py ADDED
@@ -0,0 +1,786 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ Riemann zeta and related function. """
2
+
3
+ from sympy.core.add import Add
4
+ from sympy.core.cache import cacheit
5
+ from sympy.core.function import ArgumentIndexError, expand_mul, DefinedFunction
6
+ from sympy.core.logic import fuzzy_not
7
+ from sympy.core.numbers import pi, I, Integer
8
+ from sympy.core.relational import Eq
9
+ from sympy.core.singleton import S
10
+ from sympy.core.symbol import Dummy
11
+ from sympy.core.sympify import sympify
12
+ from sympy.functions.combinatorial.numbers import bernoulli, factorial, genocchi, harmonic
13
+ from sympy.functions.elementary.complexes import re, unpolarify, Abs, polar_lift
14
+ from sympy.functions.elementary.exponential import log, exp_polar, exp
15
+ from sympy.functions.elementary.integers import ceiling, floor
16
+ from sympy.functions.elementary.miscellaneous import sqrt
17
+ from sympy.functions.elementary.piecewise import Piecewise
18
+ from sympy.polys.polytools import Poly
19
+
20
+ ###############################################################################
21
+ ###################### LERCH TRANSCENDENT #####################################
22
+ ###############################################################################
23
+
24
+
25
+ class lerchphi(DefinedFunction):
26
+ r"""
27
+ Lerch transcendent (Lerch phi function).
28
+
29
+ Explanation
30
+ ===========
31
+
32
+ For $\operatorname{Re}(a) > 0$, $|z| < 1$ and $s \in \mathbb{C}$, the
33
+ Lerch transcendent is defined as
34
+
35
+ .. math :: \Phi(z, s, a) = \sum_{n=0}^\infty \frac{z^n}{(n + a)^s},
36
+
37
+ where the standard branch of the argument is used for $n + a$,
38
+ and by analytic continuation for other values of the parameters.
39
+
40
+ A commonly used related function is the Lerch zeta function, defined by
41
+
42
+ .. math:: L(q, s, a) = \Phi(e^{2\pi i q}, s, a).
43
+
44
+ **Analytic Continuation and Branching Behavior**
45
+
46
+ It can be shown that
47
+
48
+ .. math:: \Phi(z, s, a) = z\Phi(z, s, a+1) + a^{-s}.
49
+
50
+ This provides the analytic continuation to $\operatorname{Re}(a) \le 0$.
51
+
52
+ Assume now $\operatorname{Re}(a) > 0$. The integral representation
53
+
54
+ .. math:: \Phi_0(z, s, a) = \int_0^\infty \frac{t^{s-1} e^{-at}}{1 - ze^{-t}}
55
+ \frac{\mathrm{d}t}{\Gamma(s)}
56
+
57
+ provides an analytic continuation to $\mathbb{C} - [1, \infty)$.
58
+ Finally, for $x \in (1, \infty)$ we find
59
+
60
+ .. math:: \lim_{\epsilon \to 0^+} \Phi_0(x + i\epsilon, s, a)
61
+ -\lim_{\epsilon \to 0^+} \Phi_0(x - i\epsilon, s, a)
62
+ = \frac{2\pi i \log^{s-1}{x}}{x^a \Gamma(s)},
63
+
64
+ using the standard branch for both $\log{x}$ and
65
+ $\log{\log{x}}$ (a branch of $\log{\log{x}}$ is needed to
66
+ evaluate $\log{x}^{s-1}$).
67
+ This concludes the analytic continuation. The Lerch transcendent is thus
68
+ branched at $z \in \{0, 1, \infty\}$ and
69
+ $a \in \mathbb{Z}_{\le 0}$. For fixed $z, a$ outside these
70
+ branch points, it is an entire function of $s$.
71
+
72
+ Examples
73
+ ========
74
+
75
+ The Lerch transcendent is a fairly general function, for this reason it does
76
+ not automatically evaluate to simpler functions. Use ``expand_func()`` to
77
+ achieve this.
78
+
79
+ If $z=1$, the Lerch transcendent reduces to the Hurwitz zeta function:
80
+
81
+ >>> from sympy import lerchphi, expand_func
82
+ >>> from sympy.abc import z, s, a
83
+ >>> expand_func(lerchphi(1, s, a))
84
+ zeta(s, a)
85
+
86
+ More generally, if $z$ is a root of unity, the Lerch transcendent
87
+ reduces to a sum of Hurwitz zeta functions:
88
+
89
+ >>> expand_func(lerchphi(-1, s, a))
90
+ zeta(s, a/2)/2**s - zeta(s, a/2 + 1/2)/2**s
91
+
92
+ If $a=1$, the Lerch transcendent reduces to the polylogarithm:
93
+
94
+ >>> expand_func(lerchphi(z, s, 1))
95
+ polylog(s, z)/z
96
+
97
+ More generally, if $a$ is rational, the Lerch transcendent reduces
98
+ to a sum of polylogarithms:
99
+
100
+ >>> from sympy import S
101
+ >>> expand_func(lerchphi(z, s, S(1)/2))
102
+ 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) -
103
+ polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z))
104
+ >>> expand_func(lerchphi(z, s, S(3)/2))
105
+ -2**s/z + 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) -
106
+ polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z))/z
107
+
108
+ The derivatives with respect to $z$ and $a$ can be computed in
109
+ closed form:
110
+
111
+ >>> lerchphi(z, s, a).diff(z)
112
+ (-a*lerchphi(z, s, a) + lerchphi(z, s - 1, a))/z
113
+ >>> lerchphi(z, s, a).diff(a)
114
+ -s*lerchphi(z, s + 1, a)
115
+
116
+ See Also
117
+ ========
118
+
119
+ polylog, zeta
120
+
121
+ References
122
+ ==========
123
+
124
+ .. [1] Bateman, H.; Erdelyi, A. (1953), Higher Transcendental Functions,
125
+ Vol. I, New York: McGraw-Hill. Section 1.11.
126
+ .. [2] https://dlmf.nist.gov/25.14
127
+ .. [3] https://en.wikipedia.org/wiki/Lerch_transcendent
128
+
129
+ """
130
+
131
+ def _eval_expand_func(self, **hints):
132
+ z, s, a = self.args
133
+ if z == 1:
134
+ return zeta(s, a)
135
+ if s.is_Integer and s <= 0:
136
+ t = Dummy('t')
137
+ p = Poly((t + a)**(-s), t)
138
+ start = 1/(1 - t)
139
+ res = S.Zero
140
+ for c in reversed(p.all_coeffs()):
141
+ res += c*start
142
+ start = t*start.diff(t)
143
+ return res.subs(t, z)
144
+
145
+ if a.is_Rational:
146
+ # See section 18 of
147
+ # Kelly B. Roach. Hypergeometric Function Representations.
148
+ # In: Proceedings of the 1997 International Symposium on Symbolic and
149
+ # Algebraic Computation, pages 205-211, New York, 1997. ACM.
150
+ # TODO should something be polarified here?
151
+ add = S.Zero
152
+ mul = S.One
153
+ # First reduce a to the interaval (0, 1]
154
+ if a > 1:
155
+ n = floor(a)
156
+ if n == a:
157
+ n -= 1
158
+ a -= n
159
+ mul = z**(-n)
160
+ add = Add(*[-z**(k - n)/(a + k)**s for k in range(n)])
161
+ elif a <= 0:
162
+ n = floor(-a) + 1
163
+ a += n
164
+ mul = z**n
165
+ add = Add(*[z**(n - 1 - k)/(a - k - 1)**s for k in range(n)])
166
+
167
+ m, n = S([a.p, a.q])
168
+ zet = exp_polar(2*pi*I/n)
169
+ root = z**(1/n)
170
+ up_zet = unpolarify(zet)
171
+ addargs = []
172
+ for k in range(n):
173
+ p = polylog(s, zet**k*root)
174
+ if isinstance(p, polylog):
175
+ p = p._eval_expand_func(**hints)
176
+ addargs.append(p/(up_zet**k*root)**m)
177
+ return add + mul*n**(s - 1)*Add(*addargs)
178
+
179
+ # TODO use minpoly instead of ad-hoc methods when issue 5888 is fixed
180
+ if isinstance(z, exp) and (z.args[0]/(pi*I)).is_Rational or z in [-1, I, -I]:
181
+ # TODO reference?
182
+ if z == -1:
183
+ p, q = S([1, 2])
184
+ elif z == I:
185
+ p, q = S([1, 4])
186
+ elif z == -I:
187
+ p, q = S([-1, 4])
188
+ else:
189
+ arg = z.args[0]/(2*pi*I)
190
+ p, q = S([arg.p, arg.q])
191
+ return Add(*[exp(2*pi*I*k*p/q)/q**s*zeta(s, (k + a)/q)
192
+ for k in range(q)])
193
+
194
+ return lerchphi(z, s, a)
195
+
196
+ def fdiff(self, argindex=1):
197
+ z, s, a = self.args
198
+ if argindex == 3:
199
+ return -s*lerchphi(z, s + 1, a)
200
+ elif argindex == 1:
201
+ return (lerchphi(z, s - 1, a) - a*lerchphi(z, s, a))/z
202
+ else:
203
+ raise ArgumentIndexError
204
+
205
+ def _eval_rewrite_helper(self, target):
206
+ res = self._eval_expand_func()
207
+ if res.has(target):
208
+ return res
209
+ else:
210
+ return self
211
+
212
+ def _eval_rewrite_as_zeta(self, z, s, a, **kwargs):
213
+ return self._eval_rewrite_helper(zeta)
214
+
215
+ def _eval_rewrite_as_polylog(self, z, s, a, **kwargs):
216
+ return self._eval_rewrite_helper(polylog)
217
+
218
+ ###############################################################################
219
+ ###################### POLYLOGARITHM ##########################################
220
+ ###############################################################################
221
+
222
+
223
+ class polylog(DefinedFunction):
224
+ r"""
225
+ Polylogarithm function.
226
+
227
+ Explanation
228
+ ===========
229
+
230
+ For $|z| < 1$ and $s \in \mathbb{C}$, the polylogarithm is
231
+ defined by
232
+
233
+ .. math:: \operatorname{Li}_s(z) = \sum_{n=1}^\infty \frac{z^n}{n^s},
234
+
235
+ where the standard branch of the argument is used for $n$. It admits
236
+ an analytic continuation which is branched at $z=1$ (notably not on the
237
+ sheet of initial definition), $z=0$ and $z=\infty$.
238
+
239
+ The name polylogarithm comes from the fact that for $s=1$, the
240
+ polylogarithm is related to the ordinary logarithm (see examples), and that
241
+
242
+ .. math:: \operatorname{Li}_{s+1}(z) =
243
+ \int_0^z \frac{\operatorname{Li}_s(t)}{t} \mathrm{d}t.
244
+
245
+ The polylogarithm is a special case of the Lerch transcendent:
246
+
247
+ .. math:: \operatorname{Li}_{s}(z) = z \Phi(z, s, 1).
248
+
249
+ Examples
250
+ ========
251
+
252
+ For $z \in \{0, 1, -1\}$, the polylogarithm is automatically expressed
253
+ using other functions:
254
+
255
+ >>> from sympy import polylog
256
+ >>> from sympy.abc import s
257
+ >>> polylog(s, 0)
258
+ 0
259
+ >>> polylog(s, 1)
260
+ zeta(s)
261
+ >>> polylog(s, -1)
262
+ -dirichlet_eta(s)
263
+
264
+ If $s$ is a negative integer, $0$ or $1$, the polylogarithm can be
265
+ expressed using elementary functions. This can be done using
266
+ ``expand_func()``:
267
+
268
+ >>> from sympy import expand_func
269
+ >>> from sympy.abc import z
270
+ >>> expand_func(polylog(1, z))
271
+ -log(1 - z)
272
+ >>> expand_func(polylog(0, z))
273
+ z/(1 - z)
274
+
275
+ The derivative with respect to $z$ can be computed in closed form:
276
+
277
+ >>> polylog(s, z).diff(z)
278
+ polylog(s - 1, z)/z
279
+
280
+ The polylogarithm can be expressed in terms of the lerch transcendent:
281
+
282
+ >>> from sympy import lerchphi
283
+ >>> polylog(s, z).rewrite(lerchphi)
284
+ z*lerchphi(z, s, 1)
285
+
286
+ See Also
287
+ ========
288
+
289
+ zeta, lerchphi
290
+
291
+ """
292
+
293
+ @classmethod
294
+ def eval(cls, s, z):
295
+ if z.is_number:
296
+ if z is S.One:
297
+ return zeta(s)
298
+ elif z is S.NegativeOne:
299
+ return -dirichlet_eta(s)
300
+ elif z is S.Zero:
301
+ return S.Zero
302
+ elif s == 2:
303
+ dilogtable = _dilogtable()
304
+ if z in dilogtable:
305
+ return dilogtable[z]
306
+
307
+ if z.is_zero:
308
+ return S.Zero
309
+
310
+ # Make an effort to determine if z is 1 to avoid replacing into
311
+ # expression with singularity
312
+ zone = z.equals(S.One)
313
+
314
+ if zone:
315
+ return zeta(s)
316
+ elif zone is False:
317
+ # For s = 0 or -1 use explicit formulas to evaluate, but
318
+ # automatically expanding polylog(1, z) to -log(1-z) seems
319
+ # undesirable for summation methods based on hypergeometric
320
+ # functions
321
+ if s is S.Zero:
322
+ return z/(1 - z)
323
+ elif s is S.NegativeOne:
324
+ return z/(1 - z)**2
325
+ if s.is_zero:
326
+ return z/(1 - z)
327
+
328
+ # polylog is branched, but not over the unit disk
329
+ if z.has(exp_polar, polar_lift) and (zone or (Abs(z) <= S.One) == True):
330
+ return cls(s, unpolarify(z))
331
+
332
+ def fdiff(self, argindex=1):
333
+ s, z = self.args
334
+ if argindex == 2:
335
+ return polylog(s - 1, z)/z
336
+ raise ArgumentIndexError
337
+
338
+ def _eval_rewrite_as_lerchphi(self, s, z, **kwargs):
339
+ return z*lerchphi(z, s, 1)
340
+
341
+ def _eval_expand_func(self, **hints):
342
+ s, z = self.args
343
+ if s == 1:
344
+ return -log(1 - z)
345
+ if s.is_Integer and s <= 0:
346
+ u = Dummy('u')
347
+ start = u/(1 - u)
348
+ for _ in range(-s):
349
+ start = u*start.diff(u)
350
+ return expand_mul(start).subs(u, z)
351
+ return polylog(s, z)
352
+
353
+ def _eval_is_zero(self):
354
+ z = self.args[1]
355
+ if z.is_zero:
356
+ return True
357
+
358
+ def _eval_nseries(self, x, n, logx, cdir=0):
359
+ from sympy.series.order import Order
360
+ nu, z = self.args
361
+
362
+ z0 = z.subs(x, 0)
363
+ if z0 is S.NaN:
364
+ z0 = z.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
365
+
366
+ if z0.is_zero:
367
+ # In case of powers less than 1, number of terms need to be computed
368
+ # separately to avoid repeated callings of _eval_nseries with wrong n
369
+ try:
370
+ _, exp = z.leadterm(x)
371
+ except (ValueError, NotImplementedError):
372
+ return self
373
+
374
+ if exp.is_positive:
375
+ newn = ceiling(n/exp)
376
+ o = Order(x**n, x)
377
+ r = z._eval_nseries(x, n, logx, cdir).removeO()
378
+ if r is S.Zero:
379
+ return o
380
+
381
+ term = r
382
+ s = [term]
383
+ for k in range(2, newn):
384
+ term *= r
385
+ s.append(term/k**nu)
386
+ return Add(*s) + o
387
+
388
+ return super(polylog, self)._eval_nseries(x, n, logx, cdir)
389
+
390
+ ###############################################################################
391
+ ###################### HURWITZ GENERALIZED ZETA FUNCTION ######################
392
+ ###############################################################################
393
+
394
+
395
+ class zeta(DefinedFunction):
396
+ r"""
397
+ Hurwitz zeta function (or Riemann zeta function).
398
+
399
+ Explanation
400
+ ===========
401
+
402
+ For $\operatorname{Re}(a) > 0$ and $\operatorname{Re}(s) > 1$, this
403
+ function is defined as
404
+
405
+ .. math:: \zeta(s, a) = \sum_{n=0}^\infty \frac{1}{(n + a)^s},
406
+
407
+ where the standard choice of argument for $n + a$ is used. For fixed
408
+ $a$ not a nonpositive integer the Hurwitz zeta function admits a
409
+ meromorphic continuation to all of $\mathbb{C}$; it is an unbranched
410
+ function with a simple pole at $s = 1$.
411
+
412
+ The Hurwitz zeta function is a special case of the Lerch transcendent:
413
+
414
+ .. math:: \zeta(s, a) = \Phi(1, s, a).
415
+
416
+ This formula defines an analytic continuation for all possible values of
417
+ $s$ and $a$ (also $\operatorname{Re}(a) < 0$), see the documentation of
418
+ :class:`lerchphi` for a description of the branching behavior.
419
+
420
+ If no value is passed for $a$ a default value of $a = 1$ is assumed,
421
+ yielding the Riemann zeta function.
422
+
423
+ Examples
424
+ ========
425
+
426
+ For $a = 1$ the Hurwitz zeta function reduces to the famous Riemann
427
+ zeta function:
428
+
429
+ .. math:: \zeta(s, 1) = \zeta(s) = \sum_{n=1}^\infty \frac{1}{n^s}.
430
+
431
+ >>> from sympy import zeta
432
+ >>> from sympy.abc import s
433
+ >>> zeta(s, 1)
434
+ zeta(s)
435
+ >>> zeta(s)
436
+ zeta(s)
437
+
438
+ The Riemann zeta function can also be expressed using the Dirichlet eta
439
+ function:
440
+
441
+ >>> from sympy import dirichlet_eta
442
+ >>> zeta(s).rewrite(dirichlet_eta)
443
+ dirichlet_eta(s)/(1 - 2**(1 - s))
444
+
445
+ The Riemann zeta function at nonnegative even and negative integer
446
+ values is related to the Bernoulli numbers and polynomials:
447
+
448
+ >>> zeta(2)
449
+ pi**2/6
450
+ >>> zeta(4)
451
+ pi**4/90
452
+ >>> zeta(0)
453
+ -1/2
454
+ >>> zeta(-1)
455
+ -1/12
456
+ >>> zeta(-4)
457
+ 0
458
+
459
+ The specific formulae are:
460
+
461
+ .. math:: \zeta(2n) = -\frac{(2\pi i)^{2n} B_{2n}}{2(2n)!}
462
+ .. math:: \zeta(-n,a) = -\frac{B_{n+1}(a)}{n+1}
463
+
464
+ No closed-form expressions are known at positive odd integers, but
465
+ numerical evaluation is possible:
466
+
467
+ >>> zeta(3).n()
468
+ 1.20205690315959
469
+
470
+ The derivative of $\zeta(s, a)$ with respect to $a$ can be computed:
471
+
472
+ >>> from sympy.abc import a
473
+ >>> zeta(s, a).diff(a)
474
+ -s*zeta(s + 1, a)
475
+
476
+ However the derivative with respect to $s$ has no useful closed form
477
+ expression:
478
+
479
+ >>> zeta(s, a).diff(s)
480
+ Derivative(zeta(s, a), s)
481
+
482
+ The Hurwitz zeta function can be expressed in terms of the Lerch
483
+ transcendent, :class:`~.lerchphi`:
484
+
485
+ >>> from sympy import lerchphi
486
+ >>> zeta(s, a).rewrite(lerchphi)
487
+ lerchphi(1, s, a)
488
+
489
+ See Also
490
+ ========
491
+
492
+ dirichlet_eta, lerchphi, polylog
493
+
494
+ References
495
+ ==========
496
+
497
+ .. [1] https://dlmf.nist.gov/25.11
498
+ .. [2] https://en.wikipedia.org/wiki/Hurwitz_zeta_function
499
+
500
+ """
501
+
502
+ @classmethod
503
+ def eval(cls, s, a=None):
504
+ if a is S.One:
505
+ return cls(s)
506
+ elif s is S.NaN or a is S.NaN:
507
+ return S.NaN
508
+ elif s is S.One:
509
+ return S.ComplexInfinity
510
+ elif s is S.Infinity:
511
+ return S.One
512
+ elif a is S.Infinity:
513
+ return S.Zero
514
+
515
+ sint = s.is_Integer
516
+ if a is None:
517
+ a = S.One
518
+ if sint and s.is_nonpositive:
519
+ return bernoulli(1-s, a) / (s-1)
520
+ elif a is S.One:
521
+ if sint and s.is_even:
522
+ return -(2*pi*I)**s * bernoulli(s) / (2*factorial(s))
523
+ elif sint and a.is_Integer and a.is_positive:
524
+ return cls(s) - harmonic(a-1, s)
525
+ elif a.is_Integer and a.is_nonpositive and \
526
+ (s.is_integer is False or s.is_nonpositive is False):
527
+ return S.NaN
528
+
529
+ def _eval_rewrite_as_bernoulli(self, s, a=1, **kwargs):
530
+ if a == 1 and s.is_integer and s.is_nonnegative and s.is_even:
531
+ return -(2*pi*I)**s * bernoulli(s) / (2*factorial(s))
532
+ return bernoulli(1-s, a) / (s-1)
533
+
534
+ def _eval_rewrite_as_dirichlet_eta(self, s, a=1, **kwargs):
535
+ if a != 1:
536
+ return self
537
+ s = self.args[0]
538
+ return dirichlet_eta(s)/(1 - 2**(1 - s))
539
+
540
+ def _eval_rewrite_as_lerchphi(self, s, a=1, **kwargs):
541
+ return lerchphi(1, s, a)
542
+
543
+ def _eval_is_finite(self):
544
+ return fuzzy_not((self.args[0] - 1).is_zero)
545
+
546
+ def _eval_expand_func(self, **hints):
547
+ s = self.args[0]
548
+ a = self.args[1] if len(self.args) > 1 else S.One
549
+ if a.is_integer:
550
+ if a.is_positive:
551
+ return zeta(s) - harmonic(a-1, s)
552
+ if a.is_nonpositive and (s.is_integer is False or
553
+ s.is_nonpositive is False):
554
+ return S.NaN
555
+ return self
556
+
557
+ def fdiff(self, argindex=1):
558
+ if len(self.args) == 2:
559
+ s, a = self.args
560
+ else:
561
+ s, a = self.args + (1,)
562
+ if argindex == 2:
563
+ return -s*zeta(s + 1, a)
564
+ else:
565
+ raise ArgumentIndexError
566
+
567
+ def _eval_as_leading_term(self, x, logx, cdir):
568
+ if len(self.args) == 2:
569
+ s, a = self.args
570
+ else:
571
+ s, a = self.args + (S.One,)
572
+
573
+ try:
574
+ c, e = a.leadterm(x)
575
+ except NotImplementedError:
576
+ return self
577
+
578
+ if e.is_negative and not s.is_positive:
579
+ raise NotImplementedError
580
+
581
+ return super(zeta, self)._eval_as_leading_term(x, logx=logx, cdir=cdir)
582
+
583
+
584
+ class dirichlet_eta(DefinedFunction):
585
+ r"""
586
+ Dirichlet eta function.
587
+
588
+ Explanation
589
+ ===========
590
+
591
+ For $\operatorname{Re}(s) > 0$ and $0 < x \le 1$, this function is defined as
592
+
593
+ .. math:: \eta(s, a) = \sum_{n=0}^\infty \frac{(-1)^n}{(n+a)^s}.
594
+
595
+ It admits a unique analytic continuation to all of $\mathbb{C}$ for any
596
+ fixed $a$ not a nonpositive integer. It is an entire, unbranched function.
597
+
598
+ It can be expressed using the Hurwitz zeta function as
599
+
600
+ .. math:: \eta(s, a) = \zeta(s,a) - 2^{1-s} \zeta\left(s, \frac{a+1}{2}\right)
601
+
602
+ and using the generalized Genocchi function as
603
+
604
+ .. math:: \eta(s, a) = \frac{G(1-s, a)}{2(s-1)}.
605
+
606
+ In both cases the limiting value of $\log2 - \psi(a) + \psi\left(\frac{a+1}{2}\right)$
607
+ is used when $s = 1$.
608
+
609
+ Examples
610
+ ========
611
+
612
+ >>> from sympy import dirichlet_eta, zeta
613
+ >>> from sympy.abc import s
614
+ >>> dirichlet_eta(s).rewrite(zeta)
615
+ Piecewise((log(2), Eq(s, 1)), ((1 - 2**(1 - s))*zeta(s), True))
616
+
617
+ See Also
618
+ ========
619
+
620
+ zeta
621
+
622
+ References
623
+ ==========
624
+
625
+ .. [1] https://en.wikipedia.org/wiki/Dirichlet_eta_function
626
+ .. [2] Peter Luschny, "An introduction to the Bernoulli function",
627
+ https://arxiv.org/abs/2009.06743
628
+
629
+ """
630
+
631
+ @classmethod
632
+ def eval(cls, s, a=None):
633
+ if a is S.One:
634
+ return cls(s)
635
+ if a is None:
636
+ if s == 1:
637
+ return log(2)
638
+ z = zeta(s)
639
+ if not z.has(zeta):
640
+ return (1 - 2**(1-s)) * z
641
+ return
642
+ elif s == 1:
643
+ from sympy.functions.special.gamma_functions import digamma
644
+ return log(2) - digamma(a) + digamma((a+1)/2)
645
+ z1 = zeta(s, a)
646
+ z2 = zeta(s, (a+1)/2)
647
+ if not z1.has(zeta) and not z2.has(zeta):
648
+ return z1 - 2**(1-s) * z2
649
+
650
+ def _eval_rewrite_as_zeta(self, s, a=1, **kwargs):
651
+ from sympy.functions.special.gamma_functions import digamma
652
+ if a == 1:
653
+ return Piecewise((log(2), Eq(s, 1)), ((1 - 2**(1-s)) * zeta(s), True))
654
+ return Piecewise((log(2) - digamma(a) + digamma((a+1)/2), Eq(s, 1)),
655
+ (zeta(s, a) - 2**(1-s) * zeta(s, (a+1)/2), True))
656
+
657
+ def _eval_rewrite_as_genocchi(self, s, a=S.One, **kwargs):
658
+ from sympy.functions.special.gamma_functions import digamma
659
+ return Piecewise((log(2) - digamma(a) + digamma((a+1)/2), Eq(s, 1)),
660
+ (genocchi(1-s, a) / (2 * (s-1)), True))
661
+
662
+ def _eval_evalf(self, prec):
663
+ if all(i.is_number for i in self.args):
664
+ return self.rewrite(zeta)._eval_evalf(prec)
665
+
666
+
667
+ class riemann_xi(DefinedFunction):
668
+ r"""
669
+ Riemann Xi function.
670
+
671
+ Examples
672
+ ========
673
+
674
+ The Riemann Xi function is closely related to the Riemann zeta function.
675
+ The zeros of Riemann Xi function are precisely the non-trivial zeros
676
+ of the zeta function.
677
+
678
+ >>> from sympy import riemann_xi, zeta
679
+ >>> from sympy.abc import s
680
+ >>> riemann_xi(s).rewrite(zeta)
681
+ s*(s - 1)*gamma(s/2)*zeta(s)/(2*pi**(s/2))
682
+
683
+ References
684
+ ==========
685
+
686
+ .. [1] https://en.wikipedia.org/wiki/Riemann_Xi_function
687
+
688
+ """
689
+
690
+
691
+ @classmethod
692
+ def eval(cls, s):
693
+ from sympy.functions.special.gamma_functions import gamma
694
+ z = zeta(s)
695
+ if s in (S.Zero, S.One):
696
+ return S.Half
697
+
698
+ if not isinstance(z, zeta):
699
+ return s*(s - 1)*gamma(s/2)*z/(2*pi**(s/2))
700
+
701
+ def _eval_rewrite_as_zeta(self, s, **kwargs):
702
+ from sympy.functions.special.gamma_functions import gamma
703
+ return s*(s - 1)*gamma(s/2)*zeta(s)/(2*pi**(s/2))
704
+
705
+
706
+ class stieltjes(DefinedFunction):
707
+ r"""
708
+ Represents Stieltjes constants, $\gamma_{k}$ that occur in
709
+ Laurent Series expansion of the Riemann zeta function.
710
+
711
+ Examples
712
+ ========
713
+
714
+ >>> from sympy import stieltjes
715
+ >>> from sympy.abc import n, m
716
+ >>> stieltjes(n)
717
+ stieltjes(n)
718
+
719
+ The zero'th stieltjes constant:
720
+
721
+ >>> stieltjes(0)
722
+ EulerGamma
723
+ >>> stieltjes(0, 1)
724
+ EulerGamma
725
+
726
+ For generalized stieltjes constants:
727
+
728
+ >>> stieltjes(n, m)
729
+ stieltjes(n, m)
730
+
731
+ Constants are only defined for integers >= 0:
732
+
733
+ >>> stieltjes(-1)
734
+ zoo
735
+
736
+ References
737
+ ==========
738
+
739
+ .. [1] https://en.wikipedia.org/wiki/Stieltjes_constants
740
+
741
+ """
742
+
743
+ @classmethod
744
+ def eval(cls, n, a=None):
745
+ if a is not None:
746
+ a = sympify(a)
747
+ if a is S.NaN:
748
+ return S.NaN
749
+ if a.is_Integer and a.is_nonpositive:
750
+ return S.ComplexInfinity
751
+
752
+ if n.is_Number:
753
+ if n is S.NaN:
754
+ return S.NaN
755
+ elif n < 0:
756
+ return S.ComplexInfinity
757
+ elif not n.is_Integer:
758
+ return S.ComplexInfinity
759
+ elif n is S.Zero and a in [None, 1]:
760
+ return S.EulerGamma
761
+
762
+ if n.is_extended_negative:
763
+ return S.ComplexInfinity
764
+
765
+ if n.is_zero and a in [None, 1]:
766
+ return S.EulerGamma
767
+
768
+ if n.is_integer == False:
769
+ return S.ComplexInfinity
770
+
771
+
772
+ @cacheit
773
+ def _dilogtable():
774
+ return {
775
+ S.Half: pi**2/12 - log(2)**2/2,
776
+ Integer(2) : pi**2/4 - I*pi*log(2),
777
+ -(sqrt(5) - 1)/2 : -pi**2/15 + log((sqrt(5)-1)/2)**2/2,
778
+ -(sqrt(5) + 1)/2 : -pi**2/10 - log((sqrt(5)+1)/2)**2,
779
+ (3 - sqrt(5))/2 : pi**2/15 - log((sqrt(5)-1)/2)**2,
780
+ (sqrt(5) - 1)/2 : pi**2/10 - log((sqrt(5)-1)/2)**2,
781
+ I : I*S.Catalan - pi**2/48,
782
+ -I : -I*S.Catalan - pi**2/48,
783
+ 1 - I : pi**2/16 - I*S.Catalan - pi*I/4*log(2),
784
+ 1 + I : pi**2/16 + I*S.Catalan + pi*I/4*log(2),
785
+ (1 - I)/2 : -log(2)**2/8 + pi*I*log(2)/8 + 5*pi**2/96 - I*S.Catalan
786
+ }
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (643 Bytes). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/experimental_lambdify.cpython-312.pyc ADDED
Binary file (20.7 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/plot.cpython-312.pyc ADDED
Binary file (44 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/plot_implicit.cpython-312.pyc ADDED
Binary file (8.52 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/plotgrid.cpython-312.pyc ADDED
Binary file (8.37 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/textplot.cpython-312.pyc ADDED
Binary file (7.09 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/__pycache__/utils.cpython-312.pyc ADDED
Binary file (14.4 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/backends/textbackend/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from sympy.plotting.backends.textbackend.text import TextBackend
2
+
3
+ __all__ = ["TextBackend"]
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/backends/textbackend/text.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sympy.plotting.backends.base_backend as base_backend
2
+ from sympy.plotting.series import LineOver1DRangeSeries
3
+ from sympy.plotting.textplot import textplot
4
+
5
+
6
+ class TextBackend(base_backend.Plot):
7
+ def __init__(self, *args, **kwargs):
8
+ super().__init__(*args, **kwargs)
9
+
10
+ def show(self):
11
+ if not base_backend._show:
12
+ return
13
+ if len(self._series) != 1:
14
+ raise ValueError(
15
+ 'The TextBackend supports only one graph per Plot.')
16
+ elif not isinstance(self._series[0], LineOver1DRangeSeries):
17
+ raise ValueError(
18
+ 'The TextBackend supports only expressions over a 1D range')
19
+ else:
20
+ ser = self._series[0]
21
+ textplot(ser.expr, ser.start, ser.end)
22
+
23
+ def close(self):
24
+ pass
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/intervalmath/__init__.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .interval_arithmetic import interval
2
+ from .lib_interval import (Abs, exp, log, log10, sin, cos, tan, sqrt,
3
+ imin, imax, sinh, cosh, tanh, acosh, asinh, atanh,
4
+ asin, acos, atan, ceil, floor, And, Or)
5
+
6
+ __all__ = [
7
+ 'interval',
8
+
9
+ 'Abs', 'exp', 'log', 'log10', 'sin', 'cos', 'tan', 'sqrt', 'imin', 'imax',
10
+ 'sinh', 'cosh', 'tanh', 'acosh', 'asinh', 'atanh', 'asin', 'acos', 'atan',
11
+ 'ceil', 'floor', 'And', 'Or',
12
+ ]
URSA/.venv_ursa/lib/python3.12/site-packages/sympy/plotting/intervalmath/interval_arithmetic.py ADDED
@@ -0,0 +1,413 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Interval Arithmetic for plotting.
3
+ This module does not implement interval arithmetic accurately and
4
+ hence cannot be used for purposes other than plotting. If you want
5
+ to use interval arithmetic, use mpmath's interval arithmetic.
6
+
7
+ The module implements interval arithmetic using numpy and
8
+ python floating points. The rounding up and down is not handled
9
+ and hence this is not an accurate implementation of interval
10
+ arithmetic.
11
+
12
+ The module uses numpy for speed which cannot be achieved with mpmath.
13
+ """
14
+
15
+ # Q: Why use numpy? Why not simply use mpmath's interval arithmetic?
16
+ # A: mpmath's interval arithmetic simulates a floating point unit
17
+ # and hence is slow, while numpy evaluations are orders of magnitude
18
+ # faster.
19
+
20
+ # Q: Why create a separate class for intervals? Why not use SymPy's
21
+ # Interval Sets?
22
+ # A: The functionalities that will be required for plotting is quite
23
+ # different from what Interval Sets implement.
24
+
25
+ # Q: Why is rounding up and down according to IEEE754 not handled?
26
+ # A: It is not possible to do it in both numpy and python. An external
27
+ # library has to used, which defeats the whole purpose i.e., speed. Also
28
+ # rounding is handled for very few functions in those libraries.
29
+
30
+ # Q Will my plots be affected?
31
+ # A It will not affect most of the plots. The interval arithmetic
32
+ # module based suffers the same problems as that of floating point
33
+ # arithmetic.
34
+
35
+ from sympy.core.numbers import int_valued
36
+ from sympy.core.logic import fuzzy_and
37
+ from sympy.simplify.simplify import nsimplify
38
+
39
+ from .interval_membership import intervalMembership
40
+
41
+
42
+ class interval:
43
+ """ Represents an interval containing floating points as start and
44
+ end of the interval
45
+ The is_valid variable tracks whether the interval obtained as the
46
+ result of the function is in the domain and is continuous.
47
+ - True: Represents the interval result of a function is continuous and
48
+ in the domain of the function.
49
+ - False: The interval argument of the function was not in the domain of
50
+ the function, hence the is_valid of the result interval is False
51
+ - None: The function was not continuous over the interval or
52
+ the function's argument interval is partly in the domain of the
53
+ function
54
+
55
+ A comparison between an interval and a real number, or a
56
+ comparison between two intervals may return ``intervalMembership``
57
+ of two 3-valued logic values.
58
+ """
59
+
60
+ def __init__(self, *args, is_valid=True, **kwargs):
61
+ self.is_valid = is_valid
62
+ if len(args) == 1:
63
+ if isinstance(args[0], interval):
64
+ self.start, self.end = args[0].start, args[0].end
65
+ else:
66
+ self.start = float(args[0])
67
+ self.end = float(args[0])
68
+ elif len(args) == 2:
69
+ if args[0] < args[1]:
70
+ self.start = float(args[0])
71
+ self.end = float(args[1])
72
+ else:
73
+ self.start = float(args[1])
74
+ self.end = float(args[0])
75
+
76
+ else:
77
+ raise ValueError("interval takes a maximum of two float values "
78
+ "as arguments")
79
+
80
+ @property
81
+ def mid(self):
82
+ return (self.start + self.end) / 2.0
83
+
84
+ @property
85
+ def width(self):
86
+ return self.end - self.start
87
+
88
+ def __repr__(self):
89
+ return "interval(%f, %f)" % (self.start, self.end)
90
+
91
+ def __str__(self):
92
+ return "[%f, %f]" % (self.start, self.end)
93
+
94
+ def __lt__(self, other):
95
+ if isinstance(other, (int, float)):
96
+ if self.end < other:
97
+ return intervalMembership(True, self.is_valid)
98
+ elif self.start > other:
99
+ return intervalMembership(False, self.is_valid)
100
+ else:
101
+ return intervalMembership(None, self.is_valid)
102
+
103
+ elif isinstance(other, interval):
104
+ valid = fuzzy_and([self.is_valid, other.is_valid])
105
+ if self.end < other. start:
106
+ return intervalMembership(True, valid)
107
+ if self.start > other.end:
108
+ return intervalMembership(False, valid)
109
+ return intervalMembership(None, valid)
110
+ else:
111
+ return NotImplemented
112
+
113
+ def __gt__(self, other):
114
+ if isinstance(other, (int, float)):
115
+ if self.start > other:
116
+ return intervalMembership(True, self.is_valid)
117
+ elif self.end < other:
118
+ return intervalMembership(False, self.is_valid)
119
+ else:
120
+ return intervalMembership(None, self.is_valid)
121
+ elif isinstance(other, interval):
122
+ return other.__lt__(self)
123
+ else:
124
+ return NotImplemented
125
+
126
+ def __eq__(self, other):
127
+ if isinstance(other, (int, float)):
128
+ if self.start == other and self.end == other:
129
+ return intervalMembership(True, self.is_valid)
130
+ if other in self:
131
+ return intervalMembership(None, self.is_valid)
132
+ else:
133
+ return intervalMembership(False, self.is_valid)
134
+
135
+ if isinstance(other, interval):
136
+ valid = fuzzy_and([self.is_valid, other.is_valid])
137
+ if self.start == other.start and self.end == other.end:
138
+ return intervalMembership(True, valid)
139
+ elif self.__lt__(other)[0] is not None:
140
+ return intervalMembership(False, valid)
141
+ else:
142
+ return intervalMembership(None, valid)
143
+ else:
144
+ return NotImplemented
145
+
146
+ def __ne__(self, other):
147
+ if isinstance(other, (int, float)):
148
+ if self.start == other and self.end == other:
149
+ return intervalMembership(False, self.is_valid)
150
+ if other in self:
151
+ return intervalMembership(None, self.is_valid)
152
+ else:
153
+ return intervalMembership(True, self.is_valid)
154
+
155
+ if isinstance(other, interval):
156
+ valid = fuzzy_and([self.is_valid, other.is_valid])
157
+ if self.start == other.start and self.end == other.end:
158
+ return intervalMembership(False, valid)
159
+ if not self.__lt__(other)[0] is None:
160
+ return intervalMembership(True, valid)
161
+ return intervalMembership(None, valid)
162
+ else:
163
+ return NotImplemented
164
+
165
+ def __le__(self, other):
166
+ if isinstance(other, (int, float)):
167
+ if self.end <= other:
168
+ return intervalMembership(True, self.is_valid)
169
+ if self.start > other:
170
+ return intervalMembership(False, self.is_valid)
171
+ else:
172
+ return intervalMembership(None, self.is_valid)
173
+
174
+ if isinstance(other, interval):
175
+ valid = fuzzy_and([self.is_valid, other.is_valid])
176
+ if self.end <= other.start:
177
+ return intervalMembership(True, valid)
178
+ if self.start > other.end:
179
+ return intervalMembership(False, valid)
180
+ return intervalMembership(None, valid)
181
+ else:
182
+ return NotImplemented
183
+
184
+ def __ge__(self, other):
185
+ if isinstance(other, (int, float)):
186
+ if self.start >= other:
187
+ return intervalMembership(True, self.is_valid)
188
+ elif self.end < other:
189
+ return intervalMembership(False, self.is_valid)
190
+ else:
191
+ return intervalMembership(None, self.is_valid)
192
+ elif isinstance(other, interval):
193
+ return other.__le__(self)
194
+
195
+ def __add__(self, other):
196
+ if isinstance(other, (int, float)):
197
+ if self.is_valid:
198
+ return interval(self.start + other, self.end + other)
199
+ else:
200
+ start = self.start + other
201
+ end = self.end + other
202
+ return interval(start, end, is_valid=self.is_valid)
203
+
204
+ elif isinstance(other, interval):
205
+ start = self.start + other.start
206
+ end = self.end + other.end
207
+ valid = fuzzy_and([self.is_valid, other.is_valid])
208
+ return interval(start, end, is_valid=valid)
209
+ else:
210
+ return NotImplemented
211
+
212
+ __radd__ = __add__
213
+
214
+ def __sub__(self, other):
215
+ if isinstance(other, (int, float)):
216
+ start = self.start - other
217
+ end = self.end - other
218
+ return interval(start, end, is_valid=self.is_valid)
219
+
220
+ elif isinstance(other, interval):
221
+ start = self.start - other.end
222
+ end = self.end - other.start
223
+ valid = fuzzy_and([self.is_valid, other.is_valid])
224
+ return interval(start, end, is_valid=valid)
225
+ else:
226
+ return NotImplemented
227
+
228
+ def __rsub__(self, other):
229
+ if isinstance(other, (int, float)):
230
+ start = other - self.end
231
+ end = other - self.start
232
+ return interval(start, end, is_valid=self.is_valid)
233
+ elif isinstance(other, interval):
234
+ return other.__sub__(self)
235
+ else:
236
+ return NotImplemented
237
+
238
+ def __neg__(self):
239
+ if self.is_valid:
240
+ return interval(-self.end, -self.start)
241
+ else:
242
+ return interval(-self.end, -self.start, is_valid=self.is_valid)
243
+
244
+ def __mul__(self, other):
245
+ if isinstance(other, interval):
246
+ if self.is_valid is False or other.is_valid is False:
247
+ return interval(-float('inf'), float('inf'), is_valid=False)
248
+ elif self.is_valid is None or other.is_valid is None:
249
+ return interval(-float('inf'), float('inf'), is_valid=None)
250
+ else:
251
+ inters = []
252
+ inters.append(self.start * other.start)
253
+ inters.append(self.end * other.start)
254
+ inters.append(self.start * other.end)
255
+ inters.append(self.end * other.end)
256
+ start = min(inters)
257
+ end = max(inters)
258
+ return interval(start, end)
259
+ elif isinstance(other, (int, float)):
260
+ return interval(self.start*other, self.end*other, is_valid=self.is_valid)
261
+ else:
262
+ return NotImplemented
263
+
264
+ __rmul__ = __mul__
265
+
266
+ def __contains__(self, other):
267
+ if isinstance(other, (int, float)):
268
+ return self.start <= other and self.end >= other
269
+ else:
270
+ return self.start <= other.start and other.end <= self.end
271
+
272
+ def __rtruediv__(self, other):
273
+ if isinstance(other, (int, float)):
274
+ other = interval(other)
275
+ return other.__truediv__(self)
276
+ elif isinstance(other, interval):
277
+ return other.__truediv__(self)
278
+ else:
279
+ return NotImplemented
280
+
281
+ def __truediv__(self, other):
282
+ # Both None and False are handled
283
+ if not self.is_valid:
284
+ # Don't divide as the value is not valid
285
+ return interval(-float('inf'), float('inf'), is_valid=self.is_valid)
286
+ if isinstance(other, (int, float)):
287
+ if other == 0:
288
+ # Divide by zero encountered. valid nowhere
289
+ return interval(-float('inf'), float('inf'), is_valid=False)
290
+ else:
291
+ return interval(self.start / other, self.end / other)
292
+
293
+ elif isinstance(other, interval):
294
+ if other.is_valid is False or self.is_valid is False:
295
+ return interval(-float('inf'), float('inf'), is_valid=False)
296
+ elif other.is_valid is None or self.is_valid is None:
297
+ return interval(-float('inf'), float('inf'), is_valid=None)
298
+ else:
299
+ # denominator contains both signs, i.e. being divided by zero
300
+ # return the whole real line with is_valid = None
301
+ if 0 in other:
302
+ return interval(-float('inf'), float('inf'), is_valid=None)
303
+
304
+ # denominator negative
305
+ this = self
306
+ if other.end < 0:
307
+ this = -this
308
+ other = -other
309
+
310
+ # denominator positive
311
+ inters = []
312
+ inters.append(this.start / other.start)
313
+ inters.append(this.end / other.start)
314
+ inters.append(this.start / other.end)
315
+ inters.append(this.end / other.end)
316
+ start = max(inters)
317
+ end = min(inters)
318
+ return interval(start, end)
319
+ else:
320
+ return NotImplemented
321
+
322
+ def __pow__(self, other):
323
+ # Implements only power to an integer.
324
+ from .lib_interval import exp, log
325
+ if not self.is_valid:
326
+ return self
327
+ if isinstance(other, interval):
328
+ return exp(other * log(self))
329
+ elif isinstance(other, (float, int)):
330
+ if other < 0:
331
+ return 1 / self.__pow__(abs(other))
332
+ else:
333
+ if int_valued(other):
334
+ return _pow_int(self, other)
335
+ else:
336
+ return _pow_float(self, other)
337
+ else:
338
+ return NotImplemented
339
+
340
+ def __rpow__(self, other):
341
+ if isinstance(other, (float, int)):
342
+ if not self.is_valid:
343
+ #Don't do anything
344
+ return self
345
+ elif other < 0:
346
+ if self.width > 0:
347
+ return interval(-float('inf'), float('inf'), is_valid=False)
348
+ else:
349
+ power_rational = nsimplify(self.start)
350
+ num, denom = power_rational.as_numer_denom()
351
+ if denom % 2 == 0:
352
+ return interval(-float('inf'), float('inf'),
353
+ is_valid=False)
354
+ else:
355
+ start = -abs(other)**self.start
356
+ end = start
357
+ return interval(start, end)
358
+ else:
359
+ return interval(other**self.start, other**self.end)
360
+ elif isinstance(other, interval):
361
+ return other.__pow__(self)
362
+ else:
363
+ return NotImplemented
364
+
365
+ def __hash__(self):
366
+ return hash((self.is_valid, self.start, self.end))
367
+
368
+
369
+ def _pow_float(inter, power):
370
+ """Evaluates an interval raised to a floating point."""
371
+ power_rational = nsimplify(power)
372
+ num, denom = power_rational.as_numer_denom()
373
+ if num % 2 == 0:
374
+ start = abs(inter.start)**power
375
+ end = abs(inter.end)**power
376
+ if start < 0:
377
+ ret = interval(0, max(start, end))
378
+ else:
379
+ ret = interval(start, end)
380
+ return ret
381
+ elif denom % 2 == 0:
382
+ if inter.end < 0:
383
+ return interval(-float('inf'), float('inf'), is_valid=False)
384
+ elif inter.start < 0:
385
+ return interval(0, inter.end**power, is_valid=None)
386
+ else:
387
+ return interval(inter.start**power, inter.end**power)
388
+ else:
389
+ if inter.start < 0:
390
+ start = -abs(inter.start)**power
391
+ else:
392
+ start = inter.start**power
393
+
394
+ if inter.end < 0:
395
+ end = -abs(inter.end)**power
396
+ else:
397
+ end = inter.end**power
398
+
399
+ return interval(start, end, is_valid=inter.is_valid)
400
+
401
+
402
+ def _pow_int(inter, power):
403
+ """Evaluates an interval raised to an integer power"""
404
+ power = int(power)
405
+ if power & 1:
406
+ return interval(inter.start**power, inter.end**power)
407
+ else:
408
+ if inter.start < 0 and inter.end > 0:
409
+ start = 0
410
+ end = max(inter.start**power, inter.end**power)
411
+ return interval(start, end)
412
+ else:
413
+ return interval(inter.start**power, inter.end**power)