funcprops 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- funcprops/__init__.py +234 -0
- funcprops/_semialg.py +246 -0
- funcprops/api.py +70 -0
- funcprops/branchcuts/__init__.py +141 -0
- funcprops/branchcuts/computation.py +664 -0
- funcprops/branchcuts/core.py +1204 -0
- funcprops/branchcuts/post_simplify.py +461 -0
- funcprops/conditions.py +124 -0
- funcprops/data/catalogue.json +127449 -0
- funcprops/data/dlmf_audit.json +3382 -0
- funcprops/dlmf.py +29 -0
- funcprops/engine.py +324 -0
- funcprops/exceptions.py +29 -0
- funcprops/proof_cache.py +373 -0
- funcprops/real_analysis/__init__.py +52 -0
- funcprops/real_analysis/advanced_convexity.py +217 -0
- funcprops/real_analysis/boundedness.py +168 -0
- funcprops/real_analysis/common.py +244 -0
- funcprops/real_analysis/convexity.py +698 -0
- funcprops/real_analysis/differentiability.py +112 -0
- funcprops/real_analysis/domain.py +188 -0
- funcprops/real_analysis/mapping.py +374 -0
- funcprops/real_analysis/monotonic_certificates.py +867 -0
- funcprops/real_analysis/monotonicity.py +673 -0
- funcprops/real_analysis/oscillation.py +151 -0
- funcprops/real_analysis/piecewise.py +174 -0
- funcprops/real_analysis/range.py +552 -0
- funcprops/real_analysis/sign.py +561 -0
- funcprops/real_analysis/smoothness.py +268 -0
- funcprops/real_analysis/special_functions.py +515 -0
- funcprops/real_analysis/structural_properties.py +558 -0
- funcprops/real_analysis/zeros.py +327 -0
- funcprops/registry.py +274 -0
- funcprops/results.py +239 -0
- funcprops/singularities.py +1767 -0
- funcprops/stratification.py +494 -0
- funcprops/sympy_compare.py +63 -0
- funcprops/transcendental/__init__.py +140 -0
- funcprops/transcendental/algebraize.py +201 -0
- funcprops/transcendental/analytic.py +261 -0
- funcprops/transcendental/complex_roots.py +542 -0
- funcprops/transcendental/exp_fourier.py +221 -0
- funcprops/transcendental/extrema.py +821 -0
- funcprops/transcendental/periodic.py +222 -0
- funcprops/transcendental/proof.py +104 -0
- funcprops/transcendental/real_interval.py +128 -0
- funcprops/transcendental/real_sign.py +117 -0
- funcprops/transcendental/reduce.py +288 -0
- funcprops/transcendental/roots.py +1380 -0
- funcprops/transcendental/zero_geometry.py +1197 -0
- funcprops/verification.py +410 -0
- funcprops-0.1.0.dist-info/METADATA +208 -0
- funcprops-0.1.0.dist-info/RECORD +56 -0
- funcprops-0.1.0.dist-info/WHEEL +5 -0
- funcprops-0.1.0.dist-info/licenses/LICENSE +674 -0
- funcprops-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1204 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from sympy import (
|
|
6
|
+
Abs,
|
|
7
|
+
Add,
|
|
8
|
+
AtomicExpr,
|
|
9
|
+
Chi,
|
|
10
|
+
Ci,
|
|
11
|
+
E,
|
|
12
|
+
Eq,
|
|
13
|
+
Expr,
|
|
14
|
+
I,
|
|
15
|
+
LambertW,
|
|
16
|
+
Mul,
|
|
17
|
+
Piecewise,
|
|
18
|
+
S,
|
|
19
|
+
Symbol,
|
|
20
|
+
acos,
|
|
21
|
+
acosh,
|
|
22
|
+
acot,
|
|
23
|
+
acoth,
|
|
24
|
+
acsc,
|
|
25
|
+
acsch,
|
|
26
|
+
asec,
|
|
27
|
+
asech,
|
|
28
|
+
asin,
|
|
29
|
+
asinh,
|
|
30
|
+
assoc_legendre,
|
|
31
|
+
atan,
|
|
32
|
+
atanh,
|
|
33
|
+
besseli,
|
|
34
|
+
besselj,
|
|
35
|
+
besselk,
|
|
36
|
+
bessely,
|
|
37
|
+
beta,
|
|
38
|
+
betainc,
|
|
39
|
+
betainc_regularized,
|
|
40
|
+
cos,
|
|
41
|
+
elliptic_e,
|
|
42
|
+
elliptic_f,
|
|
43
|
+
elliptic_k,
|
|
44
|
+
elliptic_pi,
|
|
45
|
+
expint,
|
|
46
|
+
factorial,
|
|
47
|
+
floor,
|
|
48
|
+
gamma,
|
|
49
|
+
hankel1,
|
|
50
|
+
hankel2,
|
|
51
|
+
hyper,
|
|
52
|
+
im,
|
|
53
|
+
lerchphi,
|
|
54
|
+
li,
|
|
55
|
+
log,
|
|
56
|
+
loggamma,
|
|
57
|
+
meijerg,
|
|
58
|
+
pi,
|
|
59
|
+
polylog,
|
|
60
|
+
re,
|
|
61
|
+
simplify,
|
|
62
|
+
sin,
|
|
63
|
+
sqrt,
|
|
64
|
+
sympify,
|
|
65
|
+
)
|
|
66
|
+
from sympy.logic.boolalg import And, Boolean, BooleanFalse, BooleanTrue
|
|
67
|
+
from sympy.sets.contains import Contains
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class _UndefinedType(AtomicExpr):
|
|
71
|
+
"""Symbolic undefined value distinct from NaN and ordinary variables."""
|
|
72
|
+
|
|
73
|
+
is_commutative = True
|
|
74
|
+
|
|
75
|
+
def _sympystr(self, printer):
|
|
76
|
+
return "Undefined()"
|
|
77
|
+
|
|
78
|
+
def __repr__(self):
|
|
79
|
+
return "Undefined()"
|
|
80
|
+
|
|
81
|
+
def __str__(self):
|
|
82
|
+
return "Undefined()"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
_UNDEFINED_SINGLETON = _UndefinedType()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def Undefined() -> _UndefinedType:
|
|
89
|
+
"""Return the singleton symbolic undefined value."""
|
|
90
|
+
return _UNDEFINED_SINGLETON
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _to_bool(cond) -> Boolean | BooleanTrue | BooleanFalse:
|
|
94
|
+
"""Canonicalize a condition into a SymPy Boolean."""
|
|
95
|
+
cond = sympify(cond)
|
|
96
|
+
if cond is True:
|
|
97
|
+
return S.true
|
|
98
|
+
if cond is False:
|
|
99
|
+
return S.false
|
|
100
|
+
if isinstance(cond, (Boolean, BooleanTrue, BooleanFalse)):
|
|
101
|
+
return cond
|
|
102
|
+
raise TypeError(f"Condition must be a SymPy Boolean, got {type(cond)!r}: {cond!r}")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _combine_conditions(*conds) -> Boolean | BooleanTrue | BooleanFalse:
|
|
106
|
+
"""Combine conditions with logical AND, simplifying trivial parts."""
|
|
107
|
+
normalized = []
|
|
108
|
+
for cond in conds:
|
|
109
|
+
c = _to_bool(cond)
|
|
110
|
+
if c == S.false:
|
|
111
|
+
return S.false
|
|
112
|
+
if c != S.true:
|
|
113
|
+
normalized.append(c)
|
|
114
|
+
if not normalized:
|
|
115
|
+
return S.true
|
|
116
|
+
if len(normalized) == 1:
|
|
117
|
+
return normalized[0]
|
|
118
|
+
combined = simplify(And(*normalized))
|
|
119
|
+
if combined is True:
|
|
120
|
+
return S.true
|
|
121
|
+
if combined is False:
|
|
122
|
+
return S.false
|
|
123
|
+
return _to_bool(combined)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class RestrictedExpr(Expr):
|
|
127
|
+
"""
|
|
128
|
+
RestrictedExpr(expr, cond) means
|
|
129
|
+
|
|
130
|
+
expr, when cond holds
|
|
131
|
+
Undefined(), otherwise.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
is_commutative = True
|
|
135
|
+
|
|
136
|
+
def __new__(cls, expr, cond):
|
|
137
|
+
expr = sympify(expr)
|
|
138
|
+
cond = _to_bool(cond)
|
|
139
|
+
|
|
140
|
+
if expr == Undefined():
|
|
141
|
+
return Undefined()
|
|
142
|
+
|
|
143
|
+
if isinstance(expr, RestrictedExpr):
|
|
144
|
+
expr, cond = expr.expr, _combine_conditions(expr.cond, cond)
|
|
145
|
+
|
|
146
|
+
if cond == S.true:
|
|
147
|
+
return expr
|
|
148
|
+
if cond == S.false:
|
|
149
|
+
return Undefined()
|
|
150
|
+
|
|
151
|
+
return Expr.__new__(cls, expr, cond)
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def expr(self):
|
|
155
|
+
return self.args[0]
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def cond(self):
|
|
159
|
+
return self.args[1]
|
|
160
|
+
|
|
161
|
+
def _sympystr(self, printer):
|
|
162
|
+
return f"RestrictedExpr({printer.doprint(self.expr)}, {printer.doprint(self.cond)})"
|
|
163
|
+
|
|
164
|
+
def to_piecewise(self, off_value=None):
|
|
165
|
+
"""Export as Piecewise; default off-condition value is Undefined()."""
|
|
166
|
+
if off_value is None:
|
|
167
|
+
off_value = Undefined()
|
|
168
|
+
return Piecewise((self.expr, self.cond), (off_value, True))
|
|
169
|
+
|
|
170
|
+
def doit(self, deep=True, **hints):
|
|
171
|
+
expr = (
|
|
172
|
+
self.expr.doit(deep=deep, **hints)
|
|
173
|
+
if hasattr(self.expr, "doit")
|
|
174
|
+
else self.expr
|
|
175
|
+
)
|
|
176
|
+
return restrict(expr, simplify(self.cond))
|
|
177
|
+
|
|
178
|
+
def _eval_simplify(self, **kwargs):
|
|
179
|
+
return simplify_restricted(self)
|
|
180
|
+
|
|
181
|
+
def _combine_with_other(self, other, op):
|
|
182
|
+
other = sympify(other)
|
|
183
|
+
if other == Undefined():
|
|
184
|
+
return Undefined()
|
|
185
|
+
if isinstance(other, RestrictedExpr):
|
|
186
|
+
return restrict(
|
|
187
|
+
op(self.expr, other.expr), _combine_conditions(self.cond, other.cond)
|
|
188
|
+
)
|
|
189
|
+
return restrict(op(self.expr, other), self.cond)
|
|
190
|
+
|
|
191
|
+
def __add__(self, other):
|
|
192
|
+
return self._combine_with_other(other, lambda a, b: Add(a, b))
|
|
193
|
+
|
|
194
|
+
def __radd__(self, other):
|
|
195
|
+
other = sympify(other)
|
|
196
|
+
if other == Undefined():
|
|
197
|
+
return Undefined()
|
|
198
|
+
return restrict(Add(other, self.expr), self.cond)
|
|
199
|
+
|
|
200
|
+
def __mul__(self, other):
|
|
201
|
+
return self._combine_with_other(other, lambda a, b: Mul(a, b))
|
|
202
|
+
|
|
203
|
+
def __rmul__(self, other):
|
|
204
|
+
other = sympify(other)
|
|
205
|
+
if other == Undefined():
|
|
206
|
+
return Undefined()
|
|
207
|
+
return restrict(Mul(other, self.expr), self.cond)
|
|
208
|
+
|
|
209
|
+
def __sub__(self, other):
|
|
210
|
+
return self._combine_with_other(other, lambda a, b: Add(a, -b))
|
|
211
|
+
|
|
212
|
+
def __rsub__(self, other):
|
|
213
|
+
other = sympify(other)
|
|
214
|
+
if other == Undefined():
|
|
215
|
+
return Undefined()
|
|
216
|
+
return restrict(Add(other, -self.expr), self.cond)
|
|
217
|
+
|
|
218
|
+
def __truediv__(self, other):
|
|
219
|
+
other = sympify(other)
|
|
220
|
+
if other == Undefined():
|
|
221
|
+
return Undefined()
|
|
222
|
+
if isinstance(other, RestrictedExpr):
|
|
223
|
+
return restrict(
|
|
224
|
+
self.expr / other.expr, _combine_conditions(self.cond, other.cond)
|
|
225
|
+
)
|
|
226
|
+
return restrict(self.expr / other, self.cond)
|
|
227
|
+
|
|
228
|
+
def __rtruediv__(self, other):
|
|
229
|
+
other = sympify(other)
|
|
230
|
+
if other == Undefined():
|
|
231
|
+
return Undefined()
|
|
232
|
+
return restrict(other / self.expr, self.cond)
|
|
233
|
+
|
|
234
|
+
def __pow__(self, power, modulo=None):
|
|
235
|
+
if modulo is not None:
|
|
236
|
+
raise TypeError("RestrictedExpr does not support modular exponentiation")
|
|
237
|
+
power = sympify(power)
|
|
238
|
+
if power == Undefined():
|
|
239
|
+
return Undefined()
|
|
240
|
+
if isinstance(power, RestrictedExpr):
|
|
241
|
+
return restrict(
|
|
242
|
+
self.expr**power.expr, _combine_conditions(self.cond, power.cond)
|
|
243
|
+
)
|
|
244
|
+
return restrict(self.expr**power, self.cond)
|
|
245
|
+
|
|
246
|
+
def __rpow__(self, base):
|
|
247
|
+
base = sympify(base)
|
|
248
|
+
if base == Undefined():
|
|
249
|
+
return Undefined()
|
|
250
|
+
return restrict(base**self.expr, self.cond)
|
|
251
|
+
|
|
252
|
+
def __neg__(self):
|
|
253
|
+
return restrict(-self.expr, self.cond)
|
|
254
|
+
|
|
255
|
+
def __pos__(self):
|
|
256
|
+
return self
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def restrict(expr, cond):
|
|
260
|
+
"""Construct a RestrictedExpr, normalizing trivial cases."""
|
|
261
|
+
expr = sympify(expr)
|
|
262
|
+
cond = _to_bool(cond)
|
|
263
|
+
|
|
264
|
+
if expr == Undefined():
|
|
265
|
+
return Undefined()
|
|
266
|
+
if isinstance(expr, RestrictedExpr):
|
|
267
|
+
return RestrictedExpr(expr.expr, _combine_conditions(expr.cond, cond))
|
|
268
|
+
if cond == S.true:
|
|
269
|
+
return expr
|
|
270
|
+
if cond == S.false:
|
|
271
|
+
return Undefined()
|
|
272
|
+
return RestrictedExpr(expr, cond)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def simplify_restricted(obj):
|
|
276
|
+
"""Simplify a RestrictedExpr or ordinary SymPy expression conservatively."""
|
|
277
|
+
obj = sympify(obj)
|
|
278
|
+
if obj == Undefined():
|
|
279
|
+
return obj
|
|
280
|
+
if isinstance(obj, RestrictedExpr):
|
|
281
|
+
return restrict(simplify(obj.expr), simplify(obj.cond))
|
|
282
|
+
return simplify(obj)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def propagate_undefined(expr):
|
|
286
|
+
"""
|
|
287
|
+
Conservative post-processor that collapses Add/Mul/Pow containing
|
|
288
|
+
Undefined() to Undefined().
|
|
289
|
+
"""
|
|
290
|
+
expr = sympify(expr)
|
|
291
|
+
if expr == Undefined():
|
|
292
|
+
return expr
|
|
293
|
+
if not getattr(expr, "args", None):
|
|
294
|
+
return expr
|
|
295
|
+
new_args = tuple(propagate_undefined(arg) for arg in expr.args)
|
|
296
|
+
if any(arg == Undefined() for arg in new_args) and isinstance(expr, (Add, Mul)):
|
|
297
|
+
return Undefined()
|
|
298
|
+
if expr.is_Pow and any(arg == Undefined() for arg in new_args):
|
|
299
|
+
return Undefined()
|
|
300
|
+
return expr.func(*new_args)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def apply_restrictions(func, *args):
|
|
304
|
+
"""Lift a function over possibly restricted arguments."""
|
|
305
|
+
raw_args = []
|
|
306
|
+
conds = []
|
|
307
|
+
for arg in args:
|
|
308
|
+
arg = sympify(arg)
|
|
309
|
+
if arg == Undefined():
|
|
310
|
+
return Undefined()
|
|
311
|
+
if isinstance(arg, RestrictedExpr):
|
|
312
|
+
raw_args.append(arg.expr)
|
|
313
|
+
conds.append(arg.cond)
|
|
314
|
+
else:
|
|
315
|
+
raw_args.append(arg)
|
|
316
|
+
result = func(*raw_args)
|
|
317
|
+
cond = _combine_conditions(*conds) if conds else S.true
|
|
318
|
+
return restrict(result, cond)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
@dataclass(frozen=True)
|
|
322
|
+
class ConditionalJump:
|
|
323
|
+
expr: Expr
|
|
324
|
+
cond: Boolean | BooleanTrue | BooleanFalse
|
|
325
|
+
note: str = ""
|
|
326
|
+
|
|
327
|
+
def to_piecewise(self, off_value=None):
|
|
328
|
+
if off_value is None:
|
|
329
|
+
off_value = Undefined()
|
|
330
|
+
return Piecewise((self.expr, self.cond), (off_value, True))
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@dataclass(frozen=True)
|
|
334
|
+
class JumpTerm:
|
|
335
|
+
expr: Expr
|
|
336
|
+
cond: Boolean | BooleanTrue | BooleanFalse
|
|
337
|
+
note: str = ""
|
|
338
|
+
|
|
339
|
+
def as_restricted(self):
|
|
340
|
+
return restrict(self.expr, self.cond)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@dataclass(frozen=True)
|
|
344
|
+
class BranchRule:
|
|
345
|
+
name: str
|
|
346
|
+
jump_terms: tuple[JumpTerm, ...]
|
|
347
|
+
remarks: str = ""
|
|
348
|
+
|
|
349
|
+
def restricted_terms(self):
|
|
350
|
+
return tuple(term.as_restricted() for term in self.jump_terms)
|
|
351
|
+
|
|
352
|
+
def as_piecewise(self, default=S.Zero):
|
|
353
|
+
return Piecewise(
|
|
354
|
+
*[(term.expr, term.cond) for term in self.jump_terms], (default, True)
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
# ---- cut-locus helpers -------------------------------------------------
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def real_lt(z, a):
|
|
362
|
+
return Contains(z, S.Reals) & (z < a)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def real_le(z, a):
|
|
366
|
+
return Contains(z, S.Reals) & (z <= a)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def real_gt(z, a):
|
|
370
|
+
return Contains(z, S.Reals) & (z > a)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def real_ge(z, a):
|
|
374
|
+
return Contains(z, S.Reals) & (z >= a)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def real_between(z, a, b):
|
|
378
|
+
return Contains(z, S.Reals) & (z > a) & (z < b)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def imag_axis_gt(z, a):
|
|
382
|
+
return Eq(re(z), 0) & (im(z) > a)
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def imag_axis_lt(z, a):
|
|
386
|
+
return Eq(re(z), 0) & (im(z) < a)
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def amplitude_vertical_seam(phi):
|
|
390
|
+
return Eq(im(cos(phi) ** 2), 0) & (re(cos(phi) ** 2) < 0)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def elliptic_sqrt_seam(phi, m):
|
|
394
|
+
return Eq(-im(m * sin(phi) ** 2), 0) & (1 - re(m * sin(phi) ** 2) < 0)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def elliptic_pi_pole_seam(phi, n):
|
|
398
|
+
return Eq(-im(n * sin(phi) ** 2), 0) & (1 - re(n * sin(phi) ** 2) <= 0)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
# ---- branch rules ------------------------------------------------------
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def branch_rule_log(z):
|
|
405
|
+
return BranchRule(
|
|
406
|
+
name="log",
|
|
407
|
+
jump_terms=(
|
|
408
|
+
JumpTerm(
|
|
409
|
+
2 * pi * I,
|
|
410
|
+
real_lt(z, 0),
|
|
411
|
+
"Principal branch cut on the negative real axis.",
|
|
412
|
+
),
|
|
413
|
+
),
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def branch_rule_sqrt(z):
|
|
418
|
+
return BranchRule(
|
|
419
|
+
name="sqrt",
|
|
420
|
+
jump_terms=(
|
|
421
|
+
JumpTerm(
|
|
422
|
+
2 * I * sqrt(-z),
|
|
423
|
+
real_lt(z, 0),
|
|
424
|
+
"Principal square root cut on the negative real axis.",
|
|
425
|
+
),
|
|
426
|
+
),
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def branch_rule_power(z, a):
|
|
431
|
+
return BranchRule(
|
|
432
|
+
name="power",
|
|
433
|
+
jump_terms=(
|
|
434
|
+
JumpTerm(
|
|
435
|
+
2 * I * sin(pi * a) * (-z) ** a,
|
|
436
|
+
real_lt(z, 0) & ~Contains(a, S.Integers),
|
|
437
|
+
"Principal z**a jump for non-integer exponent.",
|
|
438
|
+
),
|
|
439
|
+
),
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def branch_rule_acos(z):
|
|
444
|
+
return BranchRule(
|
|
445
|
+
name="acos",
|
|
446
|
+
jump_terms=(
|
|
447
|
+
JumpTerm(2 * I * acosh(z), real_gt(z, 1), "Right-hand cut."),
|
|
448
|
+
JumpTerm(-2 * I * acosh(-z), real_lt(z, -1), "Left-hand cut."),
|
|
449
|
+
),
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def branch_rule_asin(z):
|
|
454
|
+
return BranchRule(
|
|
455
|
+
name="asin",
|
|
456
|
+
jump_terms=(
|
|
457
|
+
JumpTerm(-2 * I * acosh(z), real_gt(z, 1), "Right-hand cut."),
|
|
458
|
+
JumpTerm(2 * I * acosh(-z), real_lt(z, -1), "Left-hand cut."),
|
|
459
|
+
),
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def branch_rule_atanh(z):
|
|
464
|
+
return BranchRule(
|
|
465
|
+
name="atanh",
|
|
466
|
+
jump_terms=(
|
|
467
|
+
JumpTerm(-pi * I, real_gt(z, 1), "Cut on (1, oo)."),
|
|
468
|
+
JumpTerm(pi * I, real_lt(z, -1), "Cut on (-oo, -1)."),
|
|
469
|
+
),
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def branch_rule_acosh(z):
|
|
474
|
+
return BranchRule(
|
|
475
|
+
name="acosh",
|
|
476
|
+
jump_terms=(
|
|
477
|
+
JumpTerm(
|
|
478
|
+
2 * I * acos(z), real_between(z, -1, 1), "Interior cut on (-1, 1)."
|
|
479
|
+
),
|
|
480
|
+
JumpTerm(2 * pi * I, real_le(z, -1), "Exterior cut on (-oo, -1]."),
|
|
481
|
+
),
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def branch_rule_atan(z):
|
|
486
|
+
return BranchRule(
|
|
487
|
+
name="atan",
|
|
488
|
+
jump_terms=(
|
|
489
|
+
JumpTerm(pi, imag_axis_gt(z, 1), "Upper imaginary-axis cut outside i."),
|
|
490
|
+
JumpTerm(-pi, imag_axis_lt(z, -1), "Lower imaginary-axis cut outside -i."),
|
|
491
|
+
),
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def branch_rule_asinh(z):
|
|
496
|
+
return BranchRule(
|
|
497
|
+
name="asinh",
|
|
498
|
+
jump_terms=(
|
|
499
|
+
JumpTerm(
|
|
500
|
+
2 * acosh(Abs(im(z))),
|
|
501
|
+
Eq(re(z), 0) & (Abs(im(z)) > 1),
|
|
502
|
+
"Principal cut on the imaginary axis outside [-I, I].",
|
|
503
|
+
),
|
|
504
|
+
),
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def branch_rule_acot(z):
|
|
509
|
+
return BranchRule(
|
|
510
|
+
name="acot",
|
|
511
|
+
jump_terms=(
|
|
512
|
+
JumpTerm(-pi, imag_axis_gt(z, 1), "Upper imaginary-axis cut outside i."),
|
|
513
|
+
JumpTerm(pi, imag_axis_lt(z, -1), "Lower imaginary-axis cut outside -i."),
|
|
514
|
+
),
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def branch_rule_acoth(z):
|
|
519
|
+
return BranchRule(
|
|
520
|
+
name="acoth",
|
|
521
|
+
jump_terms=(
|
|
522
|
+
JumpTerm(-pi * I, real_between(z, 0, 1), "Mapped cut from atanh(1/z)."),
|
|
523
|
+
JumpTerm(pi * I, real_between(z, -1, 0), "Mapped cut from atanh(1/z)."),
|
|
524
|
+
),
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def branch_rule_asec(z):
|
|
529
|
+
return BranchRule(
|
|
530
|
+
name="asec",
|
|
531
|
+
jump_terms=(
|
|
532
|
+
JumpTerm(
|
|
533
|
+
2 * I * acosh(1 / z),
|
|
534
|
+
real_between(z, 0, 1),
|
|
535
|
+
"Mapped right-hand cut from acos(1/z).",
|
|
536
|
+
),
|
|
537
|
+
JumpTerm(
|
|
538
|
+
-2 * I * acosh(-1 / z),
|
|
539
|
+
real_between(z, -1, 0),
|
|
540
|
+
"Mapped left-hand cut from acos(1/z).",
|
|
541
|
+
),
|
|
542
|
+
),
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
def branch_rule_acsc(z):
|
|
547
|
+
return BranchRule(
|
|
548
|
+
name="acsc",
|
|
549
|
+
jump_terms=(
|
|
550
|
+
JumpTerm(
|
|
551
|
+
-2 * I * acosh(1 / z),
|
|
552
|
+
real_between(z, 0, 1),
|
|
553
|
+
"Mapped right-hand cut from asin(1/z).",
|
|
554
|
+
),
|
|
555
|
+
JumpTerm(
|
|
556
|
+
2 * I * acosh(-1 / z),
|
|
557
|
+
real_between(z, -1, 0),
|
|
558
|
+
"Mapped left-hand cut from asin(1/z).",
|
|
559
|
+
),
|
|
560
|
+
),
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def branch_rule_asech(z):
|
|
565
|
+
return BranchRule(
|
|
566
|
+
name="asech",
|
|
567
|
+
jump_terms=(
|
|
568
|
+
JumpTerm(2 * I * acos(1 / z), real_gt(z, 1), "Mapped cut from acosh(1/z)."),
|
|
569
|
+
JumpTerm(
|
|
570
|
+
2 * pi * I,
|
|
571
|
+
real_ge(z, -1) & real_lt(z, 0),
|
|
572
|
+
"Mapped logarithmic cut from acosh(1/z).",
|
|
573
|
+
),
|
|
574
|
+
),
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
def branch_rule_acsch(z):
|
|
579
|
+
return BranchRule(
|
|
580
|
+
name="acsch",
|
|
581
|
+
jump_terms=(
|
|
582
|
+
JumpTerm(
|
|
583
|
+
2 * acosh(Abs(im(z)) / Abs(z)),
|
|
584
|
+
Eq(re(z), 0) & (Abs(im(z)) < 1) & (Abs(im(z)) > 0),
|
|
585
|
+
"Mapped imaginary-axis cut from acsch(z)=asinh(1/z).",
|
|
586
|
+
),
|
|
587
|
+
),
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def branch_rule_expint_ei(z):
|
|
592
|
+
return BranchRule(
|
|
593
|
+
name="Ei",
|
|
594
|
+
jump_terms=(
|
|
595
|
+
JumpTerm(
|
|
596
|
+
2 * pi * I, real_lt(z, 0), "Principal cut on the negative real axis."
|
|
597
|
+
),
|
|
598
|
+
),
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def branch_rule_ci(z):
|
|
603
|
+
return BranchRule(
|
|
604
|
+
name="Ci",
|
|
605
|
+
jump_terms=(
|
|
606
|
+
JumpTerm(
|
|
607
|
+
2 * pi * I, real_lt(z, 0), "Principal cut on the negative real axis."
|
|
608
|
+
),
|
|
609
|
+
),
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
def branch_rule_chi(z):
|
|
614
|
+
return BranchRule(
|
|
615
|
+
name="Chi",
|
|
616
|
+
jump_terms=(
|
|
617
|
+
JumpTerm(
|
|
618
|
+
2 * pi * I, real_lt(z, 0), "Principal cut on the negative real axis."
|
|
619
|
+
),
|
|
620
|
+
),
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def branch_rule_li(z):
|
|
625
|
+
return BranchRule(
|
|
626
|
+
name="li",
|
|
627
|
+
jump_terms=(
|
|
628
|
+
JumpTerm(
|
|
629
|
+
2 * pi * I,
|
|
630
|
+
real_between(z, 0, 1),
|
|
631
|
+
"Inherited from Ei(log(z)) across 0<z<1.",
|
|
632
|
+
),
|
|
633
|
+
),
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
def branch_rule_expint(z, nu):
|
|
638
|
+
return BranchRule(
|
|
639
|
+
name="expint",
|
|
640
|
+
jump_terms=(
|
|
641
|
+
JumpTerm(
|
|
642
|
+
-2 * pi * I * (-z) ** (nu - 1) / gamma(nu),
|
|
643
|
+
real_lt(z, 0),
|
|
644
|
+
"Principal cut on the negative real axis for expint(nu, z).",
|
|
645
|
+
),
|
|
646
|
+
),
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
def branch_rule_loggamma(z):
|
|
651
|
+
return BranchRule(
|
|
652
|
+
name="loggamma",
|
|
653
|
+
jump_terms=(
|
|
654
|
+
JumpTerm(
|
|
655
|
+
2 * pi * I * floor(-z),
|
|
656
|
+
real_lt(z, 0) & ~Contains(z, S.Integers),
|
|
657
|
+
"Jump away from poles on the negative real axis.",
|
|
658
|
+
),
|
|
659
|
+
),
|
|
660
|
+
)
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
def branch_rule_polylog(z, s):
|
|
664
|
+
return BranchRule(
|
|
665
|
+
name="polylog",
|
|
666
|
+
jump_terms=(
|
|
667
|
+
JumpTerm(
|
|
668
|
+
2 * pi * I * log(z) ** (s - 1) / gamma(s),
|
|
669
|
+
real_gt(z, 1) & ~Contains(s, S.Integers),
|
|
670
|
+
"Generic principal cut for non-integer order.",
|
|
671
|
+
),
|
|
672
|
+
JumpTerm(
|
|
673
|
+
2 * pi * I * log(z) ** (s - 1) / factorial(s - 1),
|
|
674
|
+
real_gt(z, 1) & Contains(s, S.PositiveIntegers),
|
|
675
|
+
"Principal cut for positive integer order.",
|
|
676
|
+
),
|
|
677
|
+
),
|
|
678
|
+
)
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
def branch_rule_lerchphi(z, s, a):
|
|
682
|
+
return BranchRule(
|
|
683
|
+
name="lerchphi",
|
|
684
|
+
jump_terms=(
|
|
685
|
+
JumpTerm(
|
|
686
|
+
2 * pi * I * z ** (-a) * log(z) ** (s - 1) / gamma(s),
|
|
687
|
+
real_gt(z, 1),
|
|
688
|
+
"Principal cut at z>1.",
|
|
689
|
+
),
|
|
690
|
+
),
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
def branch_rule_lambertw(z):
|
|
695
|
+
return BranchRule(
|
|
696
|
+
name="LambertW",
|
|
697
|
+
jump_terms=(
|
|
698
|
+
JumpTerm(
|
|
699
|
+
LambertW(z) - LambertW(z, -1),
|
|
700
|
+
real_between(z, -1 / E, 0),
|
|
701
|
+
"Principal-sheet jump across the standard cut on (-1/e, 0).",
|
|
702
|
+
),
|
|
703
|
+
),
|
|
704
|
+
)
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
def branch_rule_hyperu(z, a, b):
|
|
708
|
+
return BranchRule(
|
|
709
|
+
name="hyperu",
|
|
710
|
+
jump_terms=(
|
|
711
|
+
JumpTerm(
|
|
712
|
+
-2 * pi * I * z ** (1 - b) * hyper([1 + a - b], [2 - b], z),
|
|
713
|
+
real_lt(z, 0),
|
|
714
|
+
"Confluent hypergeometric U cut on (-oo, 0].",
|
|
715
|
+
),
|
|
716
|
+
),
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
def branch_rule_besselj(z, nu):
|
|
721
|
+
return BranchRule(
|
|
722
|
+
name="besselj",
|
|
723
|
+
jump_terms=(
|
|
724
|
+
JumpTerm(
|
|
725
|
+
2 * I * sin(pi * nu) * besselj(nu, -z),
|
|
726
|
+
real_lt(z, 0) & ~Contains(nu, S.Integers),
|
|
727
|
+
"Noninteger-order principal cut on the negative real axis.",
|
|
728
|
+
),
|
|
729
|
+
),
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
def branch_rule_besseli(z, nu):
|
|
734
|
+
return BranchRule(
|
|
735
|
+
name="besseli",
|
|
736
|
+
jump_terms=(
|
|
737
|
+
JumpTerm(
|
|
738
|
+
2 * I * sin(pi * nu) * besseli(nu, -z),
|
|
739
|
+
real_lt(z, 0) & ~Contains(nu, S.Integers),
|
|
740
|
+
"Noninteger-order principal cut on the negative real axis.",
|
|
741
|
+
),
|
|
742
|
+
),
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
def branch_rule_bessely(z, nu):
|
|
747
|
+
return BranchRule(
|
|
748
|
+
name="bessely",
|
|
749
|
+
jump_terms=(
|
|
750
|
+
JumpTerm(
|
|
751
|
+
-2 * sin(pi * nu) * besselj(nu, -z),
|
|
752
|
+
real_lt(z, 0) & ~Contains(nu, S.Integers),
|
|
753
|
+
"Noninteger-order principal cut on the negative real axis.",
|
|
754
|
+
),
|
|
755
|
+
),
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
def branch_rule_besselk(z, nu):
|
|
760
|
+
return BranchRule(
|
|
761
|
+
name="besselk",
|
|
762
|
+
jump_terms=(
|
|
763
|
+
JumpTerm(
|
|
764
|
+
-I * (2 * sin(pi * nu) * besselk(nu, -z) + pi * besseli(nu, -z)),
|
|
765
|
+
real_lt(z, 0),
|
|
766
|
+
"Principal cut on the negative real axis.",
|
|
767
|
+
),
|
|
768
|
+
),
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
def branch_rule_hankel1(z, nu):
|
|
773
|
+
return BranchRule(
|
|
774
|
+
name="hankel1",
|
|
775
|
+
jump_terms=(
|
|
776
|
+
JumpTerm(
|
|
777
|
+
2 * I * sin(pi * nu) * hankel2(nu, -z),
|
|
778
|
+
real_lt(z, 0),
|
|
779
|
+
"Principal cut on the negative real axis.",
|
|
780
|
+
),
|
|
781
|
+
),
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
def branch_rule_hankel2(z, nu):
|
|
786
|
+
return BranchRule(
|
|
787
|
+
name="hankel2",
|
|
788
|
+
jump_terms=(
|
|
789
|
+
JumpTerm(
|
|
790
|
+
-2 * I * sin(pi * nu) * hankel1(nu, -z),
|
|
791
|
+
real_lt(z, 0),
|
|
792
|
+
"Principal cut on the negative real axis.",
|
|
793
|
+
),
|
|
794
|
+
),
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
def branch_rule_hyper(var, a_params, b_params):
|
|
799
|
+
return BranchRule(
|
|
800
|
+
name="hyper",
|
|
801
|
+
jump_terms=(
|
|
802
|
+
JumpTerm(
|
|
803
|
+
2
|
|
804
|
+
* pi
|
|
805
|
+
* I
|
|
806
|
+
* (
|
|
807
|
+
Mul(*[gamma(b) for b in b_params])
|
|
808
|
+
/ Mul(*[gamma(a) for a in a_params])
|
|
809
|
+
)
|
|
810
|
+
* meijerg(
|
|
811
|
+
((), tuple(1 - a for a in a_params)),
|
|
812
|
+
((0,), tuple(1 - b for b in b_params)),
|
|
813
|
+
var,
|
|
814
|
+
),
|
|
815
|
+
real_gt(var, 1),
|
|
816
|
+
"Generic pFq jump for p=q+1 on the principal cut z>1, represented via Meijer G.",
|
|
817
|
+
),
|
|
818
|
+
),
|
|
819
|
+
)
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def branch_rule_betainc(z, a, b):
|
|
823
|
+
return branch_rule_betainc_endpoint(z, a, b, sign=1, regularized=False)
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
def branch_rule_betainc_regularized(z, a, b):
|
|
827
|
+
return branch_rule_betainc_endpoint(z, a, b, sign=1, regularized=True)
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
def branch_rule_elliptic_k(m):
|
|
831
|
+
return BranchRule(
|
|
832
|
+
name="elliptic_k",
|
|
833
|
+
jump_terms=(
|
|
834
|
+
JumpTerm(
|
|
835
|
+
(-2 * I) / sqrt(m) * elliptic_k(1 - 1 / m),
|
|
836
|
+
real_gt(m, 1),
|
|
837
|
+
"Principal cut on (1, oo).",
|
|
838
|
+
),
|
|
839
|
+
),
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
def branch_rule_elliptic_e_m(m):
|
|
844
|
+
return BranchRule(
|
|
845
|
+
name="elliptic_e",
|
|
846
|
+
jump_terms=(
|
|
847
|
+
JumpTerm(
|
|
848
|
+
2 * I * sqrt(m) * (elliptic_e(1 - 1 / m) - elliptic_k(1 - 1 / m)),
|
|
849
|
+
real_gt(m, 1),
|
|
850
|
+
"Parameter cut on (1, oo).",
|
|
851
|
+
),
|
|
852
|
+
),
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
def branch_rule_elliptic_pi_m(m, n):
|
|
857
|
+
return BranchRule(
|
|
858
|
+
name="elliptic_pi",
|
|
859
|
+
jump_terms=(
|
|
860
|
+
JumpTerm(
|
|
861
|
+
2 * I * sqrt(m) * elliptic_pi(n / (n - 1), 1 - 1 / m),
|
|
862
|
+
real_gt(m, 1) & ~Eq(n, 1),
|
|
863
|
+
"Parameter cut in m on (1, oo), away from n=1.",
|
|
864
|
+
),
|
|
865
|
+
),
|
|
866
|
+
)
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
def branch_rule_elliptic_pi_n(n, m):
|
|
870
|
+
return BranchRule(
|
|
871
|
+
name="elliptic_pi",
|
|
872
|
+
jump_terms=(
|
|
873
|
+
JumpTerm(
|
|
874
|
+
-pi * I * sqrt(n) / sqrt((n - 1) * (n - m)),
|
|
875
|
+
real_gt(n, 1) & ~Eq(m, n),
|
|
876
|
+
"Parameter cut in n on (1, oo), away from coincident pole m=n.",
|
|
877
|
+
),
|
|
878
|
+
),
|
|
879
|
+
)
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
def branch_rule_assoc_legendre(z, nu, mu):
|
|
883
|
+
return BranchRule(
|
|
884
|
+
name="assoc_legendre",
|
|
885
|
+
jump_terms=(
|
|
886
|
+
JumpTerm(
|
|
887
|
+
2 * I * sin(pi * mu) * assoc_legendre(nu, mu, z),
|
|
888
|
+
real_between(z, -1, 1) & ~Contains(mu, S.Integers),
|
|
889
|
+
"Principal cut on (-1, 1) for noninteger order.",
|
|
890
|
+
),
|
|
891
|
+
),
|
|
892
|
+
)
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
def branch_rule_hyper_2f1(z, a, b, c):
|
|
896
|
+
genericity = (
|
|
897
|
+
(re(c) > 0) & (re(c - a) > 0) & (re(c - b) > 0) & (re(a) > 0) & (re(b) > 0)
|
|
898
|
+
)
|
|
899
|
+
return BranchRule(
|
|
900
|
+
name="hyp2f1",
|
|
901
|
+
jump_terms=(
|
|
902
|
+
JumpTerm(
|
|
903
|
+
2
|
|
904
|
+
* pi
|
|
905
|
+
* I
|
|
906
|
+
* (gamma(c) / (gamma(a) * gamma(b) * gamma(c - a) * gamma(c - b)))
|
|
907
|
+
* (S.Exp1 ** (I * pi * (c - a - b)))
|
|
908
|
+
* (z - 1) ** (c - a - b)
|
|
909
|
+
* hyper([c - a, c - b], [c - a - b + 1], 1 - z),
|
|
910
|
+
real_gt(z, 1) & genericity,
|
|
911
|
+
"Gauss hypergeometric principal cut on (1, oo) under generic parameter conditions.",
|
|
912
|
+
),
|
|
913
|
+
),
|
|
914
|
+
)
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
def branch_rule_elliptic_f_phi(phi, m):
|
|
918
|
+
return BranchRule(
|
|
919
|
+
name="elliptic_f",
|
|
920
|
+
jump_terms=(
|
|
921
|
+
JumpTerm(
|
|
922
|
+
2 * elliptic_k(m),
|
|
923
|
+
amplitude_vertical_seam(phi),
|
|
924
|
+
"Amplitude seam where cos(phi)^2 crosses the negative real axis.",
|
|
925
|
+
),
|
|
926
|
+
),
|
|
927
|
+
)
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
def branch_rule_elliptic_e_phi(phi, m):
|
|
931
|
+
return BranchRule(
|
|
932
|
+
name="elliptic_e",
|
|
933
|
+
jump_terms=(
|
|
934
|
+
JumpTerm(
|
|
935
|
+
2 * elliptic_e(m),
|
|
936
|
+
amplitude_vertical_seam(phi),
|
|
937
|
+
"Amplitude seam where cos(phi)^2 crosses the negative real axis.",
|
|
938
|
+
),
|
|
939
|
+
),
|
|
940
|
+
)
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
def branch_rule_elliptic_pi_phi(phi, n, m):
|
|
944
|
+
seam_a = (
|
|
945
|
+
amplitude_vertical_seam(phi)
|
|
946
|
+
& ~elliptic_pi_pole_seam(phi, n)
|
|
947
|
+
& ~elliptic_sqrt_seam(phi, m)
|
|
948
|
+
)
|
|
949
|
+
seam_b = elliptic_sqrt_seam(phi, m) & ~elliptic_pi_pole_seam(phi, n)
|
|
950
|
+
seam_c = elliptic_pi_pole_seam(phi, n) & ~Eq(m, n)
|
|
951
|
+
return BranchRule(
|
|
952
|
+
name="elliptic_pi",
|
|
953
|
+
jump_terms=(
|
|
954
|
+
JumpTerm(2 * elliptic_pi(n, m), seam_a, "Amplitude seam from cos(phi)^2."),
|
|
955
|
+
JumpTerm(
|
|
956
|
+
2 * elliptic_pi(n, m), seam_b, "Square-root seam from 1 - m*sin(phi)^2."
|
|
957
|
+
),
|
|
958
|
+
JumpTerm(
|
|
959
|
+
-pi * I * sqrt(n) / sqrt((n - 1) * (n - m)),
|
|
960
|
+
seam_c,
|
|
961
|
+
"Pole seam from 1 - n*sin(phi)^2 = 0.",
|
|
962
|
+
),
|
|
963
|
+
),
|
|
964
|
+
)
|
|
965
|
+
|
|
966
|
+
|
|
967
|
+
def _betainc_jump_terms(var, a, b):
|
|
968
|
+
return (
|
|
969
|
+
JumpTerm(
|
|
970
|
+
2 * I * sin(pi * a) * (-var) ** a / a * hyper([a, 1 - b], [a + 1], var),
|
|
971
|
+
real_lt(var, 0) & ~Contains(a, S.Integers),
|
|
972
|
+
"Incomplete beta cut on (-oo, 0) for noninteger a.",
|
|
973
|
+
),
|
|
974
|
+
JumpTerm(
|
|
975
|
+
2
|
|
976
|
+
* pi
|
|
977
|
+
* I
|
|
978
|
+
* var**a
|
|
979
|
+
* (S.Exp1 ** (I * pi * b))
|
|
980
|
+
/ (gamma(1 - b) * gamma(a + b))
|
|
981
|
+
* (var - 1) ** b
|
|
982
|
+
* hyper([1, a + b], [b + 1], 1 - var),
|
|
983
|
+
real_gt(var, 1),
|
|
984
|
+
"Incomplete beta continuation across (1, oo).",
|
|
985
|
+
),
|
|
986
|
+
)
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
def branch_rule_betainc_endpoint(var, a, b, sign=1, regularized=False):
|
|
990
|
+
terms = []
|
|
991
|
+
factor = 1 / beta(a, b) if regularized else 1
|
|
992
|
+
for term in _betainc_jump_terms(var, a, b):
|
|
993
|
+
note = term.note
|
|
994
|
+
if sign == -1:
|
|
995
|
+
note = "Lower-endpoint contribution with opposite sign. " + note
|
|
996
|
+
if regularized:
|
|
997
|
+
note += " Regularized by division through beta(a,b)."
|
|
998
|
+
terms.append(JumpTerm(sign * factor * term.expr, term.cond, note))
|
|
999
|
+
return BranchRule(
|
|
1000
|
+
name="betainc_regularized" if regularized else "betainc",
|
|
1001
|
+
jump_terms=tuple(terms),
|
|
1002
|
+
)
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
def get_branch_rule(expr, z: Symbol):
|
|
1006
|
+
"""Return a BranchRule for a supported expression in the variable z."""
|
|
1007
|
+
expr = sympify(expr)
|
|
1008
|
+
|
|
1009
|
+
if expr.func == log and len(expr.args) == 1 and expr.args[0] == z:
|
|
1010
|
+
return branch_rule_log(z)
|
|
1011
|
+
|
|
1012
|
+
if expr.func == acos and len(expr.args) == 1 and expr.args[0] == z:
|
|
1013
|
+
return branch_rule_acos(z)
|
|
1014
|
+
|
|
1015
|
+
if expr.func == asin and len(expr.args) == 1 and expr.args[0] == z:
|
|
1016
|
+
return branch_rule_asin(z)
|
|
1017
|
+
|
|
1018
|
+
if expr.func == atanh and len(expr.args) == 1 and expr.args[0] == z:
|
|
1019
|
+
return branch_rule_atanh(z)
|
|
1020
|
+
|
|
1021
|
+
if expr.func == acosh and len(expr.args) == 1 and expr.args[0] == z:
|
|
1022
|
+
return branch_rule_acosh(z)
|
|
1023
|
+
|
|
1024
|
+
if expr.func == atan and len(expr.args) == 1 and expr.args[0] == z:
|
|
1025
|
+
return branch_rule_atan(z)
|
|
1026
|
+
|
|
1027
|
+
if expr.func == asinh and len(expr.args) == 1 and expr.args[0] == z:
|
|
1028
|
+
return branch_rule_asinh(z)
|
|
1029
|
+
|
|
1030
|
+
if expr.func == acot and len(expr.args) == 1 and expr.args[0] == z:
|
|
1031
|
+
return branch_rule_acot(z)
|
|
1032
|
+
|
|
1033
|
+
if expr.func == acoth and len(expr.args) == 1 and expr.args[0] == z:
|
|
1034
|
+
return branch_rule_acoth(z)
|
|
1035
|
+
|
|
1036
|
+
if expr.func == asec and len(expr.args) == 1 and expr.args[0] == z:
|
|
1037
|
+
return branch_rule_asec(z)
|
|
1038
|
+
|
|
1039
|
+
if expr.func == acsc and len(expr.args) == 1 and expr.args[0] == z:
|
|
1040
|
+
return branch_rule_acsc(z)
|
|
1041
|
+
|
|
1042
|
+
if expr.func == asech and len(expr.args) == 1 and expr.args[0] == z:
|
|
1043
|
+
return branch_rule_asech(z)
|
|
1044
|
+
|
|
1045
|
+
if expr.func == acsch and len(expr.args) == 1 and expr.args[0] == z:
|
|
1046
|
+
return branch_rule_acsch(z)
|
|
1047
|
+
|
|
1048
|
+
if expr.is_Pow and expr.base == z:
|
|
1049
|
+
a = expr.exp
|
|
1050
|
+
if a == S.Half:
|
|
1051
|
+
return branch_rule_sqrt(z)
|
|
1052
|
+
return branch_rule_power(z, a)
|
|
1053
|
+
|
|
1054
|
+
name = expr.func.__name__.lower()
|
|
1055
|
+
if name == "ei" and len(expr.args) == 1 and expr.args[0] == z:
|
|
1056
|
+
return branch_rule_expint_ei(z)
|
|
1057
|
+
if expr.func == Ci and len(expr.args) == 1 and expr.args[0] == z:
|
|
1058
|
+
return branch_rule_ci(z)
|
|
1059
|
+
if expr.func == Chi and len(expr.args) == 1 and expr.args[0] == z:
|
|
1060
|
+
return branch_rule_chi(z)
|
|
1061
|
+
if expr.func == li and len(expr.args) == 1 and expr.args[0] == z:
|
|
1062
|
+
return branch_rule_li(z)
|
|
1063
|
+
if expr.func == expint and len(expr.args) == 2 and expr.args[1] == z:
|
|
1064
|
+
return branch_rule_expint(z, expr.args[0])
|
|
1065
|
+
if expr.func == loggamma and len(expr.args) == 1 and expr.args[0] == z:
|
|
1066
|
+
return branch_rule_loggamma(z)
|
|
1067
|
+
if expr.func == polylog and len(expr.args) == 2 and expr.args[1] == z:
|
|
1068
|
+
return branch_rule_polylog(z, expr.args[0])
|
|
1069
|
+
if expr.func == lerchphi and len(expr.args) == 3 and expr.args[0] == z:
|
|
1070
|
+
return branch_rule_lerchphi(z, expr.args[1], expr.args[2])
|
|
1071
|
+
if (
|
|
1072
|
+
expr.func == LambertW
|
|
1073
|
+
and len(expr.args) in {1, 2}
|
|
1074
|
+
and expr.args[0] == z
|
|
1075
|
+
and (len(expr.args) == 1 or expr.args[1] == 0)
|
|
1076
|
+
):
|
|
1077
|
+
return branch_rule_lambertw(z)
|
|
1078
|
+
if name == "hyperu" and len(expr.args) == 3 and expr.args[2] == z:
|
|
1079
|
+
return branch_rule_hyperu(z, expr.args[0], expr.args[1])
|
|
1080
|
+
if expr.func == besselj and len(expr.args) == 2 and expr.args[1] == z:
|
|
1081
|
+
return branch_rule_besselj(z, expr.args[0])
|
|
1082
|
+
if expr.func == besseli and len(expr.args) == 2 and expr.args[1] == z:
|
|
1083
|
+
return branch_rule_besseli(z, expr.args[0])
|
|
1084
|
+
if expr.func == bessely and len(expr.args) == 2 and expr.args[1] == z:
|
|
1085
|
+
return branch_rule_bessely(z, expr.args[0])
|
|
1086
|
+
if expr.func == besselk and len(expr.args) == 2 and expr.args[1] == z:
|
|
1087
|
+
return branch_rule_besselk(z, expr.args[0])
|
|
1088
|
+
if expr.func == hankel1 and len(expr.args) == 2 and expr.args[1] == z:
|
|
1089
|
+
return branch_rule_hankel1(z, expr.args[0])
|
|
1090
|
+
if expr.func == hankel2 and len(expr.args) == 2 and expr.args[1] == z:
|
|
1091
|
+
return branch_rule_hankel2(z, expr.args[0])
|
|
1092
|
+
if expr.func == betainc and len(expr.args) == 4 and expr.args[3] == z:
|
|
1093
|
+
return branch_rule_betainc_endpoint(
|
|
1094
|
+
z, expr.args[0], expr.args[1], sign=1, regularized=False
|
|
1095
|
+
)
|
|
1096
|
+
if expr.func == betainc and len(expr.args) == 4 and expr.args[2] == z:
|
|
1097
|
+
return branch_rule_betainc_endpoint(
|
|
1098
|
+
z, expr.args[0], expr.args[1], sign=-1, regularized=False
|
|
1099
|
+
)
|
|
1100
|
+
if expr.func == betainc_regularized and len(expr.args) == 4 and expr.args[3] == z:
|
|
1101
|
+
return branch_rule_betainc_endpoint(
|
|
1102
|
+
z, expr.args[0], expr.args[1], sign=1, regularized=True
|
|
1103
|
+
)
|
|
1104
|
+
if expr.func == betainc_regularized and len(expr.args) == 4 and expr.args[2] == z:
|
|
1105
|
+
return branch_rule_betainc_endpoint(
|
|
1106
|
+
z, expr.args[0], expr.args[1], sign=-1, regularized=True
|
|
1107
|
+
)
|
|
1108
|
+
if expr.func == elliptic_k and len(expr.args) == 1 and expr.args[0] == z:
|
|
1109
|
+
return branch_rule_elliptic_k(z)
|
|
1110
|
+
if expr.func == elliptic_e and len(expr.args) == 1 and expr.args[0] == z:
|
|
1111
|
+
return branch_rule_elliptic_e_m(z)
|
|
1112
|
+
if expr.func == elliptic_f and len(expr.args) == 2 and expr.args[0] == z:
|
|
1113
|
+
return branch_rule_elliptic_f_phi(z, expr.args[1])
|
|
1114
|
+
if expr.func == elliptic_e and len(expr.args) == 2 and expr.args[0] == z:
|
|
1115
|
+
return branch_rule_elliptic_e_phi(z, expr.args[1])
|
|
1116
|
+
if expr.func == elliptic_pi and len(expr.args) == 2 and expr.args[1] == z:
|
|
1117
|
+
return branch_rule_elliptic_pi_m(z, expr.args[0])
|
|
1118
|
+
if expr.func == elliptic_pi and len(expr.args) == 2 and expr.args[0] == z:
|
|
1119
|
+
return branch_rule_elliptic_pi_n(z, expr.args[1])
|
|
1120
|
+
if expr.func == elliptic_pi and len(expr.args) == 3 and expr.args[1] == z:
|
|
1121
|
+
return branch_rule_elliptic_pi_phi(z, expr.args[0], expr.args[2])
|
|
1122
|
+
if expr.func == assoc_legendre and len(expr.args) == 3 and expr.args[2] == z:
|
|
1123
|
+
return branch_rule_assoc_legendre(z, expr.args[0], expr.args[1])
|
|
1124
|
+
if (
|
|
1125
|
+
expr.func == hyper
|
|
1126
|
+
and len(expr.args) == 3
|
|
1127
|
+
and expr.args[2] == z
|
|
1128
|
+
and len(expr.args[0]) == 2
|
|
1129
|
+
and len(expr.args[1]) == 1
|
|
1130
|
+
):
|
|
1131
|
+
return branch_rule_hyper_2f1(
|
|
1132
|
+
z, expr.args[0][0], expr.args[0][1], expr.args[1][0]
|
|
1133
|
+
)
|
|
1134
|
+
if (
|
|
1135
|
+
expr.func == hyper
|
|
1136
|
+
and len(expr.args) == 3
|
|
1137
|
+
and expr.args[2] == z
|
|
1138
|
+
and len(expr.args[0]) == len(expr.args[1]) + 1
|
|
1139
|
+
):
|
|
1140
|
+
return branch_rule_hyper(z, tuple(expr.args[0]), tuple(expr.args[1]))
|
|
1141
|
+
|
|
1142
|
+
raise NotImplementedError(f"No branch rule registered for expression: {expr!r}")
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
def branch_jump(expr, z: Symbol, mode: str = "piecewise"):
|
|
1146
|
+
"""
|
|
1147
|
+
Compute the branch-cut jump representation for a supported expression.
|
|
1148
|
+
|
|
1149
|
+
mode='piecewise' -> Piecewise(..., (0, True))
|
|
1150
|
+
mode='restricted' -> tuple of RestrictedExpr terms
|
|
1151
|
+
mode='terms' -> tuple of JumpTerm objects
|
|
1152
|
+
"""
|
|
1153
|
+
rule = get_branch_rule(expr, z)
|
|
1154
|
+
if mode == "piecewise":
|
|
1155
|
+
return rule.as_piecewise(default=S.Zero)
|
|
1156
|
+
if mode == "restricted":
|
|
1157
|
+
return rule.restricted_terms()
|
|
1158
|
+
if mode == "terms":
|
|
1159
|
+
return rule.jump_terms
|
|
1160
|
+
raise ValueError("mode must be one of: 'piecewise', 'restricted', 'terms'")
|
|
1161
|
+
|
|
1162
|
+
|
|
1163
|
+
IMPLEMENTED_RULE_NAMES = {
|
|
1164
|
+
"log",
|
|
1165
|
+
"sqrt",
|
|
1166
|
+
"power",
|
|
1167
|
+
"acos",
|
|
1168
|
+
"asin",
|
|
1169
|
+
"atanh",
|
|
1170
|
+
"acosh",
|
|
1171
|
+
"atan",
|
|
1172
|
+
"asinh",
|
|
1173
|
+
"acot",
|
|
1174
|
+
"acoth",
|
|
1175
|
+
"asec",
|
|
1176
|
+
"acsc",
|
|
1177
|
+
"asech",
|
|
1178
|
+
"acsch",
|
|
1179
|
+
"ei",
|
|
1180
|
+
"ci",
|
|
1181
|
+
"chi",
|
|
1182
|
+
"li",
|
|
1183
|
+
"expint",
|
|
1184
|
+
"loggamma",
|
|
1185
|
+
"polylog",
|
|
1186
|
+
"lerchphi",
|
|
1187
|
+
"lambertw",
|
|
1188
|
+
"hyperu",
|
|
1189
|
+
"betainc",
|
|
1190
|
+
"betainc_regularized",
|
|
1191
|
+
"elliptic_k",
|
|
1192
|
+
"elliptic_e",
|
|
1193
|
+
"elliptic_f",
|
|
1194
|
+
"elliptic_pi",
|
|
1195
|
+
"assoc_legendre",
|
|
1196
|
+
"hyp2f1",
|
|
1197
|
+
"besselj",
|
|
1198
|
+
"besseli",
|
|
1199
|
+
"bessely",
|
|
1200
|
+
"besselk",
|
|
1201
|
+
"hankel1",
|
|
1202
|
+
"hankel2",
|
|
1203
|
+
"hyper",
|
|
1204
|
+
}
|