switching to high quality piper tts and added label translations
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
"""A functions module, includes all the standard functions.
|
||||
|
||||
Combinatorial - factorial, fibonacci, harmonic, bernoulli...
|
||||
Elementary - hyperbolic, trigonometric, exponential, floor and ceiling, sqrt...
|
||||
Special - gamma, zeta,spherical harmonics...
|
||||
"""
|
||||
|
||||
from sympy.functions.combinatorial.factorials import (factorial, factorial2,
|
||||
rf, ff, binomial, RisingFactorial, FallingFactorial, subfactorial)
|
||||
from sympy.functions.combinatorial.numbers import (carmichael, fibonacci, lucas, tribonacci,
|
||||
harmonic, bernoulli, bell, euler, catalan, genocchi, andre, partition, divisor_sigma,
|
||||
udivisor_sigma, legendre_symbol, jacobi_symbol, kronecker_symbol, mobius,
|
||||
primenu, primeomega, totient, reduced_totient, primepi, motzkin)
|
||||
from sympy.functions.elementary.miscellaneous import (sqrt, root, Min, Max,
|
||||
Id, real_root, cbrt, Rem)
|
||||
from sympy.functions.elementary.complexes import (re, im, sign, Abs,
|
||||
conjugate, arg, polar_lift, periodic_argument, unbranched_argument,
|
||||
principal_branch, transpose, adjoint, polarify, unpolarify)
|
||||
from sympy.functions.elementary.trigonometric import (sin, cos, tan,
|
||||
sec, csc, cot, sinc, asin, acos, atan, asec, acsc, acot, atan2)
|
||||
from sympy.functions.elementary.exponential import (exp_polar, exp, log,
|
||||
LambertW)
|
||||
from sympy.functions.elementary.hyperbolic import (sinh, cosh, tanh, coth,
|
||||
sech, csch, asinh, acosh, atanh, acoth, asech, acsch)
|
||||
from sympy.functions.elementary.integers import floor, ceiling, frac
|
||||
from sympy.functions.elementary.piecewise import (Piecewise, piecewise_fold,
|
||||
piecewise_exclusive)
|
||||
from sympy.functions.special.error_functions import (erf, erfc, erfi, erf2,
|
||||
erfinv, erfcinv, erf2inv, Ei, expint, E1, li, Li, Si, Ci, Shi, Chi,
|
||||
fresnels, fresnelc)
|
||||
from sympy.functions.special.gamma_functions import (gamma, lowergamma,
|
||||
uppergamma, polygamma, loggamma, digamma, trigamma, multigamma)
|
||||
from sympy.functions.special.zeta_functions import (dirichlet_eta, zeta,
|
||||
lerchphi, polylog, stieltjes, riemann_xi)
|
||||
from sympy.functions.special.tensor_functions import (Eijk, LeviCivita,
|
||||
KroneckerDelta)
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
from sympy.functions.special.delta_functions import DiracDelta, Heaviside
|
||||
from sympy.functions.special.bsplines import bspline_basis, bspline_basis_set, interpolating_spline
|
||||
from sympy.functions.special.bessel import (besselj, bessely, besseli, besselk,
|
||||
hankel1, hankel2, jn, yn, jn_zeros, hn1, hn2, airyai, airybi, airyaiprime, airybiprime, marcumq)
|
||||
from sympy.functions.special.hyper import hyper, meijerg, appellf1
|
||||
from sympy.functions.special.polynomials import (legendre, assoc_legendre,
|
||||
hermite, hermite_prob, chebyshevt, chebyshevu, chebyshevu_root,
|
||||
chebyshevt_root, laguerre, assoc_laguerre, gegenbauer, jacobi, jacobi_normalized)
|
||||
from sympy.functions.special.spherical_harmonics import Ynm, Ynm_c, Znm
|
||||
from sympy.functions.special.elliptic_integrals import (elliptic_k,
|
||||
elliptic_f, elliptic_e, elliptic_pi)
|
||||
from sympy.functions.special.beta_functions import beta, betainc, betainc_regularized
|
||||
from sympy.functions.special.mathieu_functions import (mathieus, mathieuc,
|
||||
mathieusprime, mathieucprime)
|
||||
ln = log
|
||||
|
||||
__all__ = [
|
||||
'factorial', 'factorial2', 'rf', 'ff', 'binomial', 'RisingFactorial',
|
||||
'FallingFactorial', 'subfactorial',
|
||||
|
||||
'carmichael', 'fibonacci', 'lucas', 'motzkin', 'tribonacci', 'harmonic',
|
||||
'bernoulli', 'bell', 'euler', 'catalan', 'genocchi', 'andre', 'partition',
|
||||
'divisor_sigma', 'udivisor_sigma', 'legendre_symbol', 'jacobi_symbol', 'kronecker_symbol',
|
||||
'mobius', 'primenu', 'primeomega', 'totient', 'reduced_totient', 'primepi',
|
||||
|
||||
'sqrt', 'root', 'Min', 'Max', 'Id', 'real_root', 'cbrt', 'Rem',
|
||||
|
||||
're', 'im', 'sign', 'Abs', 'conjugate', 'arg', 'polar_lift',
|
||||
'periodic_argument', 'unbranched_argument', 'principal_branch',
|
||||
'transpose', 'adjoint', 'polarify', 'unpolarify',
|
||||
|
||||
'sin', 'cos', 'tan', 'sec', 'csc', 'cot', 'sinc', 'asin', 'acos', 'atan',
|
||||
'asec', 'acsc', 'acot', 'atan2',
|
||||
|
||||
'exp_polar', 'exp', 'ln', 'log', 'LambertW',
|
||||
|
||||
'sinh', 'cosh', 'tanh', 'coth', 'sech', 'csch', 'asinh', 'acosh', 'atanh',
|
||||
'acoth', 'asech', 'acsch',
|
||||
|
||||
'floor', 'ceiling', 'frac',
|
||||
|
||||
'Piecewise', 'piecewise_fold', 'piecewise_exclusive',
|
||||
|
||||
'erf', 'erfc', 'erfi', 'erf2', 'erfinv', 'erfcinv', 'erf2inv', 'Ei',
|
||||
'expint', 'E1', 'li', 'Li', 'Si', 'Ci', 'Shi', 'Chi', 'fresnels',
|
||||
'fresnelc',
|
||||
|
||||
'gamma', 'lowergamma', 'uppergamma', 'polygamma', 'loggamma', 'digamma',
|
||||
'trigamma', 'multigamma',
|
||||
|
||||
'dirichlet_eta', 'zeta', 'lerchphi', 'polylog', 'stieltjes', 'riemann_xi',
|
||||
|
||||
'Eijk', 'LeviCivita', 'KroneckerDelta',
|
||||
|
||||
'SingularityFunction',
|
||||
|
||||
'DiracDelta', 'Heaviside',
|
||||
|
||||
'bspline_basis', 'bspline_basis_set', 'interpolating_spline',
|
||||
|
||||
'besselj', 'bessely', 'besseli', 'besselk', 'hankel1', 'hankel2', 'jn',
|
||||
'yn', 'jn_zeros', 'hn1', 'hn2', 'airyai', 'airybi', 'airyaiprime',
|
||||
'airybiprime', 'marcumq',
|
||||
|
||||
'hyper', 'meijerg', 'appellf1',
|
||||
|
||||
'legendre', 'assoc_legendre', 'hermite', 'hermite_prob', 'chebyshevt',
|
||||
'chebyshevu', 'chebyshevu_root', 'chebyshevt_root', 'laguerre',
|
||||
'assoc_laguerre', 'gegenbauer', 'jacobi', 'jacobi_normalized',
|
||||
|
||||
'Ynm', 'Ynm_c', 'Znm',
|
||||
|
||||
'elliptic_k', 'elliptic_f', 'elliptic_e', 'elliptic_pi',
|
||||
|
||||
'beta', 'betainc', 'betainc_regularized',
|
||||
|
||||
'mathieus', 'mathieuc', 'mathieusprime', 'mathieucprime',
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
# Stub __init__.py for sympy.functions.combinatorial
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+653
@@ -0,0 +1,653 @@
|
||||
from sympy.concrete.products import Product
|
||||
from sympy.core.function import expand_func
|
||||
from sympy.core.mod import Mod
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core import EulerGamma
|
||||
from sympy.core.numbers import (Float, I, Rational, nan, oo, pi, zoo)
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, Symbol, symbols)
|
||||
from sympy.functions.combinatorial.factorials import (ff, rf, binomial, factorial, factorial2)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.special.gamma_functions import (gamma, polygamma)
|
||||
from sympy.polys.polytools import Poly
|
||||
from sympy.series.order import O
|
||||
from sympy.simplify.simplify import simplify
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.functions.combinatorial.factorials import subfactorial
|
||||
from sympy.functions.special.gamma_functions import uppergamma
|
||||
from sympy.testing.pytest import XFAIL, raises, slow
|
||||
|
||||
#Solves and Fixes Issue #10388 - This is the updated test for the same solved issue
|
||||
|
||||
def test_rf_eval_apply():
|
||||
x, y = symbols('x,y')
|
||||
n, k = symbols('n k', integer=True)
|
||||
m = Symbol('m', integer=True, nonnegative=True)
|
||||
|
||||
assert rf(nan, y) is nan
|
||||
assert rf(x, nan) is nan
|
||||
|
||||
assert unchanged(rf, x, y)
|
||||
|
||||
assert rf(oo, 0) == 1
|
||||
assert rf(-oo, 0) == 1
|
||||
|
||||
assert rf(oo, 6) is oo
|
||||
assert rf(-oo, 7) is -oo
|
||||
assert rf(-oo, 6) is oo
|
||||
|
||||
assert rf(oo, -6) is oo
|
||||
assert rf(-oo, -7) is oo
|
||||
|
||||
assert rf(-1, pi) == 0
|
||||
assert rf(-5, 1 + I) == 0
|
||||
|
||||
assert unchanged(rf, -3, k)
|
||||
assert unchanged(rf, x, Symbol('k', integer=False))
|
||||
assert rf(-3, Symbol('k', integer=False)) == 0
|
||||
assert rf(Symbol('x', negative=True, integer=True), Symbol('k', integer=False)) == 0
|
||||
|
||||
assert rf(x, 0) == 1
|
||||
assert rf(x, 1) == x
|
||||
assert rf(x, 2) == x*(x + 1)
|
||||
assert rf(x, 3) == x*(x + 1)*(x + 2)
|
||||
assert rf(x, 5) == x*(x + 1)*(x + 2)*(x + 3)*(x + 4)
|
||||
|
||||
assert rf(x, -1) == 1/(x - 1)
|
||||
assert rf(x, -2) == 1/((x - 1)*(x - 2))
|
||||
assert rf(x, -3) == 1/((x - 1)*(x - 2)*(x - 3))
|
||||
|
||||
assert rf(1, 100) == factorial(100)
|
||||
|
||||
assert rf(x**2 + 3*x, 2) == (x**2 + 3*x)*(x**2 + 3*x + 1)
|
||||
assert isinstance(rf(x**2 + 3*x, 2), Mul)
|
||||
assert rf(x**3 + x, -2) == 1/((x**3 + x - 1)*(x**3 + x - 2))
|
||||
|
||||
assert rf(Poly(x**2 + 3*x, x), 2) == Poly(x**4 + 8*x**3 + 19*x**2 + 12*x, x)
|
||||
assert isinstance(rf(Poly(x**2 + 3*x, x), 2), Poly)
|
||||
raises(ValueError, lambda: rf(Poly(x**2 + 3*x, x, y), 2))
|
||||
assert rf(Poly(x**3 + x, x), -2) == 1/(x**6 - 9*x**5 + 35*x**4 - 75*x**3 + 94*x**2 - 66*x + 20)
|
||||
raises(ValueError, lambda: rf(Poly(x**3 + x, x, y), -2))
|
||||
|
||||
assert rf(x, m).is_integer is None
|
||||
assert rf(n, k).is_integer is None
|
||||
assert rf(n, m).is_integer is True
|
||||
assert rf(n, k + pi).is_integer is False
|
||||
assert rf(n, m + pi).is_integer is False
|
||||
assert rf(pi, m).is_integer is False
|
||||
|
||||
def check(x, k, o, n):
|
||||
a, b = Dummy(), Dummy()
|
||||
r = lambda x, k: o(a, b).rewrite(n).subs({a:x,b:k})
|
||||
for i in range(-5,5):
|
||||
for j in range(-5,5):
|
||||
assert o(i, j) == r(i, j), (o, n, i, j)
|
||||
check(x, k, rf, ff)
|
||||
check(x, k, rf, binomial)
|
||||
check(n, k, rf, factorial)
|
||||
check(x, y, rf, factorial)
|
||||
check(x, y, rf, binomial)
|
||||
|
||||
assert rf(x, k).rewrite(ff) == ff(x + k - 1, k)
|
||||
assert rf(x, k).rewrite(gamma) == Piecewise(
|
||||
(gamma(k + x)/gamma(x), x > 0),
|
||||
((-1)**k*gamma(1 - x)/gamma(-k - x + 1), True))
|
||||
assert rf(5, k).rewrite(gamma) == gamma(k + 5)/24
|
||||
assert rf(x, k).rewrite(binomial) == factorial(k)*binomial(x + k - 1, k)
|
||||
assert rf(n, k).rewrite(factorial) == Piecewise(
|
||||
(factorial(k + n - 1)/factorial(n - 1), n > 0),
|
||||
((-1)**k*factorial(-n)/factorial(-k - n), True))
|
||||
assert rf(5, k).rewrite(factorial) == factorial(k + 4)/24
|
||||
assert rf(x, y).rewrite(factorial) == rf(x, y)
|
||||
assert rf(x, y).rewrite(binomial) == rf(x, y)
|
||||
|
||||
import random
|
||||
from mpmath import rf as mpmath_rf
|
||||
for i in range(100):
|
||||
x = -500 + 500 * random.random()
|
||||
k = -500 + 500 * random.random()
|
||||
assert (abs(mpmath_rf(x, k) - rf(x, k)) < 10**(-15))
|
||||
|
||||
|
||||
def test_ff_eval_apply():
|
||||
x, y = symbols('x,y')
|
||||
n, k = symbols('n k', integer=True)
|
||||
m = Symbol('m', integer=True, nonnegative=True)
|
||||
|
||||
assert ff(nan, y) is nan
|
||||
assert ff(x, nan) is nan
|
||||
|
||||
assert unchanged(ff, x, y)
|
||||
|
||||
assert ff(oo, 0) == 1
|
||||
assert ff(-oo, 0) == 1
|
||||
|
||||
assert ff(oo, 6) is oo
|
||||
assert ff(-oo, 7) is -oo
|
||||
assert ff(-oo, 6) is oo
|
||||
|
||||
assert ff(oo, -6) is oo
|
||||
assert ff(-oo, -7) is oo
|
||||
|
||||
assert ff(x, 0) == 1
|
||||
assert ff(x, 1) == x
|
||||
assert ff(x, 2) == x*(x - 1)
|
||||
assert ff(x, 3) == x*(x - 1)*(x - 2)
|
||||
assert ff(x, 5) == x*(x - 1)*(x - 2)*(x - 3)*(x - 4)
|
||||
|
||||
assert ff(x, -1) == 1/(x + 1)
|
||||
assert ff(x, -2) == 1/((x + 1)*(x + 2))
|
||||
assert ff(x, -3) == 1/((x + 1)*(x + 2)*(x + 3))
|
||||
|
||||
assert ff(100, 100) == factorial(100)
|
||||
|
||||
assert ff(2*x**2 - 5*x, 2) == (2*x**2 - 5*x)*(2*x**2 - 5*x - 1)
|
||||
assert isinstance(ff(2*x**2 - 5*x, 2), Mul)
|
||||
assert ff(x**2 + 3*x, -2) == 1/((x**2 + 3*x + 1)*(x**2 + 3*x + 2))
|
||||
|
||||
assert ff(Poly(2*x**2 - 5*x, x), 2) == Poly(4*x**4 - 28*x**3 + 59*x**2 - 35*x, x)
|
||||
assert isinstance(ff(Poly(2*x**2 - 5*x, x), 2), Poly)
|
||||
raises(ValueError, lambda: ff(Poly(2*x**2 - 5*x, x, y), 2))
|
||||
assert ff(Poly(x**2 + 3*x, x), -2) == 1/(x**4 + 12*x**3 + 49*x**2 + 78*x + 40)
|
||||
raises(ValueError, lambda: ff(Poly(x**2 + 3*x, x, y), -2))
|
||||
|
||||
|
||||
assert ff(x, m).is_integer is None
|
||||
assert ff(n, k).is_integer is None
|
||||
assert ff(n, m).is_integer is True
|
||||
assert ff(n, k + pi).is_integer is False
|
||||
assert ff(n, m + pi).is_integer is False
|
||||
assert ff(pi, m).is_integer is False
|
||||
|
||||
assert isinstance(ff(x, x), ff)
|
||||
assert ff(n, n) == factorial(n)
|
||||
|
||||
def check(x, k, o, n):
|
||||
a, b = Dummy(), Dummy()
|
||||
r = lambda x, k: o(a, b).rewrite(n).subs({a:x,b:k})
|
||||
for i in range(-5,5):
|
||||
for j in range(-5,5):
|
||||
assert o(i, j) == r(i, j), (o, n)
|
||||
check(x, k, ff, rf)
|
||||
check(x, k, ff, gamma)
|
||||
check(n, k, ff, factorial)
|
||||
check(x, k, ff, binomial)
|
||||
check(x, y, ff, factorial)
|
||||
check(x, y, ff, binomial)
|
||||
|
||||
assert ff(x, k).rewrite(rf) == rf(x - k + 1, k)
|
||||
assert ff(x, k).rewrite(gamma) == Piecewise(
|
||||
(gamma(x + 1)/gamma(-k + x + 1), x >= 0),
|
||||
((-1)**k*gamma(k - x)/gamma(-x), True))
|
||||
assert ff(5, k).rewrite(gamma) == 120/gamma(6 - k)
|
||||
assert ff(n, k).rewrite(factorial) == Piecewise(
|
||||
(factorial(n)/factorial(-k + n), n >= 0),
|
||||
((-1)**k*factorial(k - n - 1)/factorial(-n - 1), True))
|
||||
assert ff(5, k).rewrite(factorial) == 120/factorial(5 - k)
|
||||
assert ff(x, k).rewrite(binomial) == factorial(k) * binomial(x, k)
|
||||
assert ff(x, y).rewrite(factorial) == ff(x, y)
|
||||
assert ff(x, y).rewrite(binomial) == ff(x, y)
|
||||
|
||||
import random
|
||||
from mpmath import ff as mpmath_ff
|
||||
for i in range(100):
|
||||
x = -500 + 500 * random.random()
|
||||
k = -500 + 500 * random.random()
|
||||
a = mpmath_ff(x, k)
|
||||
b = ff(x, k)
|
||||
assert (abs(a - b) < abs(a) * 10**(-15))
|
||||
|
||||
|
||||
def test_rf_ff_eval_hiprec():
|
||||
maple = Float('6.9109401292234329956525265438452')
|
||||
us = ff(18, Rational(2, 3)).evalf(32)
|
||||
assert abs(us - maple)/us < 1e-31
|
||||
|
||||
maple = Float('6.8261540131125511557924466355367')
|
||||
us = rf(18, Rational(2, 3)).evalf(32)
|
||||
assert abs(us - maple)/us < 1e-31
|
||||
|
||||
maple = Float('34.007346127440197150854651814225')
|
||||
us = rf(Float('4.4', 32), Float('2.2', 32))
|
||||
assert abs(us - maple)/us < 1e-31
|
||||
|
||||
|
||||
def test_rf_lambdify_mpmath():
|
||||
from sympy.utilities.lambdify import lambdify
|
||||
x, y = symbols('x,y')
|
||||
f = lambdify((x,y), rf(x, y), 'mpmath')
|
||||
maple = Float('34.007346127440197')
|
||||
us = f(4.4, 2.2)
|
||||
assert abs(us - maple)/us < 1e-15
|
||||
|
||||
|
||||
def test_factorial():
|
||||
x = Symbol('x')
|
||||
n = Symbol('n', integer=True)
|
||||
k = Symbol('k', integer=True, nonnegative=True)
|
||||
r = Symbol('r', integer=False)
|
||||
s = Symbol('s', integer=False, negative=True)
|
||||
t = Symbol('t', nonnegative=True)
|
||||
u = Symbol('u', noninteger=True)
|
||||
|
||||
assert factorial(-2) is zoo
|
||||
assert factorial(0) == 1
|
||||
assert factorial(7) == 5040
|
||||
assert factorial(19) == 121645100408832000
|
||||
assert factorial(31) == 8222838654177922817725562880000000
|
||||
assert factorial(n).func == factorial
|
||||
assert factorial(2*n).func == factorial
|
||||
|
||||
assert factorial(x).is_integer is None
|
||||
assert factorial(n).is_integer is None
|
||||
assert factorial(k).is_integer
|
||||
assert factorial(r).is_integer is None
|
||||
|
||||
assert factorial(n).is_positive is None
|
||||
assert factorial(k).is_positive
|
||||
|
||||
assert factorial(x).is_real is None
|
||||
assert factorial(n).is_real is None
|
||||
assert factorial(k).is_real is True
|
||||
assert factorial(r).is_real is None
|
||||
assert factorial(s).is_real is True
|
||||
assert factorial(t).is_real is True
|
||||
assert factorial(u).is_real is True
|
||||
|
||||
assert factorial(x).is_composite is None
|
||||
assert factorial(n).is_composite is None
|
||||
assert factorial(k).is_composite is None
|
||||
assert factorial(k + 3).is_composite is True
|
||||
assert factorial(r).is_composite is None
|
||||
assert factorial(s).is_composite is None
|
||||
assert factorial(t).is_composite is None
|
||||
assert factorial(u).is_composite is None
|
||||
|
||||
assert factorial(oo) is oo
|
||||
|
||||
|
||||
def test_factorial_Mod():
|
||||
pr = Symbol('pr', prime=True)
|
||||
p, q = 10**9 + 9, 10**9 + 33 # prime modulo
|
||||
r, s = 10**7 + 5, 33333333 # composite modulo
|
||||
assert Mod(factorial(pr - 1), pr) == pr - 1
|
||||
assert Mod(factorial(pr - 1), -pr) == -1
|
||||
assert Mod(factorial(r - 1, evaluate=False), r) == 0
|
||||
assert Mod(factorial(s - 1, evaluate=False), s) == 0
|
||||
assert Mod(factorial(p - 1, evaluate=False), p) == p - 1
|
||||
assert Mod(factorial(q - 1, evaluate=False), q) == q - 1
|
||||
assert Mod(factorial(p - 50, evaluate=False), p) == 854928834
|
||||
assert Mod(factorial(q - 1800, evaluate=False), q) == 905504050
|
||||
assert Mod(factorial(153, evaluate=False), r) == Mod(factorial(153), r)
|
||||
assert Mod(factorial(255, evaluate=False), s) == Mod(factorial(255), s)
|
||||
assert Mod(factorial(4, evaluate=False), 3) == S.Zero
|
||||
assert Mod(factorial(5, evaluate=False), 6) == S.Zero
|
||||
|
||||
|
||||
def test_factorial_diff():
|
||||
n = Symbol('n', integer=True)
|
||||
|
||||
assert factorial(n).diff(n) == \
|
||||
gamma(1 + n)*polygamma(0, 1 + n)
|
||||
assert factorial(n**2).diff(n) == \
|
||||
2*n*gamma(1 + n**2)*polygamma(0, 1 + n**2)
|
||||
raises(ArgumentIndexError, lambda: factorial(n**2).fdiff(2))
|
||||
|
||||
|
||||
def test_factorial_series():
|
||||
n = Symbol('n', integer=True)
|
||||
|
||||
assert factorial(n).series(n, 0, 3) == \
|
||||
1 - n*EulerGamma + n**2*(EulerGamma**2/2 + pi**2/12) + O(n**3)
|
||||
|
||||
|
||||
def test_factorial_rewrite():
|
||||
n = Symbol('n', integer=True)
|
||||
k = Symbol('k', integer=True, nonnegative=True)
|
||||
|
||||
assert factorial(n).rewrite(gamma) == gamma(n + 1)
|
||||
_i = Dummy('i')
|
||||
assert factorial(k).rewrite(Product).dummy_eq(Product(_i, (_i, 1, k)))
|
||||
assert factorial(n).rewrite(Product) == factorial(n)
|
||||
|
||||
|
||||
def test_factorial2():
|
||||
n = Symbol('n', integer=True)
|
||||
|
||||
assert factorial2(-1) == 1
|
||||
assert factorial2(0) == 1
|
||||
assert factorial2(7) == 105
|
||||
assert factorial2(8) == 384
|
||||
|
||||
# The following is exhaustive
|
||||
tt = Symbol('tt', integer=True, nonnegative=True)
|
||||
tte = Symbol('tte', even=True, nonnegative=True)
|
||||
tpe = Symbol('tpe', even=True, positive=True)
|
||||
tto = Symbol('tto', odd=True, nonnegative=True)
|
||||
tf = Symbol('tf', integer=True, nonnegative=False)
|
||||
tfe = Symbol('tfe', even=True, nonnegative=False)
|
||||
tfo = Symbol('tfo', odd=True, nonnegative=False)
|
||||
ft = Symbol('ft', integer=False, nonnegative=True)
|
||||
ff = Symbol('ff', integer=False, nonnegative=False)
|
||||
fn = Symbol('fn', integer=False)
|
||||
nt = Symbol('nt', nonnegative=True)
|
||||
nf = Symbol('nf', nonnegative=False)
|
||||
nn = Symbol('nn')
|
||||
z = Symbol('z', zero=True)
|
||||
#Solves and Fixes Issue #10388 - This is the updated test for the same solved issue
|
||||
raises(ValueError, lambda: factorial2(oo))
|
||||
raises(ValueError, lambda: factorial2(Rational(5, 2)))
|
||||
raises(ValueError, lambda: factorial2(-4))
|
||||
assert factorial2(n).is_integer is None
|
||||
assert factorial2(tt - 1).is_integer
|
||||
assert factorial2(tte - 1).is_integer
|
||||
assert factorial2(tpe - 3).is_integer
|
||||
assert factorial2(tto - 4).is_integer
|
||||
assert factorial2(tto - 2).is_integer
|
||||
assert factorial2(tf).is_integer is None
|
||||
assert factorial2(tfe).is_integer is None
|
||||
assert factorial2(tfo).is_integer is None
|
||||
assert factorial2(ft).is_integer is None
|
||||
assert factorial2(ff).is_integer is None
|
||||
assert factorial2(fn).is_integer is None
|
||||
assert factorial2(nt).is_integer is None
|
||||
assert factorial2(nf).is_integer is None
|
||||
assert factorial2(nn).is_integer is None
|
||||
|
||||
assert factorial2(n).is_positive is None
|
||||
assert factorial2(tt - 1).is_positive is True
|
||||
assert factorial2(tte - 1).is_positive is True
|
||||
assert factorial2(tpe - 3).is_positive is True
|
||||
assert factorial2(tpe - 1).is_positive is True
|
||||
assert factorial2(tto - 2).is_positive is True
|
||||
assert factorial2(tto - 1).is_positive is True
|
||||
assert factorial2(tf).is_positive is None
|
||||
assert factorial2(tfe).is_positive is None
|
||||
assert factorial2(tfo).is_positive is None
|
||||
assert factorial2(ft).is_positive is None
|
||||
assert factorial2(ff).is_positive is None
|
||||
assert factorial2(fn).is_positive is None
|
||||
assert factorial2(nt).is_positive is None
|
||||
assert factorial2(nf).is_positive is None
|
||||
assert factorial2(nn).is_positive is None
|
||||
|
||||
assert factorial2(tt).is_even is None
|
||||
assert factorial2(tt).is_odd is None
|
||||
assert factorial2(tte).is_even is None
|
||||
assert factorial2(tte).is_odd is None
|
||||
assert factorial2(tte + 2).is_even is True
|
||||
assert factorial2(tpe).is_even is True
|
||||
assert factorial2(tpe).is_odd is False
|
||||
assert factorial2(tto).is_odd is True
|
||||
assert factorial2(tf).is_even is None
|
||||
assert factorial2(tf).is_odd is None
|
||||
assert factorial2(tfe).is_even is None
|
||||
assert factorial2(tfe).is_odd is None
|
||||
assert factorial2(tfo).is_even is False
|
||||
assert factorial2(tfo).is_odd is None
|
||||
assert factorial2(z).is_even is False
|
||||
assert factorial2(z).is_odd is True
|
||||
|
||||
|
||||
def test_factorial2_rewrite():
|
||||
n = Symbol('n', integer=True)
|
||||
assert factorial2(n).rewrite(gamma) == \
|
||||
2**(n/2)*Piecewise((1, Eq(Mod(n, 2), 0)), (sqrt(2)/sqrt(pi), Eq(Mod(n, 2), 1)))*gamma(n/2 + 1)
|
||||
assert factorial2(2*n).rewrite(gamma) == 2**n*gamma(n + 1)
|
||||
assert factorial2(2*n + 1).rewrite(gamma) == \
|
||||
sqrt(2)*2**(n + S.Half)*gamma(n + Rational(3, 2))/sqrt(pi)
|
||||
|
||||
|
||||
def test_binomial():
|
||||
x = Symbol('x')
|
||||
n = Symbol('n', integer=True)
|
||||
nz = Symbol('nz', integer=True, nonzero=True)
|
||||
k = Symbol('k', integer=True)
|
||||
kp = Symbol('kp', integer=True, positive=True)
|
||||
kn = Symbol('kn', integer=True, negative=True)
|
||||
u = Symbol('u', negative=True)
|
||||
v = Symbol('v', nonnegative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
z = Symbol('z', zero=True)
|
||||
nt = Symbol('nt', integer=False)
|
||||
kt = Symbol('kt', integer=False)
|
||||
a = Symbol('a', integer=True, nonnegative=True)
|
||||
b = Symbol('b', integer=True, nonnegative=True)
|
||||
|
||||
assert binomial(0, 0) == 1
|
||||
assert binomial(1, 1) == 1
|
||||
assert binomial(10, 10) == 1
|
||||
assert binomial(n, z) == 1
|
||||
assert binomial(1, 2) == 0
|
||||
assert binomial(-1, 2) == 1
|
||||
assert binomial(1, -1) == 0
|
||||
assert binomial(-1, 1) == -1
|
||||
assert binomial(-1, -1) == 0
|
||||
assert binomial(S.Half, S.Half) == 1
|
||||
assert binomial(-10, 1) == -10
|
||||
assert binomial(-10, 7) == -11440
|
||||
assert binomial(n, -1) == 0 # holds for all integers (negative, zero, positive)
|
||||
assert binomial(kp, -1) == 0
|
||||
assert binomial(nz, 0) == 1
|
||||
assert expand_func(binomial(n, 1)) == n
|
||||
assert expand_func(binomial(n, 2)) == n*(n - 1)/2
|
||||
assert expand_func(binomial(n, n - 2)) == n*(n - 1)/2
|
||||
assert expand_func(binomial(n, n - 1)) == n
|
||||
assert binomial(n, 3).func == binomial
|
||||
assert binomial(n, 3).expand(func=True) == n**3/6 - n**2/2 + n/3
|
||||
assert expand_func(binomial(n, 3)) == n*(n - 2)*(n - 1)/6
|
||||
assert binomial(n, n).func == binomial # e.g. (-1, -1) == 0, (2, 2) == 1
|
||||
assert binomial(n, n + 1).func == binomial # e.g. (-1, 0) == 1
|
||||
assert binomial(kp, kp + 1) == 0
|
||||
assert binomial(kn, kn) == 0 # issue #14529
|
||||
assert binomial(n, u).func == binomial
|
||||
assert binomial(kp, u).func == binomial
|
||||
assert binomial(n, p).func == binomial
|
||||
assert binomial(n, k).func == binomial
|
||||
assert binomial(n, n + p).func == binomial
|
||||
assert binomial(kp, kp + p).func == binomial
|
||||
|
||||
assert expand_func(binomial(n, n - 3)) == n*(n - 2)*(n - 1)/6
|
||||
|
||||
assert binomial(n, k).is_integer
|
||||
assert binomial(nt, k).is_integer is None
|
||||
assert binomial(x, nt).is_integer is False
|
||||
|
||||
assert binomial(gamma(25), 6) == 79232165267303928292058750056084441948572511312165380965440075720159859792344339983120618959044048198214221915637090855535036339620413440000
|
||||
assert binomial(1324, 47) == 906266255662694632984994480774946083064699457235920708992926525848438478406790323869952
|
||||
assert binomial(1735, 43) == 190910140420204130794758005450919715396159959034348676124678207874195064798202216379800
|
||||
assert binomial(2512, 53) == 213894469313832631145798303740098720367984955243020898718979538096223399813295457822575338958939834177325304000
|
||||
assert binomial(3383, 52) == 27922807788818096863529701501764372757272890613101645521813434902890007725667814813832027795881839396839287659777235
|
||||
assert binomial(4321, 51) == 124595639629264868916081001263541480185227731958274383287107643816863897851139048158022599533438936036467601690983780576
|
||||
|
||||
assert binomial(a, b).is_nonnegative is True
|
||||
assert binomial(-1, 2, evaluate=False).is_nonnegative is True
|
||||
assert binomial(10, 5, evaluate=False).is_nonnegative is True
|
||||
assert binomial(10, -3, evaluate=False).is_nonnegative is True
|
||||
assert binomial(-10, -3, evaluate=False).is_nonnegative is True
|
||||
assert binomial(-10, 2, evaluate=False).is_nonnegative is True
|
||||
assert binomial(-10, 1, evaluate=False).is_nonnegative is False
|
||||
assert binomial(-10, 7, evaluate=False).is_nonnegative is False
|
||||
|
||||
# issue #14625
|
||||
for _ in (pi, -pi, nt, v, a):
|
||||
assert binomial(_, _) == 1
|
||||
assert binomial(_, _ - 1) == _
|
||||
assert isinstance(binomial(u, u), binomial)
|
||||
assert isinstance(binomial(u, u - 1), binomial)
|
||||
assert isinstance(binomial(x, x), binomial)
|
||||
assert isinstance(binomial(x, x - 1), binomial)
|
||||
|
||||
#issue #18802
|
||||
assert expand_func(binomial(x + 1, x)) == x + 1
|
||||
assert expand_func(binomial(x, x - 1)) == x
|
||||
assert expand_func(binomial(x + 1, x - 1)) == x*(x + 1)/2
|
||||
assert expand_func(binomial(x**2 + 1, x**2)) == x**2 + 1
|
||||
|
||||
# issue #13980 and #13981
|
||||
assert binomial(-7, -5) == 0
|
||||
assert binomial(-23, -12) == 0
|
||||
assert binomial(Rational(13, 2), -10) == 0
|
||||
assert binomial(-49, -51) == 0
|
||||
|
||||
assert binomial(19, Rational(-7, 2)) == S(-68719476736)/(911337863661225*pi)
|
||||
assert binomial(0, Rational(3, 2)) == S(-2)/(3*pi)
|
||||
assert binomial(-3, Rational(-7, 2)) is zoo
|
||||
assert binomial(kn, kt) is zoo
|
||||
|
||||
assert binomial(nt, kt).func == binomial
|
||||
assert binomial(nt, Rational(15, 6)) == 8*gamma(nt + 1)/(15*sqrt(pi)*gamma(nt - Rational(3, 2)))
|
||||
assert binomial(Rational(20, 3), Rational(-10, 8)) == gamma(Rational(23, 3))/(gamma(Rational(-1, 4))*gamma(Rational(107, 12)))
|
||||
assert binomial(Rational(19, 2), Rational(-7, 2)) == Rational(-1615, 8388608)
|
||||
assert binomial(Rational(-13, 5), Rational(-7, 8)) == gamma(Rational(-8, 5))/(gamma(Rational(-29, 40))*gamma(Rational(1, 8)))
|
||||
assert binomial(Rational(-19, 8), Rational(-13, 5)) == gamma(Rational(-11, 8))/(gamma(Rational(-8, 5))*gamma(Rational(49, 40)))
|
||||
|
||||
# binomial for complexes
|
||||
assert binomial(I, Rational(-89, 8)) == gamma(1 + I)/(gamma(Rational(-81, 8))*gamma(Rational(97, 8) + I))
|
||||
assert binomial(I, 2*I) == gamma(1 + I)/(gamma(1 - I)*gamma(1 + 2*I))
|
||||
assert binomial(-7, I) is zoo
|
||||
assert binomial(Rational(-7, 6), I) == gamma(Rational(-1, 6))/(gamma(Rational(-1, 6) - I)*gamma(1 + I))
|
||||
assert binomial((1+2*I), (1+3*I)) == gamma(2 + 2*I)/(gamma(1 - I)*gamma(2 + 3*I))
|
||||
assert binomial(I, 5) == Rational(1, 3) - I/S(12)
|
||||
assert binomial((2*I + 3), 7) == -13*I/S(63)
|
||||
assert isinstance(binomial(I, n), binomial)
|
||||
assert expand_func(binomial(3, 2, evaluate=False)) == 3
|
||||
assert expand_func(binomial(n, 0, evaluate=False)) == 1
|
||||
assert expand_func(binomial(n, -2, evaluate=False)) == 0
|
||||
assert expand_func(binomial(n, k)) == binomial(n, k)
|
||||
|
||||
|
||||
def test_binomial_Mod():
|
||||
p, q = 10**5 + 3, 10**9 + 33 # prime modulo
|
||||
r = 10**7 + 5 # composite modulo
|
||||
|
||||
# A few tests to get coverage
|
||||
# Lucas Theorem
|
||||
assert Mod(binomial(156675, 4433, evaluate=False), p) == Mod(binomial(156675, 4433), p)
|
||||
|
||||
# factorial Mod
|
||||
assert Mod(binomial(1234, 432, evaluate=False), q) == Mod(binomial(1234, 432), q)
|
||||
|
||||
# binomial factorize
|
||||
assert Mod(binomial(253, 113, evaluate=False), r) == Mod(binomial(253, 113), r)
|
||||
|
||||
# using Granville's generalisation of Lucas' Theorem
|
||||
assert Mod(binomial(10**18, 10**12, evaluate=False), p*p) == 3744312326
|
||||
|
||||
|
||||
@slow
|
||||
def test_binomial_Mod_slow():
|
||||
p, q = 10**5 + 3, 10**9 + 33 # prime modulo
|
||||
r, s = 10**7 + 5, 33333333 # composite modulo
|
||||
|
||||
n, k, m = symbols('n k m')
|
||||
assert (binomial(n, k) % q).subs({n: s, k: p}) == Mod(binomial(s, p), q)
|
||||
assert (binomial(n, k) % m).subs({n: 8, k: 5, m: 13}) == 4
|
||||
assert (binomial(9, k) % 7).subs(k, 2) == 1
|
||||
|
||||
# Lucas Theorem
|
||||
assert Mod(binomial(123456, 43253, evaluate=False), p) == Mod(binomial(123456, 43253), p)
|
||||
assert Mod(binomial(-178911, 237, evaluate=False), p) == Mod(-binomial(178911 + 237 - 1, 237), p)
|
||||
assert Mod(binomial(-178911, 238, evaluate=False), p) == Mod(binomial(178911 + 238 - 1, 238), p)
|
||||
|
||||
# factorial Mod
|
||||
assert Mod(binomial(9734, 451, evaluate=False), q) == Mod(binomial(9734, 451), q)
|
||||
assert Mod(binomial(-10733, 4459, evaluate=False), q) == Mod(binomial(-10733, 4459), q)
|
||||
assert Mod(binomial(-15733, 4458, evaluate=False), q) == Mod(binomial(-15733, 4458), q)
|
||||
assert Mod(binomial(23, -38, evaluate=False), q) is S.Zero
|
||||
assert Mod(binomial(23, 38, evaluate=False), q) is S.Zero
|
||||
|
||||
# binomial factorize
|
||||
assert Mod(binomial(753, 119, evaluate=False), r) == Mod(binomial(753, 119), r)
|
||||
assert Mod(binomial(3781, 948, evaluate=False), s) == Mod(binomial(3781, 948), s)
|
||||
assert Mod(binomial(25773, 1793, evaluate=False), s) == Mod(binomial(25773, 1793), s)
|
||||
assert Mod(binomial(-753, 118, evaluate=False), r) == Mod(binomial(-753, 118), r)
|
||||
assert Mod(binomial(-25773, 1793, evaluate=False), s) == Mod(binomial(-25773, 1793), s)
|
||||
|
||||
|
||||
def test_binomial_diff():
|
||||
n = Symbol('n', integer=True)
|
||||
k = Symbol('k', integer=True)
|
||||
|
||||
assert binomial(n, k).diff(n) == \
|
||||
(-polygamma(0, 1 + n - k) + polygamma(0, 1 + n))*binomial(n, k)
|
||||
assert binomial(n**2, k**3).diff(n) == \
|
||||
2*n*(-polygamma(
|
||||
0, 1 + n**2 - k**3) + polygamma(0, 1 + n**2))*binomial(n**2, k**3)
|
||||
|
||||
assert binomial(n, k).diff(k) == \
|
||||
(-polygamma(0, 1 + k) + polygamma(0, 1 + n - k))*binomial(n, k)
|
||||
assert binomial(n**2, k**3).diff(k) == \
|
||||
3*k**2*(-polygamma(
|
||||
0, 1 + k**3) + polygamma(0, 1 + n**2 - k**3))*binomial(n**2, k**3)
|
||||
raises(ArgumentIndexError, lambda: binomial(n, k).fdiff(3))
|
||||
|
||||
|
||||
def test_binomial_rewrite():
|
||||
n = Symbol('n', integer=True)
|
||||
k = Symbol('k', integer=True)
|
||||
x = Symbol('x')
|
||||
|
||||
assert binomial(n, k).rewrite(
|
||||
factorial) == factorial(n)/(factorial(k)*factorial(n - k))
|
||||
assert binomial(
|
||||
n, k).rewrite(gamma) == gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1))
|
||||
assert binomial(n, k).rewrite(ff) == ff(n, k) / factorial(k)
|
||||
assert binomial(n, x).rewrite(ff) == binomial(n, x)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_factorial_simplify_fail():
|
||||
# simplify(factorial(x + 1).diff(x) - ((x + 1)*factorial(x)).diff(x))) == 0
|
||||
from sympy.abc import x
|
||||
assert simplify(x*polygamma(0, x + 1) - x*polygamma(0, x + 2) +
|
||||
polygamma(0, x + 1) - polygamma(0, x + 2) + 1) == 0
|
||||
|
||||
|
||||
def test_subfactorial():
|
||||
assert all(subfactorial(i) == ans for i, ans in enumerate(
|
||||
[1, 0, 1, 2, 9, 44, 265, 1854, 14833, 133496]))
|
||||
assert subfactorial(oo) is oo
|
||||
assert subfactorial(nan) is nan
|
||||
assert subfactorial(23) == 9510425471055777937262
|
||||
assert unchanged(subfactorial, 2.2)
|
||||
|
||||
x = Symbol('x')
|
||||
assert subfactorial(x).rewrite(uppergamma) == uppergamma(x + 1, -1)/S.Exp1
|
||||
|
||||
tt = Symbol('tt', integer=True, nonnegative=True)
|
||||
tf = Symbol('tf', integer=True, nonnegative=False)
|
||||
tn = Symbol('tf', integer=True)
|
||||
ft = Symbol('ft', integer=False, nonnegative=True)
|
||||
ff = Symbol('ff', integer=False, nonnegative=False)
|
||||
fn = Symbol('ff', integer=False)
|
||||
nt = Symbol('nt', nonnegative=True)
|
||||
nf = Symbol('nf', nonnegative=False)
|
||||
nn = Symbol('nf')
|
||||
te = Symbol('te', even=True, nonnegative=True)
|
||||
to = Symbol('to', odd=True, nonnegative=True)
|
||||
assert subfactorial(tt).is_integer
|
||||
assert subfactorial(tf).is_integer is None
|
||||
assert subfactorial(tn).is_integer is None
|
||||
assert subfactorial(ft).is_integer is None
|
||||
assert subfactorial(ff).is_integer is None
|
||||
assert subfactorial(fn).is_integer is None
|
||||
assert subfactorial(nt).is_integer is None
|
||||
assert subfactorial(nf).is_integer is None
|
||||
assert subfactorial(nn).is_integer is None
|
||||
assert subfactorial(tt).is_nonnegative
|
||||
assert subfactorial(tf).is_nonnegative is None
|
||||
assert subfactorial(tn).is_nonnegative is None
|
||||
assert subfactorial(ft).is_nonnegative is None
|
||||
assert subfactorial(ff).is_nonnegative is None
|
||||
assert subfactorial(fn).is_nonnegative is None
|
||||
assert subfactorial(nt).is_nonnegative is None
|
||||
assert subfactorial(nf).is_nonnegative is None
|
||||
assert subfactorial(nn).is_nonnegative is None
|
||||
assert subfactorial(tt).is_even is None
|
||||
assert subfactorial(tt).is_odd is None
|
||||
assert subfactorial(te).is_odd is True
|
||||
assert subfactorial(to).is_even is True
|
||||
+1250
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
# Stub __init__.py for sympy.functions.elementary
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
r"""A module for special angle formulas for trigonometric functions
|
||||
|
||||
TODO
|
||||
====
|
||||
|
||||
This module should be developed in the future to contain direct square root
|
||||
representation of
|
||||
|
||||
.. math
|
||||
F(\frac{n}{m} \pi)
|
||||
|
||||
for every
|
||||
|
||||
- $m \in \{ 3, 5, 17, 257, 65537 \}$
|
||||
- $n \in \mathbb{N}$, $0 \le n < m$
|
||||
- $F \in \{\sin, \cos, \tan, \csc, \sec, \cot\}$
|
||||
|
||||
Without multi-step rewrites
|
||||
(e.g. $\tan \to \cos/\sin \to \cos/\sqrt \to \ sqrt$)
|
||||
or using chebyshev identities
|
||||
(e.g. $\cos \to \cos + \cos^2 + \cdots \to \sqrt{} + \sqrt{}^2 + \cdots $),
|
||||
which are trivial to implement in sympy,
|
||||
and had used to give overly complicated expressions.
|
||||
|
||||
The reference can be found below, if anyone may need help implementing them.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [*] Gottlieb, Christian. (1999). The Simple and straightforward construction
|
||||
of the regular 257-gon. The Mathematical Intelligencer. 21. 31-37.
|
||||
10.1007/BF03024829.
|
||||
.. [*] https://resources.wolframcloud.com/FunctionRepository/resources/Cos2PiOverFermatPrime
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Callable
|
||||
from functools import reduce
|
||||
from sympy.core.expr import Expr
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.intfunc import igcdex
|
||||
from sympy.core.numbers import Integer
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.core.cache import cacheit
|
||||
|
||||
|
||||
def migcdex(*x: int) -> tuple[tuple[int, ...], int]:
|
||||
r"""Compute extended gcd for multiple integers.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given the integers $x_1, \cdots, x_n$ and
|
||||
an extended gcd for multiple arguments are defined as a solution
|
||||
$(y_1, \cdots, y_n), g$ for the diophantine equation
|
||||
$x_1 y_1 + \cdots + x_n y_n = g$ such that
|
||||
$g = \gcd(x_1, \cdots, x_n)$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.functions.elementary._trigonometric_special import migcdex
|
||||
>>> migcdex()
|
||||
((), 0)
|
||||
>>> migcdex(4)
|
||||
((1,), 4)
|
||||
>>> migcdex(4, 6)
|
||||
((-1, 1), 2)
|
||||
>>> migcdex(6, 10, 15)
|
||||
((1, 1, -1), 1)
|
||||
"""
|
||||
if not x:
|
||||
return (), 0
|
||||
|
||||
if len(x) == 1:
|
||||
return (1,), x[0]
|
||||
|
||||
if len(x) == 2:
|
||||
u, v, h = igcdex(x[0], x[1])
|
||||
return (u, v), h
|
||||
|
||||
y, g = migcdex(*x[1:])
|
||||
u, v, h = igcdex(x[0], g)
|
||||
return (u, *(v * i for i in y)), h
|
||||
|
||||
|
||||
def ipartfrac(*denoms: int) -> tuple[int, ...]:
|
||||
r"""Compute the partial fraction decomposition.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a rational number $\frac{1}{q_1 \cdots q_n}$ where all
|
||||
$q_1, \cdots, q_n$ are pairwise coprime,
|
||||
|
||||
A partial fraction decomposition is defined as
|
||||
|
||||
.. math::
|
||||
\frac{1}{q_1 \cdots q_n} = \frac{p_1}{q_1} + \cdots + \frac{p_n}{q_n}
|
||||
|
||||
And it can be derived from solving the following diophantine equation for
|
||||
the $p_1, \cdots, p_n$
|
||||
|
||||
.. math::
|
||||
1 = p_1 \prod_{i \ne 1}q_i + \cdots + p_n \prod_{i \ne n}q_i
|
||||
|
||||
Where $q_1, \cdots, q_n$ being pairwise coprime implies
|
||||
$\gcd(\prod_{i \ne 1}q_i, \cdots, \prod_{i \ne n}q_i) = 1$,
|
||||
which guarantees the existence of the solution.
|
||||
|
||||
It is sufficient to compute partial fraction decomposition only
|
||||
for numerator $1$ because partial fraction decomposition for any
|
||||
$\frac{n}{q_1 \cdots q_n}$ can be easily computed by multiplying
|
||||
the result by $n$ afterwards.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
denoms : int
|
||||
The pairwise coprime integer denominators $q_i$ which defines the
|
||||
rational number $\frac{1}{q_1 \cdots q_n}$
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
tuple[int, ...]
|
||||
The list of numerators which semantically corresponds to $p_i$ of the
|
||||
partial fraction decomposition
|
||||
$\frac{1}{q_1 \cdots q_n} = \frac{p_1}{q_1} + \cdots + \frac{p_n}{q_n}$
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Rational, Mul
|
||||
>>> from sympy.functions.elementary._trigonometric_special import ipartfrac
|
||||
|
||||
>>> denoms = 2, 3, 5
|
||||
>>> numers = ipartfrac(2, 3, 5)
|
||||
>>> numers
|
||||
(1, 7, -14)
|
||||
|
||||
>>> Rational(1, Mul(*denoms))
|
||||
1/30
|
||||
>>> out = 0
|
||||
>>> for n, d in zip(numers, denoms):
|
||||
... out += Rational(n, d)
|
||||
>>> out
|
||||
1/30
|
||||
"""
|
||||
if not denoms:
|
||||
return ()
|
||||
|
||||
def mul(x: int, y: int) -> int:
|
||||
return x * y
|
||||
|
||||
denom = reduce(mul, denoms)
|
||||
a = [denom // x for x in denoms]
|
||||
h, _ = migcdex(*a)
|
||||
return h
|
||||
|
||||
|
||||
def fermat_coords(n: int) -> list[int] | None:
|
||||
"""If n can be factored in terms of Fermat primes with
|
||||
multiplicity of each being 1, return those primes, else
|
||||
None
|
||||
"""
|
||||
primes = []
|
||||
for p in [3, 5, 17, 257, 65537]:
|
||||
quotient, remainder = divmod(n, p)
|
||||
if remainder == 0:
|
||||
n = quotient
|
||||
primes.append(p)
|
||||
if n == 1:
|
||||
return primes
|
||||
return None
|
||||
|
||||
|
||||
@cacheit
|
||||
def cos_3() -> Expr:
|
||||
r"""Computes $\cos \frac{\pi}{3}$ in square roots"""
|
||||
return S.Half
|
||||
|
||||
|
||||
@cacheit
|
||||
def cos_5() -> Expr:
|
||||
r"""Computes $\cos \frac{\pi}{5}$ in square roots"""
|
||||
return (sqrt(5) + 1) / 4
|
||||
|
||||
|
||||
@cacheit
|
||||
def cos_17() -> Expr:
|
||||
r"""Computes $\cos \frac{\pi}{17}$ in square roots"""
|
||||
return sqrt(
|
||||
(15 + sqrt(17)) / 32 + sqrt(2) * (sqrt(17 - sqrt(17)) +
|
||||
sqrt(sqrt(2) * (-8 * sqrt(17 + sqrt(17)) - (1 - sqrt(17))
|
||||
* sqrt(17 - sqrt(17))) + 6 * sqrt(17) + 34)) / 32)
|
||||
|
||||
|
||||
@cacheit
|
||||
def cos_257() -> Expr:
|
||||
r"""Computes $\cos \frac{\pi}{257}$ in square roots
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [*] https://math.stackexchange.com/questions/516142/how-does-cos2-pi-257-look-like-in-real-radicals
|
||||
.. [*] https://r-knott.surrey.ac.uk/Fibonacci/simpleTrig.html
|
||||
"""
|
||||
def f1(a: Expr, b: Expr) -> tuple[Expr, Expr]:
|
||||
return (a + sqrt(a**2 + b)) / 2, (a - sqrt(a**2 + b)) / 2
|
||||
|
||||
def f2(a: Expr, b: Expr) -> Expr:
|
||||
return (a - sqrt(a**2 + b))/2
|
||||
|
||||
t1, t2 = f1(S.NegativeOne, Integer(256))
|
||||
z1, z3 = f1(t1, Integer(64))
|
||||
z2, z4 = f1(t2, Integer(64))
|
||||
y1, y5 = f1(z1, 4*(5 + t1 + 2*z1))
|
||||
y6, y2 = f1(z2, 4*(5 + t2 + 2*z2))
|
||||
y3, y7 = f1(z3, 4*(5 + t1 + 2*z3))
|
||||
y8, y4 = f1(z4, 4*(5 + t2 + 2*z4))
|
||||
x1, x9 = f1(y1, -4*(t1 + y1 + y3 + 2*y6))
|
||||
x2, x10 = f1(y2, -4*(t2 + y2 + y4 + 2*y7))
|
||||
x3, x11 = f1(y3, -4*(t1 + y3 + y5 + 2*y8))
|
||||
x4, x12 = f1(y4, -4*(t2 + y4 + y6 + 2*y1))
|
||||
x5, x13 = f1(y5, -4*(t1 + y5 + y7 + 2*y2))
|
||||
x6, x14 = f1(y6, -4*(t2 + y6 + y8 + 2*y3))
|
||||
x15, x7 = f1(y7, -4*(t1 + y7 + y1 + 2*y4))
|
||||
x8, x16 = f1(y8, -4*(t2 + y8 + y2 + 2*y5))
|
||||
v1 = f2(x1, -4*(x1 + x2 + x3 + x6))
|
||||
v2 = f2(x2, -4*(x2 + x3 + x4 + x7))
|
||||
v3 = f2(x8, -4*(x8 + x9 + x10 + x13))
|
||||
v4 = f2(x9, -4*(x9 + x10 + x11 + x14))
|
||||
v5 = f2(x10, -4*(x10 + x11 + x12 + x15))
|
||||
v6 = f2(x16, -4*(x16 + x1 + x2 + x5))
|
||||
u1 = -f2(-v1, -4*(v2 + v3))
|
||||
u2 = -f2(-v4, -4*(v5 + v6))
|
||||
w1 = -2*f2(-u1, -4*u2)
|
||||
return sqrt(sqrt(2)*sqrt(w1 + 4)/8 + S.Half)
|
||||
|
||||
|
||||
def cos_table() -> dict[int, Callable[[], Expr]]:
|
||||
r"""Lazily evaluated table for $\cos \frac{\pi}{n}$ in square roots for
|
||||
$n \in \{3, 5, 17, 257, 65537\}$.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
65537 is the only other known Fermat prime and it is nearly impossible to
|
||||
build in the current SymPy due to performance issues.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
https://r-knott.surrey.ac.uk/Fibonacci/simpleTrig.html
|
||||
"""
|
||||
return {
|
||||
3: cos_3,
|
||||
5: cos_5,
|
||||
17: cos_17,
|
||||
257: cos_257
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.exponential import exp
|
||||
|
||||
x, y = symbols('x,y')
|
||||
|
||||
e = exp(2*x)
|
||||
q = exp(3*x)
|
||||
|
||||
|
||||
def timeit_exp_subs():
|
||||
e.subs(q, y)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,710 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from sympy.core.basic import Basic
|
||||
from sympy.core.expr import Expr
|
||||
|
||||
from sympy.core import Add, S
|
||||
from sympy.core.evalf import get_integer_part, PrecisionExhausted
|
||||
from sympy.core.function import DefinedFunction
|
||||
from sympy.core.logic import fuzzy_or, fuzzy_and
|
||||
from sympy.core.numbers import Integer, int_valued
|
||||
from sympy.core.relational import Gt, Lt, Ge, Le, Relational, is_eq, is_le, is_lt
|
||||
from sympy.core.sympify import _sympify
|
||||
from sympy.functions.elementary.complexes import im, re
|
||||
from sympy.multipledispatch import dispatch
|
||||
|
||||
###############################################################################
|
||||
######################### FLOOR and CEILING FUNCTIONS #########################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class RoundFunction(DefinedFunction):
|
||||
"""Abstract base class for rounding functions."""
|
||||
|
||||
args: tuple[Expr]
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg):
|
||||
if (v := cls._eval_number(arg)) is not None:
|
||||
return v
|
||||
if (v := cls._eval_const_number(arg)) is not None:
|
||||
return v
|
||||
|
||||
if arg.is_integer or arg.is_finite is False:
|
||||
return arg
|
||||
if arg.is_imaginary or (S.ImaginaryUnit*arg).is_real:
|
||||
i = im(arg)
|
||||
if not i.has(S.ImaginaryUnit):
|
||||
return cls(i)*S.ImaginaryUnit
|
||||
return cls(arg, evaluate=False)
|
||||
|
||||
# Integral, numerical, symbolic part
|
||||
ipart = npart = spart = S.Zero
|
||||
|
||||
# Extract integral (or complex integral) terms
|
||||
intof = lambda x: int(x) if int_valued(x) else (
|
||||
x if x.is_integer else None)
|
||||
for t in Add.make_args(arg):
|
||||
if t.is_imaginary and (i := intof(im(t))) is not None:
|
||||
ipart += i*S.ImaginaryUnit
|
||||
elif (i := intof(t)) is not None:
|
||||
ipart += i
|
||||
elif t.is_number:
|
||||
npart += t
|
||||
else:
|
||||
spart += t
|
||||
|
||||
if not (npart or spart):
|
||||
return ipart
|
||||
|
||||
# Evaluate npart numerically if independent of spart
|
||||
if npart and (
|
||||
not spart or
|
||||
npart.is_real and (spart.is_imaginary or (S.ImaginaryUnit*spart).is_real) or
|
||||
npart.is_imaginary and spart.is_real):
|
||||
try:
|
||||
r, i = get_integer_part(
|
||||
npart, cls._dir, {}, return_ints=True)
|
||||
ipart += Integer(r) + Integer(i)*S.ImaginaryUnit
|
||||
npart = S.Zero
|
||||
except (PrecisionExhausted, NotImplementedError):
|
||||
pass
|
||||
|
||||
spart += npart
|
||||
if not spart:
|
||||
return ipart
|
||||
elif spart.is_imaginary or (S.ImaginaryUnit*spart).is_real:
|
||||
return ipart + cls(im(spart), evaluate=False)*S.ImaginaryUnit
|
||||
elif isinstance(spart, (floor, ceiling)):
|
||||
return ipart + spart
|
||||
else:
|
||||
return ipart + cls(spart, evaluate=False)
|
||||
|
||||
@classmethod
|
||||
def _eval_number(cls, arg):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _eval_is_finite(self):
|
||||
return self.args[0].is_finite
|
||||
|
||||
def _eval_is_real(self):
|
||||
return self.args[0].is_real
|
||||
|
||||
def _eval_is_integer(self):
|
||||
return self.args[0].is_real
|
||||
|
||||
|
||||
class floor(RoundFunction):
|
||||
"""
|
||||
Floor is a univariate function which returns the largest integer
|
||||
value not greater than its argument. This implementation
|
||||
generalizes floor to complex numbers by taking the floor of the
|
||||
real and imaginary parts separately.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import floor, E, I, S, Float, Rational
|
||||
>>> floor(17)
|
||||
17
|
||||
>>> floor(Rational(23, 10))
|
||||
2
|
||||
>>> floor(2*E)
|
||||
5
|
||||
>>> floor(-Float(0.567))
|
||||
-1
|
||||
>>> floor(-I/2)
|
||||
-I
|
||||
>>> floor(S(5)/2 + 5*I/2)
|
||||
2 + 2*I
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.functions.elementary.integers.ceiling
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] "Concrete mathematics" by Graham, pp. 87
|
||||
.. [2] https://mathworld.wolfram.com/FloorFunction.html
|
||||
|
||||
"""
|
||||
_dir = -1
|
||||
|
||||
@classmethod
|
||||
def _eval_number(cls, arg):
|
||||
if arg.is_Number:
|
||||
return arg.floor()
|
||||
if any(isinstance(i, j)
|
||||
for i in (arg, -arg) for j in (floor, ceiling)):
|
||||
return arg
|
||||
if arg.is_NumberSymbol:
|
||||
return arg.approximation_interval(Integer)[0]
|
||||
|
||||
@classmethod
|
||||
def _eval_const_number(cls, arg):
|
||||
if arg.is_real:
|
||||
if arg.is_zero:
|
||||
return S.Zero
|
||||
if arg.is_positive:
|
||||
num, den = arg.as_numer_denom()
|
||||
s = den.is_negative
|
||||
if s is None:
|
||||
return None
|
||||
if s:
|
||||
num, den = -num, -den
|
||||
# 0 <= num/den < 1 -> 0
|
||||
if is_lt(num, den):
|
||||
return S.Zero
|
||||
# 1 <= num/den < 2 -> 1
|
||||
if fuzzy_and([is_le(den, num), is_lt(num, 2*den)]):
|
||||
return S.One
|
||||
if arg.is_negative:
|
||||
num, den = arg.as_numer_denom()
|
||||
s = den.is_negative
|
||||
if s is None:
|
||||
return None
|
||||
if s:
|
||||
num, den = -num, -den
|
||||
# -1 <= num/den < 0 -> -1
|
||||
if is_le(-den, num):
|
||||
return S.NegativeOne
|
||||
# -2 <= num/den < -1 -> -2
|
||||
if fuzzy_and([is_le(-2*den, num), is_lt(num, -den)]):
|
||||
return Integer(-2)
|
||||
|
||||
def _eval_as_leading_term(self, x, logx, cdir):
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
arg = self.args[0]
|
||||
arg0 = arg.subs(x, 0)
|
||||
r = self.subs(x, 0)
|
||||
if arg0 is S.NaN or isinstance(arg0, AccumBounds):
|
||||
arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
|
||||
r = floor(arg0)
|
||||
if arg0.is_finite:
|
||||
if arg0 == r:
|
||||
ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
|
||||
if ndir.is_negative:
|
||||
return r - 1
|
||||
elif ndir.is_positive:
|
||||
return r
|
||||
else:
|
||||
raise NotImplementedError("Not sure of sign of %s" % ndir)
|
||||
else:
|
||||
return r
|
||||
return arg.as_leading_term(x, logx=logx, cdir=cdir)
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
arg = self.args[0]
|
||||
arg0 = arg.subs(x, 0)
|
||||
r = self.subs(x, 0)
|
||||
if arg0 is S.NaN:
|
||||
arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
|
||||
r = floor(arg0)
|
||||
if arg0.is_infinite:
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
from sympy.series.order import Order
|
||||
s = arg._eval_nseries(x, n, logx, cdir)
|
||||
o = Order(1, (x, 0)) if n <= 0 else AccumBounds(-1, 0)
|
||||
return s + o
|
||||
if arg0 == r:
|
||||
ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
|
||||
if ndir.is_negative:
|
||||
return r - 1
|
||||
elif ndir.is_positive:
|
||||
return r
|
||||
else:
|
||||
raise NotImplementedError("Not sure of sign of %s" % ndir)
|
||||
else:
|
||||
return r
|
||||
|
||||
def _eval_is_negative(self):
|
||||
return self.args[0].is_negative
|
||||
|
||||
def _eval_is_nonnegative(self):
|
||||
return self.args[0].is_nonnegative
|
||||
|
||||
def _eval_rewrite_as_ceiling(self, arg, **kwargs):
|
||||
return -ceiling(-arg)
|
||||
|
||||
def _eval_rewrite_as_frac(self, arg, **kwargs):
|
||||
return arg - frac(arg)
|
||||
|
||||
def __le__(self, other):
|
||||
other = S(other)
|
||||
if self.args[0].is_real:
|
||||
if other.is_integer:
|
||||
return self.args[0] < other + 1
|
||||
if other.is_number and other.is_real:
|
||||
return self.args[0] < ceiling(other)
|
||||
if self.args[0] == other and other.is_real:
|
||||
return S.true
|
||||
if other is S.Infinity and self.is_finite:
|
||||
return S.true
|
||||
|
||||
return Le(self, other, evaluate=False)
|
||||
|
||||
def __ge__(self, other):
|
||||
other = S(other)
|
||||
if self.args[0].is_real:
|
||||
if other.is_integer:
|
||||
return self.args[0] >= other
|
||||
if other.is_number and other.is_real:
|
||||
return self.args[0] >= ceiling(other)
|
||||
if self.args[0] == other and other.is_real and other.is_noninteger:
|
||||
return S.false
|
||||
if other is S.NegativeInfinity and self.is_finite:
|
||||
return S.true
|
||||
|
||||
return Ge(self, other, evaluate=False)
|
||||
|
||||
def __gt__(self, other):
|
||||
other = S(other)
|
||||
if self.args[0].is_real:
|
||||
if other.is_integer:
|
||||
return self.args[0] >= other + 1
|
||||
if other.is_number and other.is_real:
|
||||
return self.args[0] >= ceiling(other)
|
||||
if self.args[0] == other and other.is_real:
|
||||
return S.false
|
||||
if other is S.NegativeInfinity and self.is_finite:
|
||||
return S.true
|
||||
|
||||
return Gt(self, other, evaluate=False)
|
||||
|
||||
def __lt__(self, other):
|
||||
other = S(other)
|
||||
if self.args[0].is_real:
|
||||
if other.is_integer:
|
||||
return self.args[0] < other
|
||||
if other.is_number and other.is_real:
|
||||
return self.args[0] < ceiling(other)
|
||||
if self.args[0] == other and other.is_real and other.is_noninteger:
|
||||
return S.true
|
||||
if other is S.Infinity and self.is_finite:
|
||||
return S.true
|
||||
|
||||
return Lt(self, other, evaluate=False)
|
||||
|
||||
|
||||
@dispatch(floor, Expr)
|
||||
def _eval_is_eq(lhs, rhs): # noqa:F811
|
||||
return is_eq(lhs.rewrite(ceiling), rhs) or \
|
||||
is_eq(lhs.rewrite(frac),rhs)
|
||||
|
||||
|
||||
class ceiling(RoundFunction):
|
||||
"""
|
||||
Ceiling is a univariate function which returns the smallest integer
|
||||
value not less than its argument. This implementation
|
||||
generalizes ceiling to complex numbers by taking the ceiling of the
|
||||
real and imaginary parts separately.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import ceiling, E, I, S, Float, Rational
|
||||
>>> ceiling(17)
|
||||
17
|
||||
>>> ceiling(Rational(23, 10))
|
||||
3
|
||||
>>> ceiling(2*E)
|
||||
6
|
||||
>>> ceiling(-Float(0.567))
|
||||
0
|
||||
>>> ceiling(I/2)
|
||||
I
|
||||
>>> ceiling(S(5)/2 + 5*I/2)
|
||||
3 + 3*I
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.functions.elementary.integers.floor
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] "Concrete mathematics" by Graham, pp. 87
|
||||
.. [2] https://mathworld.wolfram.com/CeilingFunction.html
|
||||
|
||||
"""
|
||||
_dir = 1
|
||||
|
||||
@classmethod
|
||||
def _eval_number(cls, arg):
|
||||
if arg.is_Number:
|
||||
return arg.ceiling()
|
||||
if any(isinstance(i, j)
|
||||
for i in (arg, -arg) for j in (floor, ceiling)):
|
||||
return arg
|
||||
if arg.is_NumberSymbol:
|
||||
return arg.approximation_interval(Integer)[1]
|
||||
|
||||
@classmethod
|
||||
def _eval_const_number(cls, arg):
|
||||
if arg.is_real:
|
||||
if arg.is_zero:
|
||||
return S.Zero
|
||||
if arg.is_positive:
|
||||
num, den = arg.as_numer_denom()
|
||||
s = den.is_negative
|
||||
if s is None:
|
||||
return None
|
||||
if s:
|
||||
num, den = -num, -den
|
||||
# 0 < num/den <= 1 -> 1
|
||||
if is_le(num, den):
|
||||
return S.One
|
||||
# 1 < num/den <= 2 -> 2
|
||||
if fuzzy_and([is_lt(den, num), is_le(num, 2*den)]):
|
||||
return Integer(2)
|
||||
if arg.is_negative:
|
||||
num, den = arg.as_numer_denom()
|
||||
s = den.is_negative
|
||||
if s is None:
|
||||
return None
|
||||
if s:
|
||||
num, den = -num, -den
|
||||
# -1 < num/den <= 0 -> 0
|
||||
if is_lt(-den, num):
|
||||
return S.Zero
|
||||
# -2 < num/den <= -1 -> -1
|
||||
if fuzzy_and([is_lt(-2*den, num), is_le(num, -den)]):
|
||||
return S.NegativeOne
|
||||
|
||||
def _eval_as_leading_term(self, x, logx, cdir):
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
arg = self.args[0]
|
||||
arg0 = arg.subs(x, 0)
|
||||
r = self.subs(x, 0)
|
||||
if arg0 is S.NaN or isinstance(arg0, AccumBounds):
|
||||
arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
|
||||
r = ceiling(arg0)
|
||||
if arg0.is_finite:
|
||||
if arg0 == r:
|
||||
ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
|
||||
if ndir.is_negative:
|
||||
return r
|
||||
elif ndir.is_positive:
|
||||
return r + 1
|
||||
else:
|
||||
raise NotImplementedError("Not sure of sign of %s" % ndir)
|
||||
else:
|
||||
return r
|
||||
return arg.as_leading_term(x, logx=logx, cdir=cdir)
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
arg = self.args[0]
|
||||
arg0 = arg.subs(x, 0)
|
||||
r = self.subs(x, 0)
|
||||
if arg0 is S.NaN:
|
||||
arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
|
||||
r = ceiling(arg0)
|
||||
if arg0.is_infinite:
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
from sympy.series.order import Order
|
||||
s = arg._eval_nseries(x, n, logx, cdir)
|
||||
o = Order(1, (x, 0)) if n <= 0 else AccumBounds(0, 1)
|
||||
return s + o
|
||||
if arg0 == r:
|
||||
ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
|
||||
if ndir.is_negative:
|
||||
return r
|
||||
elif ndir.is_positive:
|
||||
return r + 1
|
||||
else:
|
||||
raise NotImplementedError("Not sure of sign of %s" % ndir)
|
||||
else:
|
||||
return r
|
||||
|
||||
def _eval_rewrite_as_floor(self, arg, **kwargs):
|
||||
return -floor(-arg)
|
||||
|
||||
def _eval_rewrite_as_frac(self, arg, **kwargs):
|
||||
return arg + frac(-arg)
|
||||
|
||||
def _eval_is_positive(self):
|
||||
return self.args[0].is_positive
|
||||
|
||||
def _eval_is_nonpositive(self):
|
||||
return self.args[0].is_nonpositive
|
||||
|
||||
def __lt__(self, other):
|
||||
other = S(other)
|
||||
if self.args[0].is_real:
|
||||
if other.is_integer:
|
||||
return self.args[0] <= other - 1
|
||||
if other.is_number and other.is_real:
|
||||
return self.args[0] <= floor(other)
|
||||
if self.args[0] == other and other.is_real:
|
||||
return S.false
|
||||
if other is S.Infinity and self.is_finite:
|
||||
return S.true
|
||||
|
||||
return Lt(self, other, evaluate=False)
|
||||
|
||||
def __gt__(self, other):
|
||||
other = S(other)
|
||||
if self.args[0].is_real:
|
||||
if other.is_integer:
|
||||
return self.args[0] > other
|
||||
if other.is_number and other.is_real:
|
||||
return self.args[0] > floor(other)
|
||||
if self.args[0] == other and other.is_real and other.is_noninteger:
|
||||
return S.true
|
||||
if other is S.NegativeInfinity and self.is_finite:
|
||||
return S.true
|
||||
|
||||
return Gt(self, other, evaluate=False)
|
||||
|
||||
def __ge__(self, other):
|
||||
other = S(other)
|
||||
if self.args[0].is_real:
|
||||
if other.is_integer:
|
||||
return self.args[0] > other - 1
|
||||
if other.is_number and other.is_real:
|
||||
return self.args[0] > floor(other)
|
||||
if self.args[0] == other and other.is_real:
|
||||
return S.true
|
||||
if other is S.NegativeInfinity and self.is_finite:
|
||||
return S.true
|
||||
|
||||
return Ge(self, other, evaluate=False)
|
||||
|
||||
def __le__(self, other):
|
||||
other = S(other)
|
||||
if self.args[0].is_real:
|
||||
if other.is_integer:
|
||||
return self.args[0] <= other
|
||||
if other.is_number and other.is_real:
|
||||
return self.args[0] <= floor(other)
|
||||
if self.args[0] == other and other.is_real and other.is_noninteger:
|
||||
return S.false
|
||||
if other is S.Infinity and self.is_finite:
|
||||
return S.true
|
||||
|
||||
return Le(self, other, evaluate=False)
|
||||
|
||||
|
||||
@dispatch(ceiling, Basic) # type:ignore
|
||||
def _eval_is_eq(lhs, rhs): # noqa:F811
|
||||
return is_eq(lhs.rewrite(floor), rhs) or is_eq(lhs.rewrite(frac),rhs)
|
||||
|
||||
|
||||
class frac(DefinedFunction):
|
||||
r"""Represents the fractional part of x
|
||||
|
||||
For real numbers it is defined [1]_ as
|
||||
|
||||
.. math::
|
||||
x - \left\lfloor{x}\right\rfloor
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Symbol, frac, Rational, floor, I
|
||||
>>> frac(Rational(4, 3))
|
||||
1/3
|
||||
>>> frac(-Rational(4, 3))
|
||||
2/3
|
||||
|
||||
returns zero for integer arguments
|
||||
|
||||
>>> n = Symbol('n', integer=True)
|
||||
>>> frac(n)
|
||||
0
|
||||
|
||||
rewrite as floor
|
||||
|
||||
>>> x = Symbol('x')
|
||||
>>> frac(x).rewrite(floor)
|
||||
x - floor(x)
|
||||
|
||||
for complex arguments
|
||||
|
||||
>>> r = Symbol('r', real=True)
|
||||
>>> t = Symbol('t', real=True)
|
||||
>>> frac(t + I*r)
|
||||
I*frac(r) + frac(t)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.functions.elementary.integers.floor
|
||||
sympy.functions.elementary.integers.ceiling
|
||||
|
||||
References
|
||||
===========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Fractional_part
|
||||
.. [2] https://mathworld.wolfram.com/FractionalPart.html
|
||||
|
||||
"""
|
||||
@classmethod
|
||||
def eval(cls, arg):
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
|
||||
def _eval(arg):
|
||||
if arg in (S.Infinity, S.NegativeInfinity):
|
||||
return AccumBounds(0, 1)
|
||||
if arg.is_integer:
|
||||
return S.Zero
|
||||
if arg.is_number:
|
||||
if arg is S.NaN:
|
||||
return S.NaN
|
||||
elif arg is S.ComplexInfinity:
|
||||
return S.NaN
|
||||
else:
|
||||
return arg - floor(arg)
|
||||
return cls(arg, evaluate=False)
|
||||
|
||||
real, imag = S.Zero, S.Zero
|
||||
for t in Add.make_args(arg):
|
||||
# Two checks are needed for complex arguments
|
||||
# see issue-7649 for details
|
||||
if t.is_imaginary or (S.ImaginaryUnit*t).is_real:
|
||||
i = im(t)
|
||||
if not i.has(S.ImaginaryUnit):
|
||||
imag += i
|
||||
else:
|
||||
real += t
|
||||
else:
|
||||
real += t
|
||||
|
||||
real = _eval(real)
|
||||
imag = _eval(imag)
|
||||
return real + S.ImaginaryUnit*imag
|
||||
|
||||
def _eval_rewrite_as_floor(self, arg, **kwargs):
|
||||
return arg - floor(arg)
|
||||
|
||||
def _eval_rewrite_as_ceiling(self, arg, **kwargs):
|
||||
return arg + ceiling(-arg)
|
||||
|
||||
def _eval_is_finite(self):
|
||||
return True
|
||||
|
||||
def _eval_is_real(self):
|
||||
return self.args[0].is_extended_real
|
||||
|
||||
def _eval_is_imaginary(self):
|
||||
return self.args[0].is_imaginary
|
||||
|
||||
def _eval_is_integer(self):
|
||||
return self.args[0].is_integer
|
||||
|
||||
def _eval_is_zero(self):
|
||||
return fuzzy_or([self.args[0].is_zero, self.args[0].is_integer])
|
||||
|
||||
def _eval_is_negative(self):
|
||||
return False
|
||||
|
||||
def __ge__(self, other):
|
||||
if self.is_extended_real:
|
||||
other = _sympify(other)
|
||||
# Check if other <= 0
|
||||
if other.is_extended_nonpositive:
|
||||
return S.true
|
||||
# Check if other >= 1
|
||||
res = self._value_one_or_more(other)
|
||||
if res is not None:
|
||||
return not(res)
|
||||
return Ge(self, other, evaluate=False)
|
||||
|
||||
def __gt__(self, other):
|
||||
if self.is_extended_real:
|
||||
other = _sympify(other)
|
||||
# Check if other < 0
|
||||
res = self._value_one_or_more(other)
|
||||
if res is not None:
|
||||
return not(res)
|
||||
# Check if other >= 1
|
||||
if other.is_extended_negative:
|
||||
return S.true
|
||||
return Gt(self, other, evaluate=False)
|
||||
|
||||
def __le__(self, other):
|
||||
if self.is_extended_real:
|
||||
other = _sympify(other)
|
||||
# Check if other < 0
|
||||
if other.is_extended_negative:
|
||||
return S.false
|
||||
# Check if other >= 1
|
||||
res = self._value_one_or_more(other)
|
||||
if res is not None:
|
||||
return res
|
||||
return Le(self, other, evaluate=False)
|
||||
|
||||
def __lt__(self, other):
|
||||
if self.is_extended_real:
|
||||
other = _sympify(other)
|
||||
# Check if other <= 0
|
||||
if other.is_extended_nonpositive:
|
||||
return S.false
|
||||
# Check if other >= 1
|
||||
res = self._value_one_or_more(other)
|
||||
if res is not None:
|
||||
return res
|
||||
return Lt(self, other, evaluate=False)
|
||||
|
||||
def _value_one_or_more(self, other):
|
||||
if other.is_extended_real:
|
||||
if other.is_number:
|
||||
res = other >= 1
|
||||
if res and not isinstance(res, Relational):
|
||||
return S.true
|
||||
if other.is_integer and other.is_positive:
|
||||
return S.true
|
||||
|
||||
def _eval_as_leading_term(self, x, logx, cdir):
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
arg = self.args[0]
|
||||
arg0 = arg.subs(x, 0)
|
||||
r = self.subs(x, 0)
|
||||
|
||||
if arg0.is_finite:
|
||||
if r.is_zero:
|
||||
ndir = arg.dir(x, cdir=cdir)
|
||||
if ndir.is_negative:
|
||||
return S.One
|
||||
return (arg - arg0).as_leading_term(x, logx=logx, cdir=cdir)
|
||||
else:
|
||||
return r
|
||||
elif arg0 in (S.ComplexInfinity, S.Infinity, S.NegativeInfinity):
|
||||
return AccumBounds(0, 1)
|
||||
return arg.as_leading_term(x, logx=logx, cdir=cdir)
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
from sympy.series.order import Order
|
||||
arg = self.args[0]
|
||||
arg0 = arg.subs(x, 0)
|
||||
r = self.subs(x, 0)
|
||||
|
||||
if arg0.is_infinite:
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
o = Order(1, (x, 0)) if n <= 0 else AccumBounds(0, 1) + Order(x**n, (x, 0))
|
||||
return o
|
||||
else:
|
||||
res = (arg - arg0)._eval_nseries(x, n, logx=logx, cdir=cdir)
|
||||
if r.is_zero:
|
||||
ndir = arg.dir(x, cdir=cdir)
|
||||
res += S.One if ndir.is_negative else S.Zero
|
||||
else:
|
||||
res += r
|
||||
return res
|
||||
|
||||
|
||||
@dispatch(frac, Basic) # type:ignore
|
||||
def _eval_is_eq(lhs, rhs): # noqa:F811
|
||||
if (lhs.rewrite(floor) == rhs) or \
|
||||
(lhs.rewrite(ceiling) == rhs):
|
||||
return True
|
||||
# Check if other < 0
|
||||
if rhs.is_extended_negative:
|
||||
return False
|
||||
# Check if other >= 1
|
||||
res = lhs._value_one_or_more(rhs)
|
||||
if res is not None:
|
||||
return False
|
||||
@@ -0,0 +1,915 @@
|
||||
from sympy.core import S, sympify, NumberKind
|
||||
from sympy.utilities.iterables import sift
|
||||
from sympy.core.add import Add
|
||||
from sympy.core.containers import Tuple
|
||||
from sympy.core.operations import LatticeOp, ShortCircuit
|
||||
from sympy.core.function import (Application, Lambda,
|
||||
ArgumentIndexError, DefinedFunction)
|
||||
from sympy.core.expr import Expr
|
||||
from sympy.core.exprtools import factor_terms
|
||||
from sympy.core.mod import Mod
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core.numbers import Rational
|
||||
from sympy.core.power import Pow
|
||||
from sympy.core.relational import Eq, Relational
|
||||
from sympy.core.singleton import Singleton
|
||||
from sympy.core.sorting import ordered
|
||||
from sympy.core.symbol import Dummy
|
||||
from sympy.core.rules import Transform
|
||||
from sympy.core.logic import fuzzy_and, fuzzy_or, _torf
|
||||
from sympy.core.traversal import walk
|
||||
from sympy.core.numbers import Integer
|
||||
from sympy.logic.boolalg import And, Or
|
||||
|
||||
|
||||
def _minmax_as_Piecewise(op, *args):
|
||||
# helper for Min/Max rewrite as Piecewise
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
ec = []
|
||||
for i, a in enumerate(args):
|
||||
c = [Relational(a, args[j], op) for j in range(i + 1, len(args))]
|
||||
ec.append((a, And(*c)))
|
||||
return Piecewise(*ec)
|
||||
|
||||
|
||||
class IdentityFunction(Lambda, metaclass=Singleton):
|
||||
"""
|
||||
The identity function
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Id, Symbol
|
||||
>>> x = Symbol('x')
|
||||
>>> Id(x)
|
||||
x
|
||||
|
||||
"""
|
||||
|
||||
_symbol = Dummy('x')
|
||||
|
||||
@property
|
||||
def signature(self):
|
||||
return Tuple(self._symbol)
|
||||
|
||||
@property
|
||||
def expr(self):
|
||||
return self._symbol
|
||||
|
||||
|
||||
Id = S.IdentityFunction
|
||||
|
||||
###############################################################################
|
||||
############################# ROOT and SQUARE ROOT FUNCTION ###################
|
||||
###############################################################################
|
||||
|
||||
|
||||
def sqrt(arg, evaluate=None):
|
||||
"""Returns the principal square root.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
evaluate : bool, optional
|
||||
The parameter determines if the expression should be evaluated.
|
||||
If ``None``, its value is taken from
|
||||
``global_parameters.evaluate``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import sqrt, Symbol, S
|
||||
>>> x = Symbol('x')
|
||||
|
||||
>>> sqrt(x)
|
||||
sqrt(x)
|
||||
|
||||
>>> sqrt(x)**2
|
||||
x
|
||||
|
||||
Note that sqrt(x**2) does not simplify to x.
|
||||
|
||||
>>> sqrt(x**2)
|
||||
sqrt(x**2)
|
||||
|
||||
This is because the two are not equal to each other in general.
|
||||
For example, consider x == -1:
|
||||
|
||||
>>> from sympy import Eq
|
||||
>>> Eq(sqrt(x**2), x).subs(x, -1)
|
||||
False
|
||||
|
||||
This is because sqrt computes the principal square root, so the square may
|
||||
put the argument in a different branch. This identity does hold if x is
|
||||
positive:
|
||||
|
||||
>>> y = Symbol('y', positive=True)
|
||||
>>> sqrt(y**2)
|
||||
y
|
||||
|
||||
You can force this simplification by using the powdenest() function with
|
||||
the force option set to True:
|
||||
|
||||
>>> from sympy import powdenest
|
||||
>>> sqrt(x**2)
|
||||
sqrt(x**2)
|
||||
>>> powdenest(sqrt(x**2), force=True)
|
||||
x
|
||||
|
||||
To get both branches of the square root you can use the rootof function:
|
||||
|
||||
>>> from sympy import rootof
|
||||
|
||||
>>> [rootof(x**2-3,i) for i in (0,1)]
|
||||
[-sqrt(3), sqrt(3)]
|
||||
|
||||
Although ``sqrt`` is printed, there is no ``sqrt`` function so looking for
|
||||
``sqrt`` in an expression will fail:
|
||||
|
||||
>>> from sympy.utilities.misc import func_name
|
||||
>>> func_name(sqrt(x))
|
||||
'Pow'
|
||||
>>> sqrt(x).has(sqrt)
|
||||
False
|
||||
|
||||
To find ``sqrt`` look for ``Pow`` with an exponent of ``1/2``:
|
||||
|
||||
>>> (x + 1/sqrt(x)).find(lambda i: i.is_Pow and abs(i.exp) is S.Half)
|
||||
{1/sqrt(x)}
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.polys.rootoftools.rootof, root, real_root
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Square_root
|
||||
.. [2] https://en.wikipedia.org/wiki/Principal_value
|
||||
"""
|
||||
# arg = sympify(arg) is handled by Pow
|
||||
return Pow(arg, S.Half, evaluate=evaluate)
|
||||
|
||||
|
||||
def cbrt(arg, evaluate=None):
|
||||
"""Returns the principal cube root.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
evaluate : bool, optional
|
||||
The parameter determines if the expression should be evaluated.
|
||||
If ``None``, its value is taken from
|
||||
``global_parameters.evaluate``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import cbrt, Symbol
|
||||
>>> x = Symbol('x')
|
||||
|
||||
>>> cbrt(x)
|
||||
x**(1/3)
|
||||
|
||||
>>> cbrt(x)**3
|
||||
x
|
||||
|
||||
Note that cbrt(x**3) does not simplify to x.
|
||||
|
||||
>>> cbrt(x**3)
|
||||
(x**3)**(1/3)
|
||||
|
||||
This is because the two are not equal to each other in general.
|
||||
For example, consider `x == -1`:
|
||||
|
||||
>>> from sympy import Eq
|
||||
>>> Eq(cbrt(x**3), x).subs(x, -1)
|
||||
False
|
||||
|
||||
This is because cbrt computes the principal cube root, this
|
||||
identity does hold if `x` is positive:
|
||||
|
||||
>>> y = Symbol('y', positive=True)
|
||||
>>> cbrt(y**3)
|
||||
y
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.polys.rootoftools.rootof, root, real_root
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Cube_root
|
||||
.. [2] https://en.wikipedia.org/wiki/Principal_value
|
||||
|
||||
"""
|
||||
return Pow(arg, Rational(1, 3), evaluate=evaluate)
|
||||
|
||||
|
||||
def root(arg, n, k=0, evaluate=None):
|
||||
r"""Returns the *k*-th *n*-th root of ``arg``.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
k : int, optional
|
||||
Should be an integer in $\{0, 1, ..., n-1\}$.
|
||||
Defaults to the principal root if $0$.
|
||||
|
||||
evaluate : bool, optional
|
||||
The parameter determines if the expression should be evaluated.
|
||||
If ``None``, its value is taken from
|
||||
``global_parameters.evaluate``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import root, Rational
|
||||
>>> from sympy.abc import x, n
|
||||
|
||||
>>> root(x, 2)
|
||||
sqrt(x)
|
||||
|
||||
>>> root(x, 3)
|
||||
x**(1/3)
|
||||
|
||||
>>> root(x, n)
|
||||
x**(1/n)
|
||||
|
||||
>>> root(x, -Rational(2, 3))
|
||||
x**(-3/2)
|
||||
|
||||
To get the k-th n-th root, specify k:
|
||||
|
||||
>>> root(-2, 3, 2)
|
||||
-(-1)**(2/3)*2**(1/3)
|
||||
|
||||
To get all n n-th roots you can use the rootof function.
|
||||
The following examples show the roots of unity for n
|
||||
equal 2, 3 and 4:
|
||||
|
||||
>>> from sympy import rootof
|
||||
|
||||
>>> [rootof(x**2 - 1, i) for i in range(2)]
|
||||
[-1, 1]
|
||||
|
||||
>>> [rootof(x**3 - 1,i) for i in range(3)]
|
||||
[1, -1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2]
|
||||
|
||||
>>> [rootof(x**4 - 1,i) for i in range(4)]
|
||||
[-1, 1, -I, I]
|
||||
|
||||
SymPy, like other symbolic algebra systems, returns the
|
||||
complex root of negative numbers. This is the principal
|
||||
root and differs from the text-book result that one might
|
||||
be expecting. For example, the cube root of -8 does not
|
||||
come back as -2:
|
||||
|
||||
>>> root(-8, 3)
|
||||
2*(-1)**(1/3)
|
||||
|
||||
The real_root function can be used to either make the principal
|
||||
result real (or simply to return the real root directly):
|
||||
|
||||
>>> from sympy import real_root
|
||||
>>> real_root(_)
|
||||
-2
|
||||
>>> real_root(-32, 5)
|
||||
-2
|
||||
|
||||
Alternatively, the n//2-th n-th root of a negative number can be
|
||||
computed with root:
|
||||
|
||||
>>> root(-32, 5, 5//2)
|
||||
-2
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.polys.rootoftools.rootof
|
||||
sympy.core.intfunc.integer_nthroot
|
||||
sqrt, real_root
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Square_root
|
||||
.. [2] https://en.wikipedia.org/wiki/Real_root
|
||||
.. [3] https://en.wikipedia.org/wiki/Root_of_unity
|
||||
.. [4] https://en.wikipedia.org/wiki/Principal_value
|
||||
.. [5] https://mathworld.wolfram.com/CubeRoot.html
|
||||
|
||||
"""
|
||||
n = sympify(n)
|
||||
if k:
|
||||
return Mul(Pow(arg, S.One/n, evaluate=evaluate), S.NegativeOne**(2*k/n), evaluate=evaluate)
|
||||
return Pow(arg, 1/n, evaluate=evaluate)
|
||||
|
||||
|
||||
def real_root(arg, n=None, evaluate=None):
|
||||
r"""Return the real *n*'th-root of *arg* if possible.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : int or None, optional
|
||||
If *n* is ``None``, then all instances of
|
||||
$(-n)^{1/\text{odd}}$ will be changed to $-n^{1/\text{odd}}$.
|
||||
This will only create a real root of a principal root.
|
||||
The presence of other factors may cause the result to not be
|
||||
real.
|
||||
|
||||
evaluate : bool, optional
|
||||
The parameter determines if the expression should be evaluated.
|
||||
If ``None``, its value is taken from
|
||||
``global_parameters.evaluate``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import root, real_root
|
||||
|
||||
>>> real_root(-8, 3)
|
||||
-2
|
||||
>>> root(-8, 3)
|
||||
2*(-1)**(1/3)
|
||||
>>> real_root(_)
|
||||
-2
|
||||
|
||||
If one creates a non-principal root and applies real_root, the
|
||||
result will not be real (so use with caution):
|
||||
|
||||
>>> root(-8, 3, 2)
|
||||
-2*(-1)**(2/3)
|
||||
>>> real_root(_)
|
||||
-2*(-1)**(2/3)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.polys.rootoftools.rootof
|
||||
sympy.core.intfunc.integer_nthroot
|
||||
root, sqrt
|
||||
"""
|
||||
from sympy.functions.elementary.complexes import Abs, im, sign
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
if n is not None:
|
||||
return Piecewise(
|
||||
(root(arg, n, evaluate=evaluate), Or(Eq(n, S.One), Eq(n, S.NegativeOne))),
|
||||
(Mul(sign(arg), root(Abs(arg), n, evaluate=evaluate), evaluate=evaluate),
|
||||
And(Eq(im(arg), S.Zero), Eq(Mod(n, 2), S.One))),
|
||||
(root(arg, n, evaluate=evaluate), True))
|
||||
rv = sympify(arg)
|
||||
n1pow = Transform(lambda x: -(-x.base)**x.exp,
|
||||
lambda x:
|
||||
x.is_Pow and
|
||||
x.base.is_negative and
|
||||
x.exp.is_Rational and
|
||||
x.exp.p == 1 and x.exp.q % 2)
|
||||
return rv.xreplace(n1pow)
|
||||
|
||||
###############################################################################
|
||||
############################# MINIMUM and MAXIMUM #############################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class MinMaxBase(Expr, LatticeOp):
|
||||
def __new__(cls, *args, **assumptions):
|
||||
from sympy.core.parameters import global_parameters
|
||||
evaluate = assumptions.pop('evaluate', global_parameters.evaluate)
|
||||
args = (sympify(arg) for arg in args)
|
||||
|
||||
# first standard filter, for cls.zero and cls.identity
|
||||
# also reshape Max(a, Max(b, c)) to Max(a, b, c)
|
||||
|
||||
if evaluate:
|
||||
try:
|
||||
args = frozenset(cls._new_args_filter(args))
|
||||
except ShortCircuit:
|
||||
return cls.zero
|
||||
# remove redundant args that are easily identified
|
||||
args = cls._collapse_arguments(args, **assumptions)
|
||||
# find local zeros
|
||||
args = cls._find_localzeros(args, **assumptions)
|
||||
args = frozenset(args)
|
||||
|
||||
if not args:
|
||||
return cls.identity
|
||||
|
||||
if len(args) == 1:
|
||||
return list(args).pop()
|
||||
|
||||
# base creation
|
||||
obj = Expr.__new__(cls, *ordered(args), **assumptions)
|
||||
obj._argset = args
|
||||
return obj
|
||||
|
||||
@classmethod
|
||||
def _collapse_arguments(cls, args, **assumptions):
|
||||
"""Remove redundant args.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Min, Max
|
||||
>>> from sympy.abc import a, b, c, d, e
|
||||
|
||||
Any arg in parent that appears in any
|
||||
parent-like function in any of the flat args
|
||||
of parent can be removed from that sub-arg:
|
||||
|
||||
>>> Min(a, Max(b, Min(a, c, d)))
|
||||
Min(a, Max(b, Min(c, d)))
|
||||
|
||||
If the arg of parent appears in an opposite-than parent
|
||||
function in any of the flat args of parent that function
|
||||
can be replaced with the arg:
|
||||
|
||||
>>> Min(a, Max(b, Min(c, d, Max(a, e))))
|
||||
Min(a, Max(b, Min(a, c, d)))
|
||||
"""
|
||||
if not args:
|
||||
return args
|
||||
args = list(ordered(args))
|
||||
if cls == Min:
|
||||
other = Max
|
||||
else:
|
||||
other = Min
|
||||
|
||||
# find global comparable max of Max and min of Min if a new
|
||||
# value is being introduced in these args at position 0 of
|
||||
# the ordered args
|
||||
if args[0].is_number:
|
||||
sifted = mins, maxs = [], []
|
||||
for i in args:
|
||||
for v in walk(i, Min, Max):
|
||||
if v.args[0].is_comparable:
|
||||
sifted[isinstance(v, Max)].append(v)
|
||||
small = Min.identity
|
||||
for i in mins:
|
||||
v = i.args[0]
|
||||
if v.is_number and (v < small) == True:
|
||||
small = v
|
||||
big = Max.identity
|
||||
for i in maxs:
|
||||
v = i.args[0]
|
||||
if v.is_number and (v > big) == True:
|
||||
big = v
|
||||
# at the point when this function is called from __new__,
|
||||
# there may be more than one numeric arg present since
|
||||
# local zeros have not been handled yet, so look through
|
||||
# more than the first arg
|
||||
if cls == Min:
|
||||
for arg in args:
|
||||
if not arg.is_number:
|
||||
break
|
||||
if (arg < small) == True:
|
||||
small = arg
|
||||
elif cls == Max:
|
||||
for arg in args:
|
||||
if not arg.is_number:
|
||||
break
|
||||
if (arg > big) == True:
|
||||
big = arg
|
||||
T = None
|
||||
if cls == Min:
|
||||
if small != Min.identity:
|
||||
other = Max
|
||||
T = small
|
||||
elif big != Max.identity:
|
||||
other = Min
|
||||
T = big
|
||||
if T is not None:
|
||||
# remove numerical redundancy
|
||||
for i in range(len(args)):
|
||||
a = args[i]
|
||||
if isinstance(a, other):
|
||||
a0 = a.args[0]
|
||||
if ((a0 > T) if other == Max else (a0 < T)) == True:
|
||||
args[i] = cls.identity
|
||||
|
||||
# remove redundant symbolic args
|
||||
def do(ai, a):
|
||||
if not isinstance(ai, (Min, Max)):
|
||||
return ai
|
||||
cond = a in ai.args
|
||||
if not cond:
|
||||
return ai.func(*[do(i, a) for i in ai.args],
|
||||
evaluate=False)
|
||||
if isinstance(ai, cls):
|
||||
return ai.func(*[do(i, a) for i in ai.args if i != a],
|
||||
evaluate=False)
|
||||
return a
|
||||
for i, a in enumerate(args):
|
||||
args[i + 1:] = [do(ai, a) for ai in args[i + 1:]]
|
||||
|
||||
# factor out common elements as for
|
||||
# Min(Max(x, y), Max(x, z)) -> Max(x, Min(y, z))
|
||||
# and vice versa when swapping Min/Max -- do this only for the
|
||||
# easy case where all functions contain something in common;
|
||||
# trying to find some optimal subset of args to modify takes
|
||||
# too long
|
||||
|
||||
def factor_minmax(args):
|
||||
is_other = lambda arg: isinstance(arg, other)
|
||||
other_args, remaining_args = sift(args, is_other, binary=True)
|
||||
if not other_args:
|
||||
return args
|
||||
|
||||
# Min(Max(x, y, z), Max(x, y, u, v)) -> {x,y}, ({z}, {u,v})
|
||||
arg_sets = [set(arg.args) for arg in other_args]
|
||||
common = set.intersection(*arg_sets)
|
||||
if not common:
|
||||
return args
|
||||
|
||||
new_other_args = list(common)
|
||||
arg_sets_diff = [arg_set - common for arg_set in arg_sets]
|
||||
|
||||
# If any set is empty after removing common then all can be
|
||||
# discarded e.g. Min(Max(a, b, c), Max(a, b)) -> Max(a, b)
|
||||
if all(arg_sets_diff):
|
||||
other_args_diff = [other(*s, evaluate=False) for s in arg_sets_diff]
|
||||
new_other_args.append(cls(*other_args_diff, evaluate=False))
|
||||
|
||||
other_args_factored = other(*new_other_args, evaluate=False)
|
||||
return remaining_args + [other_args_factored]
|
||||
|
||||
if len(args) > 1:
|
||||
args = factor_minmax(args)
|
||||
|
||||
return args
|
||||
|
||||
@classmethod
|
||||
def _new_args_filter(cls, arg_sequence):
|
||||
"""
|
||||
Generator filtering args.
|
||||
|
||||
first standard filter, for cls.zero and cls.identity.
|
||||
Also reshape ``Max(a, Max(b, c))`` to ``Max(a, b, c)``,
|
||||
and check arguments for comparability
|
||||
"""
|
||||
for arg in arg_sequence:
|
||||
# pre-filter, checking comparability of arguments
|
||||
if not isinstance(arg, Expr) or arg.is_extended_real is False or (
|
||||
arg.is_number and
|
||||
not arg.is_comparable):
|
||||
raise ValueError("The argument '%s' is not comparable." % arg)
|
||||
|
||||
if arg == cls.zero:
|
||||
raise ShortCircuit(arg)
|
||||
elif arg == cls.identity:
|
||||
continue
|
||||
elif arg.func == cls:
|
||||
yield from arg.args
|
||||
else:
|
||||
yield arg
|
||||
|
||||
@classmethod
|
||||
def _find_localzeros(cls, values, **options):
|
||||
"""
|
||||
Sequentially allocate values to localzeros.
|
||||
|
||||
When a value is identified as being more extreme than another member it
|
||||
replaces that member; if this is never true, then the value is simply
|
||||
appended to the localzeros.
|
||||
"""
|
||||
localzeros = set()
|
||||
for v in values:
|
||||
is_newzero = True
|
||||
localzeros_ = list(localzeros)
|
||||
for z in localzeros_:
|
||||
if id(v) == id(z):
|
||||
is_newzero = False
|
||||
else:
|
||||
con = cls._is_connected(v, z)
|
||||
if con:
|
||||
is_newzero = False
|
||||
if con is True or con == cls:
|
||||
localzeros.remove(z)
|
||||
localzeros.update([v])
|
||||
if is_newzero:
|
||||
localzeros.update([v])
|
||||
return localzeros
|
||||
|
||||
@classmethod
|
||||
def _is_connected(cls, x, y):
|
||||
"""
|
||||
Check if x and y are connected somehow.
|
||||
"""
|
||||
for i in range(2):
|
||||
if x == y:
|
||||
return True
|
||||
t, f = Max, Min
|
||||
for op in "><":
|
||||
for j in range(2):
|
||||
try:
|
||||
if op == ">":
|
||||
v = x >= y
|
||||
else:
|
||||
v = x <= y
|
||||
except TypeError:
|
||||
return False # non-real arg
|
||||
if not v.is_Relational:
|
||||
return t if v else f
|
||||
t, f = f, t
|
||||
x, y = y, x
|
||||
x, y = y, x # run next pass with reversed order relative to start
|
||||
# simplification can be expensive, so be conservative
|
||||
# in what is attempted
|
||||
x = factor_terms(x - y)
|
||||
y = S.Zero
|
||||
|
||||
return False
|
||||
|
||||
def _eval_derivative(self, s):
|
||||
# f(x).diff(s) -> x.diff(s) * f.fdiff(1)(s)
|
||||
i = 0
|
||||
l = []
|
||||
for a in self.args:
|
||||
i += 1
|
||||
da = a.diff(s)
|
||||
if da.is_zero:
|
||||
continue
|
||||
try:
|
||||
df = self.fdiff(i)
|
||||
except ArgumentIndexError:
|
||||
df = super().fdiff(i)
|
||||
l.append(df * da)
|
||||
return Add(*l)
|
||||
|
||||
def _eval_rewrite_as_Abs(self, *args, **kwargs):
|
||||
from sympy.functions.elementary.complexes import Abs
|
||||
s = (args[0] + self.func(*args[1:]))/2
|
||||
d = abs(args[0] - self.func(*args[1:]))/2
|
||||
return (s + d if isinstance(self, Max) else s - d).rewrite(Abs)
|
||||
|
||||
def evalf(self, n=15, **options):
|
||||
return self.func(*[a.evalf(n, **options) for a in self.args])
|
||||
|
||||
def n(self, *args, **kwargs):
|
||||
return self.evalf(*args, **kwargs)
|
||||
|
||||
_eval_is_algebraic = lambda s: _torf(i.is_algebraic for i in s.args)
|
||||
_eval_is_antihermitian = lambda s: _torf(i.is_antihermitian for i in s.args)
|
||||
_eval_is_commutative = lambda s: _torf(i.is_commutative for i in s.args)
|
||||
_eval_is_complex = lambda s: _torf(i.is_complex for i in s.args)
|
||||
_eval_is_composite = lambda s: _torf(i.is_composite for i in s.args)
|
||||
_eval_is_even = lambda s: _torf(i.is_even for i in s.args)
|
||||
_eval_is_finite = lambda s: _torf(i.is_finite for i in s.args)
|
||||
_eval_is_hermitian = lambda s: _torf(i.is_hermitian for i in s.args)
|
||||
_eval_is_imaginary = lambda s: _torf(i.is_imaginary for i in s.args)
|
||||
_eval_is_infinite = lambda s: _torf(i.is_infinite for i in s.args)
|
||||
_eval_is_integer = lambda s: _torf(i.is_integer for i in s.args)
|
||||
_eval_is_irrational = lambda s: _torf(i.is_irrational for i in s.args)
|
||||
_eval_is_negative = lambda s: _torf(i.is_negative for i in s.args)
|
||||
_eval_is_noninteger = lambda s: _torf(i.is_noninteger for i in s.args)
|
||||
_eval_is_nonnegative = lambda s: _torf(i.is_nonnegative for i in s.args)
|
||||
_eval_is_nonpositive = lambda s: _torf(i.is_nonpositive for i in s.args)
|
||||
_eval_is_nonzero = lambda s: _torf(i.is_nonzero for i in s.args)
|
||||
_eval_is_odd = lambda s: _torf(i.is_odd for i in s.args)
|
||||
_eval_is_polar = lambda s: _torf(i.is_polar for i in s.args)
|
||||
_eval_is_positive = lambda s: _torf(i.is_positive for i in s.args)
|
||||
_eval_is_prime = lambda s: _torf(i.is_prime for i in s.args)
|
||||
_eval_is_rational = lambda s: _torf(i.is_rational for i in s.args)
|
||||
_eval_is_real = lambda s: _torf(i.is_real for i in s.args)
|
||||
_eval_is_extended_real = lambda s: _torf(i.is_extended_real for i in s.args)
|
||||
_eval_is_transcendental = lambda s: _torf(i.is_transcendental for i in s.args)
|
||||
_eval_is_zero = lambda s: _torf(i.is_zero for i in s.args)
|
||||
|
||||
|
||||
class Max(MinMaxBase, Application):
|
||||
r"""
|
||||
Return, if possible, the maximum value of the list.
|
||||
|
||||
When number of arguments is equal one, then
|
||||
return this argument.
|
||||
|
||||
When number of arguments is equal two, then
|
||||
return, if possible, the value from (a, b) that is $\ge$ the other.
|
||||
|
||||
In common case, when the length of list greater than 2, the task
|
||||
is more complicated. Return only the arguments, which are greater
|
||||
than others, if it is possible to determine directional relation.
|
||||
|
||||
If is not possible to determine such a relation, return a partially
|
||||
evaluated result.
|
||||
|
||||
Assumptions are used to make the decision too.
|
||||
|
||||
Also, only comparable arguments are permitted.
|
||||
|
||||
It is named ``Max`` and not ``max`` to avoid conflicts
|
||||
with the built-in function ``max``.
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Max, Symbol, oo
|
||||
>>> from sympy.abc import x, y, z
|
||||
>>> p = Symbol('p', positive=True)
|
||||
>>> n = Symbol('n', negative=True)
|
||||
|
||||
>>> Max(x, -2)
|
||||
Max(-2, x)
|
||||
>>> Max(x, -2).subs(x, 3)
|
||||
3
|
||||
>>> Max(p, -2)
|
||||
p
|
||||
>>> Max(x, y)
|
||||
Max(x, y)
|
||||
>>> Max(x, y) == Max(y, x)
|
||||
True
|
||||
>>> Max(x, Max(y, z))
|
||||
Max(x, y, z)
|
||||
>>> Max(n, 8, p, 7, -oo)
|
||||
Max(8, p)
|
||||
>>> Max (1, x, oo)
|
||||
oo
|
||||
|
||||
* Algorithm
|
||||
|
||||
The task can be considered as searching of supremums in the
|
||||
directed complete partial orders [1]_.
|
||||
|
||||
The source values are sequentially allocated by the isolated subsets
|
||||
in which supremums are searched and result as Max arguments.
|
||||
|
||||
If the resulted supremum is single, then it is returned.
|
||||
|
||||
The isolated subsets are the sets of values which are only the comparable
|
||||
with each other in the current set. E.g. natural numbers are comparable with
|
||||
each other, but not comparable with the `x` symbol. Another example: the
|
||||
symbol `x` with negative assumption is comparable with a natural number.
|
||||
|
||||
Also there are "least" elements, which are comparable with all others,
|
||||
and have a zero property (maximum or minimum for all elements).
|
||||
For example, in case of $\infty$, the allocation operation is terminated
|
||||
and only this value is returned.
|
||||
|
||||
Assumption:
|
||||
- if $A > B > C$ then $A > C$
|
||||
- if $A = B$ then $B$ can be removed
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Directed_complete_partial_order
|
||||
.. [2] https://en.wikipedia.org/wiki/Lattice_%28order%29
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Min : find minimum values
|
||||
"""
|
||||
zero = S.Infinity
|
||||
identity = S.NegativeInfinity
|
||||
|
||||
def fdiff( self, argindex ):
|
||||
from sympy.functions.special.delta_functions import Heaviside
|
||||
n = len(self.args)
|
||||
if 0 < argindex and argindex <= n:
|
||||
argindex -= 1
|
||||
if n == 2:
|
||||
return Heaviside(self.args[argindex] - self.args[1 - argindex])
|
||||
newargs = tuple([self.args[i] for i in range(n) if i != argindex])
|
||||
return Heaviside(self.args[argindex] - Max(*newargs))
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
|
||||
from sympy.functions.special.delta_functions import Heaviside
|
||||
return Add(*[j*Mul(*[Heaviside(j - i) for i in args if i!=j]) \
|
||||
for j in args])
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
|
||||
return _minmax_as_Piecewise('>=', *args)
|
||||
|
||||
def _eval_is_positive(self):
|
||||
return fuzzy_or(a.is_positive for a in self.args)
|
||||
|
||||
def _eval_is_nonnegative(self):
|
||||
return fuzzy_or(a.is_nonnegative for a in self.args)
|
||||
|
||||
def _eval_is_negative(self):
|
||||
return fuzzy_and(a.is_negative for a in self.args)
|
||||
|
||||
|
||||
class Min(MinMaxBase, Application):
|
||||
"""
|
||||
Return, if possible, the minimum value of the list.
|
||||
It is named ``Min`` and not ``min`` to avoid conflicts
|
||||
with the built-in function ``min``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Min, Symbol, oo
|
||||
>>> from sympy.abc import x, y
|
||||
>>> p = Symbol('p', positive=True)
|
||||
>>> n = Symbol('n', negative=True)
|
||||
|
||||
>>> Min(x, -2)
|
||||
Min(-2, x)
|
||||
>>> Min(x, -2).subs(x, 3)
|
||||
-2
|
||||
>>> Min(p, -3)
|
||||
-3
|
||||
>>> Min(x, y)
|
||||
Min(x, y)
|
||||
>>> Min(n, 8, p, -7, p, oo)
|
||||
Min(-7, n)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Max : find maximum values
|
||||
"""
|
||||
zero = S.NegativeInfinity
|
||||
identity = S.Infinity
|
||||
|
||||
def fdiff( self, argindex ):
|
||||
from sympy.functions.special.delta_functions import Heaviside
|
||||
n = len(self.args)
|
||||
if 0 < argindex and argindex <= n:
|
||||
argindex -= 1
|
||||
if n == 2:
|
||||
return Heaviside( self.args[1-argindex] - self.args[argindex] )
|
||||
newargs = tuple([ self.args[i] for i in range(n) if i != argindex])
|
||||
return Heaviside( Min(*newargs) - self.args[argindex] )
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
|
||||
from sympy.functions.special.delta_functions import Heaviside
|
||||
return Add(*[j*Mul(*[Heaviside(i-j) for i in args if i!=j]) \
|
||||
for j in args])
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
|
||||
return _minmax_as_Piecewise('<=', *args)
|
||||
|
||||
def _eval_is_positive(self):
|
||||
return fuzzy_and(a.is_positive for a in self.args)
|
||||
|
||||
def _eval_is_nonnegative(self):
|
||||
return fuzzy_and(a.is_nonnegative for a in self.args)
|
||||
|
||||
def _eval_is_negative(self):
|
||||
return fuzzy_or(a.is_negative for a in self.args)
|
||||
|
||||
|
||||
class Rem(DefinedFunction):
|
||||
"""Returns the remainder when ``p`` is divided by ``q`` where ``p`` is finite
|
||||
and ``q`` is not equal to zero. The result, ``p - int(p/q)*q``, has the same sign
|
||||
as the divisor.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
p : Expr
|
||||
Dividend.
|
||||
|
||||
q : Expr
|
||||
Divisor.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
``Rem`` corresponds to the ``%`` operator in C.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.abc import x, y
|
||||
>>> from sympy import Rem
|
||||
>>> Rem(x**3, y)
|
||||
Rem(x**3, y)
|
||||
>>> Rem(x**3, y).subs({x: -5, y: 3})
|
||||
-2
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Mod
|
||||
"""
|
||||
kind = NumberKind
|
||||
|
||||
@classmethod
|
||||
def eval(cls, p, q):
|
||||
"""Return the function remainder if both p, q are numbers and q is not
|
||||
zero.
|
||||
"""
|
||||
|
||||
if q.is_zero:
|
||||
raise ZeroDivisionError("Division by zero")
|
||||
if p is S.NaN or q is S.NaN or p.is_finite is False or q.is_finite is False:
|
||||
return S.NaN
|
||||
if p is S.Zero or p in (q, -q) or (p.is_integer and q == 1):
|
||||
return S.Zero
|
||||
|
||||
if q.is_Number:
|
||||
if p.is_Number:
|
||||
return p - Integer(p/q)*q
|
||||
File diff suppressed because it is too large
Load Diff
+1030
File diff suppressed because it is too large
Load Diff
+810
@@ -0,0 +1,810 @@
|
||||
from sympy.assumptions.refine import refine
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
from sympy.concrete.products import Product
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.function import expand_log
|
||||
from sympy.core.numbers import (E, Float, I, Rational, nan, oo, pi, zoo)
|
||||
from sympy.core.power import Pow
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.elementary.complexes import (adjoint, conjugate, re, sign, transpose)
|
||||
from sympy.functions.elementary.exponential import (LambertW, exp, exp_polar, log)
|
||||
from sympy.functions.elementary.hyperbolic import (cosh, sinh, tanh)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin, tan)
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.polys.polytools import gcd
|
||||
from sympy.series.order import O
|
||||
from sympy.simplify.simplify import simplify
|
||||
from sympy.core.parameters import global_parameters
|
||||
from sympy.functions.elementary.exponential import match_real_imag
|
||||
from sympy.abc import x, y, z
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.testing.pytest import raises, XFAIL, _both_exp_pow
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_values():
|
||||
if global_parameters.exp_is_pow:
|
||||
assert type(exp(x)) is Pow
|
||||
else:
|
||||
assert type(exp(x)) is exp
|
||||
|
||||
k = Symbol('k', integer=True)
|
||||
|
||||
assert exp(nan) is nan
|
||||
|
||||
assert exp(oo) is oo
|
||||
assert exp(-oo) == 0
|
||||
|
||||
assert exp(0) == 1
|
||||
assert exp(1) == E
|
||||
assert exp(-1 + x).as_base_exp() == (S.Exp1, x - 1)
|
||||
assert exp(1 + x).as_base_exp() == (S.Exp1, x + 1)
|
||||
|
||||
assert exp(pi*I/2) == I
|
||||
assert exp(pi*I) == -1
|
||||
assert exp(pi*I*Rational(3, 2)) == -I
|
||||
assert exp(2*pi*I) == 1
|
||||
|
||||
assert refine(exp(pi*I*2*k)) == 1
|
||||
assert refine(exp(pi*I*2*(k + S.Half))) == -1
|
||||
assert refine(exp(pi*I*2*(k + Rational(1, 4)))) == I
|
||||
assert refine(exp(pi*I*2*(k + Rational(3, 4)))) == -I
|
||||
|
||||
assert exp(log(x)) == x
|
||||
assert exp(2*log(x)) == x**2
|
||||
assert exp(pi*log(x)) == x**pi
|
||||
|
||||
assert exp(17*log(x) + E*log(y)) == x**17 * y**E
|
||||
|
||||
assert exp(x*log(x)) != x**x
|
||||
assert exp(sin(x)*log(x)) != x
|
||||
|
||||
assert exp(3*log(x) + oo*x) == exp(oo*x) * x**3
|
||||
assert exp(4*log(x)*log(y) + 3*log(x)) == x**3 * exp(4*log(x)*log(y))
|
||||
|
||||
assert exp(-oo, evaluate=False).is_finite is True
|
||||
assert exp(oo, evaluate=False).is_finite is False
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_period():
|
||||
assert exp(I*pi*Rational(9, 4)) == exp(I*pi/4)
|
||||
assert exp(I*pi*Rational(46, 18)) == exp(I*pi*Rational(5, 9))
|
||||
assert exp(I*pi*Rational(25, 7)) == exp(I*pi*Rational(-3, 7))
|
||||
assert exp(I*pi*Rational(-19, 3)) == exp(-I*pi/3)
|
||||
assert exp(I*pi*Rational(37, 8)) - exp(I*pi*Rational(-11, 8)) == 0
|
||||
assert exp(I*pi*Rational(-5, 3)) / exp(I*pi*Rational(11, 5)) * exp(I*pi*Rational(148, 15)) == 1
|
||||
|
||||
assert exp(2 - I*pi*Rational(17, 5)) == exp(2 + I*pi*Rational(3, 5))
|
||||
assert exp(log(3) + I*pi*Rational(29, 9)) == 3 * exp(I*pi*Rational(-7, 9))
|
||||
|
||||
n = Symbol('n', integer=True)
|
||||
e = Symbol('e', even=True)
|
||||
assert exp(e*I*pi) == 1
|
||||
assert exp((e + 1)*I*pi) == -1
|
||||
assert exp((1 + 4*n)*I*pi/2) == I
|
||||
assert exp((-1 + 4*n)*I*pi/2) == -I
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_log():
|
||||
x = Symbol("x", real=True)
|
||||
assert log(exp(x)) == x
|
||||
assert exp(log(x)) == x
|
||||
|
||||
if not global_parameters.exp_is_pow:
|
||||
assert log(x).inverse() == exp
|
||||
assert exp(x).inverse() == log
|
||||
|
||||
y = Symbol("y", polar=True)
|
||||
assert log(exp_polar(z)) == z
|
||||
assert exp(log(y)) == y
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_expand():
|
||||
e = exp(log(Rational(2))*(1 + x) - log(Rational(2))*x)
|
||||
assert e.expand() == 2
|
||||
assert exp(x + y) != exp(x)*exp(y)
|
||||
assert exp(x + y).expand() == exp(x)*exp(y)
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp__as_base_exp():
|
||||
assert exp(x).as_base_exp() == (E, x)
|
||||
assert exp(2*x).as_base_exp() == (E, 2*x)
|
||||
assert exp(x*y).as_base_exp() == (E, x*y)
|
||||
assert exp(-x).as_base_exp() == (E, -x)
|
||||
|
||||
# Pow( *expr.as_base_exp() ) == expr invariant should hold
|
||||
assert E**x == exp(x)
|
||||
assert E**(2*x) == exp(2*x)
|
||||
assert E**(x*y) == exp(x*y)
|
||||
|
||||
assert exp(x).base is S.Exp1
|
||||
assert exp(x).exp == x
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_infinity():
|
||||
assert exp(I*y) != nan
|
||||
assert refine(exp(I*oo)) is nan
|
||||
assert refine(exp(-I*oo)) is nan
|
||||
assert exp(y*I*oo) != nan
|
||||
assert exp(zoo) is nan
|
||||
x = Symbol('x', extended_real=True, finite=False)
|
||||
assert exp(x).is_complex is None
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_subs():
|
||||
x = Symbol('x')
|
||||
e = (exp(3*log(x), evaluate=False)) # evaluates to x**3
|
||||
assert e.subs(x**3, y**3) == e
|
||||
assert e.subs(x**2, 5) == e
|
||||
assert (x**3).subs(x**2, y) != y**Rational(3, 2)
|
||||
assert exp(exp(x) + exp(x**2)).subs(exp(exp(x)), y) == y * exp(exp(x**2))
|
||||
assert exp(x).subs(E, y) == y**x
|
||||
x = symbols('x', real=True)
|
||||
assert exp(5*x).subs(exp(7*x), y) == y**Rational(5, 7)
|
||||
assert exp(2*x + 7).subs(exp(3*x), y) == y**Rational(2, 3) * exp(7)
|
||||
x = symbols('x', positive=True)
|
||||
assert exp(3*log(x)).subs(x**2, y) == y**Rational(3, 2)
|
||||
# differentiate between E and exp
|
||||
assert exp(exp(x + E)).subs(exp, 3) == 3**(3**(x + E))
|
||||
assert exp(exp(x + E)).subs(exp, sin) == sin(sin(x + E))
|
||||
assert exp(exp(x + E)).subs(E, 3) == 3**(3**(x + 3))
|
||||
assert exp(3).subs(E, sin) == sin(3)
|
||||
|
||||
|
||||
def test_exp_adjoint():
|
||||
x = Symbol('x', commutative=False)
|
||||
assert adjoint(exp(x)) == exp(adjoint(x))
|
||||
|
||||
|
||||
def test_exp_conjugate():
|
||||
assert conjugate(exp(x)) == exp(conjugate(x))
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_transpose():
|
||||
assert transpose(exp(x)) == exp(transpose(x))
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_rewrite():
|
||||
assert exp(x).rewrite(sin) == sinh(x) + cosh(x)
|
||||
assert exp(x*I).rewrite(cos) == cos(x) + I*sin(x)
|
||||
assert exp(1).rewrite(cos) == sinh(1) + cosh(1)
|
||||
assert exp(1).rewrite(sin) == sinh(1) + cosh(1)
|
||||
assert exp(1).rewrite(sin) == sinh(1) + cosh(1)
|
||||
assert exp(x).rewrite(tanh) == (1 + tanh(x/2))/(1 - tanh(x/2))
|
||||
assert exp(pi*I/4).rewrite(sqrt) == sqrt(2)/2 + sqrt(2)*I/2
|
||||
assert exp(pi*I/3).rewrite(sqrt) == S.Half + sqrt(3)*I/2
|
||||
if not global_parameters.exp_is_pow:
|
||||
assert exp(x*log(y)).rewrite(Pow) == y**x
|
||||
assert exp(log(x)*log(y)).rewrite(Pow) in [x**log(y), y**log(x)]
|
||||
assert exp(log(log(x))*y).rewrite(Pow) == log(x)**y
|
||||
|
||||
n = Symbol('n', integer=True)
|
||||
|
||||
assert Sum((exp(pi*I/2)/2)**n, (n, 0, oo)).rewrite(sqrt).doit() == Rational(4, 5) + I*2/5
|
||||
assert Sum((exp(pi*I/4)/2)**n, (n, 0, oo)).rewrite(sqrt).doit() == 1/(1 - sqrt(2)*(1 + I)/4)
|
||||
assert (Sum((exp(pi*I/3)/2)**n, (n, 0, oo)).rewrite(sqrt).doit().cancel()
|
||||
== 4*I/(sqrt(3) + 3*I))
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_leading_term():
|
||||
assert exp(x).as_leading_term(x) == 1
|
||||
assert exp(2 + x).as_leading_term(x) == exp(2)
|
||||
assert exp((2*x + 3) / (x+1)).as_leading_term(x) == exp(3)
|
||||
|
||||
# The following tests are commented, since now SymPy returns the
|
||||
# original function when the leading term in the series expansion does
|
||||
# not exist.
|
||||
# raises(NotImplementedError, lambda: exp(1/x).as_leading_term(x))
|
||||
# raises(NotImplementedError, lambda: exp((x + 1) / x**2).as_leading_term(x))
|
||||
# raises(NotImplementedError, lambda: exp(x + 1/x).as_leading_term(x))
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_taylor_term():
|
||||
x = symbols('x')
|
||||
assert exp(x).taylor_term(1, x) == x
|
||||
assert exp(x).taylor_term(3, x) == x**3/6
|
||||
assert exp(x).taylor_term(4, x) == x**4/24
|
||||
assert exp(x).taylor_term(-1, x) is S.Zero
|
||||
|
||||
|
||||
def test_exp_MatrixSymbol():
|
||||
A = MatrixSymbol("A", 2, 2)
|
||||
assert exp(A).has(exp)
|
||||
|
||||
|
||||
def test_exp_fdiff():
|
||||
x = Symbol('x')
|
||||
raises(ArgumentIndexError, lambda: exp(x).fdiff(2))
|
||||
|
||||
|
||||
def test_log_values():
|
||||
assert log(nan) is nan
|
||||
|
||||
assert log(oo) is oo
|
||||
assert log(-oo) is oo
|
||||
|
||||
assert log(zoo) is zoo
|
||||
assert log(-zoo) is zoo
|
||||
|
||||
assert log(0) is zoo
|
||||
|
||||
assert log(1) == 0
|
||||
assert log(-1) == I*pi
|
||||
|
||||
assert log(E) == 1
|
||||
assert log(-E).expand() == 1 + I*pi
|
||||
|
||||
assert unchanged(log, pi)
|
||||
assert log(-pi).expand() == log(pi) + I*pi
|
||||
|
||||
assert unchanged(log, 17)
|
||||
assert log(-17) == log(17) + I*pi
|
||||
|
||||
assert log(I) == I*pi/2
|
||||
assert log(-I) == -I*pi/2
|
||||
|
||||
assert log(17*I) == I*pi/2 + log(17)
|
||||
assert log(-17*I).expand() == -I*pi/2 + log(17)
|
||||
|
||||
assert log(oo*I) is oo
|
||||
assert log(-oo*I) is oo
|
||||
assert log(0, 2) is zoo
|
||||
assert log(0, 5) is zoo
|
||||
|
||||
assert exp(-log(3))**(-1) == 3
|
||||
|
||||
assert log(S.Half) == -log(2)
|
||||
assert log(2*3).func is log
|
||||
assert log(2*3**2).func is log
|
||||
|
||||
|
||||
def test_match_real_imag():
|
||||
x, y = symbols('x,y', real=True)
|
||||
i = Symbol('i', imaginary=True)
|
||||
assert match_real_imag(S.One) == (1, 0)
|
||||
assert match_real_imag(I) == (0, 1)
|
||||
assert match_real_imag(3 - 5*I) == (3, -5)
|
||||
assert match_real_imag(-sqrt(3) + S.Half*I) == (-sqrt(3), S.Half)
|
||||
assert match_real_imag(x + y*I) == (x, y)
|
||||
assert match_real_imag(x*I + y*I) == (0, x + y)
|
||||
assert match_real_imag((x + y)*I) == (0, x + y)
|
||||
assert match_real_imag(Rational(-2, 3)*i*I) == (None, None)
|
||||
assert match_real_imag(1 - 2*i) == (None, None)
|
||||
assert match_real_imag(sqrt(2)*(3 - 5*I)) == (None, None)
|
||||
|
||||
|
||||
def test_log_exact():
|
||||
# check for pi/2, pi/3, pi/4, pi/6, pi/8, pi/12; pi/5, pi/10:
|
||||
for n in range(-23, 24):
|
||||
if gcd(n, 24) != 1:
|
||||
assert log(exp(n*I*pi/24).rewrite(sqrt)) == n*I*pi/24
|
||||
for n in range(-9, 10):
|
||||
assert log(exp(n*I*pi/10).rewrite(sqrt)) == n*I*pi/10
|
||||
|
||||
assert log(S.Half - I*sqrt(3)/2) == -I*pi/3
|
||||
assert log(Rational(-1, 2) + I*sqrt(3)/2) == I*pi*Rational(2, 3)
|
||||
assert log(-sqrt(2)/2 - I*sqrt(2)/2) == -I*pi*Rational(3, 4)
|
||||
assert log(-sqrt(3)/2 - I*S.Half) == -I*pi*Rational(5, 6)
|
||||
|
||||
assert log(Rational(-1, 4) + sqrt(5)/4 - I*sqrt(sqrt(5)/8 + Rational(5, 8))) == -I*pi*Rational(2, 5)
|
||||
assert log(sqrt(Rational(5, 8) - sqrt(5)/8) + I*(Rational(1, 4) + sqrt(5)/4)) == I*pi*Rational(3, 10)
|
||||
assert log(-sqrt(sqrt(2)/4 + S.Half) + I*sqrt(S.Half - sqrt(2)/4)) == I*pi*Rational(7, 8)
|
||||
assert log(-sqrt(6)/4 - sqrt(2)/4 + I*(-sqrt(6)/4 + sqrt(2)/4)) == -I*pi*Rational(11, 12)
|
||||
|
||||
assert log(-1 + I*sqrt(3)) == log(2) + I*pi*Rational(2, 3)
|
||||
assert log(5 + 5*I) == log(5*sqrt(2)) + I*pi/4
|
||||
assert log(sqrt(-12)) == log(2*sqrt(3)) + I*pi/2
|
||||
assert log(-sqrt(6) + sqrt(2) - I*sqrt(6) - I*sqrt(2)) == log(4) - I*pi*Rational(7, 12)
|
||||
assert log(-sqrt(6-3*sqrt(2)) - I*sqrt(6+3*sqrt(2))) == log(2*sqrt(3)) - I*pi*Rational(5, 8)
|
||||
assert log(1 + I*sqrt(2-sqrt(2))/sqrt(2+sqrt(2))) == log(2/sqrt(sqrt(2) + 2)) + I*pi/8
|
||||
assert log(cos(pi*Rational(7, 12)) + I*sin(pi*Rational(7, 12))) == I*pi*Rational(7, 12)
|
||||
assert log(cos(pi*Rational(6, 5)) + I*sin(pi*Rational(6, 5))) == I*pi*Rational(-4, 5)
|
||||
|
||||
assert log(5*(1 + I)/sqrt(2)) == log(5) + I*pi/4
|
||||
assert log(sqrt(2)*(-sqrt(3) + 1 - sqrt(3)*I - I)) == log(4) - I*pi*Rational(7, 12)
|
||||
assert log(-sqrt(2)*(1 - I*sqrt(3))) == log(2*sqrt(2)) + I*pi*Rational(2, 3)
|
||||
assert log(sqrt(3)*I*(-sqrt(6 - 3*sqrt(2)) - I*sqrt(3*sqrt(2) + 6))) == log(6) - I*pi/8
|
||||
|
||||
zero = (1 + sqrt(2))**2 - 3 - 2*sqrt(2)
|
||||
assert log(zero - I*sqrt(3)) == log(sqrt(3)) - I*pi/2
|
||||
assert unchanged(log, zero + I*zero) or log(zero + zero*I) is zoo
|
||||
|
||||
# bail quickly if no obvious simplification is possible:
|
||||
assert unchanged(log, (sqrt(2)-1/sqrt(sqrt(3)+I))**1000)
|
||||
# beware of non-real coefficients
|
||||
assert unchanged(log, sqrt(2-sqrt(5))*(1 + I))
|
||||
|
||||
|
||||
def test_log_base():
|
||||
assert log(1, 2) == 0
|
||||
assert log(2, 2) == 1
|
||||
assert log(3, 2) == log(3)/log(2)
|
||||
assert log(6, 2) == 1 + log(3)/log(2)
|
||||
assert log(6, 3) == 1 + log(2)/log(3)
|
||||
assert log(2**3, 2) == 3
|
||||
assert log(3**3, 3) == 3
|
||||
assert log(5, 1) is zoo
|
||||
assert log(1, 1) is nan
|
||||
assert log(Rational(2, 3), 10) == log(Rational(2, 3))/log(10)
|
||||
assert log(Rational(2, 3), Rational(1, 3)) == -log(2)/log(3) + 1
|
||||
assert log(Rational(2, 3), Rational(2, 5)) == \
|
||||
log(Rational(2, 3))/log(Rational(2, 5))
|
||||
# issue 17148
|
||||
assert log(Rational(8, 3), 2) == -log(3)/log(2) + 3
|
||||
|
||||
|
||||
def test_log_symbolic():
|
||||
assert log(x, exp(1)) == log(x)
|
||||
assert log(exp(x)) != x
|
||||
|
||||
assert log(x, exp(1)) == log(x)
|
||||
assert log(x*y) != log(x) + log(y)
|
||||
assert log(x/y).expand() != log(x) - log(y)
|
||||
assert log(x/y).expand(force=True) == log(x) - log(y)
|
||||
assert log(x**y).expand() != y*log(x)
|
||||
assert log(x**y).expand(force=True) == y*log(x)
|
||||
|
||||
assert log(x, 2) == log(x)/log(2)
|
||||
assert log(E, 2) == 1/log(2)
|
||||
|
||||
p, q = symbols('p,q', positive=True)
|
||||
r = Symbol('r', real=True)
|
||||
|
||||
assert log(p**2) != 2*log(p)
|
||||
assert log(p**2).expand() == 2*log(p)
|
||||
assert log(x**2).expand() != 2*log(x)
|
||||
assert log(p**q) != q*log(p)
|
||||
assert log(exp(p)) == p
|
||||
assert log(p*q) != log(p) + log(q)
|
||||
assert log(p*q).expand() == log(p) + log(q)
|
||||
|
||||
assert log(-sqrt(3)) == log(sqrt(3)) + I*pi
|
||||
assert log(-exp(p)) != p + I*pi
|
||||
assert log(-exp(x)).expand() != x + I*pi
|
||||
assert log(-exp(r)).expand() == r + I*pi
|
||||
|
||||
assert log(x**y) != y*log(x)
|
||||
|
||||
assert (log(x**-5)**-1).expand() != -1/log(x)/5
|
||||
assert (log(p**-5)**-1).expand() == -1/log(p)/5
|
||||
assert log(-x).func is log and log(-x).args[0] == -x
|
||||
assert log(-p).func is log and log(-p).args[0] == -p
|
||||
|
||||
|
||||
def test_log_exp():
|
||||
assert log(exp(4*I*pi)) == 0 # exp evaluates
|
||||
assert log(exp(-5*I*pi)) == I*pi # exp evaluates
|
||||
assert log(exp(I*pi*Rational(19, 4))) == I*pi*Rational(3, 4)
|
||||
assert log(exp(I*pi*Rational(25, 7))) == I*pi*Rational(-3, 7)
|
||||
assert log(exp(-5*I)) == -5*I + 2*I*pi
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_assumptions():
|
||||
r = Symbol('r', real=True)
|
||||
i = Symbol('i', imaginary=True)
|
||||
for e in exp, exp_polar:
|
||||
assert e(x).is_real is None
|
||||
assert e(x).is_imaginary is None
|
||||
assert e(i).is_real is None
|
||||
assert e(i).is_imaginary is None
|
||||
assert e(r).is_real is True
|
||||
assert e(r).is_imaginary is False
|
||||
assert e(re(x)).is_extended_real is True
|
||||
assert e(re(x)).is_imaginary is False
|
||||
|
||||
assert Pow(E, I*pi, evaluate=False).is_imaginary == False
|
||||
assert Pow(E, 2*I*pi, evaluate=False).is_imaginary == False
|
||||
assert Pow(E, I*pi/2, evaluate=False).is_imaginary == True
|
||||
assert Pow(E, I*pi/3, evaluate=False).is_imaginary is None
|
||||
|
||||
assert exp(0, evaluate=False).is_algebraic
|
||||
|
||||
a = Symbol('a', algebraic=True)
|
||||
an = Symbol('an', algebraic=True, nonzero=True)
|
||||
r = Symbol('r', rational=True)
|
||||
rn = Symbol('rn', rational=True, nonzero=True)
|
||||
assert exp(a).is_algebraic is None
|
||||
assert exp(an).is_algebraic is False
|
||||
assert exp(pi*r).is_algebraic is None
|
||||
assert exp(pi*rn).is_algebraic is False
|
||||
|
||||
assert exp(0, evaluate=False).is_algebraic is True
|
||||
assert exp(I*pi/3, evaluate=False).is_algebraic is True
|
||||
assert exp(I*pi*r, evaluate=False).is_algebraic is True
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_exp_AccumBounds():
|
||||
assert exp(AccumBounds(1, 2)) == AccumBounds(E, E**2)
|
||||
|
||||
|
||||
def test_log_assumptions():
|
||||
p = symbols('p', positive=True)
|
||||
n = symbols('n', negative=True)
|
||||
z = symbols('z', zero=True)
|
||||
x = symbols('x', infinite=True, extended_positive=True)
|
||||
|
||||
assert log(z).is_positive is False
|
||||
assert log(x).is_extended_positive is True
|
||||
assert log(2) > 0
|
||||
assert log(1, evaluate=False).is_zero
|
||||
assert log(1 + z).is_zero
|
||||
assert log(p).is_zero is None
|
||||
assert log(n).is_zero is False
|
||||
assert log(0.5).is_negative is True
|
||||
assert log(exp(p) + 1).is_positive
|
||||
|
||||
assert log(1, evaluate=False).is_algebraic
|
||||
assert log(42, evaluate=False).is_algebraic is False
|
||||
|
||||
assert log(1 + z).is_rational
|
||||
|
||||
|
||||
def test_log_hashing():
|
||||
assert x != log(log(x))
|
||||
assert hash(x) != hash(log(log(x)))
|
||||
assert log(x) != log(log(log(x)))
|
||||
|
||||
e = 1/log(log(x) + log(log(x)))
|
||||
assert e.base.func is log
|
||||
e = 1/log(log(x) + log(log(log(x))))
|
||||
assert e.base.func is log
|
||||
|
||||
e = log(log(x))
|
||||
assert e.func is log
|
||||
assert x.func is not log
|
||||
assert hash(log(log(x))) != hash(x)
|
||||
assert e != x
|
||||
|
||||
|
||||
def test_log_sign():
|
||||
assert sign(log(2)) == 1
|
||||
|
||||
|
||||
def test_log_expand_complex():
|
||||
assert log(1 + I).expand(complex=True) == log(2)/2 + I*pi/4
|
||||
assert log(1 - sqrt(2)).expand(complex=True) == log(sqrt(2) - 1) + I*pi
|
||||
|
||||
|
||||
def test_log_apply_evalf():
|
||||
value = (log(3)/log(2) - 1).evalf()
|
||||
assert value.epsilon_eq(Float("0.58496250072115618145373"))
|
||||
|
||||
|
||||
def test_log_leading_term():
|
||||
p = Symbol('p')
|
||||
|
||||
# Test for STEP 3
|
||||
assert log(1 + x + x**2).as_leading_term(x, cdir=1) == x
|
||||
# Test for STEP 4
|
||||
assert log(2*x).as_leading_term(x, cdir=1) == log(x) + log(2)
|
||||
assert log(2*x).as_leading_term(x, cdir=-1) == log(x) + log(2)
|
||||
assert log(-2*x).as_leading_term(x, cdir=1, logx=p) == p + log(2) + I*pi
|
||||
assert log(-2*x).as_leading_term(x, cdir=-1, logx=p) == p + log(2) - I*pi
|
||||
# Test for STEP 5
|
||||
assert log(-2*x + (3 - I)*x**2).as_leading_term(x, cdir=1) == log(x) + log(2) - I*pi
|
||||
assert log(-2*x + (3 - I)*x**2).as_leading_term(x, cdir=-1) == log(x) + log(2) - I*pi
|
||||
assert log(2*x + (3 - I)*x**2).as_leading_term(x, cdir=1) == log(x) + log(2)
|
||||
assert log(2*x + (3 - I)*x**2).as_leading_term(x, cdir=-1) == log(x) + log(2) - 2*I*pi
|
||||
assert log(-1 + x - I*x**2 + I*x**3).as_leading_term(x, cdir=1) == -I*pi
|
||||
assert log(-1 + x - I*x**2 + I*x**3).as_leading_term(x, cdir=-1) == -I*pi
|
||||
assert log(-1/(1 - x)).as_leading_term(x, cdir=1) == I*pi
|
||||
assert log(-1/(1 - x)).as_leading_term(x, cdir=-1) == I*pi
|
||||
|
||||
|
||||
def test_log_nseries():
|
||||
p = Symbol('p')
|
||||
assert log(1/x)._eval_nseries(x, 4, logx=-p, cdir=1) == p
|
||||
assert log(1/x)._eval_nseries(x, 4, logx=-p, cdir=-1) == p + 2*I*pi
|
||||
assert log(x - 1)._eval_nseries(x, 4, None, I) == I*pi - x - x**2/2 - x**3/3 + O(x**4)
|
||||
assert log(x - 1)._eval_nseries(x, 4, None, -I) == -I*pi - x - x**2/2 - x**3/3 + O(x**4)
|
||||
assert log(I*x + I*x**3 - 1)._eval_nseries(x, 3, None, 1) == I*pi - I*x + x**2/2 + O(x**3)
|
||||
assert log(I*x + I*x**3 - 1)._eval_nseries(x, 3, None, -1) == -I*pi - I*x + x**2/2 + O(x**3)
|
||||
assert log(I*x**2 + I*x**3 - 1)._eval_nseries(x, 3, None, 1) == I*pi - I*x**2 + O(x**3)
|
||||
assert log(I*x**2 + I*x**3 - 1)._eval_nseries(x, 3, None, -1) == I*pi - I*x**2 + O(x**3)
|
||||
assert log(2*x + (3 - I)*x**2)._eval_nseries(x, 3, None, 1) == log(2) + log(x) + \
|
||||
x*(S(3)/2 - I/2) + x**2*(-1 + 3*I/4) + O(x**3)
|
||||
assert log(2*x + (3 - I)*x**2)._eval_nseries(x, 3, None, -1) == -2*I*pi + log(2) + \
|
||||
log(x) - x*(-S(3)/2 + I/2) + x**2*(-1 + 3*I/4) + O(x**3)
|
||||
assert log(-2*x + (3 - I)*x**2)._eval_nseries(x, 3, None, 1) == -I*pi + log(2) + log(x) + \
|
||||
x*(-S(3)/2 + I/2) + x**2*(-1 + 3*I/4) + O(x**3)
|
||||
assert log(-2*x + (3 - I)*x**2)._eval_nseries(x, 3, None, -1) == -I*pi + log(2) + log(x) - \
|
||||
x*(S(3)/2 - I/2) + x**2*(-1 + 3*I/4) + O(x**3)
|
||||
assert log(sqrt(-I*x**2 - 3)*sqrt(-I*x**2 - 1) - 2)._eval_nseries(x, 3, None, 1) == -I*pi + \
|
||||
log(sqrt(3) + 2) + 2*sqrt(3)*I*x**2/(3*sqrt(3) + 6) + O(x**3)
|
||||
assert log(-1/(1 - x))._eval_nseries(x, 3, None, 1) == I*pi + x + x**2/2 + O(x**3)
|
||||
assert log(-1/(1 - x))._eval_nseries(x, 3, None, -1) == I*pi + x + x**2/2 + O(x**3)
|
||||
|
||||
|
||||
def test_log_series():
|
||||
# Note Series at infinities other than oo/-oo were introduced as a part of
|
||||
# pull request 23798. Refer https://github.com/sympy/sympy/pull/23798 for
|
||||
# more information.
|
||||
expr1 = log(1 + x)
|
||||
expr2 = log(x + sqrt(x**2 + 1))
|
||||
|
||||
assert expr1.series(x, x0=I*oo, n=4) == 1/(3*x**3) - 1/(2*x**2) + 1/x + \
|
||||
I*pi/2 - log(I/x) + O(x**(-4), (x, oo*I))
|
||||
assert expr1.series(x, x0=-I*oo, n=4) == 1/(3*x**3) - 1/(2*x**2) + 1/x - \
|
||||
I*pi/2 - log(-I/x) + O(x**(-4), (x, -oo*I))
|
||||
assert expr2.series(x, x0=I*oo, n=4) == 1/(4*x**2) + I*pi/2 + log(2) - \
|
||||
log(I/x) + O(x**(-4), (x, oo*I))
|
||||
assert expr2.series(x, x0=-I*oo, n=4) == -1/(4*x**2) - I*pi/2 - log(2) + \
|
||||
log(-I/x) + O(x**(-4), (x, -oo*I))
|
||||
|
||||
|
||||
def test_log_expand():
|
||||
w = Symbol("w", positive=True)
|
||||
e = log(w**(log(5)/log(3)))
|
||||
assert e.expand() == log(5)/log(3) * log(w)
|
||||
x, y, z = symbols('x,y,z', positive=True)
|
||||
assert log(x*(y + z)).expand(mul=False) == log(x) + log(y + z)
|
||||
assert log(log(x**2)*log(y*z)).expand() in [log(2*log(x)*log(y) +
|
||||
2*log(x)*log(z)), log(log(x)*log(z) + log(y)*log(x)) + log(2),
|
||||
log((log(y) + log(z))*log(x)) + log(2)]
|
||||
assert log(x**log(x**2)).expand(deep=False) == log(x)*log(x**2)
|
||||
assert log(x**log(x**2)).expand() == 2*log(x)**2
|
||||
x, y = symbols('x,y')
|
||||
assert log(x*y).expand(force=True) == log(x) + log(y)
|
||||
assert log(x**y).expand(force=True) == y*log(x)
|
||||
assert log(exp(x)).expand(force=True) == x
|
||||
|
||||
# there's generally no need to expand out logs since this requires
|
||||
# factoring and if simplification is sought, it's cheaper to put
|
||||
# logs together than it is to take them apart.
|
||||
assert log(2*3**2).expand() != 2*log(3) + log(2)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_log_expand_fail():
|
||||
x, y, z = symbols('x,y,z', positive=True)
|
||||
assert (log(x*(y + z))*(x + y)).expand(mul=True, log=True) == y*log(
|
||||
x) + y*log(y + z) + z*log(x) + z*log(y + z)
|
||||
|
||||
|
||||
def test_log_simplify():
|
||||
x = Symbol("x", positive=True)
|
||||
assert log(x**2).expand() == 2*log(x)
|
||||
assert expand_log(log(x**(2 + log(2)))) == (2 + log(2))*log(x)
|
||||
|
||||
z = Symbol('z')
|
||||
assert log(sqrt(z)).expand() == log(z)/2
|
||||
assert expand_log(log(z**(log(2) - 1))) == (log(2) - 1)*log(z)
|
||||
assert log(z**(-1)).expand() != -log(z)
|
||||
assert log(z**(x/(x+1))).expand() == x*log(z)/(x + 1)
|
||||
|
||||
|
||||
def test_log_AccumBounds():
|
||||
assert log(AccumBounds(1, E)) == AccumBounds(0, 1)
|
||||
assert log(AccumBounds(0, E)) == AccumBounds(-oo, 1)
|
||||
assert log(AccumBounds(-1, E)) == S.NaN
|
||||
assert log(AccumBounds(0, oo)) == AccumBounds(-oo, oo)
|
||||
assert log(AccumBounds(-oo, 0)) == S.NaN
|
||||
assert log(AccumBounds(-oo, oo)) == S.NaN
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_lambertw():
|
||||
k = Symbol('k')
|
||||
|
||||
assert LambertW(x, 0) == LambertW(x)
|
||||
assert LambertW(x, 0, evaluate=False) != LambertW(x)
|
||||
assert LambertW(0) == 0
|
||||
assert LambertW(E) == 1
|
||||
assert LambertW(-1/E) == -1
|
||||
assert LambertW(-log(2)/2) == -log(2)
|
||||
assert LambertW(oo) is oo
|
||||
assert LambertW(0, 1) is -oo
|
||||
assert LambertW(0, 42) is -oo
|
||||
assert LambertW(-pi/2, -1) == -I*pi/2
|
||||
assert LambertW(-1/E, -1) == -1
|
||||
assert LambertW(-2*exp(-2), -1) == -2
|
||||
assert LambertW(2*log(2)) == log(2)
|
||||
assert LambertW(-pi/2) == I*pi/2
|
||||
assert LambertW(exp(1 + E)) == E
|
||||
|
||||
assert LambertW(x**2).diff(x) == 2*LambertW(x**2)/x/(1 + LambertW(x**2))
|
||||
assert LambertW(x, k).diff(x) == LambertW(x, k)/x/(1 + LambertW(x, k))
|
||||
|
||||
assert LambertW(sqrt(2)).evalf(30).epsilon_eq(
|
||||
Float("0.701338383413663009202120278965", 30), 1e-29)
|
||||
assert re(LambertW(2, -1)).evalf().epsilon_eq(Float("-0.834310366631110"))
|
||||
|
||||
assert LambertW(-1).is_real is False # issue 5215
|
||||
assert LambertW(2, evaluate=False).is_real
|
||||
p = Symbol('p', positive=True)
|
||||
assert LambertW(p, evaluate=False).is_real
|
||||
assert LambertW(p - 1, evaluate=False).is_real is None
|
||||
assert LambertW(-p - 2/S.Exp1, evaluate=False).is_real is False
|
||||
assert LambertW(S.Half, -1, evaluate=False).is_real is False
|
||||
assert LambertW(Rational(-1, 10), -1, evaluate=False).is_real
|
||||
assert LambertW(-10, -1, evaluate=False).is_real is False
|
||||
assert LambertW(-2, 2, evaluate=False).is_real is False
|
||||
|
||||
assert LambertW(0, evaluate=False).is_algebraic
|
||||
na = Symbol('na', nonzero=True, algebraic=True)
|
||||
assert LambertW(na).is_algebraic is False
|
||||
assert LambertW(p).is_zero is False
|
||||
n = Symbol('n', negative=True)
|
||||
assert LambertW(n).is_zero is False
|
||||
|
||||
|
||||
def test_issue_5673():
|
||||
e = LambertW(-1)
|
||||
assert e.is_comparable is False
|
||||
assert e.is_positive is not True
|
||||
e2 = 1 - 1/(1 - exp(-1000))
|
||||
assert e2.is_positive is not True
|
||||
e3 = -2 + exp(exp(LambertW(log(2)))*LambertW(log(2)))
|
||||
assert e3.is_nonzero is not True
|
||||
|
||||
|
||||
def test_log_fdiff():
|
||||
x = Symbol('x')
|
||||
raises(ArgumentIndexError, lambda: log(x).fdiff(2))
|
||||
|
||||
|
||||
def test_log_taylor_term():
|
||||
x = symbols('x')
|
||||
assert log(x).taylor_term(0, x) == x
|
||||
assert log(x).taylor_term(1, x) == -x**2/2
|
||||
assert log(x).taylor_term(4, x) == x**5/5
|
||||
assert log(x).taylor_term(-1, x) is S.Zero
|
||||
|
||||
|
||||
def test_exp_expand_NC():
|
||||
A, B, C = symbols('A,B,C', commutative=False)
|
||||
|
||||
assert exp(A + B).expand() == exp(A + B)
|
||||
assert exp(A + B + C).expand() == exp(A + B + C)
|
||||
assert exp(x + y).expand() == exp(x)*exp(y)
|
||||
assert exp(x + y + z).expand() == exp(x)*exp(y)*exp(z)
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_as_numer_denom():
|
||||
n = symbols('n', negative=True)
|
||||
assert exp(x).as_numer_denom() == (exp(x), 1)
|
||||
assert exp(-x).as_numer_denom() == (1, exp(x))
|
||||
assert exp(-2*x).as_numer_denom() == (1, exp(2*x))
|
||||
assert exp(-2).as_numer_denom() == (1, exp(2))
|
||||
assert exp(n).as_numer_denom() == (1, exp(-n))
|
||||
assert exp(-n).as_numer_denom() == (exp(-n), 1)
|
||||
assert exp(-I*x).as_numer_denom() == (1, exp(I*x))
|
||||
assert exp(-I*n).as_numer_denom() == (1, exp(I*n))
|
||||
assert exp(-n).as_numer_denom() == (exp(-n), 1)
|
||||
# Check noncommutativity
|
||||
a = symbols('a', commutative=False)
|
||||
assert exp(-a).as_numer_denom() == (exp(-a), 1)
|
||||
|
||||
|
||||
@_both_exp_pow
|
||||
def test_polar():
|
||||
x, y = symbols('x y', polar=True)
|
||||
|
||||
assert abs(exp_polar(I*4)) == 1
|
||||
assert abs(exp_polar(0)) == 1
|
||||
assert abs(exp_polar(2 + 3*I)) == exp(2)
|
||||
assert exp_polar(I*10).n() == exp_polar(I*10)
|
||||
|
||||
assert log(exp_polar(z)) == z
|
||||
assert log(x*y).expand() == log(x) + log(y)
|
||||
assert log(x**z).expand() == z*log(x)
|
||||
|
||||
assert exp_polar(3).exp == 3
|
||||
|
||||
# Compare exp(1.0*pi*I).
|
||||
assert (exp_polar(1.0*pi*I).n(n=5)).as_real_imag()[1] >= 0
|
||||
|
||||
assert exp_polar(0).is_rational is True # issue 8008
|
||||
|
||||
|
||||
def test_exp_summation():
|
||||
w = symbols("w")
|
||||
m, n, i, j = symbols("m n i j")
|
||||
expr = exp(Sum(w*i, (i, 0, n), (j, 0, m)))
|
||||
assert expr.expand() == Product(exp(w*i), (i, 0, n), (j, 0, m))
|
||||
|
||||
|
||||
def test_log_product():
|
||||
from sympy.abc import n, m
|
||||
|
||||
i, j = symbols('i,j', positive=True, integer=True)
|
||||
x, y = symbols('x,y', positive=True)
|
||||
z = symbols('z', real=True)
|
||||
w = symbols('w')
|
||||
|
||||
expr = log(Product(x**i, (i, 1, n)))
|
||||
assert simplify(expr) == expr
|
||||
assert expr.expand() == Sum(i*log(x), (i, 1, n))
|
||||
expr = log(Product(x**i*y**j, (i, 1, n), (j, 1, m)))
|
||||
assert simplify(expr) == expr
|
||||
assert expr.expand() == Sum(i*log(x) + j*log(y), (i, 1, n), (j, 1, m))
|
||||
|
||||
expr = log(Product(-2, (n, 0, 4)))
|
||||
assert simplify(expr) == expr
|
||||
assert expr.expand() == expr
|
||||
assert expr.expand(force=True) == Sum(log(-2), (n, 0, 4))
|
||||
|
||||
expr = log(Product(exp(z*i), (i, 0, n)))
|
||||
assert expr.expand() == Sum(z*i, (i, 0, n))
|
||||
|
||||
expr = log(Product(exp(w*i), (i, 0, n)))
|
||||
assert expr.expand() == expr
|
||||
assert expr.expand(force=True) == Sum(w*i, (i, 0, n))
|
||||
|
||||
expr = log(Product(i**2*abs(j), (i, 1, n), (j, 1, m)))
|
||||
assert expr.expand() == Sum(2*log(i) + log(j), (i, 1, n), (j, 1, m))
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_log_product_simplify_to_sum():
|
||||
from sympy.abc import n, m
|
||||
i, j = symbols('i,j', positive=True, integer=True)
|
||||
x, y = symbols('x,y', positive=True)
|
||||
assert simplify(log(Product(x**i, (i, 1, n)))) == Sum(i*log(x), (i, 1, n))
|
||||
assert simplify(log(Product(x**i*y**j, (i, 1, n), (j, 1, m)))) == \
|
||||
Sum(i*log(x) + j*log(y), (i, 1, n), (j, 1, m))
|
||||
|
||||
|
||||
def test_issue_8866():
|
||||
assert simplify(log(x, 10, evaluate=False)) == simplify(log(x, 10))
|
||||
assert expand_log(log(x, 10, evaluate=False)) == expand_log(log(x, 10))
|
||||
|
||||
y = Symbol('y', positive=True)
|
||||
l1 = log(exp(y), exp(10))
|
||||
b1 = log(exp(y), exp(5))
|
||||
l2 = log(exp(y), exp(10), evaluate=False)
|
||||
b2 = log(exp(y), exp(5), evaluate=False)
|
||||
assert simplify(log(l1, b1)) == simplify(log(l2, b2))
|
||||
assert expand_log(log(l1, b1)) == expand_log(log(l2, b2))
|
||||
|
||||
|
||||
def test_log_expand_factor():
|
||||
assert (log(18)/log(3) - 2).expand(factor=True) == log(2)/log(3)
|
||||
assert (log(12)/log(2)).expand(factor=True) == log(3)/log(2) + 2
|
||||
assert (log(15)/log(3)).expand(factor=True) == 1 + log(5)/log(3)
|
||||
assert (log(2)/(-log(12) + log(24))).expand(factor=True) == 1
|
||||
|
||||
assert expand_log(log(12), factor=True) == log(3) + 2*log(2)
|
||||
assert expand_log(log(21)/log(7), factor=False) == log(3)/log(7) + 1
|
||||
assert expand_log(log(45)/log(5) + log(20), factor=False) == \
|
||||
1 + 2*log(3)/log(5) + log(20)
|
||||
assert expand_log(log(45)/log(5) + log(26), factor=True) == \
|
||||
log(2) + log(13) + (log(5) + 2*log(3))/log(5)
|
||||
|
||||
|
||||
def test_issue_9116():
|
||||
n = Symbol('n', positive=True, integer=True)
|
||||
assert log(n).is_nonnegative is True
|
||||
|
||||
|
||||
def test_issue_18473():
|
||||
assert exp(x*log(cos(1/x))).as_leading_term(x) == S.NaN
|
||||
assert exp(x*log(tan(1/x))).as_leading_term(x) == S.NaN
|
||||
assert log(cos(1/x)).as_leading_term(x) == S.NaN
|
||||
assert log(tan(1/x)).as_leading_term(x) == S.NaN
|
||||
assert log(cos(1/x) + 2).as_leading_term(x) == AccumBounds(0, log(3))
|
||||
assert exp(x*log(cos(1/x) + 2)).as_leading_term(x) == 1
|
||||
assert log(cos(1/x) - 2).as_leading_term(x) == S.NaN
|
||||
assert exp(x*log(cos(1/x) - 2)).as_leading_term(x) == S.NaN
|
||||
assert log(cos(1/x) + 1).as_leading_term(x) == AccumBounds(-oo, log(2))
|
||||
assert exp(x*log(cos(1/x) + 1)).as_leading_term(x) == AccumBounds(0, 1)
|
||||
assert log(sin(1/x)**2).as_leading_term(x) == AccumBounds(-oo, 0)
|
||||
assert exp(x*log(sin(1/x)**2)).as_leading_term(x) == AccumBounds(0, 1)
|
||||
assert log(tan(1/x)**2).as_leading_term(x) == AccumBounds(-oo, oo)
|
||||
assert exp(2*x*(log(tan(1/x)**2))).as_leading_term(x) == AccumBounds(0, oo)
|
||||
+1553
File diff suppressed because it is too large
Load Diff
+688
@@ -0,0 +1,688 @@
|
||||
from sympy.calculus.accumulationbounds import AccumBounds
|
||||
from sympy.core.numbers import (E, Float, I, Rational, Integer, nan, oo, pi, zoo)
|
||||
from sympy.core.relational import (Eq, Ge, Gt, Le, Lt, Ne)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.elementary.exponential import (exp, log)
|
||||
from sympy.functions.elementary.integers import (ceiling, floor, frac)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import sin, cos, tan, asin
|
||||
from sympy.polys.rootoftools import RootOf, CRootOf
|
||||
from sympy import Integers
|
||||
from sympy.sets.sets import Interval
|
||||
from sympy.sets.fancysets import ImageSet
|
||||
from sympy.core.function import Lambda
|
||||
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.testing.pytest import XFAIL, raises
|
||||
|
||||
x = Symbol('x')
|
||||
i = Symbol('i', imaginary=True)
|
||||
y = Symbol('y', real=True)
|
||||
k, n = symbols('k,n', integer=True)
|
||||
b = Symbol('b', real=True, noninteger=True)
|
||||
m = Symbol('m', positive=True)
|
||||
|
||||
|
||||
def test_floor():
|
||||
|
||||
assert floor(nan) is nan
|
||||
|
||||
assert floor(oo) is oo
|
||||
assert floor(-oo) is -oo
|
||||
assert floor(zoo) is zoo
|
||||
|
||||
assert floor(0) == 0
|
||||
|
||||
assert floor(1) == 1
|
||||
assert floor(-1) == -1
|
||||
|
||||
assert floor(I*log(asin(5)/abs(asin(5)))) == 0
|
||||
assert floor(-I*log(asin(7)/abs(asin(7)))) == -2
|
||||
|
||||
assert floor(E) == 2
|
||||
assert floor(-E) == -3
|
||||
|
||||
assert floor(2*E) == 5
|
||||
assert floor(-2*E) == -6
|
||||
|
||||
assert floor(pi) == 3
|
||||
assert floor(-pi) == -4
|
||||
|
||||
assert floor(S.Half) == 0
|
||||
assert floor(Rational(-1, 2)) == -1
|
||||
|
||||
assert floor(Rational(7, 3)) == 2
|
||||
assert floor(Rational(-7, 3)) == -3
|
||||
assert floor(-Rational(7, 3)) == -3
|
||||
|
||||
assert floor(Float(17.0)) == 17
|
||||
assert floor(-Float(17.0)) == -17
|
||||
|
||||
assert floor(Float(7.69)) == 7
|
||||
assert floor(-Float(7.69)) == -8
|
||||
|
||||
assert floor(1/(m+1)) == S.Zero
|
||||
assert floor((m+2)/(m+1)) == S.One
|
||||
assert floor(-1/(m+1)) == S.NegativeOne
|
||||
assert floor((m+2)/(-m-1)) == Integer(-2)
|
||||
|
||||
assert floor(I) == I
|
||||
assert floor(-I) == -I
|
||||
e = floor(i)
|
||||
assert e.func is floor and e.args[0] == i
|
||||
|
||||
assert floor(oo*I) == oo*I
|
||||
assert floor(-oo*I) == -oo*I
|
||||
assert floor(exp(I*pi/4)*oo) == exp(I*pi/4)*oo
|
||||
|
||||
assert floor(2*I) == 2*I
|
||||
assert floor(-2*I) == -2*I
|
||||
|
||||
assert floor(I/2) == 0
|
||||
assert floor(-I/2) == -I
|
||||
|
||||
assert floor(E + 17) == 19
|
||||
assert floor(pi + 2) == 5
|
||||
|
||||
assert floor(E + pi) == 5
|
||||
assert floor(I + pi) == 3 + I
|
||||
|
||||
assert floor(floor(pi)) == 3
|
||||
assert floor(floor(y)) == floor(y)
|
||||
assert floor(floor(x)) == floor(x)
|
||||
|
||||
assert unchanged(floor, x)
|
||||
assert unchanged(floor, 2*x)
|
||||
assert unchanged(floor, k*x)
|
||||
|
||||
assert floor(k) == k
|
||||
assert floor(2*k) == 2*k
|
||||
assert floor(k*n) == k*n
|
||||
|
||||
assert unchanged(floor, k/2)
|
||||
|
||||
assert unchanged(floor, x + y)
|
||||
|
||||
assert floor(x + 3) == floor(x) + 3
|
||||
assert floor(x + k) == floor(x) + k
|
||||
|
||||
assert floor(y + 3) == floor(y) + 3
|
||||
assert floor(y + k) == floor(y) + k
|
||||
|
||||
assert floor(3 + I*y + pi) == 6 + floor(y)*I
|
||||
|
||||
assert floor(k + n) == k + n
|
||||
|
||||
assert unchanged(floor, x*I)
|
||||
assert floor(k*I) == k*I
|
||||
|
||||
assert floor(Rational(23, 10) - E*I) == 2 - 3*I
|
||||
|
||||
assert floor(sin(1)) == 0
|
||||
assert floor(sin(-1)) == -1
|
||||
|
||||
assert floor(exp(2)) == 7
|
||||
|
||||
assert floor(log(8)/log(2)) != 2
|
||||
assert int(floor(log(8)/log(2)).evalf(chop=True)) == 3
|
||||
|
||||
assert floor(factorial(50)/exp(1)) == \
|
||||
11188719610782480504630258070757734324011354208865721592720336800
|
||||
|
||||
assert (floor(y) < y).is_Relational
|
||||
assert (floor(y) <= y) == True
|
||||
assert (floor(y) > y) == False
|
||||
assert (floor(y) >= y).is_Relational
|
||||
assert (floor(x) <= x).is_Relational # x could be non-real
|
||||
assert (floor(x) > x).is_Relational
|
||||
assert (floor(x) <= y).is_Relational # arg is not same as rhs
|
||||
assert (floor(x) > y).is_Relational
|
||||
assert (floor(y) <= oo) == True
|
||||
assert (floor(y) < oo) == True
|
||||
assert (floor(y) >= -oo) == True
|
||||
assert (floor(y) > -oo) == True
|
||||
assert (floor(b) < b) == True
|
||||
assert (floor(b) <= b) == True
|
||||
assert (floor(b) > b) == False
|
||||
assert (floor(b) >= b) == False
|
||||
|
||||
assert floor(y).rewrite(frac) == y - frac(y)
|
||||
assert floor(y).rewrite(ceiling) == -ceiling(-y)
|
||||
assert floor(y).rewrite(frac).subs(y, -pi) == floor(-pi)
|
||||
assert floor(y).rewrite(frac).subs(y, E) == floor(E)
|
||||
assert floor(y).rewrite(ceiling).subs(y, E) == -ceiling(-E)
|
||||
assert floor(y).rewrite(ceiling).subs(y, -pi) == -ceiling(pi)
|
||||
|
||||
assert Eq(floor(y), y - frac(y))
|
||||
assert Eq(floor(y), -ceiling(-y))
|
||||
|
||||
neg = Symbol('neg', negative=True)
|
||||
nn = Symbol('nn', nonnegative=True)
|
||||
pos = Symbol('pos', positive=True)
|
||||
np = Symbol('np', nonpositive=True)
|
||||
|
||||
assert (floor(neg) < 0) == True
|
||||
assert (floor(neg) <= 0) == True
|
||||
assert (floor(neg) > 0) == False
|
||||
assert (floor(neg) >= 0) == False
|
||||
assert (floor(neg) <= -1) == True
|
||||
assert (floor(neg) >= -3) == (neg >= -3)
|
||||
assert (floor(neg) < 5) == (neg < 5)
|
||||
|
||||
assert (floor(nn) < 0) == False
|
||||
assert (floor(nn) >= 0) == True
|
||||
|
||||
assert (floor(pos) < 0) == False
|
||||
assert (floor(pos) <= 0) == (pos < 1)
|
||||
assert (floor(pos) > 0) == (pos >= 1)
|
||||
assert (floor(pos) >= 0) == True
|
||||
assert (floor(pos) >= 3) == (pos >= 3)
|
||||
|
||||
assert (floor(np) <= 0) == True
|
||||
assert (floor(np) > 0) == False
|
||||
|
||||
assert floor(neg).is_negative == True
|
||||
assert floor(neg).is_nonnegative == False
|
||||
assert floor(nn).is_negative == False
|
||||
assert floor(nn).is_nonnegative == True
|
||||
assert floor(pos).is_negative == False
|
||||
assert floor(pos).is_nonnegative == True
|
||||
assert floor(np).is_negative is None
|
||||
assert floor(np).is_nonnegative is None
|
||||
|
||||
assert (floor(7, evaluate=False) >= 7) == True
|
||||
assert (floor(7, evaluate=False) > 7) == False
|
||||
assert (floor(7, evaluate=False) <= 7) == True
|
||||
assert (floor(7, evaluate=False) < 7) == False
|
||||
|
||||
assert (floor(7, evaluate=False) >= 6) == True
|
||||
assert (floor(7, evaluate=False) > 6) == True
|
||||
assert (floor(7, evaluate=False) <= 6) == False
|
||||
assert (floor(7, evaluate=False) < 6) == False
|
||||
|
||||
assert (floor(7, evaluate=False) >= 8) == False
|
||||
assert (floor(7, evaluate=False) > 8) == False
|
||||
assert (floor(7, evaluate=False) <= 8) == True
|
||||
assert (floor(7, evaluate=False) < 8) == True
|
||||
|
||||
assert (floor(x) <= 5.5) == Le(floor(x), 5.5, evaluate=False)
|
||||
assert (floor(x) >= -3.2) == Ge(floor(x), -3.2, evaluate=False)
|
||||
assert (floor(x) < 2.9) == Lt(floor(x), 2.9, evaluate=False)
|
||||
assert (floor(x) > -1.7) == Gt(floor(x), -1.7, evaluate=False)
|
||||
|
||||
assert (floor(y) <= 5.5) == (y < 6)
|
||||
assert (floor(y) >= -3.2) == (y >= -3)
|
||||
assert (floor(y) < 2.9) == (y < 3)
|
||||
assert (floor(y) > -1.7) == (y >= -1)
|
||||
|
||||
assert (floor(y) <= n) == (y < n + 1)
|
||||
assert (floor(y) >= n) == (y >= n)
|
||||
assert (floor(y) < n) == (y < n)
|
||||
assert (floor(y) > n) == (y >= n + 1)
|
||||
|
||||
assert floor(RootOf(x**3 - 27*x, 2)) == 5
|
||||
|
||||
|
||||
def test_ceiling():
|
||||
|
||||
assert ceiling(nan) is nan
|
||||
|
||||
assert ceiling(oo) is oo
|
||||
assert ceiling(-oo) is -oo
|
||||
assert ceiling(zoo) is zoo
|
||||
|
||||
assert ceiling(0) == 0
|
||||
|
||||
assert ceiling(1) == 1
|
||||
assert ceiling(-1) == -1
|
||||
|
||||
assert ceiling(I*log(asin(5)/abs(asin(5)))) == 1
|
||||
assert ceiling(-I*log(asin(7)/abs(asin(7)))) == -1
|
||||
|
||||
assert ceiling(E) == 3
|
||||
assert ceiling(-E) == -2
|
||||
|
||||
assert ceiling(2*E) == 6
|
||||
assert ceiling(-2*E) == -5
|
||||
|
||||
assert ceiling(pi) == 4
|
||||
assert ceiling(-pi) == -3
|
||||
|
||||
assert ceiling(S.Half) == 1
|
||||
assert ceiling(Rational(-1, 2)) == 0
|
||||
|
||||
assert ceiling(Rational(7, 3)) == 3
|
||||
assert ceiling(-Rational(7, 3)) == -2
|
||||
|
||||
assert ceiling(Float(17.0)) == 17
|
||||
assert ceiling(-Float(17.0)) == -17
|
||||
|
||||
assert ceiling(Float(7.69)) == 8
|
||||
assert ceiling(-Float(7.69)) == -7
|
||||
|
||||
assert ceiling(1/(m+1)) == S.One
|
||||
assert ceiling((m+2)/(m+1)) == Integer(2)
|
||||
assert ceiling(-1/(m+1)) == S.Zero
|
||||
assert ceiling((m+2)/(-m-1)) == S.NegativeOne
|
||||
|
||||
assert ceiling(I) == I
|
||||
assert ceiling(-I) == -I
|
||||
e = ceiling(i)
|
||||
assert e.func is ceiling and e.args[0] == i
|
||||
|
||||
assert ceiling(oo*I) == oo*I
|
||||
assert ceiling(-oo*I) == -oo*I
|
||||
assert ceiling(exp(I*pi/4)*oo) == exp(I*pi/4)*oo
|
||||
|
||||
assert ceiling(2*I) == 2*I
|
||||
assert ceiling(-2*I) == -2*I
|
||||
|
||||
assert ceiling(I/2) == I
|
||||
assert ceiling(-I/2) == 0
|
||||
|
||||
assert ceiling(E + 17) == 20
|
||||
assert ceiling(pi + 2) == 6
|
||||
|
||||
assert ceiling(E + pi) == 6
|
||||
assert ceiling(I + pi) == I + 4
|
||||
|
||||
assert ceiling(ceiling(pi)) == 4
|
||||
assert ceiling(ceiling(y)) == ceiling(y)
|
||||
assert ceiling(ceiling(x)) == ceiling(x)
|
||||
|
||||
assert unchanged(ceiling, x)
|
||||
assert unchanged(ceiling, 2*x)
|
||||
assert unchanged(ceiling, k*x)
|
||||
|
||||
assert ceiling(k) == k
|
||||
assert ceiling(2*k) == 2*k
|
||||
assert ceiling(k*n) == k*n
|
||||
|
||||
assert unchanged(ceiling, k/2)
|
||||
|
||||
assert unchanged(ceiling, x + y)
|
||||
|
||||
assert ceiling(x + 3) == ceiling(x) + 3
|
||||
assert ceiling(x + 3.0) == ceiling(x) + 3
|
||||
assert ceiling(x + 3.0*I) == ceiling(x) + 3*I
|
||||
assert ceiling(x + k) == ceiling(x) + k
|
||||
|
||||
assert ceiling(y + 3) == ceiling(y) + 3
|
||||
assert ceiling(y + k) == ceiling(y) + k
|
||||
|
||||
assert ceiling(3 + pi + y*I) == 7 + ceiling(y)*I
|
||||
|
||||
assert ceiling(k + n) == k + n
|
||||
|
||||
assert unchanged(ceiling, x*I)
|
||||
assert ceiling(k*I) == k*I
|
||||
|
||||
assert ceiling(Rational(23, 10) - E*I) == 3 - 2*I
|
||||
|
||||
assert ceiling(sin(1)) == 1
|
||||
assert ceiling(sin(-1)) == 0
|
||||
|
||||
assert ceiling(exp(2)) == 8
|
||||
|
||||
assert ceiling(-log(8)/log(2)) != -2
|
||||
assert int(ceiling(-log(8)/log(2)).evalf(chop=True)) == -3
|
||||
|
||||
assert ceiling(factorial(50)/exp(1)) == \
|
||||
11188719610782480504630258070757734324011354208865721592720336801
|
||||
|
||||
assert (ceiling(y) >= y) == True
|
||||
assert (ceiling(y) > y).is_Relational
|
||||
assert (ceiling(y) < y) == False
|
||||
assert (ceiling(y) <= y).is_Relational
|
||||
assert (ceiling(x) >= x).is_Relational # x could be non-real
|
||||
assert (ceiling(x) < x).is_Relational
|
||||
assert (ceiling(x) >= y).is_Relational # arg is not same as rhs
|
||||
assert (ceiling(x) < y).is_Relational
|
||||
assert (ceiling(y) >= -oo) == True
|
||||
assert (ceiling(y) > -oo) == True
|
||||
assert (ceiling(y) <= oo) == True
|
||||
assert (ceiling(y) < oo) == True
|
||||
assert (ceiling(b) < b) == False
|
||||
assert (ceiling(b) <= b) == False
|
||||
assert (ceiling(b) > b) == True
|
||||
assert (ceiling(b) >= b) == True
|
||||
|
||||
assert ceiling(y).rewrite(floor) == -floor(-y)
|
||||
assert ceiling(y).rewrite(frac) == y + frac(-y)
|
||||
assert ceiling(y).rewrite(floor).subs(y, -pi) == -floor(pi)
|
||||
assert ceiling(y).rewrite(floor).subs(y, E) == -floor(-E)
|
||||
assert ceiling(y).rewrite(frac).subs(y, pi) == ceiling(pi)
|
||||
assert ceiling(y).rewrite(frac).subs(y, -E) == ceiling(-E)
|
||||
|
||||
assert Eq(ceiling(y), y + frac(-y))
|
||||
assert Eq(ceiling(y), -floor(-y))
|
||||
|
||||
neg = Symbol('neg', negative=True)
|
||||
nn = Symbol('nn', nonnegative=True)
|
||||
pos = Symbol('pos', positive=True)
|
||||
np = Symbol('np', nonpositive=True)
|
||||
|
||||
assert (ceiling(neg) <= 0) == True
|
||||
assert (ceiling(neg) < 0) == (neg <= -1)
|
||||
assert (ceiling(neg) > 0) == False
|
||||
assert (ceiling(neg) >= 0) == (neg > -1)
|
||||
assert (ceiling(neg) > -3) == (neg > -3)
|
||||
assert (ceiling(neg) <= 10) == (neg <= 10)
|
||||
|
||||
assert (ceiling(nn) < 0) == False
|
||||
assert (ceiling(nn) >= 0) == True
|
||||
|
||||
assert (ceiling(pos) < 0) == False
|
||||
assert (ceiling(pos) <= 0) == False
|
||||
assert (ceiling(pos) > 0) == True
|
||||
assert (ceiling(pos) >= 0) == True
|
||||
assert (ceiling(pos) >= 1) == True
|
||||
assert (ceiling(pos) > 5) == (pos > 5)
|
||||
|
||||
assert (ceiling(np) <= 0) == True
|
||||
assert (ceiling(np) > 0) == False
|
||||
|
||||
assert ceiling(neg).is_positive == False
|
||||
assert ceiling(neg).is_nonpositive == True
|
||||
assert ceiling(nn).is_positive is None
|
||||
assert ceiling(nn).is_nonpositive is None
|
||||
assert ceiling(pos).is_positive == True
|
||||
assert ceiling(pos).is_nonpositive == False
|
||||
assert ceiling(np).is_positive == False
|
||||
assert ceiling(np).is_nonpositive == True
|
||||
|
||||
assert (ceiling(7, evaluate=False) >= 7) == True
|
||||
assert (ceiling(7, evaluate=False) > 7) == False
|
||||
assert (ceiling(7, evaluate=False) <= 7) == True
|
||||
assert (ceiling(7, evaluate=False) < 7) == False
|
||||
|
||||
assert (ceiling(7, evaluate=False) >= 6) == True
|
||||
assert (ceiling(7, evaluate=False) > 6) == True
|
||||
assert (ceiling(7, evaluate=False) <= 6) == False
|
||||
assert (ceiling(7, evaluate=False) < 6) == False
|
||||
|
||||
assert (ceiling(7, evaluate=False) >= 8) == False
|
||||
assert (ceiling(7, evaluate=False) > 8) == False
|
||||
assert (ceiling(7, evaluate=False) <= 8) == True
|
||||
assert (ceiling(7, evaluate=False) < 8) == True
|
||||
|
||||
assert (ceiling(x) <= 5.5) == Le(ceiling(x), 5.5, evaluate=False)
|
||||
assert (ceiling(x) >= -3.2) == Ge(ceiling(x), -3.2, evaluate=False)
|
||||
assert (ceiling(x) < 2.9) == Lt(ceiling(x), 2.9, evaluate=False)
|
||||
assert (ceiling(x) > -1.7) == Gt(ceiling(x), -1.7, evaluate=False)
|
||||
|
||||
assert (ceiling(y) <= 5.5) == (y <= 5)
|
||||
assert (ceiling(y) >= -3.2) == (y > -4)
|
||||
assert (ceiling(y) < 2.9) == (y <= 2)
|
||||
assert (ceiling(y) > -1.7) == (y > -2)
|
||||
|
||||
assert (ceiling(y) <= n) == (y <= n)
|
||||
assert (ceiling(y) >= n) == (y > n - 1)
|
||||
assert (ceiling(y) < n) == (y <= n - 1)
|
||||
assert (ceiling(y) > n) == (y > n)
|
||||
|
||||
assert ceiling(RootOf(x**3 - 27*x, 2)) == 6
|
||||
s = ImageSet(Lambda(n, n + (CRootOf(x**5 - x**2 + 1, 0))), Integers)
|
||||
f = CRootOf(x**5 - x**2 + 1, 0)
|
||||
s = ImageSet(Lambda(n, n + f), Integers)
|
||||
assert s.intersect(Interval(-10, 10)) == {i + f for i in range(-9, 11)}
|
||||
|
||||
|
||||
def test_frac():
|
||||
assert isinstance(frac(x), frac)
|
||||
assert frac(oo) == AccumBounds(0, 1)
|
||||
assert frac(-oo) == AccumBounds(0, 1)
|
||||
assert frac(zoo) is nan
|
||||
|
||||
assert frac(n) == 0
|
||||
assert frac(nan) is nan
|
||||
assert frac(Rational(4, 3)) == Rational(1, 3)
|
||||
assert frac(-Rational(4, 3)) == Rational(2, 3)
|
||||
assert frac(Rational(-4, 3)) == Rational(2, 3)
|
||||
|
||||
r = Symbol('r', real=True)
|
||||
assert frac(I*r) == I*frac(r)
|
||||
assert frac(1 + I*r) == I*frac(r)
|
||||
assert frac(0.5 + I*r) == 0.5 + I*frac(r)
|
||||
assert frac(n + I*r) == I*frac(r)
|
||||
assert frac(n + I*k) == 0
|
||||
assert unchanged(frac, x + I*x)
|
||||
assert frac(x + I*n) == frac(x)
|
||||
|
||||
assert frac(x).rewrite(floor) == x - floor(x)
|
||||
assert frac(x).rewrite(ceiling) == x + ceiling(-x)
|
||||
assert frac(y).rewrite(floor).subs(y, pi) == frac(pi)
|
||||
assert frac(y).rewrite(floor).subs(y, -E) == frac(-E)
|
||||
assert frac(y).rewrite(ceiling).subs(y, -pi) == frac(-pi)
|
||||
assert frac(y).rewrite(ceiling).subs(y, E) == frac(E)
|
||||
|
||||
assert Eq(frac(y), y - floor(y))
|
||||
assert Eq(frac(y), y + ceiling(-y))
|
||||
|
||||
r = Symbol('r', real=True)
|
||||
p_i = Symbol('p_i', integer=True, positive=True)
|
||||
n_i = Symbol('p_i', integer=True, negative=True)
|
||||
np_i = Symbol('np_i', integer=True, nonpositive=True)
|
||||
nn_i = Symbol('nn_i', integer=True, nonnegative=True)
|
||||
p_r = Symbol('p_r', positive=True)
|
||||
n_r = Symbol('n_r', negative=True)
|
||||
np_r = Symbol('np_r', real=True, nonpositive=True)
|
||||
nn_r = Symbol('nn_r', real=True, nonnegative=True)
|
||||
|
||||
# Real frac argument, integer rhs
|
||||
assert frac(r) <= p_i
|
||||
assert not frac(r) <= n_i
|
||||
assert (frac(r) <= np_i).has(Le)
|
||||
assert (frac(r) <= nn_i).has(Le)
|
||||
assert frac(r) < p_i
|
||||
assert not frac(r) < n_i
|
||||
assert not frac(r) < np_i
|
||||
assert (frac(r) < nn_i).has(Lt)
|
||||
assert not frac(r) >= p_i
|
||||
assert frac(r) >= n_i
|
||||
assert frac(r) >= np_i
|
||||
assert (frac(r) >= nn_i).has(Ge)
|
||||
assert not frac(r) > p_i
|
||||
assert frac(r) > n_i
|
||||
assert (frac(r) > np_i).has(Gt)
|
||||
assert (frac(r) > nn_i).has(Gt)
|
||||
|
||||
assert not Eq(frac(r), p_i)
|
||||
assert not Eq(frac(r), n_i)
|
||||
assert Eq(frac(r), np_i).has(Eq)
|
||||
assert Eq(frac(r), nn_i).has(Eq)
|
||||
|
||||
assert Ne(frac(r), p_i)
|
||||
assert Ne(frac(r), n_i)
|
||||
assert Ne(frac(r), np_i).has(Ne)
|
||||
assert Ne(frac(r), nn_i).has(Ne)
|
||||
|
||||
|
||||
# Real frac argument, real rhs
|
||||
assert (frac(r) <= p_r).has(Le)
|
||||
assert not frac(r) <= n_r
|
||||
assert (frac(r) <= np_r).has(Le)
|
||||
assert (frac(r) <= nn_r).has(Le)
|
||||
assert (frac(r) < p_r).has(Lt)
|
||||
assert not frac(r) < n_r
|
||||
assert not frac(r) < np_r
|
||||
assert (frac(r) < nn_r).has(Lt)
|
||||
assert (frac(r) >= p_r).has(Ge)
|
||||
assert frac(r) >= n_r
|
||||
assert frac(r) >= np_r
|
||||
assert (frac(r) >= nn_r).has(Ge)
|
||||
assert (frac(r) > p_r).has(Gt)
|
||||
assert frac(r) > n_r
|
||||
assert (frac(r) > np_r).has(Gt)
|
||||
assert (frac(r) > nn_r).has(Gt)
|
||||
|
||||
assert not Eq(frac(r), n_r)
|
||||
assert Eq(frac(r), p_r).has(Eq)
|
||||
assert Eq(frac(r), np_r).has(Eq)
|
||||
assert Eq(frac(r), nn_r).has(Eq)
|
||||
|
||||
assert Ne(frac(r), p_r).has(Ne)
|
||||
assert Ne(frac(r), n_r)
|
||||
assert Ne(frac(r), np_r).has(Ne)
|
||||
assert Ne(frac(r), nn_r).has(Ne)
|
||||
|
||||
# Real frac argument, +/- oo rhs
|
||||
assert frac(r) < oo
|
||||
assert frac(r) <= oo
|
||||
assert not frac(r) > oo
|
||||
assert not frac(r) >= oo
|
||||
|
||||
assert not frac(r) < -oo
|
||||
assert not frac(r) <= -oo
|
||||
assert frac(r) > -oo
|
||||
assert frac(r) >= -oo
|
||||
|
||||
assert frac(r) < 1
|
||||
assert frac(r) <= 1
|
||||
assert not frac(r) > 1
|
||||
assert not frac(r) >= 1
|
||||
|
||||
assert not frac(r) < 0
|
||||
assert (frac(r) <= 0).has(Le)
|
||||
assert (frac(r) > 0).has(Gt)
|
||||
assert frac(r) >= 0
|
||||
|
||||
# Some test for numbers
|
||||
assert frac(r) <= sqrt(2)
|
||||
assert (frac(r) <= sqrt(3) - sqrt(2)).has(Le)
|
||||
assert not frac(r) <= sqrt(2) - sqrt(3)
|
||||
assert not frac(r) >= sqrt(2)
|
||||
assert (frac(r) >= sqrt(3) - sqrt(2)).has(Ge)
|
||||
assert frac(r) >= sqrt(2) - sqrt(3)
|
||||
|
||||
assert not Eq(frac(r), sqrt(2))
|
||||
assert Eq(frac(r), sqrt(3) - sqrt(2)).has(Eq)
|
||||
assert not Eq(frac(r), sqrt(2) - sqrt(3))
|
||||
assert Ne(frac(r), sqrt(2))
|
||||
assert Ne(frac(r), sqrt(3) - sqrt(2)).has(Ne)
|
||||
assert Ne(frac(r), sqrt(2) - sqrt(3))
|
||||
|
||||
assert frac(p_i, evaluate=False).is_zero
|
||||
assert frac(p_i, evaluate=False).is_finite
|
||||
assert frac(p_i, evaluate=False).is_integer
|
||||
assert frac(p_i, evaluate=False).is_real
|
||||
assert frac(r).is_finite
|
||||
assert frac(r).is_real
|
||||
assert frac(r).is_zero is None
|
||||
assert frac(r).is_integer is None
|
||||
|
||||
assert frac(oo).is_finite
|
||||
assert frac(oo).is_real
|
||||
|
||||
|
||||
def test_series():
|
||||
x, y = symbols('x,y')
|
||||
assert floor(x).nseries(x, y, 100) == floor(y)
|
||||
assert ceiling(x).nseries(x, y, 100) == ceiling(y)
|
||||
assert floor(x).nseries(x, pi, 100) == 3
|
||||
assert ceiling(x).nseries(x, pi, 100) == 4
|
||||
assert floor(x).nseries(x, 0, 100) == 0
|
||||
assert ceiling(x).nseries(x, 0, 100) == 1
|
||||
assert floor(-x).nseries(x, 0, 100) == -1
|
||||
assert ceiling(-x).nseries(x, 0, 100) == 0
|
||||
|
||||
|
||||
def test_issue_14355():
|
||||
# This test checks the leading term and series for the floor and ceil
|
||||
# function when arg0 evaluates to S.NaN.
|
||||
assert floor((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = 1) == -2
|
||||
assert floor((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = -1) == -1
|
||||
assert floor((cos(x) - 1)/x).as_leading_term(x, cdir = 1) == -1
|
||||
assert floor((cos(x) - 1)/x).as_leading_term(x, cdir = -1) == 0
|
||||
assert floor(sin(x)/x).as_leading_term(x, cdir = 1) == 0
|
||||
assert floor(sin(x)/x).as_leading_term(x, cdir = -1) == 0
|
||||
assert floor(-tan(x)/x).as_leading_term(x, cdir = 1) == -2
|
||||
assert floor(-tan(x)/x).as_leading_term(x, cdir = -1) == -2
|
||||
assert floor(sin(x)/x/3).as_leading_term(x, cdir = 1) == 0
|
||||
assert floor(sin(x)/x/3).as_leading_term(x, cdir = -1) == 0
|
||||
assert ceiling((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = 1) == -1
|
||||
assert ceiling((x**3 + x)/(x**2 - x)).as_leading_term(x, cdir = -1) == 0
|
||||
assert ceiling((cos(x) - 1)/x).as_leading_term(x, cdir = 1) == 0
|
||||
assert ceiling((cos(x) - 1)/x).as_leading_term(x, cdir = -1) == 1
|
||||
assert ceiling(sin(x)/x).as_leading_term(x, cdir = 1) == 1
|
||||
assert ceiling(sin(x)/x).as_leading_term(x, cdir = -1) == 1
|
||||
assert ceiling(-tan(x)/x).as_leading_term(x, cdir = 1) == -1
|
||||
assert ceiling(-tan(x)/x).as_leading_term(x, cdir = 1) == -1
|
||||
assert ceiling(sin(x)/x/3).as_leading_term(x, cdir = 1) == 1
|
||||
assert ceiling(sin(x)/x/3).as_leading_term(x, cdir = -1) == 1
|
||||
# test for series
|
||||
assert floor(sin(x)/x).series(x, 0, 100, cdir = 1) == 0
|
||||
assert floor(sin(x)/x).series(x, 0, 100, cdir = 1) == 0
|
||||
assert floor((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = 1) == -2
|
||||
assert floor((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = -1) == -1
|
||||
assert ceiling(sin(x)/x).series(x, 0, 100, cdir = 1) == 1
|
||||
assert ceiling(sin(x)/x).series(x, 0, 100, cdir = -1) == 1
|
||||
assert ceiling((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = 1) == -1
|
||||
assert ceiling((x**3 + x)/(x**2 - x)).series(x, 0, 100, cdir = -1) == 0
|
||||
|
||||
|
||||
def test_frac_leading_term():
|
||||
assert frac(x).as_leading_term(x) == x
|
||||
assert frac(x).as_leading_term(x, cdir = 1) == x
|
||||
assert frac(x).as_leading_term(x, cdir = -1) == 1
|
||||
assert frac(x + S.Half).as_leading_term(x, cdir = 1) == S.Half
|
||||
assert frac(x + S.Half).as_leading_term(x, cdir = -1) == S.Half
|
||||
assert frac(-2*x + 1).as_leading_term(x, cdir = 1) == S.One
|
||||
assert frac(-2*x + 1).as_leading_term(x, cdir = -1) == -2*x
|
||||
assert frac(sin(x) + 5).as_leading_term(x, cdir = 1) == x
|
||||
assert frac(sin(x) + 5).as_leading_term(x, cdir = -1) == S.One
|
||||
assert frac(sin(x**2) + 5).as_leading_term(x, cdir = 1) == x**2
|
||||
assert frac(sin(x**2) + 5).as_leading_term(x, cdir = -1) == x**2
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_4149():
|
||||
assert floor(3 + pi*I + y*I) == 3 + floor(pi + y)*I
|
||||
assert floor(3*I + pi*I + y*I) == floor(3 + pi + y)*I
|
||||
assert floor(3 + E + pi*I + y*I) == 5 + floor(pi + y)*I
|
||||
|
||||
|
||||
def test_issue_21651():
|
||||
k = Symbol('k', positive=True, integer=True)
|
||||
exp = 2*2**(-k)
|
||||
assert isinstance(floor(exp), floor)
|
||||
|
||||
|
||||
def test_issue_11207():
|
||||
assert floor(floor(x)) == floor(x)
|
||||
assert floor(ceiling(x)) == ceiling(x)
|
||||
assert ceiling(floor(x)) == floor(x)
|
||||
assert ceiling(ceiling(x)) == ceiling(x)
|
||||
|
||||
|
||||
def test_nested_floor_ceiling():
|
||||
assert floor(-floor(ceiling(x**3)/y)) == -floor(ceiling(x**3)/y)
|
||||
assert ceiling(-floor(ceiling(x**3)/y)) == -floor(ceiling(x**3)/y)
|
||||
assert floor(ceiling(-floor(x**Rational(7, 2)/y))) == -floor(x**Rational(7, 2)/y)
|
||||
assert -ceiling(-ceiling(floor(x)/y)) == ceiling(floor(x)/y)
|
||||
|
||||
def test_issue_18689():
|
||||
assert floor(floor(floor(x)) + 3) == floor(x) + 3
|
||||
assert ceiling(ceiling(ceiling(x)) + 1) == ceiling(x) + 1
|
||||
assert ceiling(ceiling(floor(x)) + 3) == floor(x) + 3
|
||||
|
||||
def test_issue_18421():
|
||||
assert floor(float(0)) is S.Zero
|
||||
assert ceiling(float(0)) is S.Zero
|
||||
|
||||
def test_issue_25230():
|
||||
a = Symbol('a', real = True)
|
||||
b = Symbol('b', positive = True)
|
||||
c = Symbol('c', negative = True)
|
||||
raises(NotImplementedError, lambda: floor(x/a).as_leading_term(x, cdir = 1))
|
||||
raises(NotImplementedError, lambda: ceiling(x/a).as_leading_term(x, cdir = 1))
|
||||
assert floor(x/b).as_leading_term(x, cdir = 1) == 0
|
||||
assert floor(x/b).as_leading_term(x, cdir = -1) == -1
|
||||
assert floor(x/c).as_leading_term(x, cdir = 1) == -1
|
||||
assert floor(x/c).as_leading_term(x, cdir = -1) == 0
|
||||
assert ceiling(x/b).as_leading_term(x, cdir = 1) == 1
|
||||
assert ceiling(x/b).as_leading_term(x, cdir = -1) == 0
|
||||
assert ceiling(x/c).as_leading_term(x, cdir = 1) == 0
|
||||
assert ceiling(x/c).as_leading_term(x, cdir = -1) == 1
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# This test file tests the SymPy function interface, that people use to create
|
||||
# their own new functions. It should be as easy as possible.
|
||||
#
|
||||
# We test that it works with both Function and DefinedFunction. New code should
|
||||
# use DefinedFunction because it has better type inference. Old code still
|
||||
# using Function should continue to work though.
|
||||
from sympy.core.function import Function, DefinedFunction
|
||||
from sympy.core.sympify import sympify
|
||||
from sympy.functions.elementary.hyperbolic import tanh
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||||
from sympy.series.limits import limit
|
||||
from sympy.abc import x
|
||||
|
||||
|
||||
def test_function_series1():
|
||||
"""Create our new "sin" function."""
|
||||
|
||||
for F in [Function, DefinedFunction]:
|
||||
|
||||
class my_function(F):
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
return cos(self.args[0])
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg):
|
||||
arg = sympify(arg)
|
||||
if arg == 0:
|
||||
return sympify(0)
|
||||
|
||||
#Test that the taylor series is correct
|
||||
assert my_function(x).series(x, 0, 10) == sin(x).series(x, 0, 10)
|
||||
assert limit(my_function(x)/x, x, 0) == 1
|
||||
|
||||
|
||||
def test_function_series2():
|
||||
"""Create our new "cos" function."""
|
||||
|
||||
for F in [Function, DefinedFunction]:
|
||||
|
||||
class my_function2(F):
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
return -sin(self.args[0])
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg):
|
||||
arg = sympify(arg)
|
||||
if arg == 0:
|
||||
return sympify(1)
|
||||
|
||||
#Test that the taylor series is correct
|
||||
assert my_function2(x).series(x, 0, 10) == cos(x).series(x, 0, 10)
|
||||
|
||||
|
||||
def test_function_series3():
|
||||
"""
|
||||
Test our easy "tanh" function.
|
||||
|
||||
This test tests two things:
|
||||
* that the Function interface works as expected and it's easy to use
|
||||
* that the general algorithm for the series expansion works even when the
|
||||
derivative is defined recursively in terms of the original function,
|
||||
since tanh(x).diff(x) == 1-tanh(x)**2
|
||||
"""
|
||||
|
||||
for F in [Function, DefinedFunction]:
|
||||
|
||||
class mytanh(F):
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
return 1 - mytanh(self.args[0])**2
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg):
|
||||
arg = sympify(arg)
|
||||
if arg == 0:
|
||||
return sympify(0)
|
||||
|
||||
e = tanh(x)
|
||||
f = mytanh(x)
|
||||
assert e.series(x, 0, 6) == f.series(x, 0, 6)
|
||||
+504
@@ -0,0 +1,504 @@
|
||||
import itertools as it
|
||||
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.function import Function
|
||||
from sympy.core.numbers import I, oo, Rational
|
||||
from sympy.core.power import Pow
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.external import import_module
|
||||
from sympy.functions.elementary.exponential import log
|
||||
from sympy.functions.elementary.integers import floor, ceiling
|
||||
from sympy.functions.elementary.miscellaneous import (sqrt, cbrt, root, Min,
|
||||
Max, real_root, Rem)
|
||||
from sympy.functions.elementary.trigonometric import cos, sin
|
||||
from sympy.functions.special.delta_functions import Heaviside
|
||||
|
||||
from sympy.utilities.lambdify import lambdify
|
||||
from sympy.testing.pytest import raises, skip, ignore_warnings
|
||||
|
||||
def test_Min():
|
||||
from sympy.abc import x, y, z
|
||||
n = Symbol('n', negative=True)
|
||||
n_ = Symbol('n_', negative=True)
|
||||
nn = Symbol('nn', nonnegative=True)
|
||||
nn_ = Symbol('nn_', nonnegative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
p_ = Symbol('p_', positive=True)
|
||||
np = Symbol('np', nonpositive=True)
|
||||
np_ = Symbol('np_', nonpositive=True)
|
||||
r = Symbol('r', real=True)
|
||||
|
||||
assert Min(5, 4) == 4
|
||||
assert Min(-oo, -oo) is -oo
|
||||
assert Min(-oo, n) is -oo
|
||||
assert Min(n, -oo) is -oo
|
||||
assert Min(-oo, np) is -oo
|
||||
assert Min(np, -oo) is -oo
|
||||
assert Min(-oo, 0) is -oo
|
||||
assert Min(0, -oo) is -oo
|
||||
assert Min(-oo, nn) is -oo
|
||||
assert Min(nn, -oo) is -oo
|
||||
assert Min(-oo, p) is -oo
|
||||
assert Min(p, -oo) is -oo
|
||||
assert Min(-oo, oo) is -oo
|
||||
assert Min(oo, -oo) is -oo
|
||||
assert Min(n, n) == n
|
||||
assert unchanged(Min, n, np)
|
||||
assert Min(np, n) == Min(n, np)
|
||||
assert Min(n, 0) == n
|
||||
assert Min(0, n) == n
|
||||
assert Min(n, nn) == n
|
||||
assert Min(nn, n) == n
|
||||
assert Min(n, p) == n
|
||||
assert Min(p, n) == n
|
||||
assert Min(n, oo) == n
|
||||
assert Min(oo, n) == n
|
||||
assert Min(np, np) == np
|
||||
assert Min(np, 0) == np
|
||||
assert Min(0, np) == np
|
||||
assert Min(np, nn) == np
|
||||
assert Min(nn, np) == np
|
||||
assert Min(np, p) == np
|
||||
assert Min(p, np) == np
|
||||
assert Min(np, oo) == np
|
||||
assert Min(oo, np) == np
|
||||
assert Min(0, 0) == 0
|
||||
assert Min(0, nn) == 0
|
||||
assert Min(nn, 0) == 0
|
||||
assert Min(0, p) == 0
|
||||
assert Min(p, 0) == 0
|
||||
assert Min(0, oo) == 0
|
||||
assert Min(oo, 0) == 0
|
||||
assert Min(nn, nn) == nn
|
||||
assert unchanged(Min, nn, p)
|
||||
assert Min(p, nn) == Min(nn, p)
|
||||
assert Min(nn, oo) == nn
|
||||
assert Min(oo, nn) == nn
|
||||
assert Min(p, p) == p
|
||||
assert Min(p, oo) == p
|
||||
assert Min(oo, p) == p
|
||||
assert Min(oo, oo) is oo
|
||||
|
||||
assert Min(n, n_).func is Min
|
||||
assert Min(nn, nn_).func is Min
|
||||
assert Min(np, np_).func is Min
|
||||
assert Min(p, p_).func is Min
|
||||
|
||||
# lists
|
||||
assert Min() is S.Infinity
|
||||
assert Min(x) == x
|
||||
assert Min(x, y) == Min(y, x)
|
||||
assert Min(x, y, z) == Min(z, y, x)
|
||||
assert Min(x, Min(y, z)) == Min(z, y, x)
|
||||
assert Min(x, Max(y, -oo)) == Min(x, y)
|
||||
assert Min(p, oo, n, p, p, p_) == n
|
||||
assert Min(p_, n_, p) == n_
|
||||
assert Min(n, oo, -7, p, p, 2) == Min(n, -7)
|
||||
assert Min(2, x, p, n, oo, n_, p, 2, -2, -2) == Min(-2, x, n, n_)
|
||||
assert Min(0, x, 1, y) == Min(0, x, y)
|
||||
assert Min(1000, 100, -100, x, p, n) == Min(n, x, -100)
|
||||
assert unchanged(Min, sin(x), cos(x))
|
||||
assert Min(sin(x), cos(x)) == Min(cos(x), sin(x))
|
||||
assert Min(cos(x), sin(x)).subs(x, 1) == cos(1)
|
||||
assert Min(cos(x), sin(x)).subs(x, S.Half) == sin(S.Half)
|
||||
raises(ValueError, lambda: Min(cos(x), sin(x)).subs(x, I))
|
||||
raises(ValueError, lambda: Min(I))
|
||||
raises(ValueError, lambda: Min(I, x))
|
||||
raises(ValueError, lambda: Min(S.ComplexInfinity, x))
|
||||
|
||||
assert Min(1, x).diff(x) == Heaviside(1 - x)
|
||||
assert Min(x, 1).diff(x) == Heaviside(1 - x)
|
||||
assert Min(0, -x, 1 - 2*x).diff(x) == -Heaviside(x + Min(0, -2*x + 1)) \
|
||||
- 2*Heaviside(2*x + Min(0, -x) - 1)
|
||||
|
||||
# issue 7619
|
||||
f = Function('f')
|
||||
assert Min(1, 2*Min(f(1), 2)) # doesn't fail
|
||||
|
||||
# issue 7233
|
||||
e = Min(0, x)
|
||||
assert e.n().args == (0, x)
|
||||
|
||||
# issue 8643
|
||||
m = Min(n, p_, n_, r)
|
||||
assert m.is_positive is False
|
||||
assert m.is_nonnegative is False
|
||||
assert m.is_negative is True
|
||||
|
||||
m = Min(p, p_)
|
||||
assert m.is_positive is True
|
||||
assert m.is_nonnegative is True
|
||||
assert m.is_negative is False
|
||||
|
||||
m = Min(p, nn_, p_)
|
||||
assert m.is_positive is None
|
||||
assert m.is_nonnegative is True
|
||||
assert m.is_negative is False
|
||||
|
||||
m = Min(nn, p, r)
|
||||
assert m.is_positive is None
|
||||
assert m.is_nonnegative is None
|
||||
assert m.is_negative is None
|
||||
|
||||
|
||||
def test_Max():
|
||||
from sympy.abc import x, y, z
|
||||
n = Symbol('n', negative=True)
|
||||
n_ = Symbol('n_', negative=True)
|
||||
nn = Symbol('nn', nonnegative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
p_ = Symbol('p_', positive=True)
|
||||
r = Symbol('r', real=True)
|
||||
|
||||
assert Max(5, 4) == 5
|
||||
|
||||
# lists
|
||||
|
||||
assert Max() is S.NegativeInfinity
|
||||
assert Max(x) == x
|
||||
assert Max(x, y) == Max(y, x)
|
||||
assert Max(x, y, z) == Max(z, y, x)
|
||||
assert Max(x, Max(y, z)) == Max(z, y, x)
|
||||
assert Max(x, Min(y, oo)) == Max(x, y)
|
||||
assert Max(n, -oo, n_, p, 2) == Max(p, 2)
|
||||
assert Max(n, -oo, n_, p) == p
|
||||
assert Max(2, x, p, n, -oo, S.NegativeInfinity, n_, p, 2) == Max(2, x, p)
|
||||
assert Max(0, x, 1, y) == Max(1, x, y)
|
||||
assert Max(r, r + 1, r - 1) == 1 + r
|
||||
assert Max(1000, 100, -100, x, p, n) == Max(p, x, 1000)
|
||||
assert Max(cos(x), sin(x)) == Max(sin(x), cos(x))
|
||||
assert Max(cos(x), sin(x)).subs(x, 1) == sin(1)
|
||||
assert Max(cos(x), sin(x)).subs(x, S.Half) == cos(S.Half)
|
||||
raises(ValueError, lambda: Max(cos(x), sin(x)).subs(x, I))
|
||||
raises(ValueError, lambda: Max(I))
|
||||
raises(ValueError, lambda: Max(I, x))
|
||||
raises(ValueError, lambda: Max(S.ComplexInfinity, 1))
|
||||
assert Max(n, -oo, n_, p, 2) == Max(p, 2)
|
||||
assert Max(n, -oo, n_, p, 1000) == Max(p, 1000)
|
||||
|
||||
assert Max(1, x).diff(x) == Heaviside(x - 1)
|
||||
assert Max(x, 1).diff(x) == Heaviside(x - 1)
|
||||
assert Max(x**2, 1 + x, 1).diff(x) == \
|
||||
2*x*Heaviside(x**2 - Max(1, x + 1)) \
|
||||
+ Heaviside(x - Max(1, x**2) + 1)
|
||||
|
||||
e = Max(0, x)
|
||||
assert e.n().args == (0, x)
|
||||
|
||||
# issue 8643
|
||||
m = Max(p, p_, n, r)
|
||||
assert m.is_positive is True
|
||||
assert m.is_nonnegative is True
|
||||
assert m.is_negative is False
|
||||
|
||||
m = Max(n, n_)
|
||||
assert m.is_positive is False
|
||||
assert m.is_nonnegative is False
|
||||
assert m.is_negative is True
|
||||
|
||||
m = Max(n, n_, r)
|
||||
assert m.is_positive is None
|
||||
assert m.is_nonnegative is None
|
||||
assert m.is_negative is None
|
||||
|
||||
m = Max(n, nn, r)
|
||||
assert m.is_positive is None
|
||||
assert m.is_nonnegative is True
|
||||
assert m.is_negative is False
|
||||
|
||||
|
||||
def test_minmax_assumptions():
|
||||
r = Symbol('r', real=True)
|
||||
a = Symbol('a', real=True, algebraic=True)
|
||||
t = Symbol('t', real=True, transcendental=True)
|
||||
q = Symbol('q', rational=True)
|
||||
p = Symbol('p', irrational=True)
|
||||
n = Symbol('n', rational=True, integer=False)
|
||||
i = Symbol('i', integer=True)
|
||||
o = Symbol('o', odd=True)
|
||||
e = Symbol('e', even=True)
|
||||
k = Symbol('k', prime=True)
|
||||
reals = [r, a, t, q, p, n, i, o, e, k]
|
||||
|
||||
for ext in (Max, Min):
|
||||
for x, y in it.product(reals, repeat=2):
|
||||
|
||||
# Must be real
|
||||
assert ext(x, y).is_real
|
||||
|
||||
# Algebraic?
|
||||
if x.is_algebraic and y.is_algebraic:
|
||||
assert ext(x, y).is_algebraic
|
||||
elif x.is_transcendental and y.is_transcendental:
|
||||
assert ext(x, y).is_transcendental
|
||||
else:
|
||||
assert ext(x, y).is_algebraic is None
|
||||
|
||||
# Rational?
|
||||
if x.is_rational and y.is_rational:
|
||||
assert ext(x, y).is_rational
|
||||
elif x.is_irrational and y.is_irrational:
|
||||
assert ext(x, y).is_irrational
|
||||
else:
|
||||
assert ext(x, y).is_rational is None
|
||||
|
||||
# Integer?
|
||||
if x.is_integer and y.is_integer:
|
||||
assert ext(x, y).is_integer
|
||||
elif x.is_noninteger and y.is_noninteger:
|
||||
assert ext(x, y).is_noninteger
|
||||
else:
|
||||
assert ext(x, y).is_integer is None
|
||||
|
||||
# Odd?
|
||||
if x.is_odd and y.is_odd:
|
||||
assert ext(x, y).is_odd
|
||||
elif x.is_odd is False and y.is_odd is False:
|
||||
assert ext(x, y).is_odd is False
|
||||
else:
|
||||
assert ext(x, y).is_odd is None
|
||||
|
||||
# Even?
|
||||
if x.is_even and y.is_even:
|
||||
assert ext(x, y).is_even
|
||||
elif x.is_even is False and y.is_even is False:
|
||||
assert ext(x, y).is_even is False
|
||||
else:
|
||||
assert ext(x, y).is_even is None
|
||||
|
||||
# Prime?
|
||||
if x.is_prime and y.is_prime:
|
||||
assert ext(x, y).is_prime
|
||||
elif x.is_prime is False and y.is_prime is False:
|
||||
assert ext(x, y).is_prime is False
|
||||
else:
|
||||
assert ext(x, y).is_prime is None
|
||||
|
||||
|
||||
def test_issue_8413():
|
||||
x = Symbol('x', real=True)
|
||||
# we can't evaluate in general because non-reals are not
|
||||
# comparable: Min(floor(3.2 + I), 3.2 + I) -> ValueError
|
||||
assert Min(floor(x), x) == floor(x)
|
||||
assert Min(ceiling(x), x) == x
|
||||
assert Max(floor(x), x) == x
|
||||
assert Max(ceiling(x), x) == ceiling(x)
|
||||
|
||||
|
||||
def test_root():
|
||||
from sympy.abc import x
|
||||
n = Symbol('n', integer=True)
|
||||
k = Symbol('k', integer=True)
|
||||
|
||||
assert root(2, 2) == sqrt(2)
|
||||
assert root(2, 1) == 2
|
||||
assert root(2, 3) == 2**Rational(1, 3)
|
||||
assert root(2, 3) == cbrt(2)
|
||||
assert root(2, -5) == 2**Rational(4, 5)/2
|
||||
|
||||
assert root(-2, 1) == -2
|
||||
|
||||
assert root(-2, 2) == sqrt(2)*I
|
||||
assert root(-2, 1) == -2
|
||||
|
||||
assert root(x, 2) == sqrt(x)
|
||||
assert root(x, 1) == x
|
||||
assert root(x, 3) == x**Rational(1, 3)
|
||||
assert root(x, 3) == cbrt(x)
|
||||
assert root(x, -5) == x**Rational(-1, 5)
|
||||
|
||||
assert root(x, n) == x**(1/n)
|
||||
assert root(x, -n) == x**(-1/n)
|
||||
|
||||
assert root(x, n, k) == (-1)**(2*k/n)*x**(1/n)
|
||||
|
||||
|
||||
def test_real_root():
|
||||
assert real_root(-8, 3) == -2
|
||||
assert real_root(-16, 4) == root(-16, 4)
|
||||
r = root(-7, 4)
|
||||
assert real_root(r) == r
|
||||
r1 = root(-1, 3)
|
||||
r2 = r1**2
|
||||
r3 = root(-1, 4)
|
||||
assert real_root(r1 + r2 + r3) == -1 + r2 + r3
|
||||
assert real_root(root(-2, 3)) == -root(2, 3)
|
||||
assert real_root(-8., 3) == -2.0
|
||||
x = Symbol('x')
|
||||
n = Symbol('n')
|
||||
g = real_root(x, n)
|
||||
assert g.subs({"x": -8, "n": 3}) == -2
|
||||
assert g.subs({"x": 8, "n": 3}) == 2
|
||||
# give principle root if there is no real root -- if this is not desired
|
||||
# then maybe a Root class is needed to raise an error instead
|
||||
assert g.subs({"x": I, "n": 3}) == cbrt(I)
|
||||
assert g.subs({"x": -8, "n": 2}) == sqrt(-8)
|
||||
assert g.subs({"x": I, "n": 2}) == sqrt(I)
|
||||
|
||||
|
||||
def test_issue_11463():
|
||||
numpy = import_module('numpy')
|
||||
if not numpy:
|
||||
skip("numpy not installed.")
|
||||
x = Symbol('x')
|
||||
f = lambdify(x, real_root((log(x/(x-2))), 3), 'numpy')
|
||||
# numpy.select evaluates all options before considering conditions,
|
||||
# so it raises a warning about root of negative number which does
|
||||
# not affect the outcome. This warning is suppressed here
|
||||
with ignore_warnings(RuntimeWarning):
|
||||
assert f(numpy.array(-1)) < -1
|
||||
|
||||
|
||||
def test_rewrite_MaxMin_as_Heaviside():
|
||||
from sympy.abc import x
|
||||
assert Max(0, x).rewrite(Heaviside) == x*Heaviside(x)
|
||||
assert Max(3, x).rewrite(Heaviside) == x*Heaviside(x - 3) + \
|
||||
3*Heaviside(-x + 3)
|
||||
assert Max(0, x+2, 2*x).rewrite(Heaviside) == \
|
||||
2*x*Heaviside(2*x)*Heaviside(x - 2) + \
|
||||
(x + 2)*Heaviside(-x + 2)*Heaviside(x + 2)
|
||||
|
||||
assert Min(0, x).rewrite(Heaviside) == x*Heaviside(-x)
|
||||
assert Min(3, x).rewrite(Heaviside) == x*Heaviside(-x + 3) + \
|
||||
3*Heaviside(x - 3)
|
||||
assert Min(x, -x, -2).rewrite(Heaviside) == \
|
||||
x*Heaviside(-2*x)*Heaviside(-x - 2) - \
|
||||
x*Heaviside(2*x)*Heaviside(x - 2) \
|
||||
- 2*Heaviside(-x + 2)*Heaviside(x + 2)
|
||||
|
||||
|
||||
def test_rewrite_MaxMin_as_Piecewise():
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
x, y, z, a, b = symbols('x y z a b', real=True)
|
||||
vx, vy, va = symbols('vx vy va')
|
||||
assert Max(a, b).rewrite(Piecewise) == Piecewise((a, a >= b), (b, True))
|
||||
assert Max(x, y, z).rewrite(Piecewise) == Piecewise((x, (x >= y) & (x >= z)), (y, y >= z), (z, True))
|
||||
assert Max(x, y, a, b).rewrite(Piecewise) == Piecewise((a, (a >= b) & (a >= x) & (a >= y)),
|
||||
(b, (b >= x) & (b >= y)), (x, x >= y), (y, True))
|
||||
assert Min(a, b).rewrite(Piecewise) == Piecewise((a, a <= b), (b, True))
|
||||
assert Min(x, y, z).rewrite(Piecewise) == Piecewise((x, (x <= y) & (x <= z)), (y, y <= z), (z, True))
|
||||
assert Min(x, y, a, b).rewrite(Piecewise) == Piecewise((a, (a <= b) & (a <= x) & (a <= y)),
|
||||
(b, (b <= x) & (b <= y)), (x, x <= y), (y, True))
|
||||
|
||||
# Piecewise rewriting of Min/Max does also takes place for not explicitly real arguments
|
||||
assert Max(vx, vy).rewrite(Piecewise) == Piecewise((vx, vx >= vy), (vy, True))
|
||||
assert Min(va, vx, vy).rewrite(Piecewise) == Piecewise((va, (va <= vx) & (va <= vy)), (vx, vx <= vy), (vy, True))
|
||||
|
||||
|
||||
def test_issue_11099():
|
||||
from sympy.abc import x, y
|
||||
# some fixed value tests
|
||||
fixed_test_data = {x: -2, y: 3}
|
||||
assert Min(x, y).evalf(subs=fixed_test_data) == \
|
||||
Min(x, y).subs(fixed_test_data).evalf()
|
||||
assert Max(x, y).evalf(subs=fixed_test_data) == \
|
||||
Max(x, y).subs(fixed_test_data).evalf()
|
||||
# randomly generate some test data
|
||||
from sympy.core.random import randint
|
||||
for i in range(20):
|
||||
random_test_data = {x: randint(-100, 100), y: randint(-100, 100)}
|
||||
assert Min(x, y).evalf(subs=random_test_data) == \
|
||||
Min(x, y).subs(random_test_data).evalf()
|
||||
assert Max(x, y).evalf(subs=random_test_data) == \
|
||||
Max(x, y).subs(random_test_data).evalf()
|
||||
|
||||
|
||||
def test_issue_12638():
|
||||
from sympy.abc import a, b, c
|
||||
assert Min(a, b, c, Max(a, b)) == Min(a, b, c)
|
||||
assert Min(a, b, Max(a, b, c)) == Min(a, b)
|
||||
assert Min(a, b, Max(a, c)) == Min(a, b)
|
||||
|
||||
def test_issue_21399():
|
||||
from sympy.abc import a, b, c
|
||||
assert Max(Min(a, b), Min(a, b, c)) == Min(a, b)
|
||||
|
||||
|
||||
def test_instantiation_evaluation():
|
||||
from sympy.abc import v, w, x, y, z
|
||||
assert Min(1, Max(2, x)) == 1
|
||||
assert Max(3, Min(2, x)) == 3
|
||||
assert Min(Max(x, y), Max(x, z)) == Max(x, Min(y, z))
|
||||
assert set(Min(Max(w, x), Max(y, z)).args) == {
|
||||
Max(w, x), Max(y, z)}
|
||||
assert Min(Max(x, y), Max(x, z), w) == Min(
|
||||
w, Max(x, Min(y, z)))
|
||||
A, B = Min, Max
|
||||
for i in range(2):
|
||||
assert A(x, B(x, y)) == x
|
||||
assert A(x, B(y, A(x, w, z))) == A(x, B(y, A(w, z)))
|
||||
A, B = B, A
|
||||
assert Min(w, Max(x, y), Max(v, x, z)) == Min(
|
||||
w, Max(x, Min(y, Max(v, z))))
|
||||
|
||||
def test_rewrite_as_Abs():
|
||||
from itertools import permutations
|
||||
from sympy.functions.elementary.complexes import Abs
|
||||
from sympy.abc import x, y, z, w
|
||||
def test(e):
|
||||
free = e.free_symbols
|
||||
a = e.rewrite(Abs)
|
||||
assert not a.has(Min, Max)
|
||||
for i in permutations(range(len(free))):
|
||||
reps = dict(zip(free, i))
|
||||
assert a.xreplace(reps) == e.xreplace(reps)
|
||||
test(Min(x, y))
|
||||
test(Max(x, y))
|
||||
test(Min(x, y, z))
|
||||
test(Min(Max(w, x), Max(y, z)))
|
||||
|
||||
def test_issue_14000():
|
||||
assert isinstance(sqrt(4, evaluate=False), Pow) == True
|
||||
assert isinstance(cbrt(3.5, evaluate=False), Pow) == True
|
||||
assert isinstance(root(16, 4, evaluate=False), Pow) == True
|
||||
|
||||
assert sqrt(4, evaluate=False) == Pow(4, S.Half, evaluate=False)
|
||||
assert cbrt(3.5, evaluate=False) == Pow(3.5, Rational(1, 3), evaluate=False)
|
||||
assert root(4, 2, evaluate=False) == Pow(4, S.Half, evaluate=False)
|
||||
|
||||
assert root(16, 4, 2, evaluate=False).has(Pow) == True
|
||||
assert real_root(-8, 3, evaluate=False).has(Pow) == True
|
||||
|
||||
def test_issue_6899():
|
||||
from sympy.core.function import Lambda
|
||||
x = Symbol('x')
|
||||
eqn = Lambda(x, x)
|
||||
assert eqn.func(*eqn.args) == eqn
|
||||
|
||||
def test_Rem():
|
||||
from sympy.abc import x, y
|
||||
assert Rem(5, 3) == 2
|
||||
assert Rem(-5, 3) == -2
|
||||
assert Rem(5, -3) == 2
|
||||
assert Rem(-5, -3) == -2
|
||||
assert Rem(x**3, y) == Rem(x**3, y)
|
||||
assert Rem(Rem(-5, 3) + 3, 3) == 1
|
||||
|
||||
|
||||
def test_minmax_no_evaluate():
|
||||
from sympy import evaluate
|
||||
p = Symbol('p', positive=True)
|
||||
|
||||
assert Max(1, 3) == 3
|
||||
assert Max(1, 3).args == ()
|
||||
assert Max(0, p) == p
|
||||
assert Max(0, p).args == ()
|
||||
assert Min(0, p) == 0
|
||||
assert Min(0, p).args == ()
|
||||
|
||||
assert Max(1, 3, evaluate=False) != 3
|
||||
assert Max(1, 3, evaluate=False).args == (1, 3)
|
||||
assert Max(0, p, evaluate=False) != p
|
||||
assert Max(0, p, evaluate=False).args == (0, p)
|
||||
assert Min(0, p, evaluate=False) != 0
|
||||
assert Min(0, p, evaluate=False).args == (0, p)
|
||||
|
||||
with evaluate(False):
|
||||
assert Max(1, 3) != 3
|
||||
assert Max(1, 3).args == (1, 3)
|
||||
assert Max(0, p) != p
|
||||
assert Max(0, p).args == (0, p)
|
||||
assert Min(0, p) != 0
|
||||
assert Min(0, p).args == (0, p)
|
||||
+1639
File diff suppressed because it is too large
Load Diff
+2236
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
# Stub __init__.py for the sympy.functions.special package
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.special.spherical_harmonics import Ynm
|
||||
|
||||
x, y = symbols('x,y')
|
||||
|
||||
|
||||
def timeit_Ynm_xy():
|
||||
Ynm(1, 1, x, y)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,389 @@
|
||||
from sympy.core import S
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.symbol import Dummy, uniquely_named_symbol
|
||||
from sympy.functions.special.gamma_functions import gamma, digamma
|
||||
from sympy.functions.combinatorial.numbers import catalan
|
||||
from sympy.functions.elementary.complexes import conjugate
|
||||
|
||||
# See mpmath #569 and SymPy #20569
|
||||
def betainc_mpmath_fix(a, b, x1, x2, reg=0):
|
||||
from mpmath import betainc, mpf
|
||||
if x1 == x2:
|
||||
return mpf(0)
|
||||
else:
|
||||
return betainc(a, b, x1, x2, reg)
|
||||
|
||||
###############################################################################
|
||||
############################ COMPLETE BETA FUNCTION ##########################
|
||||
###############################################################################
|
||||
|
||||
class beta(DefinedFunction):
|
||||
r"""
|
||||
The beta integral is called the Eulerian integral of the first kind by
|
||||
Legendre:
|
||||
|
||||
.. math::
|
||||
\mathrm{B}(x,y) \int^{1}_{0} t^{x-1} (1-t)^{y-1} \mathrm{d}t.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Beta function or Euler's first integral is closely associated
|
||||
with the gamma function. The Beta function is often used in probability
|
||||
theory and mathematical statistics. It satisfies properties like:
|
||||
|
||||
.. math::
|
||||
\mathrm{B}(a,1) = \frac{1}{a} \\
|
||||
\mathrm{B}(a,b) = \mathrm{B}(b,a) \\
|
||||
\mathrm{B}(a,b) = \frac{\Gamma(a) \Gamma(b)}{\Gamma(a+b)}
|
||||
|
||||
Therefore for integral values of $a$ and $b$:
|
||||
|
||||
.. math::
|
||||
\mathrm{B} = \frac{(a-1)! (b-1)!}{(a+b-1)!}
|
||||
|
||||
A special case of the Beta function when `x = y` is the
|
||||
Central Beta function. It satisfies properties like:
|
||||
|
||||
.. math::
|
||||
\mathrm{B}(x) = 2^{1 - 2x}\mathrm{B}(x, \frac{1}{2})
|
||||
\mathrm{B}(x) = 2^{1 - 2x} cos(\pi x) \mathrm{B}(\frac{1}{2} - x, x)
|
||||
\mathrm{B}(x) = \int_{0}^{1} \frac{t^x}{(1 + t)^{2x}} dt
|
||||
\mathrm{B}(x) = \frac{2}{x} \prod_{n = 1}^{\infty} \frac{n(n + 2x)}{(n + x)^2}
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import I, pi
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
The Beta function obeys the mirror symmetry:
|
||||
|
||||
>>> from sympy import beta, conjugate
|
||||
>>> conjugate(beta(x, y))
|
||||
beta(conjugate(x), conjugate(y))
|
||||
|
||||
Differentiation with respect to both $x$ and $y$ is supported:
|
||||
|
||||
>>> from sympy import beta, diff
|
||||
>>> diff(beta(x, y), x)
|
||||
(polygamma(0, x) - polygamma(0, x + y))*beta(x, y)
|
||||
|
||||
>>> diff(beta(x, y), y)
|
||||
(polygamma(0, y) - polygamma(0, x + y))*beta(x, y)
|
||||
|
||||
>>> diff(beta(x), x)
|
||||
2*(polygamma(0, x) - polygamma(0, 2*x))*beta(x, x)
|
||||
|
||||
We can numerically evaluate the Beta function to
|
||||
arbitrary precision for any complex numbers x and y:
|
||||
|
||||
>>> from sympy import beta
|
||||
>>> beta(pi).evalf(40)
|
||||
0.02671848900111377452242355235388489324562
|
||||
|
||||
>>> beta(1 + I).evalf(20)
|
||||
-0.2112723729365330143 - 0.7655283165378005676*I
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gamma: Gamma function.
|
||||
uppergamma: Upper incomplete gamma function.
|
||||
lowergamma: Lower incomplete gamma function.
|
||||
polygamma: Polygamma function.
|
||||
loggamma: Log Gamma function.
|
||||
digamma: Digamma function.
|
||||
trigamma: Trigamma function.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Beta_function
|
||||
.. [2] https://mathworld.wolfram.com/BetaFunction.html
|
||||
.. [3] https://dlmf.nist.gov/5.12
|
||||
|
||||
"""
|
||||
unbranched = True
|
||||
|
||||
def fdiff(self, argindex):
|
||||
x, y = self.args
|
||||
if argindex == 1:
|
||||
# Diff wrt x
|
||||
return beta(x, y)*(digamma(x) - digamma(x + y))
|
||||
elif argindex == 2:
|
||||
# Diff wrt y
|
||||
return beta(x, y)*(digamma(y) - digamma(x + y))
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, x, y=None):
|
||||
if y is None:
|
||||
return beta(x, x)
|
||||
if x.is_Number and y.is_Number:
|
||||
return beta(x, y, evaluate=False).doit()
|
||||
|
||||
def doit(self, **hints):
|
||||
x = xold = self.args[0]
|
||||
# Deal with unevaluated single argument beta
|
||||
single_argument = len(self.args) == 1
|
||||
y = yold = self.args[0] if single_argument else self.args[1]
|
||||
if hints.get('deep', True):
|
||||
x = x.doit(**hints)
|
||||
y = y.doit(**hints)
|
||||
if y.is_zero or x.is_zero:
|
||||
return S.ComplexInfinity
|
||||
if y is S.One:
|
||||
return 1/x
|
||||
if x is S.One:
|
||||
return 1/y
|
||||
if y == x + 1:
|
||||
return 1/(x*y*catalan(x))
|
||||
s = x + y
|
||||
if (s.is_integer and s.is_negative and x.is_integer is False and
|
||||
y.is_integer is False):
|
||||
return S.Zero
|
||||
if x == xold and y == yold and not single_argument:
|
||||
return self
|
||||
return beta(x, y)
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
x, y = self.args
|
||||
return gamma(x)*gamma(y) / gamma(x + y)
|
||||
|
||||
def _eval_is_real(self):
|
||||
return self.args[0].is_real and self.args[1].is_real
|
||||
|
||||
def _eval_conjugate(self):
|
||||
return self.func(self.args[0].conjugate(), self.args[1].conjugate())
|
||||
|
||||
def _eval_rewrite_as_gamma(self, x, y, piecewise=True, **kwargs):
|
||||
return self._eval_expand_func(**kwargs)
|
||||
|
||||
def _eval_rewrite_as_Integral(self, x, y, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', [x, y]).name)
|
||||
return Integral(t**(x - 1)*(1 - t)**(y - 1), (t, 0, 1))
|
||||
|
||||
###############################################################################
|
||||
########################## INCOMPLETE BETA FUNCTION ###########################
|
||||
###############################################################################
|
||||
|
||||
class betainc(DefinedFunction):
|
||||
r"""
|
||||
The Generalized Incomplete Beta function is defined as
|
||||
|
||||
.. math::
|
||||
\mathrm{B}_{(x_1, x_2)}(a, b) = \int_{x_1}^{x_2} t^{a - 1} (1 - t)^{b - 1} dt
|
||||
|
||||
The Incomplete Beta function is a special case
|
||||
of the Generalized Incomplete Beta function :
|
||||
|
||||
.. math:: \mathrm{B}_z (a, b) = \mathrm{B}_{(0, z)}(a, b)
|
||||
|
||||
The Incomplete Beta function satisfies :
|
||||
|
||||
.. math:: \mathrm{B}_z (a, b) = (-1)^a \mathrm{B}_{\frac{z}{z - 1}} (a, 1 - a - b)
|
||||
|
||||
The Beta function is a special case of the Incomplete Beta function :
|
||||
|
||||
.. math:: \mathrm{B}(a, b) = \mathrm{B}_{1}(a, b)
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import betainc, symbols, conjugate
|
||||
>>> a, b, x, x1, x2 = symbols('a b x x1 x2')
|
||||
|
||||
The Generalized Incomplete Beta function is given by:
|
||||
|
||||
>>> betainc(a, b, x1, x2)
|
||||
betainc(a, b, x1, x2)
|
||||
|
||||
The Incomplete Beta function can be obtained as follows:
|
||||
|
||||
>>> betainc(a, b, 0, x)
|
||||
betainc(a, b, 0, x)
|
||||
|
||||
The Incomplete Beta function obeys the mirror symmetry:
|
||||
|
||||
>>> conjugate(betainc(a, b, x1, x2))
|
||||
betainc(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
|
||||
|
||||
We can numerically evaluate the Incomplete Beta function to
|
||||
arbitrary precision for any complex numbers a, b, x1 and x2:
|
||||
|
||||
>>> from sympy import betainc, I
|
||||
>>> betainc(2, 3, 4, 5).evalf(10)
|
||||
56.08333333
|
||||
>>> betainc(0.75, 1 - 4*I, 0, 2 + 3*I).evalf(25)
|
||||
0.2241657956955709603655887 + 0.3619619242700451992411724*I
|
||||
|
||||
The Generalized Incomplete Beta function can be expressed
|
||||
in terms of the Generalized Hypergeometric function.
|
||||
|
||||
>>> from sympy import hyper
|
||||
>>> betainc(a, b, x1, x2).rewrite(hyper)
|
||||
(-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/a
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
beta: Beta function
|
||||
hyper: Generalized Hypergeometric function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
|
||||
.. [2] https://dlmf.nist.gov/8.17
|
||||
.. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
|
||||
.. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
|
||||
|
||||
"""
|
||||
nargs = 4
|
||||
unbranched = True
|
||||
|
||||
def fdiff(self, argindex):
|
||||
a, b, x1, x2 = self.args
|
||||
if argindex == 3:
|
||||
# Diff wrt x1
|
||||
return -(1 - x1)**(b - 1)*x1**(a - 1)
|
||||
elif argindex == 4:
|
||||
# Diff wrt x2
|
||||
return (1 - x2)**(b - 1)*x2**(a - 1)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_mpmath(self):
|
||||
return betainc_mpmath_fix, self.args
|
||||
|
||||
def _eval_is_real(self):
|
||||
if all(arg.is_real for arg in self.args):
|
||||
return True
|
||||
|
||||
def _eval_conjugate(self):
|
||||
return self.func(*map(conjugate, self.args))
|
||||
|
||||
def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', [a, b, x1, x2]).name)
|
||||
return Integral(t**(a - 1)*(1 - t)**(b - 1), (t, x1, x2))
|
||||
|
||||
def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.functions.special.hyper import hyper
|
||||
return (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
|
||||
|
||||
###############################################################################
|
||||
#################### REGULARIZED INCOMPLETE BETA FUNCTION #####################
|
||||
###############################################################################
|
||||
|
||||
class betainc_regularized(DefinedFunction):
|
||||
r"""
|
||||
The Generalized Regularized Incomplete Beta function is given by
|
||||
|
||||
.. math::
|
||||
\mathrm{I}_{(x_1, x_2)}(a, b) = \frac{\mathrm{B}_{(x_1, x_2)}(a, b)}{\mathrm{B}(a, b)}
|
||||
|
||||
The Regularized Incomplete Beta function is a special case
|
||||
of the Generalized Regularized Incomplete Beta function :
|
||||
|
||||
.. math:: \mathrm{I}_z (a, b) = \mathrm{I}_{(0, z)}(a, b)
|
||||
|
||||
The Regularized Incomplete Beta function is the cumulative distribution
|
||||
function of the beta distribution.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import betainc_regularized, symbols, conjugate
|
||||
>>> a, b, x, x1, x2 = symbols('a b x x1 x2')
|
||||
|
||||
The Generalized Regularized Incomplete Beta
|
||||
function is given by:
|
||||
|
||||
>>> betainc_regularized(a, b, x1, x2)
|
||||
betainc_regularized(a, b, x1, x2)
|
||||
|
||||
The Regularized Incomplete Beta function
|
||||
can be obtained as follows:
|
||||
|
||||
>>> betainc_regularized(a, b, 0, x)
|
||||
betainc_regularized(a, b, 0, x)
|
||||
|
||||
The Regularized Incomplete Beta function
|
||||
obeys the mirror symmetry:
|
||||
|
||||
>>> conjugate(betainc_regularized(a, b, x1, x2))
|
||||
betainc_regularized(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
|
||||
|
||||
We can numerically evaluate the Regularized Incomplete Beta function
|
||||
to arbitrary precision for any complex numbers a, b, x1 and x2:
|
||||
|
||||
>>> from sympy import betainc_regularized, pi, E
|
||||
>>> betainc_regularized(1, 2, 0, 0.25).evalf(10)
|
||||
0.4375000000
|
||||
>>> betainc_regularized(pi, E, 0, 1).evalf(5)
|
||||
1.00000
|
||||
|
||||
The Generalized Regularized Incomplete Beta function can be
|
||||
expressed in terms of the Generalized Hypergeometric function.
|
||||
|
||||
>>> from sympy import hyper
|
||||
>>> betainc_regularized(a, b, x1, x2).rewrite(hyper)
|
||||
(-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/(a*beta(a, b))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
beta: Beta function
|
||||
hyper: Generalized Hypergeometric function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
|
||||
.. [2] https://dlmf.nist.gov/8.17
|
||||
.. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
|
||||
.. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
|
||||
|
||||
"""
|
||||
nargs = 4
|
||||
unbranched = True
|
||||
|
||||
def __new__(cls, a, b, x1, x2):
|
||||
return super().__new__(cls, a, b, x1, x2)
|
||||
|
||||
def _eval_mpmath(self):
|
||||
return betainc_mpmath_fix, (*self.args, S(1))
|
||||
|
||||
def fdiff(self, argindex):
|
||||
a, b, x1, x2 = self.args
|
||||
if argindex == 3:
|
||||
# Diff wrt x1
|
||||
return -(1 - x1)**(b - 1)*x1**(a - 1) / beta(a, b)
|
||||
elif argindex == 4:
|
||||
# Diff wrt x2
|
||||
return (1 - x2)**(b - 1)*x2**(a - 1) / beta(a, b)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_is_real(self):
|
||||
if all(arg.is_real for arg in self.args):
|
||||
return True
|
||||
|
||||
def _eval_conjugate(self):
|
||||
return self.func(*map(conjugate, self.args))
|
||||
|
||||
def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', [a, b, x1, x2]).name)
|
||||
integrand = t**(a - 1)*(1 - t)**(b - 1)
|
||||
expr = Integral(integrand, (t, x1, x2))
|
||||
return expr / Integral(integrand, (t, 0, 1))
|
||||
|
||||
def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.functions.special.hyper import hyper
|
||||
expr = (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
|
||||
return expr / beta(a, b)
|
||||
@@ -0,0 +1,348 @@
|
||||
from sympy.core import S, sympify
|
||||
from sympy.core.symbol import (Dummy, symbols)
|
||||
from sympy.functions import Piecewise, piecewise_fold
|
||||
from sympy.logic.boolalg import And
|
||||
from sympy.sets.sets import Interval
|
||||
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
def _ivl(cond, x):
|
||||
"""return the interval corresponding to the condition
|
||||
|
||||
Conditions in spline's Piecewise give the range over
|
||||
which an expression is valid like (lo <= x) & (x <= hi).
|
||||
This function returns (lo, hi).
|
||||
"""
|
||||
if isinstance(cond, And) and len(cond.args) == 2:
|
||||
a, b = cond.args
|
||||
if a.lts == x:
|
||||
a, b = b, a
|
||||
return a.lts, b.gts
|
||||
raise TypeError('unexpected cond type: %s' % cond)
|
||||
|
||||
|
||||
def _add_splines(c, b1, d, b2, x):
|
||||
"""Construct c*b1 + d*b2."""
|
||||
|
||||
if S.Zero in (b1, c):
|
||||
rv = piecewise_fold(d * b2)
|
||||
elif S.Zero in (b2, d):
|
||||
rv = piecewise_fold(c * b1)
|
||||
else:
|
||||
new_args = []
|
||||
# Just combining the Piecewise without any fancy optimization
|
||||
p1 = piecewise_fold(c * b1)
|
||||
p2 = piecewise_fold(d * b2)
|
||||
|
||||
# Search all Piecewise arguments except (0, True)
|
||||
p2args = list(p2.args[:-1])
|
||||
|
||||
# This merging algorithm assumes the conditions in
|
||||
# p1 and p2 are sorted
|
||||
for arg in p1.args[:-1]:
|
||||
expr = arg.expr
|
||||
cond = arg.cond
|
||||
|
||||
lower = _ivl(cond, x)[0]
|
||||
|
||||
# Check p2 for matching conditions that can be merged
|
||||
for i, arg2 in enumerate(p2args):
|
||||
expr2 = arg2.expr
|
||||
cond2 = arg2.cond
|
||||
|
||||
lower_2, upper_2 = _ivl(cond2, x)
|
||||
if cond2 == cond:
|
||||
# Conditions match, join expressions
|
||||
expr += expr2
|
||||
# Remove matching element
|
||||
del p2args[i]
|
||||
# No need to check the rest
|
||||
break
|
||||
elif lower_2 < lower and upper_2 <= lower:
|
||||
# Check if arg2 condition smaller than arg1,
|
||||
# add to new_args by itself (no match expected
|
||||
# in p1)
|
||||
new_args.append(arg2)
|
||||
del p2args[i]
|
||||
break
|
||||
|
||||
# Checked all, add expr and cond
|
||||
new_args.append((expr, cond))
|
||||
|
||||
# Add remaining items from p2args
|
||||
new_args.extend(p2args)
|
||||
|
||||
# Add final (0, True)
|
||||
new_args.append((0, True))
|
||||
|
||||
rv = Piecewise(*new_args, evaluate=False)
|
||||
|
||||
return rv.expand()
|
||||
|
||||
|
||||
@lru_cache(maxsize=128)
|
||||
def bspline_basis(d, knots, n, x):
|
||||
"""
|
||||
The $n$-th B-spline at $x$ of degree $d$ with knots.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
B-Splines are piecewise polynomials of degree $d$. They are defined on a
|
||||
set of knots, which is a sequence of integers or floats.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The 0th degree splines have a value of 1 on a single interval:
|
||||
|
||||
>>> from sympy import bspline_basis
|
||||
>>> from sympy.abc import x
|
||||
>>> d = 0
|
||||
>>> knots = tuple(range(5))
|
||||
>>> bspline_basis(d, knots, 0, x)
|
||||
Piecewise((1, (x >= 0) & (x <= 1)), (0, True))
|
||||
|
||||
For a given ``(d, knots)`` there are ``len(knots)-d-1`` B-splines
|
||||
defined, that are indexed by ``n`` (starting at 0).
|
||||
|
||||
Here is an example of a cubic B-spline:
|
||||
|
||||
>>> bspline_basis(3, tuple(range(5)), 0, x)
|
||||
Piecewise((x**3/6, (x >= 0) & (x <= 1)),
|
||||
(-x**3/2 + 2*x**2 - 2*x + 2/3,
|
||||
(x >= 1) & (x <= 2)),
|
||||
(x**3/2 - 4*x**2 + 10*x - 22/3,
|
||||
(x >= 2) & (x <= 3)),
|
||||
(-x**3/6 + 2*x**2 - 8*x + 32/3,
|
||||
(x >= 3) & (x <= 4)),
|
||||
(0, True))
|
||||
|
||||
By repeating knot points, you can introduce discontinuities in the
|
||||
B-splines and their derivatives:
|
||||
|
||||
>>> d = 1
|
||||
>>> knots = (0, 0, 2, 3, 4)
|
||||
>>> bspline_basis(d, knots, 0, x)
|
||||
Piecewise((1 - x/2, (x >= 0) & (x <= 2)), (0, True))
|
||||
|
||||
It is quite time consuming to construct and evaluate B-splines. If
|
||||
you need to evaluate a B-spline many times, it is best to lambdify them
|
||||
first:
|
||||
|
||||
>>> from sympy import lambdify
|
||||
>>> d = 3
|
||||
>>> knots = tuple(range(10))
|
||||
>>> b0 = bspline_basis(d, knots, 0, x)
|
||||
>>> f = lambdify(x, b0)
|
||||
>>> y = f(0.5)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
d : integer
|
||||
degree of bspline
|
||||
|
||||
knots : list of integer values
|
||||
list of knots points of bspline
|
||||
|
||||
n : integer
|
||||
$n$-th B-spline
|
||||
|
||||
x : symbol
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
bspline_basis_set
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/B-spline
|
||||
|
||||
"""
|
||||
# make sure x has no assumptions so conditions don't evaluate
|
||||
xvar = x
|
||||
x = Dummy()
|
||||
|
||||
knots = tuple(sympify(k) for k in knots)
|
||||
d = int(d)
|
||||
n = int(n)
|
||||
n_knots = len(knots)
|
||||
n_intervals = n_knots - 1
|
||||
if n + d + 1 > n_intervals:
|
||||
raise ValueError("n + d + 1 must not exceed len(knots) - 1")
|
||||
if d == 0:
|
||||
result = Piecewise(
|
||||
(S.One, Interval(knots[n], knots[n + 1]).contains(x)), (0, True)
|
||||
)
|
||||
elif d > 0:
|
||||
denom = knots[n + d + 1] - knots[n + 1]
|
||||
if denom != S.Zero:
|
||||
B = (knots[n + d + 1] - x) / denom
|
||||
b2 = bspline_basis(d - 1, knots, n + 1, x)
|
||||
else:
|
||||
b2 = B = S.Zero
|
||||
|
||||
denom = knots[n + d] - knots[n]
|
||||
if denom != S.Zero:
|
||||
A = (x - knots[n]) / denom
|
||||
b1 = bspline_basis(d - 1, knots, n, x)
|
||||
else:
|
||||
b1 = A = S.Zero
|
||||
|
||||
result = _add_splines(A, b1, B, b2, x)
|
||||
else:
|
||||
raise ValueError("degree must be non-negative: %r" % n)
|
||||
|
||||
# return result with user-given x
|
||||
return result.xreplace({x: xvar})
|
||||
|
||||
|
||||
def bspline_basis_set(d, knots, x):
|
||||
"""
|
||||
Return the ``len(knots)-d-1`` B-splines at *x* of degree *d*
|
||||
with *knots*.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function returns a list of piecewise polynomials that are the
|
||||
``len(knots)-d-1`` B-splines of degree *d* for the given knots.
|
||||
This function calls ``bspline_basis(d, knots, n, x)`` for different
|
||||
values of *n*.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import bspline_basis_set
|
||||
>>> from sympy.abc import x
|
||||
>>> d = 2
|
||||
>>> knots = range(5)
|
||||
>>> splines = bspline_basis_set(d, knots, x)
|
||||
>>> splines
|
||||
[Piecewise((x**2/2, (x >= 0) & (x <= 1)),
|
||||
(-x**2 + 3*x - 3/2, (x >= 1) & (x <= 2)),
|
||||
(x**2/2 - 3*x + 9/2, (x >= 2) & (x <= 3)),
|
||||
(0, True)),
|
||||
Piecewise((x**2/2 - x + 1/2, (x >= 1) & (x <= 2)),
|
||||
(-x**2 + 5*x - 11/2, (x >= 2) & (x <= 3)),
|
||||
(x**2/2 - 4*x + 8, (x >= 3) & (x <= 4)),
|
||||
(0, True))]
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
d : integer
|
||||
degree of bspline
|
||||
|
||||
knots : list of integers
|
||||
list of knots points of bspline
|
||||
|
||||
x : symbol
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
bspline_basis
|
||||
|
||||
"""
|
||||
n_splines = len(knots) - d - 1
|
||||
return [bspline_basis(d, tuple(knots), i, x) for i in range(n_splines)]
|
||||
|
||||
|
||||
def interpolating_spline(d, x, X, Y):
|
||||
"""
|
||||
Return spline of degree *d*, passing through the given *X*
|
||||
and *Y* values.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function returns a piecewise function such that each part is
|
||||
a polynomial of degree not greater than *d*. The value of *d*
|
||||
must be 1 or greater and the values of *X* must be strictly
|
||||
increasing.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import interpolating_spline
|
||||
>>> from sympy.abc import x
|
||||
>>> interpolating_spline(1, x, [1, 2, 4, 7], [3, 6, 5, 7])
|
||||
Piecewise((3*x, (x >= 1) & (x <= 2)),
|
||||
(7 - x/2, (x >= 2) & (x <= 4)),
|
||||
(2*x/3 + 7/3, (x >= 4) & (x <= 7)))
|
||||
>>> interpolating_spline(3, x, [-2, 0, 1, 3, 4], [4, 2, 1, 1, 3])
|
||||
Piecewise((7*x**3/117 + 7*x**2/117 - 131*x/117 + 2, (x >= -2) & (x <= 1)),
|
||||
(10*x**3/117 - 2*x**2/117 - 122*x/117 + 77/39, (x >= 1) & (x <= 4)))
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
d : integer
|
||||
Degree of Bspline strictly greater than equal to one
|
||||
|
||||
x : symbol
|
||||
|
||||
X : list of strictly increasing real values
|
||||
list of X coordinates through which the spline passes
|
||||
|
||||
Y : list of real values
|
||||
list of corresponding Y coordinates through which the spline passes
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
bspline_basis_set, interpolating_poly
|
||||
|
||||
"""
|
||||
from sympy.solvers.solveset import linsolve
|
||||
from sympy.matrices.dense import Matrix
|
||||
|
||||
# Input sanitization
|
||||
d = sympify(d)
|
||||
if not (d.is_Integer and d.is_positive):
|
||||
raise ValueError("Spline degree must be a positive integer, not %s." % d)
|
||||
if len(X) != len(Y):
|
||||
raise ValueError("Number of X and Y coordinates must be the same.")
|
||||
if len(X) < d + 1:
|
||||
raise ValueError("Degree must be less than the number of control points.")
|
||||
if not all(a < b for a, b in zip(X, X[1:])):
|
||||
raise ValueError("The x-coordinates must be strictly increasing.")
|
||||
X = [sympify(i) for i in X]
|
||||
|
||||
# Evaluating knots value
|
||||
if d.is_odd:
|
||||
j = (d + 1) // 2
|
||||
interior_knots = X[j:-j]
|
||||
else:
|
||||
j = d // 2
|
||||
interior_knots = [
|
||||
(a + b)/2 for a, b in zip(X[j : -j - 1], X[j + 1 : -j])
|
||||
]
|
||||
|
||||
knots = [X[0]] * (d + 1) + list(interior_knots) + [X[-1]] * (d + 1)
|
||||
|
||||
basis = bspline_basis_set(d, knots, x)
|
||||
|
||||
A = [[b.subs(x, v) for b in basis] for v in X]
|
||||
|
||||
coeff = linsolve((Matrix(A), Matrix(Y)), symbols("c0:{}".format(len(X)), cls=Dummy))
|
||||
coeff = list(coeff)[0]
|
||||
intervals = {c for b in basis for (e, c) in b.args if c != True}
|
||||
|
||||
# Sorting the intervals
|
||||
# ival contains the end-points of each interval
|
||||
intervals = sorted(intervals, key=lambda c: _ivl(c, x))
|
||||
|
||||
basis_dicts = [{c: e for (e, c) in b.args} for b in basis]
|
||||
spline = []
|
||||
for i in intervals:
|
||||
piece = sum(
|
||||
[c * d.get(i, S.Zero) for (c, d) in zip(coeff, basis_dicts)], S.Zero
|
||||
)
|
||||
spline.append((piece, i))
|
||||
return Piecewise(*spline)
|
||||
@@ -0,0 +1,664 @@
|
||||
from sympy.core import S, diff
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.core.relational import Eq, Ne
|
||||
from sympy.functions.elementary.complexes import im, sign
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.polys.polyerrors import PolynomialError
|
||||
from sympy.polys.polyroots import roots
|
||||
from sympy.utilities.misc import filldedent
|
||||
|
||||
|
||||
###############################################################################
|
||||
################################ DELTA FUNCTION ###############################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class DiracDelta(DefinedFunction):
|
||||
r"""
|
||||
The DiracDelta function and its derivatives.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
DiracDelta is not an ordinary function. It can be rigorously defined either
|
||||
as a distribution or as a measure.
|
||||
|
||||
DiracDelta only makes sense in definite integrals, and in particular,
|
||||
integrals of the form ``Integral(f(x)*DiracDelta(x - x0), (x, a, b))``,
|
||||
where it equals ``f(x0)`` if ``a <= x0 <= b`` and ``0`` otherwise. Formally,
|
||||
DiracDelta acts in some ways like a function that is ``0`` everywhere except
|
||||
at ``0``, but in many ways it also does not. It can often be useful to treat
|
||||
DiracDelta in formal ways, building up and manipulating expressions with
|
||||
delta functions (which may eventually be integrated), but care must be taken
|
||||
to not treat it as a real function. SymPy's ``oo`` is similar. It only
|
||||
truly makes sense formally in certain contexts (such as integration limits),
|
||||
but SymPy allows its use everywhere, and it tries to be consistent with
|
||||
operations on it (like ``1/oo``), but it is easy to get into trouble and get
|
||||
wrong results if ``oo`` is treated too much like a number. Similarly, if
|
||||
DiracDelta is treated too much like a function, it is easy to get wrong or
|
||||
nonsensical results.
|
||||
|
||||
DiracDelta function has the following properties:
|
||||
|
||||
1) $\frac{d}{d x} \theta(x) = \delta(x)$
|
||||
2) $\int_{-\infty}^\infty \delta(x - a)f(x)\, dx = f(a)$ and $\int_{a-
|
||||
\epsilon}^{a+\epsilon} \delta(x - a)f(x)\, dx = f(a)$
|
||||
3) $\delta(x) = 0$ for all $x \neq 0$
|
||||
4) $\delta(g(x)) = \sum_i \frac{\delta(x - x_i)}{\|g'(x_i)\|}$ where $x_i$
|
||||
are the roots of $g$
|
||||
5) $\delta(-x) = \delta(x)$
|
||||
|
||||
Derivatives of ``k``-th order of DiracDelta have the following properties:
|
||||
|
||||
6) $\delta(x, k) = 0$ for all $x \neq 0$
|
||||
7) $\delta(-x, k) = -\delta(x, k)$ for odd $k$
|
||||
8) $\delta(-x, k) = \delta(x, k)$ for even $k$
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, diff, pi
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> DiracDelta(x)
|
||||
DiracDelta(x)
|
||||
>>> DiracDelta(1)
|
||||
0
|
||||
>>> DiracDelta(-1)
|
||||
0
|
||||
>>> DiracDelta(pi)
|
||||
0
|
||||
>>> DiracDelta(x - 4).subs(x, 4)
|
||||
DiracDelta(0)
|
||||
>>> diff(DiracDelta(x))
|
||||
DiracDelta(x, 1)
|
||||
>>> diff(DiracDelta(x - 1), x, 2)
|
||||
DiracDelta(x - 1, 2)
|
||||
>>> diff(DiracDelta(x**2 - 1), x, 2)
|
||||
2*(2*x**2*DiracDelta(x**2 - 1, 2) + DiracDelta(x**2 - 1, 1))
|
||||
>>> DiracDelta(3*x).is_simple(x)
|
||||
True
|
||||
>>> DiracDelta(x**2).is_simple(x)
|
||||
False
|
||||
>>> DiracDelta((x**2 - 1)*y).expand(diracdelta=True, wrt=x)
|
||||
DiracDelta(x - 1)/(2*Abs(y)) + DiracDelta(x + 1)/(2*Abs(y))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Heaviside
|
||||
sympy.simplify.simplify.simplify, is_simple
|
||||
sympy.functions.special.tensor_functions.KroneckerDelta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://mathworld.wolfram.com/DeltaFunction.html
|
||||
|
||||
"""
|
||||
|
||||
is_real = True
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
"""
|
||||
Returns the first derivative of a DiracDelta Function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the
|
||||
user-level function and ``fdiff()`` is an object method. ``fdiff()`` is
|
||||
a convenience method available in the ``Function`` class. It returns
|
||||
the derivative of the function without considering the chain rule.
|
||||
``diff(function, x)`` calls ``Function._eval_derivative`` which in turn
|
||||
calls ``fdiff()`` internally to compute the derivative of the function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, diff
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> DiracDelta(x).fdiff()
|
||||
DiracDelta(x, 1)
|
||||
|
||||
>>> DiracDelta(x, 1).fdiff()
|
||||
DiracDelta(x, 2)
|
||||
|
||||
>>> DiracDelta(x**2 - 1).fdiff()
|
||||
DiracDelta(x**2 - 1, 1)
|
||||
|
||||
>>> diff(DiracDelta(x, 1)).fdiff()
|
||||
DiracDelta(x, 3)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
argindex : integer
|
||||
degree of derivative
|
||||
|
||||
"""
|
||||
if argindex == 1:
|
||||
#I didn't know if there is a better way to handle default arguments
|
||||
k = 0
|
||||
if len(self.args) > 1:
|
||||
k = self.args[1]
|
||||
return self.func(self.args[0], k + 1)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg, k=S.Zero):
|
||||
"""
|
||||
Returns a simplified form or a value of DiracDelta depending on the
|
||||
argument passed by the DiracDelta object.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The ``eval()`` method is automatically called when the ``DiracDelta``
|
||||
class is about to be instantiated and it returns either some simplified
|
||||
instance or the unevaluated instance depending on the argument passed.
|
||||
In other words, ``eval()`` method is not needed to be called explicitly,
|
||||
it is being called and evaluated once the object is called.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, S
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> DiracDelta(x)
|
||||
DiracDelta(x)
|
||||
|
||||
>>> DiracDelta(-x, 1)
|
||||
-DiracDelta(x, 1)
|
||||
|
||||
>>> DiracDelta(1)
|
||||
0
|
||||
|
||||
>>> DiracDelta(5, 1)
|
||||
0
|
||||
|
||||
>>> DiracDelta(0)
|
||||
DiracDelta(0)
|
||||
|
||||
>>> DiracDelta(-1)
|
||||
0
|
||||
|
||||
>>> DiracDelta(S.NaN)
|
||||
nan
|
||||
|
||||
>>> DiracDelta(x - 100).subs(x, 5)
|
||||
0
|
||||
|
||||
>>> DiracDelta(x - 100).subs(x, 100)
|
||||
DiracDelta(0)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
k : integer
|
||||
order of derivative
|
||||
|
||||
arg : argument passed to DiracDelta
|
||||
|
||||
"""
|
||||
if not k.is_Integer or k.is_negative:
|
||||
raise ValueError("Error: the second argument of DiracDelta must be \
|
||||
a non-negative integer, %s given instead." % (k,))
|
||||
if arg is S.NaN:
|
||||
return S.NaN
|
||||
if arg.is_nonzero:
|
||||
return S.Zero
|
||||
if fuzzy_not(im(arg).is_zero):
|
||||
raise ValueError(filldedent('''
|
||||
Function defined only for Real Values.
|
||||
Complex part: %s found in %s .''' % (
|
||||
repr(im(arg)), repr(arg))))
|
||||
c, nc = arg.args_cnc()
|
||||
if c and c[0] is S.NegativeOne:
|
||||
# keep this fast and simple instead of using
|
||||
# could_extract_minus_sign
|
||||
if k.is_odd:
|
||||
return -cls(-arg, k)
|
||||
elif k.is_even:
|
||||
return cls(-arg, k) if k else cls(-arg)
|
||||
elif k.is_zero:
|
||||
return cls(arg, evaluate=False)
|
||||
|
||||
def _eval_expand_diracdelta(self, **hints):
|
||||
"""
|
||||
Compute a simplified representation of the function using
|
||||
property number 4. Pass ``wrt`` as a hint to expand the expression
|
||||
with respect to a particular variable.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
``wrt`` is:
|
||||
|
||||
- a variable with respect to which a DiracDelta expression will
|
||||
get expanded.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> DiracDelta(x*y).expand(diracdelta=True, wrt=x)
|
||||
DiracDelta(x)/Abs(y)
|
||||
>>> DiracDelta(x*y).expand(diracdelta=True, wrt=y)
|
||||
DiracDelta(y)/Abs(x)
|
||||
|
||||
>>> DiracDelta(x**2 + x - 2).expand(diracdelta=True, wrt=x)
|
||||
DiracDelta(x - 1)/3 + DiracDelta(x + 2)/3
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_simple, Diracdelta
|
||||
|
||||
"""
|
||||
wrt = hints.get('wrt', None)
|
||||
if wrt is None:
|
||||
free = self.free_symbols
|
||||
if len(free) == 1:
|
||||
wrt = free.pop()
|
||||
else:
|
||||
raise TypeError(filldedent('''
|
||||
When there is more than 1 free symbol or variable in the expression,
|
||||
the 'wrt' keyword is required as a hint to expand when using the
|
||||
DiracDelta hint.'''))
|
||||
|
||||
if not self.args[0].has(wrt) or (len(self.args) > 1 and self.args[1] != 0 ):
|
||||
return self
|
||||
try:
|
||||
argroots = roots(self.args[0], wrt)
|
||||
result = 0
|
||||
valid = True
|
||||
darg = abs(diff(self.args[0], wrt))
|
||||
for r, m in argroots.items():
|
||||
if r.is_real is not False and m == 1:
|
||||
result += self.func(wrt - r)/darg.subs(wrt, r)
|
||||
else:
|
||||
# don't handle non-real and if m != 1 then
|
||||
# a polynomial will have a zero in the derivative (darg)
|
||||
# at r
|
||||
valid = False
|
||||
break
|
||||
if valid:
|
||||
return result
|
||||
except PolynomialError:
|
||||
pass
|
||||
return self
|
||||
|
||||
def is_simple(self, x):
|
||||
"""
|
||||
Tells whether the argument(args[0]) of DiracDelta is a linear
|
||||
expression in *x*.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, cos
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> DiracDelta(x*y).is_simple(x)
|
||||
True
|
||||
>>> DiracDelta(x*y).is_simple(y)
|
||||
True
|
||||
|
||||
>>> DiracDelta(x**2 + x - 2).is_simple(x)
|
||||
False
|
||||
|
||||
>>> DiracDelta(cos(x)).is_simple(x)
|
||||
False
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
x : can be a symbol
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.simplify.simplify.simplify, DiracDelta
|
||||
|
||||
"""
|
||||
p = self.args[0].as_poly(x)
|
||||
if p:
|
||||
return p.degree() == 1
|
||||
return False
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
|
||||
"""
|
||||
Represents DiracDelta in a piecewise form.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, Piecewise, Symbol
|
||||
>>> x = Symbol('x')
|
||||
|
||||
>>> DiracDelta(x).rewrite(Piecewise)
|
||||
Piecewise((DiracDelta(0), Eq(x, 0)), (0, True))
|
||||
|
||||
>>> DiracDelta(x - 5).rewrite(Piecewise)
|
||||
Piecewise((DiracDelta(0), Eq(x, 5)), (0, True))
|
||||
|
||||
>>> DiracDelta(x**2 - 5).rewrite(Piecewise)
|
||||
Piecewise((DiracDelta(0), Eq(x**2, 5)), (0, True))
|
||||
|
||||
>>> DiracDelta(x - 5, 4).rewrite(Piecewise)
|
||||
DiracDelta(x - 5, 4)
|
||||
|
||||
"""
|
||||
if len(args) == 1:
|
||||
return Piecewise((DiracDelta(0), Eq(args[0], 0)), (0, True))
|
||||
|
||||
def _eval_rewrite_as_SingularityFunction(self, *args, **kwargs):
|
||||
"""
|
||||
Returns the DiracDelta expression written in the form of Singularity
|
||||
Functions.
|
||||
|
||||
"""
|
||||
from sympy.solvers import solve
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
if self == DiracDelta(0):
|
||||
return SingularityFunction(0, 0, -1)
|
||||
if self == DiracDelta(0, 1):
|
||||
return SingularityFunction(0, 0, -2)
|
||||
free = self.free_symbols
|
||||
if len(free) == 1:
|
||||
x = (free.pop())
|
||||
if len(args) == 1:
|
||||
return SingularityFunction(x, solve(args[0], x)[0], -1)
|
||||
return SingularityFunction(x, solve(args[0], x)[0], -args[1] - 1)
|
||||
else:
|
||||
# I don't know how to handle the case for DiracDelta expressions
|
||||
# having arguments with more than one variable.
|
||||
raise TypeError(filldedent('''
|
||||
rewrite(SingularityFunction) does not support
|
||||
arguments with more that one variable.'''))
|
||||
|
||||
|
||||
###############################################################################
|
||||
############################## HEAVISIDE FUNCTION #############################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class Heaviside(DefinedFunction):
|
||||
r"""
|
||||
Heaviside step function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Heaviside step function has the following properties:
|
||||
|
||||
1) $\frac{d}{d x} \theta(x) = \delta(x)$
|
||||
2) $\theta(x) = \begin{cases} 0 & \text{for}\: x < 0 \\ \frac{1}{2} &
|
||||
\text{for}\: x = 0 \\1 & \text{for}\: x > 0 \end{cases}$
|
||||
3) $\frac{d}{d x} \max(x, 0) = \theta(x)$
|
||||
|
||||
Heaviside(x) is printed as $\theta(x)$ with the SymPy LaTeX printer.
|
||||
|
||||
The value at 0 is set differently in different fields. SymPy uses 1/2,
|
||||
which is a convention from electronics and signal processing, and is
|
||||
consistent with solving improper integrals by Fourier transform and
|
||||
convolution.
|
||||
|
||||
To specify a different value of Heaviside at ``x=0``, a second argument
|
||||
can be given. Using ``Heaviside(x, nan)`` gives an expression that will
|
||||
evaluate to nan for x=0.
|
||||
|
||||
.. versionchanged:: 1.9 ``Heaviside(0)`` now returns 1/2 (before: undefined)
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, nan
|
||||
>>> from sympy.abc import x
|
||||
>>> Heaviside(9)
|
||||
1
|
||||
>>> Heaviside(-9)
|
||||
0
|
||||
>>> Heaviside(0)
|
||||
1/2
|
||||
>>> Heaviside(0, nan)
|
||||
nan
|
||||
>>> (Heaviside(x) + 1).replace(Heaviside(x), Heaviside(x, 1))
|
||||
Heaviside(x, 1) + 1
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
DiracDelta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://mathworld.wolfram.com/HeavisideStepFunction.html
|
||||
.. [2] https://dlmf.nist.gov/1.16#iv
|
||||
|
||||
"""
|
||||
|
||||
is_real = True
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
"""
|
||||
Returns the first derivative of a Heaviside Function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, diff
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> Heaviside(x).fdiff()
|
||||
DiracDelta(x)
|
||||
|
||||
>>> Heaviside(x**2 - 1).fdiff()
|
||||
DiracDelta(x**2 - 1)
|
||||
|
||||
>>> diff(Heaviside(x)).fdiff()
|
||||
DiracDelta(x, 1)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
argindex : integer
|
||||
order of derivative
|
||||
|
||||
"""
|
||||
if argindex == 1:
|
||||
return DiracDelta(self.args[0])
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def __new__(cls, arg, H0=S.Half, **options):
|
||||
if isinstance(H0, Heaviside) and len(H0.args) == 1:
|
||||
H0 = S.Half
|
||||
return super(cls, cls).__new__(cls, arg, H0, **options)
|
||||
|
||||
@property
|
||||
def pargs(self):
|
||||
"""Args without default S.Half"""
|
||||
args = self.args
|
||||
if args[1] is S.Half:
|
||||
args = args[:1]
|
||||
return args
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg, H0=S.Half):
|
||||
"""
|
||||
Returns a simplified form or a value of Heaviside depending on the
|
||||
argument passed by the Heaviside object.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The ``eval()`` method is automatically called when the ``Heaviside``
|
||||
class is about to be instantiated and it returns either some simplified
|
||||
instance or the unevaluated instance depending on the argument passed.
|
||||
In other words, ``eval()`` method is not needed to be called explicitly,
|
||||
it is being called and evaluated once the object is called.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, S
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> Heaviside(x)
|
||||
Heaviside(x)
|
||||
|
||||
>>> Heaviside(19)
|
||||
1
|
||||
|
||||
>>> Heaviside(0)
|
||||
1/2
|
||||
|
||||
>>> Heaviside(0, 1)
|
||||
1
|
||||
|
||||
>>> Heaviside(-5)
|
||||
0
|
||||
|
||||
>>> Heaviside(S.NaN)
|
||||
nan
|
||||
|
||||
>>> Heaviside(x - 100).subs(x, 5)
|
||||
0
|
||||
|
||||
>>> Heaviside(x - 100).subs(x, 105)
|
||||
1
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
arg : argument passed by Heaviside object
|
||||
|
||||
H0 : value of Heaviside(0)
|
||||
|
||||
"""
|
||||
if arg.is_extended_negative:
|
||||
return S.Zero
|
||||
elif arg.is_extended_positive:
|
||||
return S.One
|
||||
elif arg.is_zero:
|
||||
return H0
|
||||
elif arg is S.NaN:
|
||||
return S.NaN
|
||||
elif fuzzy_not(im(arg).is_zero):
|
||||
raise ValueError("Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)) )
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, arg, H0=None, **kwargs):
|
||||
"""
|
||||
Represents Heaviside in a Piecewise form.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, Piecewise, Symbol, nan
|
||||
>>> x = Symbol('x')
|
||||
|
||||
>>> Heaviside(x).rewrite(Piecewise)
|
||||
Piecewise((0, x < 0), (1/2, Eq(x, 0)), (1, True))
|
||||
|
||||
>>> Heaviside(x,nan).rewrite(Piecewise)
|
||||
Piecewise((0, x < 0), (nan, Eq(x, 0)), (1, True))
|
||||
|
||||
>>> Heaviside(x - 5).rewrite(Piecewise)
|
||||
Piecewise((0, x < 5), (1/2, Eq(x, 5)), (1, True))
|
||||
|
||||
>>> Heaviside(x**2 - 1).rewrite(Piecewise)
|
||||
Piecewise((0, x**2 < 1), (1/2, Eq(x**2, 1)), (1, True))
|
||||
|
||||
"""
|
||||
if H0 == 0:
|
||||
return Piecewise((0, arg <= 0), (1, True))
|
||||
if H0 == 1:
|
||||
return Piecewise((0, arg < 0), (1, True))
|
||||
return Piecewise((0, arg < 0), (H0, Eq(arg, 0)), (1, True))
|
||||
|
||||
def _eval_rewrite_as_sign(self, arg, H0=S.Half, **kwargs):
|
||||
"""
|
||||
Represents the Heaviside function in the form of sign function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The value of Heaviside(0) must be 1/2 for rewriting as sign to be
|
||||
strictly equivalent. For easier usage, we also allow this rewriting
|
||||
when Heaviside(0) is undefined.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, Symbol, sign, nan
|
||||
>>> x = Symbol('x', real=True)
|
||||
>>> y = Symbol('y')
|
||||
|
||||
>>> Heaviside(x).rewrite(sign)
|
||||
sign(x)/2 + 1/2
|
||||
|
||||
>>> Heaviside(x, 0).rewrite(sign)
|
||||
Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (0, True))
|
||||
|
||||
>>> Heaviside(x, nan).rewrite(sign)
|
||||
Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (nan, True))
|
||||
|
||||
>>> Heaviside(x - 2).rewrite(sign)
|
||||
sign(x - 2)/2 + 1/2
|
||||
|
||||
>>> Heaviside(x**2 - 2*x + 1).rewrite(sign)
|
||||
sign(x**2 - 2*x + 1)/2 + 1/2
|
||||
|
||||
>>> Heaviside(y).rewrite(sign)
|
||||
Heaviside(y)
|
||||
|
||||
>>> Heaviside(y**2 - 2*y + 1).rewrite(sign)
|
||||
Heaviside(y**2 - 2*y + 1)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sign
|
||||
|
||||
"""
|
||||
if arg.is_extended_real:
|
||||
pw1 = Piecewise(
|
||||
((sign(arg) + 1)/2, Ne(arg, 0)),
|
||||
(Heaviside(0, H0=H0), True))
|
||||
pw2 = Piecewise(
|
||||
((sign(arg) + 1)/2, Eq(Heaviside(0, H0=H0), S.Half)),
|
||||
(pw1, True))
|
||||
return pw2
|
||||
|
||||
def _eval_rewrite_as_SingularityFunction(self, args, H0=S.Half, **kwargs):
|
||||
"""
|
||||
Returns the Heaviside expression written in the form of Singularity
|
||||
Functions.
|
||||
|
||||
"""
|
||||
from sympy.solvers import solve
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
if self == Heaviside(0):
|
||||
return SingularityFunction(0, 0, 0)
|
||||
free = self.free_symbols
|
||||
if len(free) == 1:
|
||||
x = (free.pop())
|
||||
return SingularityFunction(x, solve(args, x)[0], 0)
|
||||
# TODO
|
||||
# ((x - 5)**3*Heaviside(x - 5)).rewrite(SingularityFunction) should output
|
||||
# SingularityFunction(x, 5, 0) instead of (x - 5)**3*SingularityFunction(x, 5, 0)
|
||||
else:
|
||||
# I don't know how to handle the case for Heaviside expressions
|
||||
# having arguments with more than one variable.
|
||||
raise TypeError(filldedent('''
|
||||
rewrite(SingularityFunction) does not
|
||||
support arguments with more that one variable.'''))
|
||||
+445
@@ -0,0 +1,445 @@
|
||||
""" Elliptic Integrals. """
|
||||
|
||||
from sympy.core import S, pi, I, Rational
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.symbol import Dummy,uniquely_named_symbol
|
||||
from sympy.functions.elementary.complexes import sign
|
||||
from sympy.functions.elementary.hyperbolic import atanh
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import sin, tan
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.functions.special.hyper import hyper, meijerg
|
||||
|
||||
class elliptic_k(DefinedFunction):
|
||||
r"""
|
||||
The complete elliptic integral of the first kind, defined by
|
||||
|
||||
.. math:: K(m) = F\left(\tfrac{\pi}{2}\middle| m\right)
|
||||
|
||||
where $F\left(z\middle| m\right)$ is the Legendre incomplete
|
||||
elliptic integral of the first kind.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The function $K(m)$ is a single-valued function on the complex
|
||||
plane with branch cut along the interval $(1, \infty)$.
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_k, I
|
||||
>>> from sympy.abc import m
|
||||
>>> elliptic_k(0)
|
||||
pi/2
|
||||
>>> elliptic_k(1.0 + I)
|
||||
1.50923695405127 + 0.625146415202697*I
|
||||
>>> elliptic_k(m).series(n=3)
|
||||
pi/2 + pi*m/8 + 9*pi*m**2/128 + O(m**3)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
elliptic_f
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticK
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, m):
|
||||
if m.is_zero:
|
||||
return pi*S.Half
|
||||
elif m is S.Half:
|
||||
return 8*pi**Rational(3, 2)/gamma(Rational(-1, 4))**2
|
||||
elif m is S.One:
|
||||
return S.ComplexInfinity
|
||||
elif m is S.NegativeOne:
|
||||
return gamma(Rational(1, 4))**2/(4*sqrt(2*pi))
|
||||
elif m in (S.Infinity, S.NegativeInfinity, I*S.Infinity,
|
||||
I*S.NegativeInfinity, S.ComplexInfinity):
|
||||
return S.Zero
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
m = self.args[0]
|
||||
return (elliptic_e(m) - (1 - m)*elliptic_k(m))/(2*m*(1 - m))
|
||||
|
||||
def _eval_conjugate(self):
|
||||
m = self.args[0]
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(m.conjugate())
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
from sympy.simplify import hyperexpand
|
||||
return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx))
|
||||
|
||||
def _eval_rewrite_as_hyper(self, m, **kwargs):
|
||||
return pi*S.Half*hyper((S.Half, S.Half), (S.One,), m)
|
||||
|
||||
def _eval_rewrite_as_meijerg(self, m, **kwargs):
|
||||
return meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -m)/2
|
||||
|
||||
def _eval_is_zero(self):
|
||||
m = self.args[0]
|
||||
if m.is_infinite:
|
||||
return True
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
m = self.args[0]
|
||||
return Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, pi/2))
|
||||
|
||||
|
||||
class elliptic_f(DefinedFunction):
|
||||
r"""
|
||||
The Legendre incomplete elliptic integral of the first
|
||||
kind, defined by
|
||||
|
||||
.. math:: F\left(z\middle| m\right) =
|
||||
\int_0^z \frac{dt}{\sqrt{1 - m \sin^2 t}}
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function reduces to a complete elliptic integral of
|
||||
the first kind, $K(m)$, when $z = \pi/2$.
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_f, I
|
||||
>>> from sympy.abc import z, m
|
||||
>>> elliptic_f(z, m).series(z)
|
||||
z + z**5*(3*m**2/40 - m/30) + m*z**3/6 + O(z**6)
|
||||
>>> elliptic_f(3.0 + I/2, 1.0 + I)
|
||||
2.909449841483 + 1.74720545502474*I
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
elliptic_k
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticF
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, z, m):
|
||||
if z.is_zero:
|
||||
return S.Zero
|
||||
if m.is_zero:
|
||||
return z
|
||||
k = 2*z/pi
|
||||
if k.is_integer:
|
||||
return k*elliptic_k(m)
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif z.could_extract_minus_sign():
|
||||
return -elliptic_f(-z, m)
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
z, m = self.args
|
||||
fm = sqrt(1 - m*sin(z)**2)
|
||||
if argindex == 1:
|
||||
return 1/fm
|
||||
elif argindex == 2:
|
||||
return (elliptic_e(z, m)/(2*m*(1 - m)) - elliptic_f(z, m)/(2*m) -
|
||||
sin(2*z)/(4*(1 - m)*fm))
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_conjugate(self):
|
||||
z, m = self.args
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(z.conjugate(), m.conjugate())
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
z, m = self.args[0], self.args[1]
|
||||
return Integral(1/(sqrt(1 - m*sin(t)**2)), (t, 0, z))
|
||||
|
||||
def _eval_is_zero(self):
|
||||
z, m = self.args
|
||||
if z.is_zero:
|
||||
return True
|
||||
if m.is_extended_real and m.is_infinite:
|
||||
return True
|
||||
|
||||
|
||||
class elliptic_e(DefinedFunction):
|
||||
r"""
|
||||
Called with two arguments $z$ and $m$, evaluates the
|
||||
incomplete elliptic integral of the second kind, defined by
|
||||
|
||||
.. math:: E\left(z\middle| m\right) = \int_0^z \sqrt{1 - m \sin^2 t} dt
|
||||
|
||||
Called with a single argument $m$, evaluates the Legendre complete
|
||||
elliptic integral of the second kind
|
||||
|
||||
.. math:: E(m) = E\left(\tfrac{\pi}{2}\middle| m\right)
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The function $E(m)$ is a single-valued function on the complex
|
||||
plane with branch cut along the interval $(1, \infty)$.
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_e, I
|
||||
>>> from sympy.abc import z, m
|
||||
>>> elliptic_e(z, m).series(z)
|
||||
z + z**5*(-m**2/40 + m/30) - m*z**3/6 + O(z**6)
|
||||
>>> elliptic_e(m).series(n=4)
|
||||
pi/2 - pi*m/8 - 3*pi*m**2/128 - 5*pi*m**3/512 + O(m**4)
|
||||
>>> elliptic_e(1 + I, 2 - I/2).n()
|
||||
1.55203744279187 + 0.290764986058437*I
|
||||
>>> elliptic_e(0)
|
||||
pi/2
|
||||
>>> elliptic_e(2.0 - I)
|
||||
0.991052601328069 + 0.81879421395609*I
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticE2
|
||||
.. [3] https://functions.wolfram.com/EllipticIntegrals/EllipticE
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, m, z=None):
|
||||
if z is not None:
|
||||
z, m = m, z
|
||||
k = 2*z/pi
|
||||
if m.is_zero:
|
||||
return z
|
||||
if z.is_zero:
|
||||
return S.Zero
|
||||
elif k.is_integer:
|
||||
return k*elliptic_e(m)
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.ComplexInfinity
|
||||
elif z.could_extract_minus_sign():
|
||||
return -elliptic_e(-z, m)
|
||||
else:
|
||||
if m.is_zero:
|
||||
return pi/2
|
||||
elif m is S.One:
|
||||
return S.One
|
||||
elif m is S.Infinity:
|
||||
return I*S.Infinity
|
||||
elif m is S.NegativeInfinity:
|
||||
return S.Infinity
|
||||
elif m is S.ComplexInfinity:
|
||||
return S.ComplexInfinity
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if len(self.args) == 2:
|
||||
z, m = self.args
|
||||
if argindex == 1:
|
||||
return sqrt(1 - m*sin(z)**2)
|
||||
elif argindex == 2:
|
||||
return (elliptic_e(z, m) - elliptic_f(z, m))/(2*m)
|
||||
else:
|
||||
m = self.args[0]
|
||||
if argindex == 1:
|
||||
return (elliptic_e(m) - elliptic_k(m))/(2*m)
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_conjugate(self):
|
||||
if len(self.args) == 2:
|
||||
z, m = self.args
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(z.conjugate(), m.conjugate())
|
||||
else:
|
||||
m = self.args[0]
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(m.conjugate())
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
from sympy.simplify import hyperexpand
|
||||
if len(self.args) == 1:
|
||||
return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx))
|
||||
return super()._eval_nseries(x, n=n, logx=logx)
|
||||
|
||||
def _eval_rewrite_as_hyper(self, *args, **kwargs):
|
||||
if len(args) == 1:
|
||||
m = args[0]
|
||||
return (pi/2)*hyper((Rational(-1, 2), S.Half), (S.One,), m)
|
||||
|
||||
def _eval_rewrite_as_meijerg(self, *args, **kwargs):
|
||||
if len(args) == 1:
|
||||
m = args[0]
|
||||
return -meijerg(((S.Half, Rational(3, 2)), []), \
|
||||
((S.Zero,), (S.Zero,)), -m)/4
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
z, m = (pi/2, self.args[0]) if len(self.args) == 1 else self.args
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
return Integral(sqrt(1 - m*sin(t)**2), (t, 0, z))
|
||||
|
||||
|
||||
class elliptic_pi(DefinedFunction):
|
||||
r"""
|
||||
Called with three arguments $n$, $z$ and $m$, evaluates the
|
||||
Legendre incomplete elliptic integral of the third kind, defined by
|
||||
|
||||
.. math:: \Pi\left(n; z\middle| m\right) = \int_0^z \frac{dt}
|
||||
{\left(1 - n \sin^2 t\right) \sqrt{1 - m \sin^2 t}}
|
||||
|
||||
Called with two arguments $n$ and $m$, evaluates the complete
|
||||
elliptic integral of the third kind:
|
||||
|
||||
.. math:: \Pi\left(n\middle| m\right) =
|
||||
\Pi\left(n; \tfrac{\pi}{2}\middle| m\right)
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_pi, I
|
||||
>>> from sympy.abc import z, n, m
|
||||
>>> elliptic_pi(n, z, m).series(z, n=4)
|
||||
z + z**3*(m/6 + n/3) + O(z**4)
|
||||
>>> elliptic_pi(0.5 + I, 1.0 - I, 1.2)
|
||||
2.50232379629182 - 0.760939574180767*I
|
||||
>>> elliptic_pi(0, 0)
|
||||
pi/2
|
||||
>>> elliptic_pi(1.0 - I/3, 2.0 + I)
|
||||
3.29136443417283 + 0.32555634906645*I
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticPi3
|
||||
.. [3] https://functions.wolfram.com/EllipticIntegrals/EllipticPi
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, n, m, z=None):
|
||||
if z is not None:
|
||||
z, m = m, z
|
||||
if n.is_zero:
|
||||
return elliptic_f(z, m)
|
||||
elif n is S.One:
|
||||
return (elliptic_f(z, m) +
|
||||
(sqrt(1 - m*sin(z)**2)*tan(z) -
|
||||
elliptic_e(z, m))/(1 - m))
|
||||
k = 2*z/pi
|
||||
if k.is_integer:
|
||||
return k*elliptic_pi(n, m)
|
||||
elif m.is_zero:
|
||||
return atanh(sqrt(n - 1)*tan(z))/sqrt(n - 1)
|
||||
elif n == m:
|
||||
return (elliptic_f(z, n) - elliptic_pi(1, z, n) +
|
||||
tan(z)/sqrt(1 - n*sin(z)**2))
|
||||
elif n in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif z.could_extract_minus_sign():
|
||||
return -elliptic_pi(n, -z, m)
|
||||
if n.is_zero:
|
||||
return elliptic_f(z, m)
|
||||
if m.is_extended_real and m.is_infinite or \
|
||||
n.is_extended_real and n.is_infinite:
|
||||
return S.Zero
|
||||
else:
|
||||
if n.is_zero:
|
||||
return elliptic_k(m)
|
||||
elif n is S.One:
|
||||
return S.ComplexInfinity
|
||||
elif m.is_zero:
|
||||
return pi/(2*sqrt(1 - n))
|
||||
elif m == S.One:
|
||||
return S.NegativeInfinity/sign(n - 1)
|
||||
elif n == m:
|
||||
return elliptic_e(n)/(1 - n)
|
||||
elif n in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
if n.is_zero:
|
||||
return elliptic_k(m)
|
||||
if m.is_extended_real and m.is_infinite or \
|
||||
n.is_extended_real and n.is_infinite:
|
||||
return S.Zero
|
||||
|
||||
def _eval_conjugate(self):
|
||||
if len(self.args) == 3:
|
||||
n, z, m = self.args
|
||||
if (n.is_real and (n - 1).is_positive) is False and \
|
||||
(m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(n.conjugate(), z.conjugate(), m.conjugate())
|
||||
else:
|
||||
n, m = self.args
|
||||
return self.func(n.conjugate(), m.conjugate())
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if len(self.args) == 3:
|
||||
n, z, m = self.args
|
||||
fm, fn = sqrt(1 - m*sin(z)**2), 1 - n*sin(z)**2
|
||||
if argindex == 1:
|
||||
return (elliptic_e(z, m) + (m - n)*elliptic_f(z, m)/n +
|
||||
(n**2 - m)*elliptic_pi(n, z, m)/n -
|
||||
n*fm*sin(2*z)/(2*fn))/(2*(m - n)*(n - 1))
|
||||
elif argindex == 2:
|
||||
return 1/(fm*fn)
|
||||
elif argindex == 3:
|
||||
return (elliptic_e(z, m)/(m - 1) +
|
||||
elliptic_pi(n, z, m) -
|
||||
m*sin(2*z)/(2*(m - 1)*fm))/(2*(n - m))
|
||||
else:
|
||||
n, m = self.args
|
||||
if argindex == 1:
|
||||
return (elliptic_e(m) + (m - n)*elliptic_k(m)/n +
|
||||
(n**2 - m)*elliptic_pi(n, m)/n)/(2*(m - n)*(n - 1))
|
||||
elif argindex == 2:
|
||||
return (elliptic_e(m)/(m - 1) + elliptic_pi(n, m))/(2*(n - m))
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
if len(self.args) == 2:
|
||||
n, m, z = self.args[0], self.args[1], pi/2
|
||||
else:
|
||||
n, z, m = self.args
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
return Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, z))
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,269 @@
|
||||
""" This module contains the Mathieu functions.
|
||||
"""
|
||||
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import sin, cos
|
||||
|
||||
|
||||
class MathieuBase(DefinedFunction):
|
||||
"""
|
||||
Abstract base class for Mathieu functions.
|
||||
|
||||
This class is meant to reduce code duplication.
|
||||
|
||||
"""
|
||||
|
||||
unbranched = True
|
||||
|
||||
def _eval_conjugate(self):
|
||||
a, q, z = self.args
|
||||
return self.func(a.conjugate(), q.conjugate(), z.conjugate())
|
||||
|
||||
|
||||
class mathieus(MathieuBase):
|
||||
r"""
|
||||
The Mathieu Sine function $S(a,q,z)$.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Cosine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieus
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieus(a, q, z)
|
||||
mathieus(a, q, z)
|
||||
|
||||
>>> mathieus(a, 0, z)
|
||||
sin(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieus(a, q, z), z)
|
||||
mathieusprime(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieuc: Mathieu cosine function.
|
||||
mathieusprime: Derivative of Mathieu sine function.
|
||||
mathieucprime: Derivative of Mathieu cosine function.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuS/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return mathieusprime(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return sin(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return -cls(a, q, -z)
|
||||
|
||||
|
||||
class mathieuc(MathieuBase):
|
||||
r"""
|
||||
The Mathieu Cosine function $C(a,q,z)$.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Sine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieuc
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieuc(a, q, z)
|
||||
mathieuc(a, q, z)
|
||||
|
||||
>>> mathieuc(a, 0, z)
|
||||
cos(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieuc(a, q, z), z)
|
||||
mathieucprime(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieus: Mathieu sine function
|
||||
mathieusprime: Derivative of Mathieu sine function
|
||||
mathieucprime: Derivative of Mathieu cosine function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuC/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return mathieucprime(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return cos(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return cls(a, q, -z)
|
||||
|
||||
|
||||
class mathieusprime(MathieuBase):
|
||||
r"""
|
||||
The derivative $S^{\prime}(a,q,z)$ of the Mathieu Sine function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Cosine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieusprime
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieusprime(a, q, z)
|
||||
mathieusprime(a, q, z)
|
||||
|
||||
>>> mathieusprime(a, 0, z)
|
||||
sqrt(a)*cos(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieusprime(a, q, z), z)
|
||||
(-a + 2*q*cos(2*z))*mathieus(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieus: Mathieu sine function
|
||||
mathieuc: Mathieu cosine function
|
||||
mathieucprime: Derivative of Mathieu cosine function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuSPrime/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return (2*q*cos(2*z) - a)*mathieus(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return sqrt(a)*cos(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return cls(a, q, -z)
|
||||
|
||||
|
||||
class mathieucprime(MathieuBase):
|
||||
r"""
|
||||
The derivative $C^{\prime}(a,q,z)$ of the Mathieu Cosine function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Sine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieucprime
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieucprime(a, q, z)
|
||||
mathieucprime(a, q, z)
|
||||
|
||||
>>> mathieucprime(a, 0, z)
|
||||
-sqrt(a)*sin(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieucprime(a, q, z), z)
|
||||
(-a + 2*q*cos(2*z))*mathieuc(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieus: Mathieu sine function
|
||||
mathieuc: Mathieu cosine function
|
||||
mathieusprime: Derivative of Mathieu sine function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuCPrime/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return (2*q*cos(2*z) - a)*mathieuc(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return -sqrt(a)*sin(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return -cls(a, q, -z)
|
||||
File diff suppressed because it is too large
Load Diff
+235
@@ -0,0 +1,235 @@
|
||||
from sympy.core import S, oo, diff
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.functions.elementary.complexes import im
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.special.delta_functions import Heaviside
|
||||
|
||||
###############################################################################
|
||||
############################# SINGULARITY FUNCTION ############################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class SingularityFunction(DefinedFunction):
|
||||
r"""
|
||||
Singularity functions are a class of discontinuous functions.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Singularity functions take a variable, an offset, and an exponent as
|
||||
arguments. These functions are represented using Macaulay brackets as:
|
||||
|
||||
SingularityFunction(x, a, n) := <x - a>^n
|
||||
|
||||
The singularity function will automatically evaluate to
|
||||
``Derivative(DiracDelta(x - a), x, -n - 1)`` if ``n < 0``
|
||||
and ``(x - a)**n*Heaviside(x - a, 1)`` if ``n >= 0``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import SingularityFunction, diff, Piecewise, DiracDelta, Heaviside, Symbol
|
||||
>>> from sympy.abc import x, a, n
|
||||
>>> SingularityFunction(x, a, n)
|
||||
SingularityFunction(x, a, n)
|
||||
>>> y = Symbol('y', positive=True)
|
||||
>>> n = Symbol('n', nonnegative=True)
|
||||
>>> SingularityFunction(y, -10, n)
|
||||
(y + 10)**n
|
||||
>>> y = Symbol('y', negative=True)
|
||||
>>> SingularityFunction(y, 10, n)
|
||||
0
|
||||
>>> SingularityFunction(x, 4, -1).subs(x, 4)
|
||||
oo
|
||||
>>> SingularityFunction(x, 10, -2).subs(x, 10)
|
||||
oo
|
||||
>>> SingularityFunction(4, 1, 5)
|
||||
243
|
||||
>>> diff(SingularityFunction(x, 1, 5) + SingularityFunction(x, 1, 4), x)
|
||||
4*SingularityFunction(x, 1, 3) + 5*SingularityFunction(x, 1, 4)
|
||||
>>> diff(SingularityFunction(x, 4, 0), x, 2)
|
||||
SingularityFunction(x, 4, -2)
|
||||
>>> SingularityFunction(x, 4, 5).rewrite(Piecewise)
|
||||
Piecewise(((x - 4)**5, x >= 4), (0, True))
|
||||
>>> expr = SingularityFunction(x, a, n)
|
||||
>>> y = Symbol('y', positive=True)
|
||||
>>> n = Symbol('n', nonnegative=True)
|
||||
>>> expr.subs({x: y, a: -10, n: n})
|
||||
(y + 10)**n
|
||||
|
||||
The methods ``rewrite(DiracDelta)``, ``rewrite(Heaviside)``, and
|
||||
``rewrite('HeavisideDiracDelta')`` returns the same output. One can use any
|
||||
of these methods according to their choice.
|
||||
|
||||
>>> expr = SingularityFunction(x, 4, 5) + SingularityFunction(x, -3, -1) - SingularityFunction(x, 0, -2)
|
||||
>>> expr.rewrite(Heaviside)
|
||||
(x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
|
||||
>>> expr.rewrite(DiracDelta)
|
||||
(x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
|
||||
>>> expr.rewrite('HeavisideDiracDelta')
|
||||
(x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
DiracDelta, Heaviside
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Singularity_function
|
||||
|
||||
"""
|
||||
|
||||
is_real = True
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
"""
|
||||
Returns the first derivative of a DiracDelta Function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the
|
||||
user-level function and ``fdiff()`` is an object method. ``fdiff()`` is
|
||||
a convenience method available in the ``Function`` class. It returns
|
||||
the derivative of the function without considering the chain rule.
|
||||
``diff(function, x)`` calls ``Function._eval_derivative`` which in turn
|
||||
calls ``fdiff()`` internally to compute the derivative of the function.
|
||||
|
||||
"""
|
||||
|
||||
if argindex == 1:
|
||||
x, a, n = self.args
|
||||
if n in (S.Zero, S.NegativeOne, S(-2), S(-3)):
|
||||
return self.func(x, a, n-1)
|
||||
elif n.is_positive:
|
||||
return n*self.func(x, a, n-1)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, variable, offset, exponent):
|
||||
"""
|
||||
Returns a simplified form or a value of Singularity Function depending
|
||||
on the argument passed by the object.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The ``eval()`` method is automatically called when the
|
||||
``SingularityFunction`` class is about to be instantiated and it
|
||||
returns either some simplified instance or the unevaluated instance
|
||||
depending on the argument passed. In other words, ``eval()`` method is
|
||||
not needed to be called explicitly, it is being called and evaluated
|
||||
once the object is called.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import SingularityFunction, Symbol, nan
|
||||
>>> from sympy.abc import x, a, n
|
||||
>>> SingularityFunction(x, a, n)
|
||||
SingularityFunction(x, a, n)
|
||||
>>> SingularityFunction(5, 3, 2)
|
||||
4
|
||||
>>> SingularityFunction(x, a, nan)
|
||||
nan
|
||||
>>> SingularityFunction(x, 3, 0).subs(x, 3)
|
||||
1
|
||||
>>> SingularityFunction(4, 1, 5)
|
||||
243
|
||||
>>> x = Symbol('x', positive = True)
|
||||
>>> a = Symbol('a', negative = True)
|
||||
>>> n = Symbol('n', nonnegative = True)
|
||||
>>> SingularityFunction(x, a, n)
|
||||
(-a + x)**n
|
||||
>>> x = Symbol('x', negative = True)
|
||||
>>> a = Symbol('a', positive = True)
|
||||
>>> SingularityFunction(x, a, n)
|
||||
0
|
||||
|
||||
"""
|
||||
|
||||
x = variable
|
||||
a = offset
|
||||
n = exponent
|
||||
shift = (x - a)
|
||||
|
||||
if fuzzy_not(im(shift).is_zero):
|
||||
raise ValueError("Singularity Functions are defined only for Real Numbers.")
|
||||
if fuzzy_not(im(n).is_zero):
|
||||
raise ValueError("Singularity Functions are not defined for imaginary exponents.")
|
||||
if shift is S.NaN or n is S.NaN:
|
||||
return S.NaN
|
||||
if (n + 4).is_negative:
|
||||
raise ValueError("Singularity Functions are not defined for exponents less than -4.")
|
||||
if shift.is_extended_negative:
|
||||
return S.Zero
|
||||
if n.is_nonnegative:
|
||||
if shift.is_zero: # use literal 0 in case of Symbol('z', zero=True)
|
||||
return S.Zero**n
|
||||
if shift.is_extended_nonnegative:
|
||||
return shift**n
|
||||
if n in (S.NegativeOne, -2, -3, -4):
|
||||
if shift.is_negative or shift.is_extended_positive:
|
||||
return S.Zero
|
||||
if shift.is_zero:
|
||||
return oo
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
|
||||
'''
|
||||
Converts a Singularity Function expression into its Piecewise form.
|
||||
|
||||
'''
|
||||
x, a, n = self.args
|
||||
|
||||
if n in (S.NegativeOne, S(-2), S(-3), S(-4)):
|
||||
return Piecewise((oo, Eq(x - a, 0)), (0, True))
|
||||
elif n.is_nonnegative:
|
||||
return Piecewise(((x - a)**n, x - a >= 0), (0, True))
|
||||
|
||||
def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
|
||||
'''
|
||||
Rewrites a Singularity Function expression using Heavisides and DiracDeltas.
|
||||
|
||||
'''
|
||||
x, a, n = self.args
|
||||
|
||||
if n == -4:
|
||||
return diff(Heaviside(x - a), x.free_symbols.pop(), 4)
|
||||
if n == -3:
|
||||
return diff(Heaviside(x - a), x.free_symbols.pop(), 3)
|
||||
if n == -2:
|
||||
return diff(Heaviside(x - a), x.free_symbols.pop(), 2)
|
||||
if n == -1:
|
||||
return diff(Heaviside(x - a), x.free_symbols.pop(), 1)
|
||||
if n.is_nonnegative:
|
||||
return (x - a)**n*Heaviside(x - a, 1)
|
||||
|
||||
def _eval_as_leading_term(self, x, logx, cdir):
|
||||
z, a, n = self.args
|
||||
shift = (z - a).subs(x, 0)
|
||||
if n < 0:
|
||||
return S.Zero
|
||||
elif n.is_zero and shift.is_zero:
|
||||
return S.Zero if cdir == -1 else S.One
|
||||
elif shift.is_positive:
|
||||
return shift**n
|
||||
return S.Zero
|
||||
|
||||
def _eval_nseries(self, x, n, logx=None, cdir=0):
|
||||
z, a, n = self.args
|
||||
shift = (z - a).subs(x, 0)
|
||||
if n < 0:
|
||||
return S.Zero
|
||||
elif n.is_zero and shift.is_zero:
|
||||
return S.Zero if cdir == -1 else S.One
|
||||
elif shift.is_positive:
|
||||
return ((z - a)**n)._eval_nseries(x, n, logx=logx, cdir=cdir)
|
||||
return S.Zero
|
||||
|
||||
_eval_rewrite_as_DiracDelta = _eval_rewrite_as_Heaviside
|
||||
_eval_rewrite_as_HeavisideDiracDelta = _eval_rewrite_as_Heaviside
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
from sympy.core.expr import Expr
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.numbers import I, pi
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Dummy
|
||||
from sympy.functions import assoc_legendre
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.elementary.complexes import Abs, conjugate
|
||||
from sympy.functions.elementary.exponential import exp
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import sin, cos, cot
|
||||
|
||||
_x = Dummy("x")
|
||||
|
||||
class Ynm(DefinedFunction):
|
||||
r"""
|
||||
Spherical harmonics defined as
|
||||
|
||||
.. math::
|
||||
Y_n^m(\theta, \varphi) := \sqrt{\frac{(2n+1)(n-m)!}{4\pi(n+m)!}}
|
||||
\exp(i m \varphi)
|
||||
\mathrm{P}_n^m\left(\cos(\theta)\right)
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
``Ynm()`` gives the spherical harmonic function of order $n$ and $m$
|
||||
in $\theta$ and $\varphi$, $Y_n^m(\theta, \varphi)$. The four
|
||||
parameters are as follows: $n \geq 0$ an integer and $m$ an integer
|
||||
such that $-n \leq m \leq n$ holds. The two angles are real-valued
|
||||
with $\theta \in [0, \pi]$ and $\varphi \in [0, 2\pi]$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Ynm, Symbol, simplify
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
|
||||
>>> Ynm(n, m, theta, phi)
|
||||
Ynm(n, m, theta, phi)
|
||||
|
||||
Several symmetries are known, for the order:
|
||||
|
||||
>>> Ynm(n, -m, theta, phi)
|
||||
(-1)**m*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
|
||||
As well as for the angles:
|
||||
|
||||
>>> Ynm(n, m, -theta, phi)
|
||||
Ynm(n, m, theta, phi)
|
||||
|
||||
>>> Ynm(n, m, theta, -phi)
|
||||
exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
|
||||
For specific integers $n$ and $m$ we can evaluate the harmonics
|
||||
to more useful expressions:
|
||||
|
||||
>>> simplify(Ynm(0, 0, theta, phi).expand(func=True))
|
||||
1/(2*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(1, -1, theta, phi).expand(func=True))
|
||||
sqrt(6)*exp(-I*phi)*sin(theta)/(4*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(1, 0, theta, phi).expand(func=True))
|
||||
sqrt(3)*cos(theta)/(2*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(1, 1, theta, phi).expand(func=True))
|
||||
-sqrt(6)*exp(I*phi)*sin(theta)/(4*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, -2, theta, phi).expand(func=True))
|
||||
sqrt(30)*exp(-2*I*phi)*sin(theta)**2/(8*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, -1, theta, phi).expand(func=True))
|
||||
sqrt(30)*exp(-I*phi)*sin(2*theta)/(8*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, 0, theta, phi).expand(func=True))
|
||||
sqrt(5)*(3*cos(theta)**2 - 1)/(4*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, 1, theta, phi).expand(func=True))
|
||||
-sqrt(30)*exp(I*phi)*sin(2*theta)/(8*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, 2, theta, phi).expand(func=True))
|
||||
sqrt(30)*exp(2*I*phi)*sin(theta)**2/(8*sqrt(pi))
|
||||
|
||||
We can differentiate the functions with respect
|
||||
to both angles:
|
||||
|
||||
>>> from sympy import Ynm, Symbol, diff
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
|
||||
>>> diff(Ynm(n, m, theta, phi), theta)
|
||||
m*cot(theta)*Ynm(n, m, theta, phi) + sqrt((-m + n)*(m + n + 1))*exp(-I*phi)*Ynm(n, m + 1, theta, phi)
|
||||
|
||||
>>> diff(Ynm(n, m, theta, phi), phi)
|
||||
I*m*Ynm(n, m, theta, phi)
|
||||
|
||||
Further we can compute the complex conjugation:
|
||||
|
||||
>>> from sympy import Ynm, Symbol, conjugate
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
|
||||
>>> conjugate(Ynm(n, m, theta, phi))
|
||||
(-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
|
||||
To get back the well known expressions in spherical
|
||||
coordinates, we use full expansion:
|
||||
|
||||
>>> from sympy import Ynm, Symbol, expand_func
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
|
||||
>>> expand_func(Ynm(n, m, theta, phi))
|
||||
sqrt((2*n + 1)*factorial(-m + n)/factorial(m + n))*exp(I*m*phi)*assoc_legendre(n, m, cos(theta))/(2*sqrt(pi))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Ynm_c, Znm
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Spherical_harmonics
|
||||
.. [2] https://mathworld.wolfram.com/SphericalHarmonic.html
|
||||
.. [3] https://functions.wolfram.com/Polynomials/SphericalHarmonicY/
|
||||
.. [4] https://dlmf.nist.gov/14.30
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, n, m, theta, phi):
|
||||
# Handle negative index m and arguments theta, phi
|
||||
if m.could_extract_minus_sign():
|
||||
m = -m
|
||||
return S.NegativeOne**m * exp(-2*I*m*phi) * Ynm(n, m, theta, phi)
|
||||
if theta.could_extract_minus_sign():
|
||||
theta = -theta
|
||||
return Ynm(n, m, theta, phi)
|
||||
if phi.could_extract_minus_sign():
|
||||
phi = -phi
|
||||
return exp(-2*I*m*phi) * Ynm(n, m, theta, phi)
|
||||
|
||||
# TODO Add more simplififcation here
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
n, m, theta, phi = self.args
|
||||
rv = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) *
|
||||
exp(I*m*phi) * assoc_legendre(n, m, cos(theta)))
|
||||
# We can do this because of the range of theta
|
||||
return rv.subs(sqrt(-cos(theta)**2 + 1), sin(theta))
|
||||
|
||||
def fdiff(self, argindex=4):
|
||||
if argindex == 1:
|
||||
# Diff wrt n
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
elif argindex == 2:
|
||||
# Diff wrt m
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
elif argindex == 3:
|
||||
# Diff wrt theta
|
||||
n, m, theta, phi = self.args
|
||||
return (m * cot(theta) * Ynm(n, m, theta, phi) +
|
||||
sqrt((n - m)*(n + m + 1)) * exp(-I*phi) * Ynm(n, m + 1, theta, phi))
|
||||
elif argindex == 4:
|
||||
# Diff wrt phi
|
||||
n, m, theta, phi = self.args
|
||||
return I * m * Ynm(n, m, theta, phi)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_rewrite_as_polynomial(self, n, m, theta, phi, **kwargs):
|
||||
# TODO: Make sure n \in N
|
||||
# TODO: Assert |m| <= n ortherwise we should return 0
|
||||
return self.expand(func=True)
|
||||
|
||||
def _eval_rewrite_as_sin(self, n, m, theta, phi, **kwargs):
|
||||
return self.rewrite(cos)
|
||||
|
||||
def _eval_rewrite_as_cos(self, n, m, theta, phi, **kwargs):
|
||||
# This method can be expensive due to extensive use of simplification!
|
||||
from sympy.simplify import simplify, trigsimp
|
||||
# TODO: Make sure n \in N
|
||||
# TODO: Assert |m| <= n ortherwise we should return 0
|
||||
term = simplify(self.expand(func=True))
|
||||
# We can do this because of the range of theta
|
||||
term = term.xreplace({Abs(sin(theta)):sin(theta)})
|
||||
return simplify(trigsimp(term))
|
||||
|
||||
def _eval_conjugate(self):
|
||||
# TODO: Make sure theta \in R and phi \in R
|
||||
n, m, theta, phi = self.args
|
||||
return S.NegativeOne**m * self.func(n, -m, theta, phi)
|
||||
|
||||
def as_real_imag(self, deep=True, **hints):
|
||||
# TODO: Handle deep and hints
|
||||
n, m, theta, phi = self.args
|
||||
re = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) *
|
||||
cos(m*phi) * assoc_legendre(n, m, cos(theta)))
|
||||
im = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) *
|
||||
sin(m*phi) * assoc_legendre(n, m, cos(theta)))
|
||||
return (re, im)
|
||||
|
||||
def _eval_evalf(self, prec):
|
||||
# Note: works without this function by just calling
|
||||
# mpmath for Legendre polynomials. But using
|
||||
# the dedicated function directly is cleaner.
|
||||
from mpmath import mp, workprec
|
||||
n = self.args[0]._to_mpmath(prec)
|
||||
m = self.args[1]._to_mpmath(prec)
|
||||
theta = self.args[2]._to_mpmath(prec)
|
||||
phi = self.args[3]._to_mpmath(prec)
|
||||
with workprec(prec):
|
||||
res = mp.spherharm(n, m, theta, phi)
|
||||
return Expr._from_mpmath(res, prec)
|
||||
|
||||
|
||||
def Ynm_c(n, m, theta, phi):
|
||||
r"""
|
||||
Conjugate spherical harmonics defined as
|
||||
|
||||
.. math::
|
||||
\overline{Y_n^m(\theta, \varphi)} := (-1)^m Y_n^{-m}(\theta, \varphi).
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Ynm_c, Symbol, simplify
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
>>> Ynm_c(n, m, theta, phi)
|
||||
(-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
>>> Ynm_c(n, m, -theta, phi)
|
||||
(-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
|
||||
For specific integers $n$ and $m$ we can evaluate the harmonics
|
||||
to more useful expressions:
|
||||
|
||||
>>> simplify(Ynm_c(0, 0, theta, phi).expand(func=True))
|
||||
1/(2*sqrt(pi))
|
||||
>>> simplify(Ynm_c(1, -1, theta, phi).expand(func=True))
|
||||
sqrt(6)*exp(I*(-phi + 2*conjugate(phi)))*sin(theta)/(4*sqrt(pi))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Ynm, Znm
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Spherical_harmonics
|
||||
.. [2] https://mathworld.wolfram.com/SphericalHarmonic.html
|
||||
.. [3] https://functions.wolfram.com/Polynomials/SphericalHarmonicY/
|
||||
|
||||
"""
|
||||
return conjugate(Ynm(n, m, theta, phi))
|
||||
|
||||
|
||||
class Znm(DefinedFunction):
|
||||
r"""
|
||||
Real spherical harmonics defined as
|
||||
|
||||
.. math::
|
||||
|
||||
Z_n^m(\theta, \varphi) :=
|
||||
\begin{cases}
|
||||
\frac{Y_n^m(\theta, \varphi) + \overline{Y_n^m(\theta, \varphi)}}{\sqrt{2}} &\quad m > 0 \\
|
||||
Y_n^m(\theta, \varphi) &\quad m = 0 \\
|
||||
\frac{Y_n^m(\theta, \varphi) - \overline{Y_n^m(\theta, \varphi)}}{i \sqrt{2}} &\quad m < 0 \\
|
||||
\end{cases}
|
||||
|
||||
which gives in simplified form
|
||||
|
||||
.. math::
|
||||
|
||||
Z_n^m(\theta, \varphi) =
|
||||
\begin{cases}
|
||||
\frac{Y_n^m(\theta, \varphi) + (-1)^m Y_n^{-m}(\theta, \varphi)}{\sqrt{2}} &\quad m > 0 \\
|
||||
Y_n^m(\theta, \varphi) &\quad m = 0 \\
|
||||
\frac{Y_n^m(\theta, \varphi) - (-1)^m Y_n^{-m}(\theta, \varphi)}{i \sqrt{2}} &\quad m < 0 \\
|
||||
\end{cases}
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Znm, Symbol, simplify
|
||||
>>> from sympy.abc import n, m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
>>> Znm(n, m, theta, phi)
|
||||
Znm(n, m, theta, phi)
|
||||
|
||||
For specific integers n and m we can evaluate the harmonics
|
||||
to more useful expressions:
|
||||
|
||||
>>> simplify(Znm(0, 0, theta, phi).expand(func=True))
|
||||
1/(2*sqrt(pi))
|
||||
>>> simplify(Znm(1, 1, theta, phi).expand(func=True))
|
||||
-sqrt(3)*sin(theta)*cos(phi)/(2*sqrt(pi))
|
||||
>>> simplify(Znm(2, 1, theta, phi).expand(func=True))
|
||||
-sqrt(15)*sin(2*theta)*cos(phi)/(4*sqrt(pi))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Ynm, Ynm_c
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Spherical_harmonics
|
||||
.. [2] https://mathworld.wolfram.com/SphericalHarmonic.html
|
||||
.. [3] https://functions.wolfram.com/Polynomials/SphericalHarmonicY/
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, n, m, theta, phi):
|
||||
if m.is_positive:
|
||||
zz = (Ynm(n, m, theta, phi) + Ynm_c(n, m, theta, phi)) / sqrt(2)
|
||||
return zz
|
||||
elif m.is_zero:
|
||||
return Ynm(n, m, theta, phi)
|
||||
elif m.is_negative:
|
||||
zz = (Ynm(n, m, theta, phi) - Ynm_c(n, m, theta, phi)) / (sqrt(2)*I)
|
||||
return zz
|
||||
@@ -0,0 +1,474 @@
|
||||
from math import prod
|
||||
|
||||
from sympy.core import S, Integer
|
||||
from sympy.core.function import DefinedFunction
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.core.relational import Ne
|
||||
from sympy.core.sorting import default_sort_key
|
||||
from sympy.external.gmpy import SYMPY_INTS
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.utilities.iterables import has_dups
|
||||
|
||||
###############################################################################
|
||||
###################### Kronecker Delta, Levi-Civita etc. ######################
|
||||
###############################################################################
|
||||
|
||||
|
||||
def Eijk(*args, **kwargs):
|
||||
"""
|
||||
Represent the Levi-Civita symbol.
|
||||
|
||||
This is a compatibility wrapper to ``LeviCivita()``.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
LeviCivita
|
||||
|
||||
"""
|
||||
return LeviCivita(*args, **kwargs)
|
||||
|
||||
|
||||
def eval_levicivita(*args):
|
||||
"""Evaluate Levi-Civita symbol."""
|
||||
n = len(args)
|
||||
return prod(
|
||||
prod(args[j] - args[i] for j in range(i + 1, n))
|
||||
/ factorial(i) for i in range(n))
|
||||
# converting factorial(i) to int is slightly faster
|
||||
|
||||
|
||||
class LeviCivita(DefinedFunction):
|
||||
"""
|
||||
Represent the Levi-Civita symbol.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For even permutations of indices it returns 1, for odd permutations -1, and
|
||||
for everything else (a repeated index) it returns 0.
|
||||
|
||||
Thus it represents an alternating pseudotensor.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import LeviCivita
|
||||
>>> from sympy.abc import i, j, k
|
||||
>>> LeviCivita(1, 2, 3)
|
||||
1
|
||||
>>> LeviCivita(1, 3, 2)
|
||||
-1
|
||||
>>> LeviCivita(1, 2, 2)
|
||||
0
|
||||
>>> LeviCivita(i, j, k)
|
||||
LeviCivita(i, j, k)
|
||||
>>> LeviCivita(i, j, i)
|
||||
0
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Eijk
|
||||
|
||||
"""
|
||||
|
||||
is_integer = True
|
||||
|
||||
@classmethod
|
||||
def eval(cls, *args):
|
||||
if all(isinstance(a, (SYMPY_INTS, Integer)) for a in args):
|
||||
return eval_levicivita(*args)
|
||||
if has_dups(args):
|
||||
return S.Zero
|
||||
|
||||
def doit(self, **hints):
|
||||
return eval_levicivita(*self.args)
|
||||
|
||||
|
||||
class KroneckerDelta(DefinedFunction):
|
||||
"""
|
||||
The discrete, or Kronecker, delta function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
A function that takes in two integers $i$ and $j$. It returns $0$ if $i$
|
||||
and $j$ are not equal, or it returns $1$ if $i$ and $j$ are equal.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
An example with integer indices:
|
||||
|
||||
>>> from sympy import KroneckerDelta
|
||||
>>> KroneckerDelta(1, 2)
|
||||
0
|
||||
>>> KroneckerDelta(3, 3)
|
||||
1
|
||||
|
||||
Symbolic indices:
|
||||
|
||||
>>> from sympy.abc import i, j, k
|
||||
>>> KroneckerDelta(i, j)
|
||||
KroneckerDelta(i, j)
|
||||
>>> KroneckerDelta(i, i)
|
||||
1
|
||||
>>> KroneckerDelta(i, i + 1)
|
||||
0
|
||||
>>> KroneckerDelta(i, i + 1 + k)
|
||||
KroneckerDelta(i, i + k + 1)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
i : Number, Symbol
|
||||
The first index of the delta function.
|
||||
j : Number, Symbol
|
||||
The second index of the delta function.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
eval
|
||||
DiracDelta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Kronecker_delta
|
||||
|
||||
"""
|
||||
|
||||
is_integer = True
|
||||
|
||||
@classmethod
|
||||
def eval(cls, i, j, delta_range=None):
|
||||
"""
|
||||
Evaluates the discrete delta function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta
|
||||
>>> from sympy.abc import i, j, k
|
||||
|
||||
>>> KroneckerDelta(i, j)
|
||||
KroneckerDelta(i, j)
|
||||
>>> KroneckerDelta(i, i)
|
||||
1
|
||||
>>> KroneckerDelta(i, i + 1)
|
||||
0
|
||||
>>> KroneckerDelta(i, i + 1 + k)
|
||||
KroneckerDelta(i, i + k + 1)
|
||||
|
||||
# indirect doctest
|
||||
|
||||
"""
|
||||
|
||||
if delta_range is not None:
|
||||
dinf, dsup = delta_range
|
||||
if (dinf - i > 0) == True:
|
||||
return S.Zero
|
||||
if (dinf - j > 0) == True:
|
||||
return S.Zero
|
||||
if (dsup - i < 0) == True:
|
||||
return S.Zero
|
||||
if (dsup - j < 0) == True:
|
||||
return S.Zero
|
||||
|
||||
diff = i - j
|
||||
if diff.is_zero:
|
||||
return S.One
|
||||
elif fuzzy_not(diff.is_zero):
|
||||
return S.Zero
|
||||
|
||||
if i.assumptions0.get("below_fermi") and \
|
||||
j.assumptions0.get("above_fermi"):
|
||||
return S.Zero
|
||||
if j.assumptions0.get("below_fermi") and \
|
||||
i.assumptions0.get("above_fermi"):
|
||||
return S.Zero
|
||||
# to make KroneckerDelta canonical
|
||||
# following lines will check if inputs are in order
|
||||
# if not, will return KroneckerDelta with correct order
|
||||
if default_sort_key(j) < default_sort_key(i):
|
||||
if delta_range:
|
||||
return cls(j, i, delta_range)
|
||||
else:
|
||||
return cls(j, i)
|
||||
|
||||
@property
|
||||
def delta_range(self):
|
||||
if len(self.args) > 2:
|
||||
return self.args[2]
|
||||
|
||||
def _eval_power(self, expt):
|
||||
if expt.is_positive:
|
||||
return self
|
||||
if expt.is_negative and expt is not S.NegativeOne:
|
||||
return 1/self
|
||||
|
||||
@property
|
||||
def is_above_fermi(self):
|
||||
"""
|
||||
True if Delta can be non-zero above fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, a).is_above_fermi
|
||||
True
|
||||
>>> KroneckerDelta(p, i).is_above_fermi
|
||||
False
|
||||
>>> KroneckerDelta(p, q).is_above_fermi
|
||||
True
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_below_fermi, is_only_below_fermi, is_only_above_fermi
|
||||
|
||||
"""
|
||||
if self.args[0].assumptions0.get("below_fermi"):
|
||||
return False
|
||||
if self.args[1].assumptions0.get("below_fermi"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_below_fermi(self):
|
||||
"""
|
||||
True if Delta can be non-zero below fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, a).is_below_fermi
|
||||
False
|
||||
>>> KroneckerDelta(p, i).is_below_fermi
|
||||
True
|
||||
>>> KroneckerDelta(p, q).is_below_fermi
|
||||
True
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_above_fermi, is_only_above_fermi, is_only_below_fermi
|
||||
|
||||
"""
|
||||
if self.args[0].assumptions0.get("above_fermi"):
|
||||
return False
|
||||
if self.args[1].assumptions0.get("above_fermi"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_only_above_fermi(self):
|
||||
"""
|
||||
True if Delta is restricted to above fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, a).is_only_above_fermi
|
||||
True
|
||||
>>> KroneckerDelta(p, q).is_only_above_fermi
|
||||
False
|
||||
>>> KroneckerDelta(p, i).is_only_above_fermi
|
||||
False
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_above_fermi, is_below_fermi, is_only_below_fermi
|
||||
|
||||
"""
|
||||
return ( self.args[0].assumptions0.get("above_fermi")
|
||||
or
|
||||
self.args[1].assumptions0.get("above_fermi")
|
||||
) or False
|
||||
|
||||
@property
|
||||
def is_only_below_fermi(self):
|
||||
"""
|
||||
True if Delta is restricted to below fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, i).is_only_below_fermi
|
||||
True
|
||||
>>> KroneckerDelta(p, q).is_only_below_fermi
|
||||
False
|
||||
>>> KroneckerDelta(p, a).is_only_below_fermi
|
||||
False
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_above_fermi, is_below_fermi, is_only_above_fermi
|
||||
|
||||
"""
|
||||
return ( self.args[0].assumptions0.get("below_fermi")
|
||||
or
|
||||
self.args[1].assumptions0.get("below_fermi")
|
||||
) or False
|
||||
|
||||
@property
|
||||
def indices_contain_equal_information(self):
|
||||
"""
|
||||
Returns True if indices are either both above or below fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, q).indices_contain_equal_information
|
||||
True
|
||||
>>> KroneckerDelta(p, q+1).indices_contain_equal_information
|
||||
True
|
||||
>>> KroneckerDelta(i, p).indices_contain_equal_information
|
||||
False
|
||||
|
||||
"""
|
||||
if (self.args[0].assumptions0.get("below_fermi") and
|
||||
self.args[1].assumptions0.get("below_fermi")):
|
||||
return True
|
||||
if (self.args[0].assumptions0.get("above_fermi")
|
||||
and self.args[1].assumptions0.get("above_fermi")):
|
||||
return True
|
||||
|
||||
# if both indices are general we are True, else false
|
||||
return self.is_below_fermi and self.is_above_fermi
|
||||
|
||||
@property
|
||||
def preferred_index(self):
|
||||
"""
|
||||
Returns the index which is preferred to keep in the final expression.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The preferred index is the index with more information regarding fermi
|
||||
level. If indices contain the same information, 'a' is preferred before
|
||||
'b'.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> j = Symbol('j', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> KroneckerDelta(p, i).preferred_index
|
||||
i
|
||||
>>> KroneckerDelta(p, a).preferred_index
|
||||
a
|
||||
>>> KroneckerDelta(i, j).preferred_index
|
||||
i
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
killable_index
|
||||
|
||||
"""
|
||||
if self._get_preferred_index():
|
||||
return self.args[1]
|
||||
else:
|
||||
return self.args[0]
|
||||
|
||||
@property
|
||||
def killable_index(self):
|
||||
"""
|
||||
Returns the index which is preferred to substitute in the final
|
||||
expression.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The index to substitute is the index with less information regarding
|
||||
fermi level. If indices contain the same information, 'a' is preferred
|
||||
before 'b'.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> j = Symbol('j', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> KroneckerDelta(p, i).killable_index
|
||||
p
|
||||
>>> KroneckerDelta(p, a).killable_index
|
||||
p
|
||||
>>> KroneckerDelta(i, j).killable_index
|
||||
j
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
preferred_index
|
||||
|
||||
"""
|
||||
if self._get_preferred_index():
|
||||
return self.args[0]
|
||||
else:
|
||||
return self.args[1]
|
||||
|
||||
def _get_preferred_index(self):
|
||||
"""
|
||||
Returns the index which is preferred to keep in the final expression.
|
||||
|
||||
The preferred index is the index with more information regarding fermi
|
||||
level. If indices contain the same information, index 0 is returned.
|
||||
|
||||
"""
|
||||
if not self.is_above_fermi:
|
||||
if self.args[0].assumptions0.get("below_fermi"):
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
elif not self.is_below_fermi:
|
||||
if self.args[0].assumptions0.get("above_fermi"):
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def indices(self):
|
||||
return self.args[0:2]
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
|
||||
i, j = args
|
||||
return Piecewise((0, Ne(i, j)), (1, True))
|
||||
@@ -0,0 +1,807 @@
|
||||
from itertools import product
|
||||
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.function import (diff, expand_func)
|
||||
from sympy.core.numbers import (I, Rational, oo, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.elementary.complexes import (conjugate, polar_lift)
|
||||
from sympy.functions.elementary.exponential import (exp, exp_polar, log)
|
||||
from sympy.functions.elementary.hyperbolic import (cosh, sinh)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||||
from sympy.functions.special.bessel import (besseli, besselj, besselk, bessely, hankel1, hankel2, hn1, hn2, jn, jn_zeros, yn)
|
||||
from sympy.functions.special.gamma_functions import (gamma, uppergamma)
|
||||
from sympy.functions.special.hyper import hyper
|
||||
from sympy.integrals.integrals import Integral
|
||||
from sympy.series.order import O
|
||||
from sympy.series.series import series
|
||||
from sympy.functions.special.bessel import (airyai, airybi,
|
||||
airyaiprime, airybiprime, marcumq)
|
||||
from sympy.core.random import (random_complex_number as randcplx,
|
||||
verify_numerically as tn,
|
||||
test_derivative_numerically as td,
|
||||
_randint)
|
||||
from sympy.simplify import besselsimp
|
||||
from sympy.testing.pytest import raises, slow
|
||||
|
||||
from sympy.abc import z, n, k, x
|
||||
|
||||
randint = _randint()
|
||||
|
||||
|
||||
def test_bessel_rand():
|
||||
for f in [besselj, bessely, besseli, besselk, hankel1, hankel2]:
|
||||
assert td(f(randcplx(), z), z)
|
||||
|
||||
for f in [jn, yn, hn1, hn2]:
|
||||
assert td(f(randint(-10, 10), z), z)
|
||||
|
||||
|
||||
def test_bessel_twoinputs():
|
||||
for f in [besselj, bessely, besseli, besselk, hankel1, hankel2, jn, yn]:
|
||||
raises(TypeError, lambda: f(1))
|
||||
raises(TypeError, lambda: f(1, 2, 3))
|
||||
|
||||
|
||||
def test_besselj_leading_term():
|
||||
assert besselj(0, x).as_leading_term(x) == 1
|
||||
assert besselj(1, sin(x)).as_leading_term(x) == x/2
|
||||
assert besselj(1, 2*sqrt(x)).as_leading_term(x) == sqrt(x)
|
||||
|
||||
# https://github.com/sympy/sympy/issues/21701
|
||||
assert (besselj(z, x)/x**z).as_leading_term(x) == 1/(2**z*gamma(z + 1))
|
||||
|
||||
|
||||
def test_bessely_leading_term():
|
||||
assert bessely(0, x).as_leading_term(x) == (2*log(x) - 2*log(2) + 2*S.EulerGamma)/pi
|
||||
assert bessely(1, sin(x)).as_leading_term(x) == -2/(pi*x)
|
||||
assert bessely(1, 2*sqrt(x)).as_leading_term(x) == -1/(pi*sqrt(x))
|
||||
|
||||
|
||||
def test_besseli_leading_term():
|
||||
assert besseli(0, x).as_leading_term(x) == 1
|
||||
assert besseli(1, sin(x)).as_leading_term(x) == x/2
|
||||
assert besseli(1, 2*sqrt(x)).as_leading_term(x) == sqrt(x)
|
||||
|
||||
|
||||
def test_besselk_leading_term():
|
||||
assert besselk(0, x).as_leading_term(x) == -log(x) - S.EulerGamma + log(2)
|
||||
assert besselk(1, sin(x)).as_leading_term(x) == 1/x
|
||||
assert besselk(1, 2*sqrt(x)).as_leading_term(x) == 1/(2*sqrt(x))
|
||||
assert besselk(S(5)/3, x).as_leading_term(x) == 2**(S(2)/3)*gamma(S(5)/3)/x**(S(5)/3)
|
||||
assert besselk(S(2)/3, x).as_leading_term(x) == besselk(-S(2)/3, x).as_leading_term(x)
|
||||
assert besselk(1,cos(x)).as_leading_term(x) == besselk(1,1)
|
||||
assert besselk(3,1/x).as_leading_term(x) == sqrt(pi)*exp(-(1/x))/sqrt(2/x)
|
||||
assert besselk(3,1/sin(x)).as_leading_term(x) == sqrt(pi)*exp(-(1/x))/sqrt(2/x)
|
||||
|
||||
nz = Symbol("nz", nonzero=True)
|
||||
assert besselk(nz, x).as_leading_term(x).subs({nz:S(5)/7}) == besselk(S(5)/7, x).series(x).as_leading_term(x)
|
||||
assert besselk(nz, x).as_leading_term(x).subs({nz:S(-15)/7}) == besselk(S(-15)/7, x).series(x).as_leading_term(x)
|
||||
assert besselk(nz, x).as_leading_term(x).subs({nz:3}) == besselk(3, x).series(x).as_leading_term(x)
|
||||
assert besselk(nz, x).as_leading_term(x).subs({nz:-2}) == besselk(-2, x).series(x).as_leading_term(x)
|
||||
|
||||
|
||||
def test_besselj_series():
|
||||
assert besselj(0, x).series(x) == 1 - x**2/4 + x**4/64 + O(x**6)
|
||||
assert besselj(0, x**(1.1)).series(x) == 1 + x**4.4/64 - x**2.2/4 + O(x**6)
|
||||
assert besselj(0, x**2 + x).series(x) == 1 - x**2/4 - x**3/2\
|
||||
- 15*x**4/64 + x**5/16 + O(x**6)
|
||||
assert besselj(0, sqrt(x) + x).series(x, n=4) == 1 - x/4 - 15*x**2/64\
|
||||
+ 215*x**3/2304 - x**Rational(3, 2)/2 + x**Rational(5, 2)/16\
|
||||
+ 23*x**Rational(7, 2)/384 + O(x**4)
|
||||
assert besselj(0, x/(1 - x)).series(x) == 1 - x**2/4 - x**3/2 - 47*x**4/64\
|
||||
- 15*x**5/16 + O(x**6)
|
||||
assert besselj(0, log(1 + x)).series(x) == 1 - x**2/4 + x**3/4\
|
||||
- 41*x**4/192 + 17*x**5/96 + O(x**6)
|
||||
assert besselj(1, sin(x)).series(x) == x/2 - 7*x**3/48 + 73*x**5/1920 + O(x**6)
|
||||
assert besselj(1, 2*sqrt(x)).series(x) == sqrt(x) - x**Rational(3, 2)/2\
|
||||
+ x**Rational(5, 2)/12 - x**Rational(7, 2)/144 + x**Rational(9, 2)/2880\
|
||||
- x**Rational(11, 2)/86400 + O(x**6)
|
||||
assert besselj(-2, sin(x)).series(x, n=4) == besselj(2, sin(x)).series(x, n=4)
|
||||
|
||||
|
||||
def test_bessely_series():
|
||||
const = 2*S.EulerGamma/pi - 2*log(2)/pi + 2*log(x)/pi
|
||||
assert bessely(0, x).series(x, n=4) == const + x**2*(-log(x)/(2*pi)\
|
||||
+ (2 - 2*S.EulerGamma)/(4*pi) + log(2)/(2*pi)) + O(x**4*log(x))
|
||||
assert bessely(1, x).series(x, n=4) == -2/(pi*x) + x*(log(x)/pi - log(2)/pi - \
|
||||
(1 - 2*S.EulerGamma)/(2*pi)) + x**3*(-log(x)/(8*pi) + \
|
||||
(S(5)/2 - 2*S.EulerGamma)/(16*pi) + log(2)/(8*pi)) + O(x**4*log(x))
|
||||
assert bessely(2, x).series(x, n=4) == -4/(pi*x**2) - 1/pi + x**2*(log(x)/(4*pi) - \
|
||||
log(2)/(4*pi) - (S(3)/2 - 2*S.EulerGamma)/(8*pi)) + O(x**4*log(x))
|
||||
assert bessely(3, x).series(x, n=4) == -16/(pi*x**3) - 2/(pi*x) - \
|
||||
x/(4*pi) + x**3*(log(x)/(24*pi) - log(2)/(24*pi) - \
|
||||
(S(11)/6 - 2*S.EulerGamma)/(48*pi)) + O(x**4*log(x))
|
||||
assert bessely(0, x**(1.1)).series(x, n=4) == 2*S.EulerGamma/pi\
|
||||
- 2*log(2)/pi + 2.2*log(x)/pi + x**2.2*(-0.55*log(x)/pi\
|
||||
+ (2 - 2*S.EulerGamma)/(4*pi) + log(2)/(2*pi)) + O(x**4*log(x))
|
||||
assert bessely(0, x**2 + x).series(x, n=4) == \
|
||||
const - (2 - 2*S.EulerGamma)*(-x**3/(2*pi) - x**2/(4*pi)) + 2*x/pi\
|
||||
+ x**2*(-log(x)/(2*pi) - 1/pi + log(2)/(2*pi))\
|
||||
+ x**3*(-log(x)/pi + 1/(6*pi) + log(2)/pi) + O(x**4*log(x))
|
||||
assert bessely(0, x/(1 - x)).series(x, n=3) == const\
|
||||
+ 2*x/pi + x**2*(-log(x)/(2*pi) + (2 - 2*S.EulerGamma)/(4*pi)\
|
||||
+ log(2)/(2*pi) + 1/pi) + O(x**3*log(x))
|
||||
assert bessely(0, log(1 + x)).series(x, n=3) == const\
|
||||
- x/pi + x**2*(-log(x)/(2*pi) + (2 - 2*S.EulerGamma)/(4*pi)\
|
||||
+ log(2)/(2*pi) + 5/(12*pi)) + O(x**3*log(x))
|
||||
assert bessely(1, sin(x)).series(x, n=4) == -1/(pi*(-x**3/12 + x/2)) - \
|
||||
(1 - 2*S.EulerGamma)*(-x**3/12 + x/2)/pi + x*(log(x)/pi - log(2)/pi) + \
|
||||
x**3*(-7*log(x)/(24*pi) - 1/(6*pi) + (S(5)/2 - 2*S.EulerGamma)/(16*pi) +
|
||||
7*log(2)/(24*pi)) + O(x**4*log(x))
|
||||
assert bessely(1, 2*sqrt(x)).series(x, n=3) == -1/(pi*sqrt(x)) + \
|
||||
sqrt(x)*(log(x)/pi - (1 - 2*S.EulerGamma)/pi) + x**(S(3)/2)*(-log(x)/(2*pi) + \
|
||||
(S(5)/2 - 2*S.EulerGamma)/(2*pi)) + x**(S(5)/2)*(log(x)/(12*pi) - \
|
||||
(S(10)/3 - 2*S.EulerGamma)/(12*pi)) + O(x**3*log(x))
|
||||
assert bessely(-2, sin(x)).series(x, n=4) == bessely(2, sin(x)).series(x, n=4)
|
||||
|
||||
|
||||
def test_besseli_series():
|
||||
assert besseli(0, x).series(x) == 1 + x**2/4 + x**4/64 + O(x**6)
|
||||
assert besseli(0, x**(1.1)).series(x) == 1 + x**4.4/64 + x**2.2/4 + O(x**6)
|
||||
assert besseli(0, x**2 + x).series(x) == 1 + x**2/4 + x**3/2 + 17*x**4/64 + \
|
||||
x**5/16 + O(x**6)
|
||||
assert besseli(0, sqrt(x) + x).series(x, n=4) == 1 + x/4 + 17*x**2/64 + \
|
||||
217*x**3/2304 + x**(S(3)/2)/2 + x**(S(5)/2)/16 + 25*x**(S(7)/2)/384 + O(x**4)
|
||||
assert besseli(0, x/(1 - x)).series(x) == 1 + x**2/4 + x**3/2 + 49*x**4/64 + \
|
||||
17*x**5/16 + O(x**6)
|
||||
assert besseli(0, log(1 + x)).series(x) == 1 + x**2/4 - x**3/4 + 47*x**4/192 - \
|
||||
23*x**5/96 + O(x**6)
|
||||
assert besseli(1, sin(x)).series(x) == x/2 - x**3/48 - 47*x**5/1920 + O(x**6)
|
||||
assert besseli(1, 2*sqrt(x)).series(x) == sqrt(x) + x**(S(3)/2)/2 + x**(S(5)/2)/12 + \
|
||||
x**(S(7)/2)/144 + x**(S(9)/2)/2880 + x**(S(11)/2)/86400 + O(x**6)
|
||||
assert besseli(-2, sin(x)).series(x, n=4) == besseli(2, sin(x)).series(x, n=4)
|
||||
|
||||
#test for aseries
|
||||
assert besseli(0,x).series(x, oo, n=4) == sqrt(2)*(sqrt(1/x) - (1/x)**(S(3)/2)/8 - \
|
||||
3*(1/x)**(S(5)/2)/128 - 15*(1/x)**(S(7)/2)/1024 + O((1/x)**(S(9)/2), (x, oo)))*exp(x)/(2*sqrt(pi))
|
||||
assert besseli(0,x).series(x,-oo, n=4) == sqrt(2)*(sqrt(-1/x) - (-1/x)**(S(3)/2)/8 - 3*(-1/x)**(S(5)/2)/128 - \
|
||||
15*(-1/x)**(S(7)/2)/1024 + O((-1/x)**(S(9)/2), (x, -oo)))*exp(-x)/(2*sqrt(pi))
|
||||
|
||||
|
||||
def test_besselk_series():
|
||||
const = log(2) - S.EulerGamma - log(x)
|
||||
assert besselk(0, x).series(x, n=4) == const + \
|
||||
x**2*(-log(x)/4 - S.EulerGamma/4 + log(2)/4 + S(1)/4) + O(x**4*log(x))
|
||||
assert besselk(1, x).series(x, n=4) == 1/x + x*(log(x)/2 - log(2)/2 - \
|
||||
S(1)/4 + S.EulerGamma/2) + x**3*(log(x)/16 - S(5)/64 - log(2)/16 + \
|
||||
S.EulerGamma/16) + O(x**4*log(x))
|
||||
assert besselk(2, x).series(x, n=4) == 2/x**2 - S(1)/2 + x**2*(-log(x)/8 - \
|
||||
S.EulerGamma/8 + log(2)/8 + S(3)/32) + O(x**4*log(x))
|
||||
assert besselk(2, x).series(x, n=1) == 2/x**2 - S(1)/2 + O(x) #edge case for series truncation
|
||||
assert besselk(0, x**(1.1)).series(x, n=4) == log(2) - S.EulerGamma - \
|
||||
1.1*log(x) + x**2.2*(-0.275*log(x) - S.EulerGamma/4 + \
|
||||
log(2)/4 + S(1)/4) + O(x**4*log(x))
|
||||
assert besselk(0, x**2 + x).series(x, n=4) == const + \
|
||||
(2 - 2*S.EulerGamma)*(x**3/4 + x**2/8) - x + x**2*(-log(x)/4 + \
|
||||
log(2)/4 + S(1)/2) + x**3*(-log(x)/2 - S(7)/12 + log(2)/2) + O(x**4*log(x))
|
||||
assert besselk(0, x/(1 - x)).series(x, n=3) == const - x + x**2*(-log(x)/4 - \
|
||||
S(1)/4 - S.EulerGamma/4 + log(2)/4) + O(x**3*log(x))
|
||||
assert besselk(0, log(1 + x)).series(x, n=3) == const + x/2 + \
|
||||
x**2*(-log(x)/4 - S.EulerGamma/4 + S(1)/24 + log(2)/4) + O(x**3*log(x))
|
||||
assert besselk(1, 2*sqrt(x)).series(x, n=3) == 1/(2*sqrt(x)) + \
|
||||
sqrt(x)*(log(x)/2 - S(1)/2 + S.EulerGamma) + x**(S(3)/2)*(log(x)/4 - S(5)/8 + \
|
||||
S.EulerGamma/2) + x**(S(5)/2)*(log(x)/24 - S(5)/36 + S.EulerGamma/12) + O(x**3*log(x))
|
||||
assert besselk(-2, sin(x)).series(x, n=4) == besselk(2, sin(x)).series(x, n=4)
|
||||
assert besselk(2, x**2).series(x, n=2) == 2/x**4 - S(1)/2 + O(x**2) #edge case for series truncation
|
||||
assert besselk(2, x**2).series(x, n=6) == 2/x**4 - S(1)/2 + x**4*(-log(x)/4 - S.EulerGamma/8 + log(2)/8 + S(3)/32) + O(x**6*log(x))
|
||||
assert (x**2*besselk(2, x)).series(x, n=2) == 2 + O(x**2)
|
||||
|
||||
#test for aseries
|
||||
assert besselk(0,x).series(x, oo, n=4) == sqrt(2)*sqrt(pi)*(sqrt(1/x) + (1/x)**(S(3)/2)/8 - \
|
||||
3*(1/x)**(S(5)/2)/128 + 15*(1/x)**(S(7)/2)/1024 + O((1/x)**(S(9)/2), (x, oo)))*exp(-x)/2
|
||||
assert besselk(0,x).series(x, -oo, n=4) == sqrt(2)*sqrt(pi)*(-I*sqrt(-1/x) + I*(-1/x)**(S(3)/2)/8 + \
|
||||
3*I*(-1/x)**(S(5)/2)/128 + 15*I*(-1/x)**(S(7)/2)/1024 + O((-1/x)**(S(9)/2), (x, -oo)))*exp(-x)/2
|
||||
|
||||
|
||||
def test_besselk_frac_order_series():
|
||||
assert besselk(S(5)/3, x).series(x, n=2) == 2**(S(2)/3)*gamma(S(5)/3)/x**(S(5)/3) - \
|
||||
3*gamma(S(5)/3)*x**(S(1)/3)/(4*2**(S(1)/3)) + \
|
||||
gamma(-S(5)/3)*x**(S(5)/3)/(4*2**(S(2)/3)) + O(x**2)
|
||||
assert besselk(S(1)/2, x).series(x, n=2) == sqrt(pi/2)/sqrt(x) - \
|
||||
sqrt(pi*x/2) + x**(S(3)/2)*sqrt(pi/2)/2 + O(x**2)
|
||||
assert besselk(S(1)/2, sqrt(x)).series(x, n=2) == sqrt(pi/2)/x**(S(1)/4) - \
|
||||
sqrt(pi/2)*x**(S(1)/4) + sqrt(pi/2)*x**(S(3)/4)/2 - \
|
||||
sqrt(pi/2)*x**(S(5)/4)/6 + sqrt(pi/2)*x**(S(7)/4)/24 + O(x**2)
|
||||
assert besselk(S(1)/2, x**2).series(x, n=2) == sqrt(pi/2)/x \
|
||||
- sqrt(pi/2)*x + O(x**2)
|
||||
assert besselk(-S(1)/2, x).series(x) == besselk(S(1)/2, x).series(x)
|
||||
assert besselk(-S(7)/6, x).series(x) == besselk(S(7)/6, x).series(x)
|
||||
|
||||
|
||||
def test_diff():
|
||||
assert besselj(n, z).diff(z) == besselj(n - 1, z)/2 - besselj(n + 1, z)/2
|
||||
assert bessely(n, z).diff(z) == bessely(n - 1, z)/2 - bessely(n + 1, z)/2
|
||||
assert besseli(n, z).diff(z) == besseli(n - 1, z)/2 + besseli(n + 1, z)/2
|
||||
assert besselk(n, z).diff(z) == -besselk(n - 1, z)/2 - besselk(n + 1, z)/2
|
||||
assert hankel1(n, z).diff(z) == hankel1(n - 1, z)/2 - hankel1(n + 1, z)/2
|
||||
assert hankel2(n, z).diff(z) == hankel2(n - 1, z)/2 - hankel2(n + 1, z)/2
|
||||
|
||||
|
||||
def test_rewrite():
|
||||
assert besselj(n, z).rewrite(jn) == sqrt(2*z/pi)*jn(n - S.Half, z)
|
||||
assert bessely(n, z).rewrite(yn) == sqrt(2*z/pi)*yn(n - S.Half, z)
|
||||
assert besseli(n, z).rewrite(besselj) == \
|
||||
exp(-I*n*pi/2)*besselj(n, polar_lift(I)*z)
|
||||
assert besselj(n, z).rewrite(besseli) == \
|
||||
exp(I*n*pi/2)*besseli(n, polar_lift(-I)*z)
|
||||
|
||||
nu = randcplx()
|
||||
|
||||
assert tn(besselj(nu, z), besselj(nu, z).rewrite(besseli), z)
|
||||
assert tn(besselj(nu, z), besselj(nu, z).rewrite(bessely), z)
|
||||
|
||||
assert tn(besseli(nu, z), besseli(nu, z).rewrite(besselj), z)
|
||||
assert tn(besseli(nu, z), besseli(nu, z).rewrite(bessely), z)
|
||||
|
||||
assert tn(bessely(nu, z), bessely(nu, z).rewrite(besselj), z)
|
||||
assert tn(bessely(nu, z), bessely(nu, z).rewrite(besseli), z)
|
||||
|
||||
assert tn(besselk(nu, z), besselk(nu, z).rewrite(besselj), z)
|
||||
assert tn(besselk(nu, z), besselk(nu, z).rewrite(besseli), z)
|
||||
assert tn(besselk(nu, z), besselk(nu, z).rewrite(bessely), z)
|
||||
|
||||
# check that a rewrite was triggered, when the order is set to a generic
|
||||
# symbol 'nu'
|
||||
assert yn(nu, z) != yn(nu, z).rewrite(jn)
|
||||
assert hn1(nu, z) != hn1(nu, z).rewrite(jn)
|
||||
assert hn2(nu, z) != hn2(nu, z).rewrite(jn)
|
||||
assert jn(nu, z) != jn(nu, z).rewrite(yn)
|
||||
assert hn1(nu, z) != hn1(nu, z).rewrite(yn)
|
||||
assert hn2(nu, z) != hn2(nu, z).rewrite(yn)
|
||||
|
||||
# rewriting spherical bessel functions (SBFs) w.r.t. besselj, bessely is
|
||||
# not allowed if a generic symbol 'nu' is used as the order of the SBFs
|
||||
# to avoid inconsistencies (the order of bessel[jy] is allowed to be
|
||||
# complex-valued, whereas SBFs are defined only for integer orders)
|
||||
order = nu
|
||||
for f in (besselj, bessely):
|
||||
assert hn1(order, z) == hn1(order, z).rewrite(f)
|
||||
assert hn2(order, z) == hn2(order, z).rewrite(f)
|
||||
|
||||
assert jn(order, z).rewrite(besselj) == sqrt(2)*sqrt(pi)*sqrt(1/z)*besselj(order + S.Half, z)/2
|
||||
assert jn(order, z).rewrite(bessely) == (-1)**nu*sqrt(2)*sqrt(pi)*sqrt(1/z)*bessely(-order - S.Half, z)/2
|
||||
|
||||
# for integral orders rewriting SBFs w.r.t bessel[jy] is allowed
|
||||
N = Symbol('n', integer=True)
|
||||
ri = randint(-11, 10)
|
||||
for order in (ri, N):
|
||||
for f in (besselj, bessely):
|
||||
assert yn(order, z) != yn(order, z).rewrite(f)
|
||||
assert jn(order, z) != jn(order, z).rewrite(f)
|
||||
assert hn1(order, z) != hn1(order, z).rewrite(f)
|
||||
assert hn2(order, z) != hn2(order, z).rewrite(f)
|
||||
|
||||
for func, refunc in product((yn, jn, hn1, hn2),
|
||||
(jn, yn, besselj, bessely)):
|
||||
assert tn(func(ri, z), func(ri, z).rewrite(refunc), z)
|
||||
|
||||
|
||||
def test_expand():
|
||||
assert expand_func(besselj(S.Half, z).rewrite(jn)) == \
|
||||
sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z))
|
||||
assert expand_func(bessely(S.Half, z).rewrite(yn)) == \
|
||||
-sqrt(2)*cos(z)/(sqrt(pi)*sqrt(z))
|
||||
|
||||
# XXX: teach sin/cos to work around arguments like
|
||||
# x*exp_polar(I*pi*n/2). Then change besselsimp -> expand_func
|
||||
assert besselsimp(besselj(S.Half, z)) == sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(besselj(Rational(-1, 2), z)) == sqrt(2)*cos(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(besselj(Rational(5, 2), z)) == \
|
||||
-sqrt(2)*(z**2*sin(z) + 3*z*cos(z) - 3*sin(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
assert besselsimp(besselj(Rational(-5, 2), z)) == \
|
||||
-sqrt(2)*(z**2*cos(z) - 3*z*sin(z) - 3*cos(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
|
||||
assert besselsimp(bessely(S.Half, z)) == \
|
||||
-(sqrt(2)*cos(z))/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(bessely(Rational(-1, 2), z)) == sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(bessely(Rational(5, 2), z)) == \
|
||||
sqrt(2)*(z**2*cos(z) - 3*z*sin(z) - 3*cos(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
assert besselsimp(bessely(Rational(-5, 2), z)) == \
|
||||
-sqrt(2)*(z**2*sin(z) + 3*z*cos(z) - 3*sin(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
|
||||
assert besselsimp(besseli(S.Half, z)) == sqrt(2)*sinh(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(besseli(Rational(-1, 2), z)) == \
|
||||
sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(besseli(Rational(5, 2), z)) == \
|
||||
sqrt(2)*(z**2*sinh(z) - 3*z*cosh(z) + 3*sinh(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
assert besselsimp(besseli(Rational(-5, 2), z)) == \
|
||||
sqrt(2)*(z**2*cosh(z) - 3*z*sinh(z) + 3*cosh(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
|
||||
assert besselsimp(besselk(S.Half, z)) == \
|
||||
besselsimp(besselk(Rational(-1, 2), z)) == sqrt(pi)*exp(-z)/(sqrt(2)*sqrt(z))
|
||||
assert besselsimp(besselk(Rational(5, 2), z)) == \
|
||||
besselsimp(besselk(Rational(-5, 2), z)) == \
|
||||
sqrt(2)*sqrt(pi)*(z**2 + 3*z + 3)*exp(-z)/(2*z**Rational(5, 2))
|
||||
|
||||
n = Symbol('n', integer=True, positive=True)
|
||||
|
||||
assert expand_func(besseli(n + 2, z)) == \
|
||||
besseli(n, z) + (-2*n - 2)*(-2*n*besseli(n, z)/z + besseli(n - 1, z))/z
|
||||
assert expand_func(besselj(n + 2, z)) == \
|
||||
-besselj(n, z) + (2*n + 2)*(2*n*besselj(n, z)/z - besselj(n - 1, z))/z
|
||||
assert expand_func(besselk(n + 2, z)) == \
|
||||
besselk(n, z) + (2*n + 2)*(2*n*besselk(n, z)/z + besselk(n - 1, z))/z
|
||||
assert expand_func(bessely(n + 2, z)) == \
|
||||
-bessely(n, z) + (2*n + 2)*(2*n*bessely(n, z)/z - bessely(n - 1, z))/z
|
||||
|
||||
assert expand_func(besseli(n + S.Half, z).rewrite(jn)) == \
|
||||
(sqrt(2)*sqrt(z)*exp(-I*pi*(n + S.Half)/2) *
|
||||
exp_polar(I*pi/4)*jn(n, z*exp_polar(I*pi/2))/sqrt(pi))
|
||||
assert expand_func(besselj(n + S.Half, z).rewrite(jn)) == \
|
||||
sqrt(2)*sqrt(z)*jn(n, z)/sqrt(pi)
|
||||
|
||||
r = Symbol('r', real=True)
|
||||
p = Symbol('p', positive=True)
|
||||
i = Symbol('i', integer=True)
|
||||
|
||||
for besselx in [besselj, bessely, besseli, besselk]:
|
||||
assert besselx(i, p).is_extended_real is True
|
||||
assert besselx(i, x).is_extended_real is None
|
||||
assert besselx(x, z).is_extended_real is None
|
||||
|
||||
for besselx in [besselj, besseli]:
|
||||
assert besselx(i, r).is_extended_real is True
|
||||
for besselx in [bessely, besselk]:
|
||||
assert besselx(i, r).is_extended_real is None
|
||||
|
||||
for besselx in [besselj, bessely, besseli, besselk]:
|
||||
assert expand_func(besselx(oo, x)) == besselx(oo, x, evaluate=False)
|
||||
assert expand_func(besselx(-oo, x)) == besselx(-oo, x, evaluate=False)
|
||||
|
||||
|
||||
# Quite varying time, but often really slow
|
||||
@slow
|
||||
def test_slow_expand():
|
||||
def check(eq, ans):
|
||||
return tn(eq, ans) and eq == ans
|
||||
|
||||
rn = randcplx(a=1, b=0, d=0, c=2)
|
||||
|
||||
for besselx in [besselj, bessely, besseli, besselk]:
|
||||
ri = S(2*randint(-11, 10) + 1) / 2 # half integer in [-21/2, 21/2]
|
||||
assert tn(besselsimp(besselx(ri, z)), besselx(ri, z))
|
||||
|
||||
assert check(expand_func(besseli(rn, x)),
|
||||
besseli(rn - 2, x) - 2*(rn - 1)*besseli(rn - 1, x)/x)
|
||||
assert check(expand_func(besseli(-rn, x)),
|
||||
besseli(-rn + 2, x) + 2*(-rn + 1)*besseli(-rn + 1, x)/x)
|
||||
|
||||
assert check(expand_func(besselj(rn, x)),
|
||||
-besselj(rn - 2, x) + 2*(rn - 1)*besselj(rn - 1, x)/x)
|
||||
assert check(expand_func(besselj(-rn, x)),
|
||||
-besselj(-rn + 2, x) + 2*(-rn + 1)*besselj(-rn + 1, x)/x)
|
||||
|
||||
assert check(expand_func(besselk(rn, x)),
|
||||
besselk(rn - 2, x) + 2*(rn - 1)*besselk(rn - 1, x)/x)
|
||||
assert check(expand_func(besselk(-rn, x)),
|
||||
besselk(-rn + 2, x) - 2*(-rn + 1)*besselk(-rn + 1, x)/x)
|
||||
|
||||
assert check(expand_func(bessely(rn, x)),
|
||||
-bessely(rn - 2, x) + 2*(rn - 1)*bessely(rn - 1, x)/x)
|
||||
assert check(expand_func(bessely(-rn, x)),
|
||||
-bessely(-rn + 2, x) + 2*(-rn + 1)*bessely(-rn + 1, x)/x)
|
||||
|
||||
|
||||
def mjn(n, z):
|
||||
return expand_func(jn(n, z))
|
||||
|
||||
|
||||
def myn(n, z):
|
||||
return expand_func(yn(n, z))
|
||||
|
||||
|
||||
def test_jn():
|
||||
z = symbols("z")
|
||||
assert jn(0, 0) == 1
|
||||
assert jn(1, 0) == 0
|
||||
assert jn(-1, 0) == S.ComplexInfinity
|
||||
assert jn(z, 0) == jn(z, 0, evaluate=False)
|
||||
assert jn(0, oo) == 0
|
||||
assert jn(0, -oo) == 0
|
||||
|
||||
assert mjn(0, z) == sin(z)/z
|
||||
assert mjn(1, z) == sin(z)/z**2 - cos(z)/z
|
||||
assert mjn(2, z) == (3/z**3 - 1/z)*sin(z) - (3/z**2) * cos(z)
|
||||
assert mjn(3, z) == (15/z**4 - 6/z**2)*sin(z) + (1/z - 15/z**3)*cos(z)
|
||||
assert mjn(4, z) == (1/z + 105/z**5 - 45/z**3)*sin(z) + \
|
||||
(-105/z**4 + 10/z**2)*cos(z)
|
||||
assert mjn(5, z) == (945/z**6 - 420/z**4 + 15/z**2)*sin(z) + \
|
||||
(-1/z - 945/z**5 + 105/z**3)*cos(z)
|
||||
assert mjn(6, z) == (-1/z + 10395/z**7 - 4725/z**5 + 210/z**3)*sin(z) + \
|
||||
(-10395/z**6 + 1260/z**4 - 21/z**2)*cos(z)
|
||||
|
||||
assert expand_func(jn(n, z)) == jn(n, z)
|
||||
|
||||
# SBFs not defined for complex-valued orders
|
||||
assert jn(2+3j, 5.2+0.3j).evalf() == jn(2+3j, 5.2+0.3j)
|
||||
|
||||
assert eq([jn(2, 5.2+0.3j).evalf(10)],
|
||||
[0.09941975672 - 0.05452508024*I])
|
||||
|
||||
|
||||
def test_yn():
|
||||
z = symbols("z")
|
||||
assert myn(0, z) == -cos(z)/z
|
||||
assert myn(1, z) == -cos(z)/z**2 - sin(z)/z
|
||||
assert myn(2, z) == -((3/z**3 - 1/z)*cos(z) + (3/z**2)*sin(z))
|
||||
assert expand_func(yn(n, z)) == yn(n, z)
|
||||
|
||||
# SBFs not defined for complex-valued orders
|
||||
assert yn(2+3j, 5.2+0.3j).evalf() == yn(2+3j, 5.2+0.3j)
|
||||
|
||||
assert eq([yn(2, 5.2+0.3j).evalf(10)],
|
||||
[0.185250342 + 0.01489557397*I])
|
||||
|
||||
|
||||
def test_sympify_yn():
|
||||
assert S(15) in myn(3, pi).atoms()
|
||||
assert myn(3, pi) == 15/pi**4 - 6/pi**2
|
||||
|
||||
|
||||
def eq(a, b, tol=1e-6):
|
||||
for u, v in zip(a, b):
|
||||
if not (abs(u - v) < tol):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def test_jn_zeros():
|
||||
assert eq(jn_zeros(0, 4), [3.141592, 6.283185, 9.424777, 12.566370])
|
||||
assert eq(jn_zeros(1, 4), [4.493409, 7.725251, 10.904121, 14.066193])
|
||||
assert eq(jn_zeros(2, 4), [5.763459, 9.095011, 12.322940, 15.514603])
|
||||
assert eq(jn_zeros(3, 4), [6.987932, 10.417118, 13.698023, 16.923621])
|
||||
assert eq(jn_zeros(4, 4), [8.182561, 11.704907, 15.039664, 18.301255])
|
||||
|
||||
|
||||
def test_bessel_eval():
|
||||
n, m, k = Symbol('n', integer=True), Symbol('m'), Symbol('k', integer=True, zero=False)
|
||||
|
||||
for f in [besselj, besseli]:
|
||||
assert f(0, 0) is S.One
|
||||
assert f(2.1, 0) is S.Zero
|
||||
assert f(-3, 0) is S.Zero
|
||||
assert f(-10.2, 0) is S.ComplexInfinity
|
||||
assert f(1 + 3*I, 0) is S.Zero
|
||||
assert f(-3 + I, 0) is S.ComplexInfinity
|
||||
assert f(-2*I, 0) is S.NaN
|
||||
assert f(n, 0) != S.One and f(n, 0) != S.Zero
|
||||
assert f(m, 0) != S.One and f(m, 0) != S.Zero
|
||||
assert f(k, 0) is S.Zero
|
||||
|
||||
assert bessely(0, 0) is S.NegativeInfinity
|
||||
assert besselk(0, 0) is S.Infinity
|
||||
for f in [bessely, besselk]:
|
||||
assert f(1 + I, 0) is S.ComplexInfinity
|
||||
assert f(I, 0) is S.NaN
|
||||
|
||||
for f in [besselj, bessely]:
|
||||
assert f(m, S.Infinity) is S.Zero
|
||||
assert f(m, S.NegativeInfinity) is S.Zero
|
||||
|
||||
for f in [besseli, besselk]:
|
||||
assert f(m, I*S.Infinity) is S.Zero
|
||||
assert f(m, I*S.NegativeInfinity) is S.Zero
|
||||
|
||||
for f in [besseli, besselk]:
|
||||
assert f(-4, z) == f(4, z)
|
||||
assert f(-3, z) == f(3, z)
|
||||
assert f(-n, z) == f(n, z)
|
||||
assert f(-m, z) != f(m, z)
|
||||
|
||||
for f in [besselj, bessely]:
|
||||
assert f(-4, z) == f(4, z)
|
||||
assert f(-3, z) == -f(3, z)
|
||||
assert f(-n, z) == (-1)**n*f(n, z)
|
||||
assert f(-m, z) != (-1)**m*f(m, z)
|
||||
|
||||
for f in [besselj, besseli]:
|
||||
assert f(m, -z) == (-z)**m*z**(-m)*f(m, z)
|
||||
|
||||
assert besseli(2, -z) == besseli(2, z)
|
||||
assert besseli(3, -z) == -besseli(3, z)
|
||||
|
||||
assert besselj(0, -z) == besselj(0, z)
|
||||
assert besselj(1, -z) == -besselj(1, z)
|
||||
|
||||
assert besseli(0, I*z) == besselj(0, z)
|
||||
assert besseli(1, I*z) == I*besselj(1, z)
|
||||
assert besselj(3, I*z) == -I*besseli(3, z)
|
||||
|
||||
|
||||
def test_bessel_nan():
|
||||
# FIXME: could have these return NaN; for now just fix infinite recursion
|
||||
for f in [besselj, bessely, besseli, besselk, hankel1, hankel2, yn, jn]:
|
||||
assert f(1, S.NaN) == f(1, S.NaN, evaluate=False)
|
||||
|
||||
|
||||
def test_meromorphic():
|
||||
assert besselj(2, x).is_meromorphic(x, 1) == True
|
||||
assert besselj(2, x).is_meromorphic(x, 0) == True
|
||||
assert besselj(2, x).is_meromorphic(x, oo) == False
|
||||
assert besselj(S(2)/3, x).is_meromorphic(x, 1) == True
|
||||
assert besselj(S(2)/3, x).is_meromorphic(x, 0) == False
|
||||
assert besselj(S(2)/3, x).is_meromorphic(x, oo) == False
|
||||
assert besselj(x, 2*x).is_meromorphic(x, 2) == False
|
||||
assert besselk(0, x).is_meromorphic(x, 1) == True
|
||||
assert besselk(2, x).is_meromorphic(x, 0) == True
|
||||
assert besseli(0, x).is_meromorphic(x, 1) == True
|
||||
assert besseli(2, x).is_meromorphic(x, 0) == True
|
||||
assert bessely(0, x).is_meromorphic(x, 1) == True
|
||||
assert bessely(0, x).is_meromorphic(x, 0) == False
|
||||
assert bessely(2, x).is_meromorphic(x, 0) == True
|
||||
assert hankel1(3, x**2 + 2*x).is_meromorphic(x, 1) == True
|
||||
assert hankel1(0, x).is_meromorphic(x, 0) == False
|
||||
assert hankel2(11, 4).is_meromorphic(x, 5) == True
|
||||
assert hn1(6, 7*x**3 + 4).is_meromorphic(x, 7) == True
|
||||
assert hn2(3, 2*x).is_meromorphic(x, 9) == True
|
||||
assert jn(5, 2*x + 7).is_meromorphic(x, 4) == True
|
||||
assert yn(8, x**2 + 11).is_meromorphic(x, 6) == True
|
||||
|
||||
|
||||
def test_conjugate():
|
||||
n = Symbol('n')
|
||||
z = Symbol('z', extended_real=False)
|
||||
x = Symbol('x', extended_real=True)
|
||||
y = Symbol('y', positive=True)
|
||||
t = Symbol('t', negative=True)
|
||||
|
||||
for f in [besseli, besselj, besselk, bessely, hankel1, hankel2]:
|
||||
assert f(n, -1).conjugate() != f(conjugate(n), -1)
|
||||
assert f(n, x).conjugate() != f(conjugate(n), x)
|
||||
assert f(n, t).conjugate() != f(conjugate(n), t)
|
||||
|
||||
rz = randcplx(b=0.5)
|
||||
|
||||
for f in [besseli, besselj, besselk, bessely]:
|
||||
assert f(n, 1 + I).conjugate() == f(conjugate(n), 1 - I)
|
||||
assert f(n, 0).conjugate() == f(conjugate(n), 0)
|
||||
assert f(n, 1).conjugate() == f(conjugate(n), 1)
|
||||
assert f(n, z).conjugate() == f(conjugate(n), conjugate(z))
|
||||
assert f(n, y).conjugate() == f(conjugate(n), y)
|
||||
assert tn(f(n, rz).conjugate(), f(conjugate(n), conjugate(rz)))
|
||||
|
||||
assert hankel1(n, 1 + I).conjugate() == hankel2(conjugate(n), 1 - I)
|
||||
assert hankel1(n, 0).conjugate() == hankel2(conjugate(n), 0)
|
||||
assert hankel1(n, 1).conjugate() == hankel2(conjugate(n), 1)
|
||||
assert hankel1(n, y).conjugate() == hankel2(conjugate(n), y)
|
||||
assert hankel1(n, z).conjugate() == hankel2(conjugate(n), conjugate(z))
|
||||
assert tn(hankel1(n, rz).conjugate(), hankel2(conjugate(n), conjugate(rz)))
|
||||
|
||||
assert hankel2(n, 1 + I).conjugate() == hankel1(conjugate(n), 1 - I)
|
||||
assert hankel2(n, 0).conjugate() == hankel1(conjugate(n), 0)
|
||||
assert hankel2(n, 1).conjugate() == hankel1(conjugate(n), 1)
|
||||
assert hankel2(n, y).conjugate() == hankel1(conjugate(n), y)
|
||||
assert hankel2(n, z).conjugate() == hankel1(conjugate(n), conjugate(z))
|
||||
assert tn(hankel2(n, rz).conjugate(), hankel1(conjugate(n), conjugate(rz)))
|
||||
|
||||
|
||||
def test_branching():
|
||||
assert besselj(polar_lift(k), x) == besselj(k, x)
|
||||
assert besseli(polar_lift(k), x) == besseli(k, x)
|
||||
|
||||
n = Symbol('n', integer=True)
|
||||
assert besselj(n, exp_polar(2*pi*I)*x) == besselj(n, x)
|
||||
assert besselj(n, polar_lift(x)) == besselj(n, x)
|
||||
assert besseli(n, exp_polar(2*pi*I)*x) == besseli(n, x)
|
||||
assert besseli(n, polar_lift(x)) == besseli(n, x)
|
||||
|
||||
def tn(func, s):
|
||||
from sympy.core.random import uniform
|
||||
c = uniform(1, 5)
|
||||
expr = func(s, c*exp_polar(I*pi)) - func(s, c*exp_polar(-I*pi))
|
||||
eps = 1e-15
|
||||
expr2 = func(s + eps, -c + eps*I) - func(s + eps, -c - eps*I)
|
||||
return abs(expr.n() - expr2.n()).n() < 1e-10
|
||||
|
||||
nu = Symbol('nu')
|
||||
assert besselj(nu, exp_polar(2*pi*I)*x) == exp(2*pi*I*nu)*besselj(nu, x)
|
||||
assert besseli(nu, exp_polar(2*pi*I)*x) == exp(2*pi*I*nu)*besseli(nu, x)
|
||||
assert tn(besselj, 2)
|
||||
assert tn(besselj, pi)
|
||||
assert tn(besselj, I)
|
||||
assert tn(besseli, 2)
|
||||
assert tn(besseli, pi)
|
||||
assert tn(besseli, I)
|
||||
|
||||
|
||||
def test_airy_base():
|
||||
z = Symbol('z')
|
||||
x = Symbol('x', real=True)
|
||||
y = Symbol('y', real=True)
|
||||
|
||||
assert conjugate(airyai(z)) == airyai(conjugate(z))
|
||||
assert airyai(x).is_extended_real
|
||||
|
||||
assert airyai(x+I*y).as_real_imag() == (
|
||||
airyai(x - I*y)/2 + airyai(x + I*y)/2,
|
||||
I*(airyai(x - I*y) - airyai(x + I*y))/2)
|
||||
|
||||
|
||||
def test_airyai():
|
||||
z = Symbol('z', real=False)
|
||||
t = Symbol('t', negative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
|
||||
assert isinstance(airyai(z), airyai)
|
||||
|
||||
assert airyai(0) == 3**Rational(1, 3)/(3*gamma(Rational(2, 3)))
|
||||
assert airyai(oo) == 0
|
||||
assert airyai(-oo) == 0
|
||||
|
||||
assert diff(airyai(z), z) == airyaiprime(z)
|
||||
|
||||
assert series(airyai(z), z, 0, 3) == (
|
||||
3**Rational(5, 6)*gamma(Rational(1, 3))/(6*pi) - 3**Rational(1, 6)*z*gamma(Rational(2, 3))/(2*pi) + O(z**3))
|
||||
|
||||
assert airyai(z).rewrite(hyper) == (
|
||||
-3**Rational(2, 3)*z*hyper((), (Rational(4, 3),), z**3/9)/(3*gamma(Rational(1, 3))) +
|
||||
3**Rational(1, 3)*hyper((), (Rational(2, 3),), z**3/9)/(3*gamma(Rational(2, 3))))
|
||||
|
||||
assert isinstance(airyai(z).rewrite(besselj), airyai)
|
||||
assert airyai(t).rewrite(besselj) == (
|
||||
sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) +
|
||||
besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3)
|
||||
assert airyai(z).rewrite(besseli) == (
|
||||
-z*besseli(Rational(1, 3), 2*z**Rational(3, 2)/3)/(3*(z**Rational(3, 2))**Rational(1, 3)) +
|
||||
(z**Rational(3, 2))**Rational(1, 3)*besseli(Rational(-1, 3), 2*z**Rational(3, 2)/3)/3)
|
||||
assert airyai(p).rewrite(besseli) == (
|
||||
sqrt(p)*(besseli(Rational(-1, 3), 2*p**Rational(3, 2)/3) -
|
||||
besseli(Rational(1, 3), 2*p**Rational(3, 2)/3))/3)
|
||||
|
||||
assert expand_func(airyai(2*(3*z**5)**Rational(1, 3))) == (
|
||||
-sqrt(3)*(-1 + (z**5)**Rational(1, 3)/z**Rational(5, 3))*airybi(2*3**Rational(1, 3)*z**Rational(5, 3))/6 +
|
||||
(1 + (z**5)**Rational(1, 3)/z**Rational(5, 3))*airyai(2*3**Rational(1, 3)*z**Rational(5, 3))/2)
|
||||
|
||||
|
||||
def test_airybi():
|
||||
z = Symbol('z', real=False)
|
||||
t = Symbol('t', negative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
|
||||
assert isinstance(airybi(z), airybi)
|
||||
|
||||
assert airybi(0) == 3**Rational(5, 6)/(3*gamma(Rational(2, 3)))
|
||||
assert airybi(oo) is oo
|
||||
assert airybi(-oo) == 0
|
||||
|
||||
assert diff(airybi(z), z) == airybiprime(z)
|
||||
|
||||
assert series(airybi(z), z, 0, 3) == (
|
||||
3**Rational(1, 3)*gamma(Rational(1, 3))/(2*pi) + 3**Rational(2, 3)*z*gamma(Rational(2, 3))/(2*pi) + O(z**3))
|
||||
|
||||
assert airybi(z).rewrite(hyper) == (
|
||||
3**Rational(1, 6)*z*hyper((), (Rational(4, 3),), z**3/9)/gamma(Rational(1, 3)) +
|
||||
3**Rational(5, 6)*hyper((), (Rational(2, 3),), z**3/9)/(3*gamma(Rational(2, 3))))
|
||||
|
||||
assert isinstance(airybi(z).rewrite(besselj), airybi)
|
||||
assert airyai(t).rewrite(besselj) == (
|
||||
sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) +
|
||||
besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3)
|
||||
assert airybi(z).rewrite(besseli) == (
|
||||
sqrt(3)*(z*besseli(Rational(1, 3), 2*z**Rational(3, 2)/3)/(z**Rational(3, 2))**Rational(1, 3) +
|
||||
(z**Rational(3, 2))**Rational(1, 3)*besseli(Rational(-1, 3), 2*z**Rational(3, 2)/3))/3)
|
||||
assert airybi(p).rewrite(besseli) == (
|
||||
sqrt(3)*sqrt(p)*(besseli(Rational(-1, 3), 2*p**Rational(3, 2)/3) +
|
||||
besseli(Rational(1, 3), 2*p**Rational(3, 2)/3))/3)
|
||||
|
||||
assert expand_func(airybi(2*(3*z**5)**Rational(1, 3))) == (
|
||||
sqrt(3)*(1 - (z**5)**Rational(1, 3)/z**Rational(5, 3))*airyai(2*3**Rational(1, 3)*z**Rational(5, 3))/2 +
|
||||
(1 + (z**5)**Rational(1, 3)/z**Rational(5, 3))*airybi(2*3**Rational(1, 3)*z**Rational(5, 3))/2)
|
||||
|
||||
|
||||
def test_airyaiprime():
|
||||
z = Symbol('z', real=False)
|
||||
t = Symbol('t', negative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
|
||||
assert isinstance(airyaiprime(z), airyaiprime)
|
||||
|
||||
assert airyaiprime(0) == -3**Rational(2, 3)/(3*gamma(Rational(1, 3)))
|
||||
assert airyaiprime(oo) == 0
|
||||
|
||||
assert diff(airyaiprime(z), z) == z*airyai(z)
|
||||
|
||||
assert series(airyaiprime(z), z, 0, 3) == (
|
||||
-3**Rational(2, 3)/(3*gamma(Rational(1, 3))) + 3**Rational(1, 3)*z**2/(6*gamma(Rational(2, 3))) + O(z**3))
|
||||
|
||||
assert airyaiprime(z).rewrite(hyper) == (
|
||||
3**Rational(1, 3)*z**2*hyper((), (Rational(5, 3),), z**3/9)/(6*gamma(Rational(2, 3))) -
|
||||
3**Rational(2, 3)*hyper((), (Rational(1, 3),), z**3/9)/(3*gamma(Rational(1, 3))))
|
||||
|
||||
assert isinstance(airyaiprime(z).rewrite(besselj), airyaiprime)
|
||||
assert airyai(t).rewrite(besselj) == (
|
||||
sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) +
|
||||
besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3)
|
||||
assert airyaiprime(z).rewrite(besseli) == (
|
||||
z**2*besseli(Rational(2, 3), 2*z**Rational(3, 2)/3)/(3*(z**Rational(3, 2))**Rational(2, 3)) -
|
||||
(z**Rational(3, 2))**Rational(2, 3)*besseli(Rational(-1, 3), 2*z**Rational(3, 2)/3)/3)
|
||||
assert airyaiprime(p).rewrite(besseli) == (
|
||||
p*(-besseli(Rational(-2, 3), 2*p**Rational(3, 2)/3) + besseli(Rational(2, 3), 2*p**Rational(3, 2)/3))/3)
|
||||
|
||||
assert expand_func(airyaiprime(2*(3*z**5)**Rational(1, 3))) == (
|
||||
sqrt(3)*(z**Rational(5, 3)/(z**5)**Rational(1, 3) - 1)*airybiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/6 +
|
||||
(z**Rational(5, 3)/(z**5)**Rational(1, 3) + 1)*airyaiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/2)
|
||||
|
||||
|
||||
def test_airybiprime():
|
||||
z = Symbol('z', real=False)
|
||||
t = Symbol('t', negative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
|
||||
assert isinstance(airybiprime(z), airybiprime)
|
||||
|
||||
assert airybiprime(0) == 3**Rational(1, 6)/gamma(Rational(1, 3))
|
||||
assert airybiprime(oo) is oo
|
||||
assert airybiprime(-oo) == 0
|
||||
|
||||
assert diff(airybiprime(z), z) == z*airybi(z)
|
||||
|
||||
assert series(airybiprime(z), z, 0, 3) == (
|
||||
3**Rational(1, 6)/gamma(Rational(1, 3)) + 3**Rational(5, 6)*z**2/(6*gamma(Rational(2, 3))) + O(z**3))
|
||||
|
||||
assert airybiprime(z).rewrite(hyper) == (
|
||||
3**Rational(5, 6)*z**2*hyper((), (Rational(5, 3),), z**3/9)/(6*gamma(Rational(2, 3))) +
|
||||
3**Rational(1, 6)*hyper((), (Rational(1, 3),), z**3/9)/gamma(Rational(1, 3)))
|
||||
|
||||
assert isinstance(airybiprime(z).rewrite(besselj), airybiprime)
|
||||
assert airyai(t).rewrite(besselj) == (
|
||||
sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) +
|
||||
besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3)
|
||||
assert airybiprime(z).rewrite(besseli) == (
|
||||
sqrt(3)*(z**2*besseli(Rational(2, 3), 2*z**Rational(3, 2)/3)/(z**Rational(3, 2))**Rational(2, 3) +
|
||||
(z**Rational(3, 2))**Rational(2, 3)*besseli(Rational(-2, 3), 2*z**Rational(3, 2)/3))/3)
|
||||
assert airybiprime(p).rewrite(besseli) == (
|
||||
sqrt(3)*p*(besseli(Rational(-2, 3), 2*p**Rational(3, 2)/3) + besseli(Rational(2, 3), 2*p**Rational(3, 2)/3))/3)
|
||||
|
||||
assert expand_func(airybiprime(2*(3*z**5)**Rational(1, 3))) == (
|
||||
sqrt(3)*(z**Rational(5, 3)/(z**5)**Rational(1, 3) - 1)*airyaiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/2 +
|
||||
(z**Rational(5, 3)/(z**5)**Rational(1, 3) + 1)*airybiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/2)
|
||||
|
||||
|
||||
def test_marcumq():
|
||||
m = Symbol('m')
|
||||
a = Symbol('a')
|
||||
b = Symbol('b')
|
||||
|
||||
assert marcumq(0, 0, 0) == 0
|
||||
assert marcumq(m, 0, b) == uppergamma(m, b**2/2)/gamma(m)
|
||||
assert marcumq(2, 0, 5) == 27*exp(Rational(-25, 2))/2
|
||||
assert marcumq(0, a, 0) == 1 - exp(-a**2/2)
|
||||
assert marcumq(0, pi, 0) == 1 - exp(-pi**2/2)
|
||||
assert marcumq(1, a, a) == S.Half + exp(-a**2)*besseli(0, a**2)/2
|
||||
assert marcumq(2, a, a) == S.Half + exp(-a**2)*besseli(0, a**2)/2 + exp(-a**2)*besseli(1, a**2)
|
||||
|
||||
assert diff(marcumq(1, a, 3), a) == a*(-marcumq(1, a, 3) + marcumq(2, a, 3))
|
||||
assert diff(marcumq(2, 3, b), b) == -b**2*exp(-b**2/2 - Rational(9, 2))*besseli(1, 3*b)/3
|
||||
|
||||
x = Symbol('x')
|
||||
assert marcumq(2, 3, 4).rewrite(Integral, x=x) == \
|
||||
Integral(x**2*exp(-x**2/2 - Rational(9, 2))*besseli(1, 3*x), (x, 4, oo))/3
|
||||
assert eq([marcumq(5, -2, 3).rewrite(Integral).evalf(10)],
|
||||
[0.7905769565])
|
||||
|
||||
k = Symbol('k')
|
||||
assert marcumq(-3, -5, -7).rewrite(Sum, k=k) == \
|
||||
exp(-37)*Sum((Rational(5, 7))**k*besseli(k, 35), (k, 4, oo))
|
||||
assert eq([marcumq(1, 3, 1).rewrite(Sum).evalf(10)],
|
||||
[0.9891705502])
|
||||
|
||||
assert marcumq(1, a, a, evaluate=False).rewrite(besseli) == S.Half + exp(-a**2)*besseli(0, a**2)/2
|
||||
assert marcumq(2, a, a, evaluate=False).rewrite(besseli) == S.Half + exp(-a**2)*besseli(0, a**2)/2 + \
|
||||
exp(-a**2)*besseli(1, a**2)
|
||||
assert marcumq(3, a, a).rewrite(besseli) == (besseli(1, a**2) + besseli(2, a**2))*exp(-a**2) + \
|
||||
S.Half + exp(-a**2)*besseli(0, a**2)/2
|
||||
assert marcumq(5, 8, 8).rewrite(besseli) == exp(-64)*besseli(0, 64)/2 + \
|
||||
(besseli(4, 64) + besseli(3, 64) + besseli(2, 64) + besseli(1, 64))*exp(-64) + S.Half
|
||||
assert marcumq(m, a, a).rewrite(besseli) == marcumq(m, a, a)
|
||||
|
||||
x = Symbol('x', integer=True)
|
||||
assert marcumq(x, a, a).rewrite(besseli) == marcumq(x, a, a)
|
||||
|
||||
|
||||
def test_issue_26134():
|
||||
x = Symbol('x')
|
||||
assert marcumq(2, 3, 4).rewrite(Integral, x=x).dummy_eq(
|
||||
Integral(x**2*exp(-x**2/2 - Rational(9, 2))*besseli(1, 3*x), (x, 4, oo))/3)
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
from sympy.core.function import (diff, expand_func)
|
||||
from sympy.core.numbers import I, Rational, pi
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, symbols)
|
||||
from sympy.functions.combinatorial.numbers import catalan
|
||||
from sympy.functions.elementary.complexes import conjugate
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.special.beta_functions import (beta, betainc, betainc_regularized)
|
||||
from sympy.functions.special.gamma_functions import gamma, polygamma
|
||||
from sympy.functions.special.hyper import hyper
|
||||
from sympy.integrals.integrals import Integral
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_beta():
|
||||
x, y = symbols('x y')
|
||||
t = Dummy('t')
|
||||
|
||||
assert unchanged(beta, x, y)
|
||||
assert unchanged(beta, x, x)
|
||||
|
||||
assert beta(5, -3).is_real == True
|
||||
assert beta(3, y).is_real is None
|
||||
|
||||
assert expand_func(beta(x, y)) == gamma(x)*gamma(y)/gamma(x + y)
|
||||
assert expand_func(beta(x, y) - beta(y, x)) == 0 # Symmetric
|
||||
assert expand_func(beta(x, y)) == expand_func(beta(x, y + 1) + beta(x + 1, y)).simplify()
|
||||
|
||||
assert diff(beta(x, y), x) == beta(x, y)*(polygamma(0, x) - polygamma(0, x + y))
|
||||
assert diff(beta(x, y), y) == beta(x, y)*(polygamma(0, y) - polygamma(0, x + y))
|
||||
|
||||
assert conjugate(beta(x, y)) == beta(conjugate(x), conjugate(y))
|
||||
|
||||
raises(ArgumentIndexError, lambda: beta(x, y).fdiff(3))
|
||||
|
||||
assert beta(x, y).rewrite(gamma) == gamma(x)*gamma(y)/gamma(x + y)
|
||||
assert beta(x).rewrite(gamma) == gamma(x)**2/gamma(2*x)
|
||||
assert beta(x, y).rewrite(Integral).dummy_eq(Integral(t**(x - 1) * (1 - t)**(y - 1), (t, 0, 1)))
|
||||
assert beta(Rational(-19, 10), Rational(-1, 10)) == S.Zero
|
||||
assert beta(Rational(-19, 10), Rational(-9, 10)) == \
|
||||
800*2**(S(4)/5)*sqrt(pi)*gamma(S.One/10)/(171*gamma(-S(7)/5))
|
||||
assert beta(Rational(19, 10), Rational(29, 10)) == 100/(551*catalan(Rational(19, 10)))
|
||||
assert beta(1, 0) == S.ComplexInfinity
|
||||
assert beta(0, 1) == S.ComplexInfinity
|
||||
assert beta(2, 3) == S.One/12
|
||||
assert unchanged(beta, x, x + 1)
|
||||
assert unchanged(beta, x, 1)
|
||||
assert unchanged(beta, 1, y)
|
||||
assert beta(x, x + 1).doit() == 1/(x*(x+1)*catalan(x))
|
||||
assert beta(1, y).doit() == 1/y
|
||||
assert beta(x, 1).doit() == 1/x
|
||||
assert beta(Rational(-19, 10), Rational(-1, 10), evaluate=False).doit() == S.Zero
|
||||
assert beta(2) == beta(2, 2)
|
||||
assert beta(x, evaluate=False) != beta(x, x)
|
||||
assert beta(x, evaluate=False).doit() == beta(x, x)
|
||||
|
||||
|
||||
def test_betainc():
|
||||
a, b, x1, x2 = symbols('a b x1 x2')
|
||||
|
||||
assert unchanged(betainc, a, b, x1, x2)
|
||||
assert unchanged(betainc, a, b, 0, x1)
|
||||
|
||||
assert betainc(1, 2, 0, -5).is_real == True
|
||||
assert betainc(1, 2, 0, x2).is_real is None
|
||||
assert conjugate(betainc(I, 2, 3 - I, 1 + 4*I)) == betainc(-I, 2, 3 + I, 1 - 4*I)
|
||||
|
||||
assert betainc(a, b, 0, 1).rewrite(Integral).dummy_eq(beta(a, b).rewrite(Integral))
|
||||
assert betainc(1, 2, 0, x2).rewrite(hyper) == x2*hyper((1, -1), (2,), x2)
|
||||
|
||||
assert betainc(1, 2, 3, 3).evalf() == 0
|
||||
|
||||
|
||||
def test_betainc_regularized():
|
||||
a, b, x1, x2 = symbols('a b x1 x2')
|
||||
|
||||
assert unchanged(betainc_regularized, a, b, x1, x2)
|
||||
assert unchanged(betainc_regularized, a, b, 0, x1)
|
||||
|
||||
assert betainc_regularized(3, 5, 0, -1).is_real == True
|
||||
assert betainc_regularized(3, 5, 0, x2).is_real is None
|
||||
assert conjugate(betainc_regularized(3*I, 1, 2 + I, 1 + 2*I)) == betainc_regularized(-3*I, 1, 2 - I, 1 - 2*I)
|
||||
|
||||
assert betainc_regularized(a, b, 0, 1).rewrite(Integral) == 1
|
||||
assert betainc_regularized(1, 2, x1, x2).rewrite(hyper) == 2*x2*hyper((1, -1), (2,), x2) - 2*x1*hyper((1, -1), (2,), x1)
|
||||
|
||||
assert betainc_regularized(4, 1, 5, 5).evalf() == 0
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
from sympy.functions import bspline_basis_set, interpolating_spline
|
||||
from sympy.core.numbers import Rational
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.logic.boolalg import And
|
||||
from sympy.sets.sets import Interval
|
||||
from sympy.testing.pytest import slow
|
||||
|
||||
x, y = symbols('x,y')
|
||||
|
||||
|
||||
def test_basic_degree_0():
|
||||
d = 0
|
||||
knots = range(5)
|
||||
splines = bspline_basis_set(d, knots, x)
|
||||
for i in range(len(splines)):
|
||||
assert splines[i] == Piecewise((1, Interval(i, i + 1).contains(x)),
|
||||
(0, True))
|
||||
|
||||
|
||||
def test_basic_degree_1():
|
||||
d = 1
|
||||
knots = range(5)
|
||||
splines = bspline_basis_set(d, knots, x)
|
||||
assert splines[0] == Piecewise((x, Interval(0, 1).contains(x)),
|
||||
(2 - x, Interval(1, 2).contains(x)),
|
||||
(0, True))
|
||||
assert splines[1] == Piecewise((-1 + x, Interval(1, 2).contains(x)),
|
||||
(3 - x, Interval(2, 3).contains(x)),
|
||||
(0, True))
|
||||
assert splines[2] == Piecewise((-2 + x, Interval(2, 3).contains(x)),
|
||||
(4 - x, Interval(3, 4).contains(x)),
|
||||
(0, True))
|
||||
|
||||
|
||||
def test_basic_degree_2():
|
||||
d = 2
|
||||
knots = range(5)
|
||||
splines = bspline_basis_set(d, knots, x)
|
||||
b0 = Piecewise((x**2/2, Interval(0, 1).contains(x)),
|
||||
(Rational(-3, 2) + 3*x - x**2, Interval(1, 2).contains(x)),
|
||||
(Rational(9, 2) - 3*x + x**2/2, Interval(2, 3).contains(x)),
|
||||
(0, True))
|
||||
b1 = Piecewise((S.Half - x + x**2/2, Interval(1, 2).contains(x)),
|
||||
(Rational(-11, 2) + 5*x - x**2, Interval(2, 3).contains(x)),
|
||||
(8 - 4*x + x**2/2, Interval(3, 4).contains(x)),
|
||||
(0, True))
|
||||
assert splines[0] == b0
|
||||
assert splines[1] == b1
|
||||
|
||||
|
||||
def test_basic_degree_3():
|
||||
d = 3
|
||||
knots = range(5)
|
||||
splines = bspline_basis_set(d, knots, x)
|
||||
b0 = Piecewise(
|
||||
(x**3/6, Interval(0, 1).contains(x)),
|
||||
(Rational(2, 3) - 2*x + 2*x**2 - x**3/2, Interval(1, 2).contains(x)),
|
||||
(Rational(-22, 3) + 10*x - 4*x**2 + x**3/2, Interval(2, 3).contains(x)),
|
||||
(Rational(32, 3) - 8*x + 2*x**2 - x**3/6, Interval(3, 4).contains(x)),
|
||||
(0, True)
|
||||
)
|
||||
assert splines[0] == b0
|
||||
|
||||
|
||||
def test_repeated_degree_1():
|
||||
d = 1
|
||||
knots = [0, 0, 1, 2, 2, 3, 4, 4]
|
||||
splines = bspline_basis_set(d, knots, x)
|
||||
assert splines[0] == Piecewise((1 - x, Interval(0, 1).contains(x)),
|
||||
(0, True))
|
||||
assert splines[1] == Piecewise((x, Interval(0, 1).contains(x)),
|
||||
(2 - x, Interval(1, 2).contains(x)),
|
||||
(0, True))
|
||||
assert splines[2] == Piecewise((-1 + x, Interval(1, 2).contains(x)),
|
||||
(0, True))
|
||||
assert splines[3] == Piecewise((3 - x, Interval(2, 3).contains(x)),
|
||||
(0, True))
|
||||
assert splines[4] == Piecewise((-2 + x, Interval(2, 3).contains(x)),
|
||||
(4 - x, Interval(3, 4).contains(x)),
|
||||
(0, True))
|
||||
assert splines[5] == Piecewise((-3 + x, Interval(3, 4).contains(x)),
|
||||
(0, True))
|
||||
|
||||
|
||||
def test_repeated_degree_2():
|
||||
d = 2
|
||||
knots = [0, 0, 1, 2, 2, 3, 4, 4]
|
||||
splines = bspline_basis_set(d, knots, x)
|
||||
|
||||
assert splines[0] == Piecewise(((-3*x**2/2 + 2*x), And(x <= 1, x >= 0)),
|
||||
(x**2/2 - 2*x + 2, And(x <= 2, x >= 1)),
|
||||
(0, True))
|
||||
assert splines[1] == Piecewise((x**2/2, And(x <= 1, x >= 0)),
|
||||
(-3*x**2/2 + 4*x - 2, And(x <= 2, x >= 1)),
|
||||
(0, True))
|
||||
assert splines[2] == Piecewise((x**2 - 2*x + 1, And(x <= 2, x >= 1)),
|
||||
(x**2 - 6*x + 9, And(x <= 3, x >= 2)),
|
||||
(0, True))
|
||||
assert splines[3] == Piecewise((-3*x**2/2 + 8*x - 10, And(x <= 3, x >= 2)),
|
||||
(x**2/2 - 4*x + 8, And(x <= 4, x >= 3)),
|
||||
(0, True))
|
||||
assert splines[4] == Piecewise((x**2/2 - 2*x + 2, And(x <= 3, x >= 2)),
|
||||
(-3*x**2/2 + 10*x - 16, And(x <= 4, x >= 3)),
|
||||
(0, True))
|
||||
|
||||
# Tests for interpolating_spline
|
||||
|
||||
|
||||
def test_10_points_degree_1():
|
||||
d = 1
|
||||
X = [-5, 2, 3, 4, 7, 9, 10, 30, 31, 34]
|
||||
Y = [-10, -2, 2, 4, 7, 6, 20, 45, 19, 25]
|
||||
spline = interpolating_spline(d, x, X, Y)
|
||||
|
||||
assert spline == Piecewise((x*Rational(8, 7) - Rational(30, 7), (x >= -5) & (x <= 2)), (4*x - 10, (x >= 2) & (x <= 3)),
|
||||
(2*x - 4, (x >= 3) & (x <= 4)), (x, (x >= 4) & (x <= 7)),
|
||||
(-x/2 + Rational(21, 2), (x >= 7) & (x <= 9)), (14*x - 120, (x >= 9) & (x <= 10)),
|
||||
(x*Rational(5, 4) + Rational(15, 2), (x >= 10) & (x <= 30)), (-26*x + 825, (x >= 30) & (x <= 31)),
|
||||
(2*x - 43, (x >= 31) & (x <= 34)))
|
||||
|
||||
|
||||
def test_3_points_degree_2():
|
||||
d = 2
|
||||
X = [-3, 10, 19]
|
||||
Y = [3, -4, 30]
|
||||
spline = interpolating_spline(d, x, X, Y)
|
||||
|
||||
assert spline == Piecewise((505*x**2/2574 - x*Rational(4921, 2574) - Rational(1931, 429), (x >= -3) & (x <= 19)))
|
||||
|
||||
|
||||
def test_5_points_degree_2():
|
||||
d = 2
|
||||
X = [-3, 2, 4, 5, 10]
|
||||
Y = [-1, 2, 5, 10, 14]
|
||||
spline = interpolating_spline(d, x, X, Y)
|
||||
|
||||
assert spline == Piecewise((4*x**2/329 + x*Rational(1007, 1645) + Rational(1196, 1645), (x >= -3) & (x <= 3)),
|
||||
(2701*x**2/1645 - x*Rational(15079, 1645) + Rational(5065, 329), (x >= 3) & (x <= Rational(9, 2))),
|
||||
(-1319*x**2/1645 + x*Rational(21101, 1645) - Rational(11216, 329), (x >= Rational(9, 2)) & (x <= 10)))
|
||||
|
||||
|
||||
@slow
|
||||
def test_6_points_degree_3():
|
||||
d = 3
|
||||
X = [-1, 0, 2, 3, 9, 12]
|
||||
Y = [-4, 3, 3, 7, 9, 20]
|
||||
spline = interpolating_spline(d, x, X, Y)
|
||||
|
||||
assert spline == Piecewise((6058*x**3/5301 - 18427*x**2/5301 + x*Rational(12622, 5301) + 3, (x >= -1) & (x <= 2)),
|
||||
(-8327*x**3/5301 + 67883*x**2/5301 - x*Rational(159998, 5301) + Rational(43661, 1767), (x >= 2) & (x <= 3)),
|
||||
(5414*x**3/47709 - 1386*x**2/589 + x*Rational(4267, 279) - Rational(12232, 589), (x >= 3) & (x <= 12)))
|
||||
|
||||
|
||||
def test_issue_19262():
|
||||
Delta = symbols('Delta', positive=True)
|
||||
knots = [i*Delta for i in range(4)]
|
||||
basis = bspline_basis_set(1, knots, x)
|
||||
y = symbols('y', nonnegative=True)
|
||||
basis2 = bspline_basis_set(1, knots, y)
|
||||
assert basis[0].subs(x, y) == basis2[0]
|
||||
assert interpolating_spline(1, x,
|
||||
[Delta*i for i in [1, 2, 4, 7]], [3, 6, 5, 7]
|
||||
) == Piecewise((3*x/Delta, (Delta <= x) & (x <= 2*Delta)),
|
||||
(7 - x/(2*Delta), (x >= 2*Delta) & (x <= 4*Delta)),
|
||||
(Rational(7, 3) + 2*x/(3*Delta), (x >= 4*Delta) & (x <= 7*Delta)))
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
from sympy.core.numbers import (I, nan, oo, pi)
|
||||
from sympy.core.relational import (Eq, Ne)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.elementary.complexes import (adjoint, conjugate, sign, transpose)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.special.delta_functions import (DiracDelta, Heaviside)
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
from sympy.simplify.simplify import signsimp
|
||||
|
||||
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
from sympy.core.expr import unchanged
|
||||
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
|
||||
|
||||
x, y = symbols('x y')
|
||||
i = symbols('t', nonzero=True)
|
||||
j = symbols('j', positive=True)
|
||||
k = symbols('k', negative=True)
|
||||
|
||||
def test_DiracDelta():
|
||||
assert DiracDelta(1) == 0
|
||||
assert DiracDelta(5.1) == 0
|
||||
assert DiracDelta(-pi) == 0
|
||||
assert DiracDelta(5, 7) == 0
|
||||
assert DiracDelta(x, 0) == DiracDelta(x)
|
||||
assert DiracDelta(i) == 0
|
||||
assert DiracDelta(j) == 0
|
||||
assert DiracDelta(k) == 0
|
||||
assert DiracDelta(nan) is nan
|
||||
assert DiracDelta(0).func is DiracDelta
|
||||
assert DiracDelta(x).func is DiracDelta
|
||||
# FIXME: this is generally undefined @ x=0
|
||||
# But then limit(Delta(c)*Heaviside(x),x,-oo)
|
||||
# need's to be implemented.
|
||||
# assert 0*DiracDelta(x) == 0
|
||||
|
||||
assert adjoint(DiracDelta(x)) == DiracDelta(x)
|
||||
assert adjoint(DiracDelta(x - y)) == DiracDelta(x - y)
|
||||
assert conjugate(DiracDelta(x)) == DiracDelta(x)
|
||||
assert conjugate(DiracDelta(x - y)) == DiracDelta(x - y)
|
||||
assert transpose(DiracDelta(x)) == DiracDelta(x)
|
||||
assert transpose(DiracDelta(x - y)) == DiracDelta(x - y)
|
||||
|
||||
assert DiracDelta(x).diff(x) == DiracDelta(x, 1)
|
||||
assert DiracDelta(x, 1).diff(x) == DiracDelta(x, 2)
|
||||
|
||||
assert DiracDelta(x).is_simple(x) is True
|
||||
assert DiracDelta(3*x).is_simple(x) is True
|
||||
assert DiracDelta(x**2).is_simple(x) is False
|
||||
assert DiracDelta(sqrt(x)).is_simple(x) is False
|
||||
assert DiracDelta(x).is_simple(y) is False
|
||||
|
||||
assert DiracDelta(x*y).expand(diracdelta=True, wrt=x) == DiracDelta(x)/abs(y)
|
||||
assert DiracDelta(x*y).expand(diracdelta=True, wrt=y) == DiracDelta(y)/abs(x)
|
||||
assert DiracDelta(x**2*y).expand(diracdelta=True, wrt=x) == DiracDelta(x**2*y)
|
||||
assert DiracDelta(y).expand(diracdelta=True, wrt=x) == DiracDelta(y)
|
||||
assert DiracDelta((x - 1)*(x - 2)*(x - 3)).expand(diracdelta=True, wrt=x) == (
|
||||
DiracDelta(x - 3)/2 + DiracDelta(x - 2) + DiracDelta(x - 1)/2)
|
||||
|
||||
assert DiracDelta(2*x) != DiracDelta(x) # scaling property
|
||||
assert DiracDelta(x) == DiracDelta(-x) # even function
|
||||
assert DiracDelta(-x, 2) == DiracDelta(x, 2)
|
||||
assert DiracDelta(-x, 1) == -DiracDelta(x, 1) # odd deriv is odd
|
||||
assert DiracDelta(-oo*x) == DiracDelta(oo*x)
|
||||
assert DiracDelta(x - y) != DiracDelta(y - x)
|
||||
assert signsimp(DiracDelta(x - y) - DiracDelta(y - x)) == 0
|
||||
|
||||
assert DiracDelta(x*y).expand(diracdelta=True, wrt=x) == DiracDelta(x)/abs(y)
|
||||
assert DiracDelta(x*y).expand(diracdelta=True, wrt=y) == DiracDelta(y)/abs(x)
|
||||
assert DiracDelta(x**2*y).expand(diracdelta=True, wrt=x) == DiracDelta(x**2*y)
|
||||
assert DiracDelta(y).expand(diracdelta=True, wrt=x) == DiracDelta(y)
|
||||
assert DiracDelta((x - 1)*(x - 2)*(x - 3)).expand(diracdelta=True) == (
|
||||
DiracDelta(x - 3)/2 + DiracDelta(x - 2) + DiracDelta(x - 1)/2)
|
||||
|
||||
raises(ArgumentIndexError, lambda: DiracDelta(x).fdiff(2))
|
||||
raises(ValueError, lambda: DiracDelta(x, -1))
|
||||
raises(ValueError, lambda: DiracDelta(I))
|
||||
raises(ValueError, lambda: DiracDelta(2 + 3*I))
|
||||
|
||||
|
||||
def test_heaviside():
|
||||
assert Heaviside(-5) == 0
|
||||
assert Heaviside(1) == 1
|
||||
assert Heaviside(0) == S.Half
|
||||
|
||||
assert Heaviside(0, x) == x
|
||||
assert unchanged(Heaviside,x, nan)
|
||||
assert Heaviside(0, nan) == nan
|
||||
|
||||
h0 = Heaviside(x, 0)
|
||||
h12 = Heaviside(x, S.Half)
|
||||
h1 = Heaviside(x, 1)
|
||||
|
||||
assert h0.args == h0.pargs == (x, 0)
|
||||
assert h1.args == h1.pargs == (x, 1)
|
||||
assert h12.args == (x, S.Half)
|
||||
assert h12.pargs == (x,) # default 1/2 suppressed
|
||||
|
||||
assert adjoint(Heaviside(x)) == Heaviside(x)
|
||||
assert adjoint(Heaviside(x - y)) == Heaviside(x - y)
|
||||
assert conjugate(Heaviside(x)) == Heaviside(x)
|
||||
assert conjugate(Heaviside(x - y)) == Heaviside(x - y)
|
||||
assert transpose(Heaviside(x)) == Heaviside(x)
|
||||
assert transpose(Heaviside(x - y)) == Heaviside(x - y)
|
||||
|
||||
assert Heaviside(x).diff(x) == DiracDelta(x)
|
||||
assert Heaviside(x + I).is_Function is True
|
||||
assert Heaviside(I*x).is_Function is True
|
||||
|
||||
raises(ArgumentIndexError, lambda: Heaviside(x).fdiff(2))
|
||||
raises(ValueError, lambda: Heaviside(I))
|
||||
raises(ValueError, lambda: Heaviside(2 + 3*I))
|
||||
|
||||
|
||||
def test_rewrite():
|
||||
x, y = Symbol('x', real=True), Symbol('y')
|
||||
assert Heaviside(x).rewrite(Piecewise) == (
|
||||
Piecewise((0, x < 0), (Heaviside(0), Eq(x, 0)), (1, True)))
|
||||
assert Heaviside(y).rewrite(Piecewise) == (
|
||||
Piecewise((0, y < 0), (Heaviside(0), Eq(y, 0)), (1, True)))
|
||||
assert Heaviside(x, y).rewrite(Piecewise) == (
|
||||
Piecewise((0, x < 0), (y, Eq(x, 0)), (1, True)))
|
||||
assert Heaviside(x, 0).rewrite(Piecewise) == (
|
||||
Piecewise((0, x <= 0), (1, True)))
|
||||
assert Heaviside(x, 1).rewrite(Piecewise) == (
|
||||
Piecewise((0, x < 0), (1, True)))
|
||||
assert Heaviside(x, nan).rewrite(Piecewise) == (
|
||||
Piecewise((0, x < 0), (nan, Eq(x, 0)), (1, True)))
|
||||
|
||||
assert Heaviside(x).rewrite(sign) == \
|
||||
Heaviside(x, H0=Heaviside(0)).rewrite(sign) == \
|
||||
Piecewise(
|
||||
(sign(x)/2 + S(1)/2, Eq(Heaviside(0), S(1)/2)),
|
||||
(Piecewise(
|
||||
(sign(x)/2 + S(1)/2, Ne(x, 0)), (Heaviside(0), True)), True)
|
||||
)
|
||||
|
||||
assert Heaviside(y).rewrite(sign) == Heaviside(y)
|
||||
assert Heaviside(x, S.Half).rewrite(sign) == (sign(x)+1)/2
|
||||
assert Heaviside(x, y).rewrite(sign) == \
|
||||
Piecewise(
|
||||
(sign(x)/2 + S(1)/2, Eq(y, S(1)/2)),
|
||||
(Piecewise(
|
||||
(sign(x)/2 + S(1)/2, Ne(x, 0)), (y, True)), True)
|
||||
)
|
||||
|
||||
assert DiracDelta(y).rewrite(Piecewise) == Piecewise((DiracDelta(0), Eq(y, 0)), (0, True))
|
||||
assert DiracDelta(y, 1).rewrite(Piecewise) == DiracDelta(y, 1)
|
||||
assert DiracDelta(x - 5).rewrite(Piecewise) == (
|
||||
Piecewise((DiracDelta(0), Eq(x - 5, 0)), (0, True)))
|
||||
|
||||
assert (x*DiracDelta(x - 10)).rewrite(SingularityFunction) == x*SingularityFunction(x, 10, -1)
|
||||
assert 5*x*y*DiracDelta(y, 1).rewrite(SingularityFunction) == 5*x*y*SingularityFunction(y, 0, -2)
|
||||
assert DiracDelta(0).rewrite(SingularityFunction) == SingularityFunction(0, 0, -1)
|
||||
assert DiracDelta(0, 1).rewrite(SingularityFunction) == SingularityFunction(0, 0, -2)
|
||||
|
||||
assert Heaviside(x).rewrite(SingularityFunction) == SingularityFunction(x, 0, 0)
|
||||
assert 5*x*y*Heaviside(y + 1).rewrite(SingularityFunction) == 5*x*y*SingularityFunction(y, -1, 0)
|
||||
assert ((x - 3)**3*Heaviside(x - 3)).rewrite(SingularityFunction) == (x - 3)**3*SingularityFunction(x, 3, 0)
|
||||
assert Heaviside(0).rewrite(SingularityFunction) == S.Half
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
from sympy.core.numbers import (I, Rational, oo, pi, zoo)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, Symbol)
|
||||
from sympy.functions.elementary.hyperbolic import atanh
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (sin, tan)
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.functions.special.hyper import (hyper, meijerg)
|
||||
from sympy.integrals.integrals import Integral
|
||||
from sympy.series.order import O
|
||||
from sympy.functions.special.elliptic_integrals import (elliptic_k as K,
|
||||
elliptic_f as F, elliptic_e as E, elliptic_pi as P)
|
||||
from sympy.core.random import (test_derivative_numerically as td,
|
||||
random_complex_number as randcplx,
|
||||
verify_numerically as tn)
|
||||
from sympy.abc import z, m, n
|
||||
|
||||
i = Symbol('i', integer=True)
|
||||
j = Symbol('k', integer=True, positive=True)
|
||||
t = Dummy('t')
|
||||
|
||||
def test_K():
|
||||
assert K(0) == pi/2
|
||||
assert K(S.Half) == 8*pi**Rational(3, 2)/gamma(Rational(-1, 4))**2
|
||||
assert K(1) is zoo
|
||||
assert K(-1) == gamma(Rational(1, 4))**2/(4*sqrt(2*pi))
|
||||
assert K(oo) == 0
|
||||
assert K(-oo) == 0
|
||||
assert K(I*oo) == 0
|
||||
assert K(-I*oo) == 0
|
||||
assert K(zoo) == 0
|
||||
|
||||
assert K(z).diff(z) == (E(z) - (1 - z)*K(z))/(2*z*(1 - z))
|
||||
assert td(K(z), z)
|
||||
|
||||
zi = Symbol('z', real=False)
|
||||
assert K(zi).conjugate() == K(zi.conjugate())
|
||||
zr = Symbol('z', negative=True)
|
||||
assert K(zr).conjugate() == K(zr)
|
||||
|
||||
assert K(z).rewrite(hyper) == \
|
||||
(pi/2)*hyper((S.Half, S.Half), (S.One,), z)
|
||||
assert tn(K(z), (pi/2)*hyper((S.Half, S.Half), (S.One,), z))
|
||||
assert K(z).rewrite(meijerg) == \
|
||||
meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -z)/2
|
||||
assert tn(K(z), meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -z)/2)
|
||||
|
||||
assert K(z).series(z) == pi/2 + pi*z/8 + 9*pi*z**2/128 + \
|
||||
25*pi*z**3/512 + 1225*pi*z**4/32768 + 3969*pi*z**5/131072 + O(z**6)
|
||||
|
||||
assert K(m).rewrite(Integral).dummy_eq(
|
||||
Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, pi/2)))
|
||||
|
||||
def test_F():
|
||||
assert F(z, 0) == z
|
||||
assert F(0, m) == 0
|
||||
assert F(pi*i/2, m) == i*K(m)
|
||||
assert F(z, oo) == 0
|
||||
assert F(z, -oo) == 0
|
||||
|
||||
assert F(-z, m) == -F(z, m)
|
||||
|
||||
assert F(z, m).diff(z) == 1/sqrt(1 - m*sin(z)**2)
|
||||
assert F(z, m).diff(m) == E(z, m)/(2*m*(1 - m)) - F(z, m)/(2*m) - \
|
||||
sin(2*z)/(4*(1 - m)*sqrt(1 - m*sin(z)**2))
|
||||
r = randcplx()
|
||||
assert td(F(z, r), z)
|
||||
assert td(F(r, m), m)
|
||||
|
||||
mi = Symbol('m', real=False)
|
||||
assert F(z, mi).conjugate() == F(z.conjugate(), mi.conjugate())
|
||||
mr = Symbol('m', negative=True)
|
||||
assert F(z, mr).conjugate() == F(z.conjugate(), mr)
|
||||
|
||||
assert F(z, m).series(z) == \
|
||||
z + z**5*(3*m**2/40 - m/30) + m*z**3/6 + O(z**6)
|
||||
|
||||
assert F(z, m).rewrite(Integral).dummy_eq(
|
||||
Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, z)))
|
||||
|
||||
def test_E():
|
||||
assert E(z, 0) == z
|
||||
assert E(0, m) == 0
|
||||
assert E(i*pi/2, m) == i*E(m)
|
||||
assert E(z, oo) is zoo
|
||||
assert E(z, -oo) is zoo
|
||||
assert E(0) == pi/2
|
||||
assert E(1) == 1
|
||||
assert E(oo) == I*oo
|
||||
assert E(-oo) is oo
|
||||
assert E(zoo) is zoo
|
||||
|
||||
assert E(-z, m) == -E(z, m)
|
||||
|
||||
assert E(z, m).diff(z) == sqrt(1 - m*sin(z)**2)
|
||||
assert E(z, m).diff(m) == (E(z, m) - F(z, m))/(2*m)
|
||||
assert E(z).diff(z) == (E(z) - K(z))/(2*z)
|
||||
r = randcplx()
|
||||
assert td(E(r, m), m)
|
||||
assert td(E(z, r), z)
|
||||
assert td(E(z), z)
|
||||
|
||||
mi = Symbol('m', real=False)
|
||||
assert E(z, mi).conjugate() == E(z.conjugate(), mi.conjugate())
|
||||
assert E(mi).conjugate() == E(mi.conjugate())
|
||||
mr = Symbol('m', negative=True)
|
||||
assert E(z, mr).conjugate() == E(z.conjugate(), mr)
|
||||
assert E(mr).conjugate() == E(mr)
|
||||
|
||||
assert E(z).rewrite(hyper) == (pi/2)*hyper((Rational(-1, 2), S.Half), (S.One,), z)
|
||||
assert tn(E(z), (pi/2)*hyper((Rational(-1, 2), S.Half), (S.One,), z))
|
||||
assert E(z).rewrite(meijerg) == \
|
||||
-meijerg(((S.Half, Rational(3, 2)), []), ((S.Zero,), (S.Zero,)), -z)/4
|
||||
assert tn(E(z), -meijerg(((S.Half, Rational(3, 2)), []), ((S.Zero,), (S.Zero,)), -z)/4)
|
||||
|
||||
assert E(z, m).series(z) == \
|
||||
z + z**5*(-m**2/40 + m/30) - m*z**3/6 + O(z**6)
|
||||
assert E(z).series(z) == pi/2 - pi*z/8 - 3*pi*z**2/128 - \
|
||||
5*pi*z**3/512 - 175*pi*z**4/32768 - 441*pi*z**5/131072 + O(z**6)
|
||||
assert E(4*z/(z+1)).series(z) == \
|
||||
pi/2 - pi*z/2 + pi*z**2/8 - 3*pi*z**3/8 - 15*pi*z**4/128 - 93*pi*z**5/128 + O(z**6)
|
||||
|
||||
assert E(z, m).rewrite(Integral).dummy_eq(
|
||||
Integral(sqrt(1 - m*sin(t)**2), (t, 0, z)))
|
||||
assert E(m).rewrite(Integral).dummy_eq(
|
||||
Integral(sqrt(1 - m*sin(t)**2), (t, 0, pi/2)))
|
||||
|
||||
def test_P():
|
||||
assert P(0, z, m) == F(z, m)
|
||||
assert P(1, z, m) == F(z, m) + \
|
||||
(sqrt(1 - m*sin(z)**2)*tan(z) - E(z, m))/(1 - m)
|
||||
assert P(n, i*pi/2, m) == i*P(n, m)
|
||||
assert P(n, z, 0) == atanh(sqrt(n - 1)*tan(z))/sqrt(n - 1)
|
||||
assert P(n, z, n) == F(z, n) - P(1, z, n) + tan(z)/sqrt(1 - n*sin(z)**2)
|
||||
assert P(oo, z, m) == 0
|
||||
assert P(-oo, z, m) == 0
|
||||
assert P(n, z, oo) == 0
|
||||
assert P(n, z, -oo) == 0
|
||||
assert P(0, m) == K(m)
|
||||
assert P(1, m) is zoo
|
||||
assert P(n, 0) == pi/(2*sqrt(1 - n))
|
||||
assert P(2, 1) is -oo
|
||||
assert P(-1, 1) is oo
|
||||
assert P(n, n) == E(n)/(1 - n)
|
||||
|
||||
assert P(n, -z, m) == -P(n, z, m)
|
||||
|
||||
ni, mi = Symbol('n', real=False), Symbol('m', real=False)
|
||||
assert P(ni, z, mi).conjugate() == \
|
||||
P(ni.conjugate(), z.conjugate(), mi.conjugate())
|
||||
nr, mr = Symbol('n', negative=True), \
|
||||
Symbol('m', negative=True)
|
||||
assert P(nr, z, mr).conjugate() == P(nr, z.conjugate(), mr)
|
||||
assert P(n, m).conjugate() == P(n.conjugate(), m.conjugate())
|
||||
|
||||
assert P(n, z, m).diff(n) == (E(z, m) + (m - n)*F(z, m)/n +
|
||||
(n**2 - m)*P(n, z, m)/n - n*sqrt(1 -
|
||||
m*sin(z)**2)*sin(2*z)/(2*(1 - n*sin(z)**2)))/(2*(m - n)*(n - 1))
|
||||
assert P(n, z, m).diff(z) == 1/(sqrt(1 - m*sin(z)**2)*(1 - n*sin(z)**2))
|
||||
assert P(n, z, m).diff(m) == (E(z, m)/(m - 1) + P(n, z, m) -
|
||||
m*sin(2*z)/(2*(m - 1)*sqrt(1 - m*sin(z)**2)))/(2*(n - m))
|
||||
assert P(n, m).diff(n) == (E(m) + (m - n)*K(m)/n +
|
||||
(n**2 - m)*P(n, m)/n)/(2*(m - n)*(n - 1))
|
||||
assert P(n, m).diff(m) == (E(m)/(m - 1) + P(n, m))/(2*(n - m))
|
||||
|
||||
# These tests fail due to
|
||||
# https://github.com/fredrik-johansson/mpmath/issues/571#issuecomment-777201962
|
||||
# https://github.com/sympy/sympy/issues/20933#issuecomment-777080385
|
||||
#
|
||||
# rx, ry = randcplx(), randcplx()
|
||||
# assert td(P(n, rx, ry), n)
|
||||
# assert td(P(rx, z, ry), z)
|
||||
# assert td(P(rx, ry, m), m)
|
||||
|
||||
assert P(n, z, m).series(z) == z + z**3*(m/6 + n/3) + \
|
||||
z**5*(3*m**2/40 + m*n/10 - m/30 + n**2/5 - n/15) + O(z**6)
|
||||
|
||||
assert P(n, z, m).rewrite(Integral).dummy_eq(
|
||||
Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, z)))
|
||||
assert P(n, m).rewrite(Integral).dummy_eq(
|
||||
Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, pi/2)))
|
||||
+860
@@ -0,0 +1,860 @@
|
||||
from sympy.core.function import (diff, expand, expand_func)
|
||||
from sympy.core import EulerGamma
|
||||
from sympy.core.numbers import (E, Float, I, Rational, nan, oo, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Symbol, symbols, Dummy)
|
||||
from sympy.functions.elementary.complexes import (conjugate, im, polar_lift, re)
|
||||
from sympy.functions.elementary.exponential import (exp, exp_polar, log)
|
||||
from sympy.functions.elementary.hyperbolic import (cosh, sinh)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin, sinc)
|
||||
from sympy.functions.special.error_functions import (Chi, Ci, E1, Ei, Li, Shi, Si, erf, erf2, erf2inv, erfc, erfcinv, erfi, erfinv, expint, fresnelc, fresnels, li)
|
||||
from sympy.functions.special.gamma_functions import (gamma, uppergamma)
|
||||
from sympy.functions.special.hyper import (hyper, meijerg)
|
||||
from sympy.integrals.integrals import (Integral, integrate)
|
||||
from sympy.series.gruntz import gruntz
|
||||
from sympy.series.limits import limit
|
||||
from sympy.series.order import O
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.functions.special.error_functions import _erfs, _eis
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
x, y, z = symbols('x,y,z')
|
||||
w = Symbol("w", real=True)
|
||||
n = Symbol("n", integer=True)
|
||||
t = Dummy('t')
|
||||
|
||||
|
||||
def test_erf():
|
||||
assert erf(nan) is nan
|
||||
|
||||
assert erf(oo) == 1
|
||||
assert erf(-oo) == -1
|
||||
|
||||
assert erf(0) is S.Zero
|
||||
|
||||
assert erf(I*oo) == oo*I
|
||||
assert erf(-I*oo) == -oo*I
|
||||
|
||||
assert erf(-2) == -erf(2)
|
||||
assert erf(-x*y) == -erf(x*y)
|
||||
assert erf(-x - y) == -erf(x + y)
|
||||
|
||||
assert erf(erfinv(x)) == x
|
||||
assert erf(erfcinv(x)) == 1 - x
|
||||
assert erf(erf2inv(0, x)) == x
|
||||
assert erf(erf2inv(0, x, evaluate=False)) == x # To cover code in erf
|
||||
assert erf(erf2inv(0, erf(erfcinv(1 - erf(erfinv(x)))))) == x
|
||||
|
||||
alpha = symbols('alpha', extended_real=True)
|
||||
assert erf(alpha).is_real is True
|
||||
assert erf(alpha).is_finite is True
|
||||
alpha = symbols('alpha', extended_real=False)
|
||||
assert erf(alpha).is_real is None
|
||||
assert erf(alpha).is_finite is None
|
||||
assert erf(alpha).is_zero is None
|
||||
assert erf(alpha).is_positive is None
|
||||
assert erf(alpha).is_negative is None
|
||||
alpha = symbols('alpha', extended_positive=True)
|
||||
assert erf(alpha).is_positive is True
|
||||
alpha = symbols('alpha', extended_negative=True)
|
||||
assert erf(alpha).is_negative is True
|
||||
assert erf(I).is_real is False
|
||||
assert erf(0, evaluate=False).is_real
|
||||
assert erf(0, evaluate=False).is_zero
|
||||
|
||||
assert conjugate(erf(z)) == erf(conjugate(z))
|
||||
|
||||
assert erf(x).as_leading_term(x) == 2*x/sqrt(pi)
|
||||
assert erf(x*y).as_leading_term(y) == 2*x*y/sqrt(pi)
|
||||
assert (erf(x*y)/erf(y)).as_leading_term(y) == x
|
||||
assert erf(1/x).as_leading_term(x) == S.One
|
||||
|
||||
assert erf(z).rewrite('uppergamma') == sqrt(z**2)*(1 - erfc(sqrt(z**2)))/z
|
||||
assert erf(z).rewrite('erfc') == S.One - erfc(z)
|
||||
assert erf(z).rewrite('erfi') == -I*erfi(I*z)
|
||||
assert erf(z).rewrite('fresnels') == (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 - I)/sqrt(pi)))
|
||||
assert erf(z).rewrite('fresnelc') == (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 - I)/sqrt(pi)))
|
||||
assert erf(z).rewrite('hyper') == 2*z*hyper([S.Half], [3*S.Half], -z**2)/sqrt(pi)
|
||||
assert erf(z).rewrite('meijerg') == z*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2)/sqrt(pi)
|
||||
assert erf(z).rewrite('expint') == sqrt(z**2)/z - z*expint(S.Half, z**2)/sqrt(S.Pi)
|
||||
|
||||
assert limit(exp(x)*exp(x**2)*(erf(x + 1/exp(x)) - erf(x)), x, oo) == \
|
||||
2/sqrt(pi)
|
||||
assert limit((1 - erf(z))*exp(z**2)*z, z, oo) == 1/sqrt(pi)
|
||||
assert limit((1 - erf(x))*exp(x**2)*sqrt(pi)*x, x, oo) == 1
|
||||
assert limit(((1 - erf(x))*exp(x**2)*sqrt(pi)*x - 1)*2*x**2, x, oo) == -1
|
||||
assert limit(erf(x)/x, x, 0) == 2/sqrt(pi)
|
||||
assert limit(x**(-4) - sqrt(pi)*erf(x**2) / (2*x**6), x, 0) == S(1)/3
|
||||
|
||||
assert erf(x).as_real_imag() == \
|
||||
(erf(re(x) - I*im(x))/2 + erf(re(x) + I*im(x))/2,
|
||||
-I*(-erf(re(x) - I*im(x)) + erf(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erf(x).as_real_imag(deep=False) == \
|
||||
(erf(re(x) - I*im(x))/2 + erf(re(x) + I*im(x))/2,
|
||||
-I*(-erf(re(x) - I*im(x)) + erf(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erf(w).as_real_imag() == (erf(w), 0)
|
||||
assert erf(w).as_real_imag(deep=False) == (erf(w), 0)
|
||||
# issue 13575
|
||||
assert erf(I).as_real_imag() == (0, -I*erf(I))
|
||||
|
||||
raises(ArgumentIndexError, lambda: erf(x).fdiff(2))
|
||||
|
||||
assert erf(x).inverse() == erfinv
|
||||
|
||||
|
||||
def test_erf_series():
|
||||
assert erf(x).series(x, 0, 7) == 2*x/sqrt(pi) - \
|
||||
2*x**3/3/sqrt(pi) + x**5/5/sqrt(pi) + O(x**7)
|
||||
|
||||
assert erf(x).series(x, oo) == \
|
||||
-exp(-x**2)*(3/(4*x**5) - 1/(2*x**3) + 1/x + O(x**(-6), (x, oo)))/sqrt(pi) + 1
|
||||
assert erf(x**2).series(x, oo, n=8) == \
|
||||
(-1/(2*x**6) + x**(-2) + O(x**(-8), (x, oo)))*exp(-x**4)/sqrt(pi)*-1 + 1
|
||||
assert erf(sqrt(x)).series(x, oo, n=3) == (sqrt(1/x) - (1/x)**(S(3)/2)/2\
|
||||
+ 3*(1/x)**(S(5)/2)/4 + O(x**(-3), (x, oo)))*exp(-x)/sqrt(pi)*-1 + 1
|
||||
|
||||
|
||||
def test_erf_evalf():
|
||||
assert abs( erf(Float(2.0)) - 0.995322265 ) < 1E-8 # XXX
|
||||
|
||||
|
||||
def test__erfs():
|
||||
assert _erfs(z).diff(z) == -2/sqrt(S.Pi) + 2*z*_erfs(z)
|
||||
|
||||
assert _erfs(1/z).series(z) == \
|
||||
z/sqrt(pi) - z**3/(2*sqrt(pi)) + 3*z**5/(4*sqrt(pi)) + O(z**6)
|
||||
|
||||
assert expand(erf(z).rewrite('tractable').diff(z).rewrite('intractable')) \
|
||||
== erf(z).diff(z)
|
||||
assert _erfs(z).rewrite("intractable") == (-erf(z) + 1)*exp(z**2)
|
||||
raises(ArgumentIndexError, lambda: _erfs(z).fdiff(2))
|
||||
|
||||
|
||||
def test_erfc():
|
||||
assert erfc(nan) is nan
|
||||
|
||||
assert erfc(oo) is S.Zero
|
||||
assert erfc(-oo) == 2
|
||||
|
||||
assert erfc(0) == 1
|
||||
|
||||
assert erfc(I*oo) == -oo*I
|
||||
assert erfc(-I*oo) == oo*I
|
||||
|
||||
assert erfc(-x) == S(2) - erfc(x)
|
||||
assert erfc(erfcinv(x)) == x
|
||||
|
||||
alpha = symbols('alpha', extended_real=True)
|
||||
assert erfc(alpha).is_real is True
|
||||
alpha = symbols('alpha', extended_real=False)
|
||||
assert erfc(alpha).is_real is None
|
||||
assert erfc(I).is_real is False
|
||||
assert erfc(0, evaluate=False).is_real
|
||||
assert erfc(0, evaluate=False).is_zero is False
|
||||
|
||||
assert erfc(erfinv(x)) == 1 - x
|
||||
|
||||
assert conjugate(erfc(z)) == erfc(conjugate(z))
|
||||
|
||||
assert erfc(x).as_leading_term(x) is S.One
|
||||
assert erfc(1/x).as_leading_term(x) == S.Zero
|
||||
|
||||
assert erfc(z).rewrite('erf') == 1 - erf(z)
|
||||
assert erfc(z).rewrite('erfi') == 1 + I*erfi(I*z)
|
||||
assert erfc(z).rewrite('fresnels') == 1 - (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 - I)/sqrt(pi)))
|
||||
assert erfc(z).rewrite('fresnelc') == 1 - (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 - I)/sqrt(pi)))
|
||||
assert erfc(z).rewrite('hyper') == 1 - 2*z*hyper([S.Half], [3*S.Half], -z**2)/sqrt(pi)
|
||||
assert erfc(z).rewrite('meijerg') == 1 - z*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2)/sqrt(pi)
|
||||
assert erfc(z).rewrite('uppergamma') == 1 - sqrt(z**2)*(1 - erfc(sqrt(z**2)))/z
|
||||
assert erfc(z).rewrite('expint') == S.One - sqrt(z**2)/z + z*expint(S.Half, z**2)/sqrt(S.Pi)
|
||||
assert erfc(z).rewrite('tractable') == _erfs(z)*exp(-z**2)
|
||||
assert expand_func(erf(x) + erfc(x)) is S.One
|
||||
|
||||
assert erfc(x).as_real_imag() == \
|
||||
(erfc(re(x) - I*im(x))/2 + erfc(re(x) + I*im(x))/2,
|
||||
-I*(-erfc(re(x) - I*im(x)) + erfc(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erfc(x).as_real_imag(deep=False) == \
|
||||
(erfc(re(x) - I*im(x))/2 + erfc(re(x) + I*im(x))/2,
|
||||
-I*(-erfc(re(x) - I*im(x)) + erfc(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erfc(w).as_real_imag() == (erfc(w), 0)
|
||||
assert erfc(w).as_real_imag(deep=False) == (erfc(w), 0)
|
||||
raises(ArgumentIndexError, lambda: erfc(x).fdiff(2))
|
||||
|
||||
assert erfc(x).inverse() == erfcinv
|
||||
|
||||
|
||||
def test_erfc_series():
|
||||
assert erfc(x).series(x, 0, 7) == 1 - 2*x/sqrt(pi) + \
|
||||
2*x**3/3/sqrt(pi) - x**5/5/sqrt(pi) + O(x**7)
|
||||
|
||||
assert erfc(x).series(x, oo) == \
|
||||
(3/(4*x**5) - 1/(2*x**3) + 1/x + O(x**(-6), (x, oo)))*exp(-x**2)/sqrt(pi)
|
||||
|
||||
|
||||
def test_erfc_evalf():
|
||||
assert abs( erfc(Float(2.0)) - 0.00467773 ) < 1E-8 # XXX
|
||||
|
||||
|
||||
def test_erfi():
|
||||
assert erfi(nan) is nan
|
||||
|
||||
assert erfi(oo) is S.Infinity
|
||||
assert erfi(-oo) is S.NegativeInfinity
|
||||
|
||||
assert erfi(0) is S.Zero
|
||||
|
||||
assert erfi(I*oo) == I
|
||||
assert erfi(-I*oo) == -I
|
||||
|
||||
assert erfi(-x) == -erfi(x)
|
||||
|
||||
assert erfi(I*erfinv(x)) == I*x
|
||||
assert erfi(I*erfcinv(x)) == I*(1 - x)
|
||||
assert erfi(I*erf2inv(0, x)) == I*x
|
||||
assert erfi(I*erf2inv(0, x, evaluate=False)) == I*x # To cover code in erfi
|
||||
|
||||
assert erfi(I).is_real is False
|
||||
assert erfi(0, evaluate=False).is_real
|
||||
assert erfi(0, evaluate=False).is_zero
|
||||
|
||||
assert conjugate(erfi(z)) == erfi(conjugate(z))
|
||||
|
||||
assert erfi(x).as_leading_term(x) == 2*x/sqrt(pi)
|
||||
assert erfi(x*y).as_leading_term(y) == 2*x*y/sqrt(pi)
|
||||
assert (erfi(x*y)/erfi(y)).as_leading_term(y) == x
|
||||
assert erfi(1/x).as_leading_term(x) == erfi(1/x)
|
||||
|
||||
assert erfi(z).rewrite('erf') == -I*erf(I*z)
|
||||
assert erfi(z).rewrite('erfc') == I*erfc(I*z) - I
|
||||
assert erfi(z).rewrite('fresnels') == (1 - I)*(fresnelc(z*(1 + I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 + I)/sqrt(pi)))
|
||||
assert erfi(z).rewrite('fresnelc') == (1 - I)*(fresnelc(z*(1 + I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 + I)/sqrt(pi)))
|
||||
assert erfi(z).rewrite('hyper') == 2*z*hyper([S.Half], [3*S.Half], z**2)/sqrt(pi)
|
||||
assert erfi(z).rewrite('meijerg') == z*meijerg([S.Half], [], [0], [Rational(-1, 2)], -z**2)/sqrt(pi)
|
||||
assert erfi(z).rewrite('uppergamma') == (sqrt(-z**2)/z*(uppergamma(S.Half,
|
||||
-z**2)/sqrt(S.Pi) - S.One))
|
||||
assert erfi(z).rewrite('expint') == sqrt(-z**2)/z - z*expint(S.Half, -z**2)/sqrt(S.Pi)
|
||||
assert erfi(z).rewrite('tractable') == -I*(-_erfs(I*z)*exp(z**2) + 1)
|
||||
assert expand_func(erfi(I*z)) == I*erf(z)
|
||||
|
||||
assert erfi(x).as_real_imag() == \
|
||||
(erfi(re(x) - I*im(x))/2 + erfi(re(x) + I*im(x))/2,
|
||||
-I*(-erfi(re(x) - I*im(x)) + erfi(re(x) + I*im(x)))/2)
|
||||
assert erfi(x).as_real_imag(deep=False) == \
|
||||
(erfi(re(x) - I*im(x))/2 + erfi(re(x) + I*im(x))/2,
|
||||
-I*(-erfi(re(x) - I*im(x)) + erfi(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erfi(w).as_real_imag() == (erfi(w), 0)
|
||||
assert erfi(w).as_real_imag(deep=False) == (erfi(w), 0)
|
||||
|
||||
raises(ArgumentIndexError, lambda: erfi(x).fdiff(2))
|
||||
|
||||
|
||||
def test_erfi_series():
|
||||
assert erfi(x).series(x, 0, 7) == 2*x/sqrt(pi) + \
|
||||
2*x**3/3/sqrt(pi) + x**5/5/sqrt(pi) + O(x**7)
|
||||
|
||||
assert erfi(x).series(x, oo) == \
|
||||
(3/(4*x**5) + 1/(2*x**3) + 1/x + O(x**(-6), (x, oo)))*exp(x**2)/sqrt(pi) - I
|
||||
|
||||
|
||||
def test_erfi_evalf():
|
||||
assert abs( erfi(Float(2.0)) - 18.5648024145756 ) < 1E-13 # XXX
|
||||
|
||||
|
||||
def test_erf2():
|
||||
|
||||
assert erf2(0, 0) is S.Zero
|
||||
assert erf2(x, x) is S.Zero
|
||||
assert erf2(nan, 0) is nan
|
||||
|
||||
assert erf2(-oo, y) == erf(y) + 1
|
||||
assert erf2( oo, y) == erf(y) - 1
|
||||
assert erf2( x, oo) == 1 - erf(x)
|
||||
assert erf2( x,-oo) == -1 - erf(x)
|
||||
assert erf2(x, erf2inv(x, y)) == y
|
||||
|
||||
assert erf2(-x, -y) == -erf2(x,y)
|
||||
assert erf2(-x, y) == erf(y) + erf(x)
|
||||
assert erf2( x, -y) == -erf(y) - erf(x)
|
||||
assert erf2(x, y).rewrite('fresnels') == erf(y).rewrite(fresnels)-erf(x).rewrite(fresnels)
|
||||
assert erf2(x, y).rewrite('fresnelc') == erf(y).rewrite(fresnelc)-erf(x).rewrite(fresnelc)
|
||||
assert erf2(x, y).rewrite('hyper') == erf(y).rewrite(hyper)-erf(x).rewrite(hyper)
|
||||
assert erf2(x, y).rewrite('meijerg') == erf(y).rewrite(meijerg)-erf(x).rewrite(meijerg)
|
||||
assert erf2(x, y).rewrite('uppergamma') == erf(y).rewrite(uppergamma) - erf(x).rewrite(uppergamma)
|
||||
assert erf2(x, y).rewrite('expint') == erf(y).rewrite(expint)-erf(x).rewrite(expint)
|
||||
|
||||
assert erf2(I, 0).is_real is False
|
||||
assert erf2(0, 0, evaluate=False).is_real
|
||||
assert erf2(0, 0, evaluate=False).is_zero
|
||||
assert erf2(x, x, evaluate=False).is_zero
|
||||
assert erf2(x, y).is_zero is None
|
||||
|
||||
assert expand_func(erf(x) + erf2(x, y)) == erf(y)
|
||||
|
||||
assert conjugate(erf2(x, y)) == erf2(conjugate(x), conjugate(y))
|
||||
|
||||
assert erf2(x, y).rewrite('erf') == erf(y) - erf(x)
|
||||
assert erf2(x, y).rewrite('erfc') == erfc(x) - erfc(y)
|
||||
assert erf2(x, y).rewrite('erfi') == I*(erfi(I*x) - erfi(I*y))
|
||||
|
||||
assert erf2(x, y).diff(x) == erf2(x, y).fdiff(1)
|
||||
assert erf2(x, y).diff(y) == erf2(x, y).fdiff(2)
|
||||
assert erf2(x, y).diff(x) == -2*exp(-x**2)/sqrt(pi)
|
||||
assert erf2(x, y).diff(y) == 2*exp(-y**2)/sqrt(pi)
|
||||
raises(ArgumentIndexError, lambda: erf2(x, y).fdiff(3))
|
||||
|
||||
assert erf2(x, y).is_extended_real is None
|
||||
xr, yr = symbols('xr yr', extended_real=True)
|
||||
assert erf2(xr, yr).is_extended_real is True
|
||||
|
||||
|
||||
def test_erfinv():
|
||||
assert erfinv(0) is S.Zero
|
||||
assert erfinv(1) is S.Infinity
|
||||
assert erfinv(nan) is S.NaN
|
||||
assert erfinv(-1) is S.NegativeInfinity
|
||||
|
||||
assert erfinv(erf(w)) == w
|
||||
assert erfinv(erf(-w)) == -w
|
||||
|
||||
assert erfinv(x).diff() == sqrt(pi)*exp(erfinv(x)**2)/2
|
||||
raises(ArgumentIndexError, lambda: erfinv(x).fdiff(2))
|
||||
|
||||
assert erfinv(z).rewrite('erfcinv') == erfcinv(1-z)
|
||||
assert erfinv(z).inverse() == erf
|
||||
|
||||
|
||||
def test_erfinv_evalf():
|
||||
assert abs( erfinv(Float(0.2)) - 0.179143454621292 ) < 1E-13
|
||||
|
||||
|
||||
def test_erfcinv():
|
||||
assert erfcinv(1) is S.Zero
|
||||
assert erfcinv(0) is S.Infinity
|
||||
assert erfcinv(0, evaluate=False).is_infinite is True
|
||||
assert erfcinv(2, evaluate=False).is_infinite is True
|
||||
assert erfcinv(nan) is S.NaN
|
||||
|
||||
assert erfcinv(x).diff() == -sqrt(pi)*exp(erfcinv(x)**2)/2
|
||||
raises(ArgumentIndexError, lambda: erfcinv(x).fdiff(2))
|
||||
|
||||
assert erfcinv(z).rewrite('erfinv') == erfinv(1-z)
|
||||
assert erfcinv(z).inverse() == erfc
|
||||
|
||||
|
||||
def test_erf2inv():
|
||||
assert erf2inv(0, 0) is S.Zero
|
||||
assert erf2inv(0, 1) is S.Infinity
|
||||
assert erf2inv(1, 0) is S.One
|
||||
assert erf2inv(0, y) == erfinv(y)
|
||||
assert erf2inv(oo, y) == erfcinv(-y)
|
||||
assert erf2inv(x, 0) == x
|
||||
assert erf2inv(x, oo) == erfinv(x)
|
||||
assert erf2inv(nan, 0) is nan
|
||||
assert erf2inv(0, nan) is nan
|
||||
|
||||
assert erf2inv(x, y).diff(x) == exp(-x**2 + erf2inv(x, y)**2)
|
||||
assert erf2inv(x, y).diff(y) == sqrt(pi)*exp(erf2inv(x, y)**2)/2
|
||||
raises(ArgumentIndexError, lambda: erf2inv(x, y).fdiff(3))
|
||||
|
||||
|
||||
# NOTE we multiply by exp_polar(I*pi) and need this to be on the principal
|
||||
# branch, hence take x in the lower half plane (d=0).
|
||||
|
||||
|
||||
def mytn(expr1, expr2, expr3, x, d=0):
|
||||
from sympy.core.random import verify_numerically, random_complex_number
|
||||
subs = {}
|
||||
for a in expr1.free_symbols:
|
||||
if a != x:
|
||||
subs[a] = random_complex_number()
|
||||
return expr2 == expr3 and verify_numerically(expr1.subs(subs),
|
||||
expr2.subs(subs), x, d=d)
|
||||
|
||||
|
||||
def mytd(expr1, expr2, x):
|
||||
from sympy.core.random import test_derivative_numerically, \
|
||||
random_complex_number
|
||||
subs = {}
|
||||
for a in expr1.free_symbols:
|
||||
if a != x:
|
||||
subs[a] = random_complex_number()
|
||||
return expr1.diff(x) == expr2 and test_derivative_numerically(expr1.subs(subs), x)
|
||||
|
||||
|
||||
def tn_branch(func, s=None):
|
||||
from sympy.core.random import uniform
|
||||
|
||||
def fn(x):
|
||||
if s is None:
|
||||
return func(x)
|
||||
return func(s, x)
|
||||
c = uniform(1, 5)
|
||||
expr = fn(c*exp_polar(I*pi)) - fn(c*exp_polar(-I*pi))
|
||||
eps = 1e-15
|
||||
expr2 = fn(-c + eps*I) - fn(-c - eps*I)
|
||||
return abs(expr.n() - expr2.n()).n() < 1e-10
|
||||
|
||||
|
||||
def test_ei():
|
||||
assert Ei(0) is S.NegativeInfinity
|
||||
assert Ei(oo) is S.Infinity
|
||||
assert Ei(-oo) is S.Zero
|
||||
|
||||
assert tn_branch(Ei)
|
||||
assert mytd(Ei(x), exp(x)/x, x)
|
||||
assert mytn(Ei(x), Ei(x).rewrite(uppergamma),
|
||||
-uppergamma(0, x*polar_lift(-1)) - I*pi, x)
|
||||
assert mytn(Ei(x), Ei(x).rewrite(expint),
|
||||
-expint(1, x*polar_lift(-1)) - I*pi, x)
|
||||
assert Ei(x).rewrite(expint).rewrite(Ei) == Ei(x)
|
||||
assert Ei(x*exp_polar(2*I*pi)) == Ei(x) + 2*I*pi
|
||||
assert Ei(x*exp_polar(-2*I*pi)) == Ei(x) - 2*I*pi
|
||||
|
||||
assert mytn(Ei(x), Ei(x).rewrite(Shi), Chi(x) + Shi(x), x)
|
||||
assert mytn(Ei(x*polar_lift(I)), Ei(x*polar_lift(I)).rewrite(Si),
|
||||
Ci(x) + I*Si(x) + I*pi/2, x)
|
||||
|
||||
assert Ei(log(x)).rewrite(li) == li(x)
|
||||
assert Ei(2*log(x)).rewrite(li) == li(x**2)
|
||||
|
||||
assert gruntz(Ei(x+exp(-x))*exp(-x)*x, x, oo) == 1
|
||||
|
||||
assert Ei(x).series(x) == EulerGamma + log(x) + x + x**2/4 + \
|
||||
x**3/18 + x**4/96 + x**5/600 + O(x**6)
|
||||
assert Ei(x).series(x, 1, 3) == Ei(1) + E*(x - 1) + O((x - 1)**3, (x, 1))
|
||||
assert Ei(x).series(x, oo) == \
|
||||
(120/x**5 + 24/x**4 + 6/x**3 + 2/x**2 + 1/x + 1 + O(x**(-6), (x, oo)))*exp(x)/x
|
||||
assert Ei(x).series(x, -oo) == \
|
||||
(120/x**5 + 24/x**4 + 6/x**3 + 2/x**2 + 1/x + 1 + O(x**(-6), (x, -oo)))*exp(x)/x
|
||||
assert Ei(-x).series(x, oo) == \
|
||||
-((-120/x**5 + 24/x**4 - 6/x**3 + 2/x**2 - 1/x + 1 + O(x**(-6), (x, oo)))*exp(-x)/x)
|
||||
|
||||
assert str(Ei(cos(2)).evalf(n=10)) == '-0.6760647401'
|
||||
raises(ArgumentIndexError, lambda: Ei(x).fdiff(2))
|
||||
|
||||
|
||||
def test_expint():
|
||||
assert mytn(expint(x, y), expint(x, y).rewrite(uppergamma),
|
||||
y**(x - 1)*uppergamma(1 - x, y), x)
|
||||
assert mytd(
|
||||
expint(x, y), -y**(x - 1)*meijerg([], [1, 1], [0, 0, 1 - x], [], y), x)
|
||||
assert mytd(expint(x, y), -expint(x - 1, y), y)
|
||||
assert mytn(expint(1, x), expint(1, x).rewrite(Ei),
|
||||
-Ei(x*polar_lift(-1)) + I*pi, x)
|
||||
|
||||
assert expint(-4, x) == exp(-x)/x + 4*exp(-x)/x**2 + 12*exp(-x)/x**3 \
|
||||
+ 24*exp(-x)/x**4 + 24*exp(-x)/x**5
|
||||
assert expint(Rational(-3, 2), x) == \
|
||||
exp(-x)/x + 3*exp(-x)/(2*x**2) + 3*sqrt(pi)*erfc(sqrt(x))/(4*x**S('5/2'))
|
||||
|
||||
assert tn_branch(expint, 1)
|
||||
assert tn_branch(expint, 2)
|
||||
assert tn_branch(expint, 3)
|
||||
assert tn_branch(expint, 1.7)
|
||||
assert tn_branch(expint, pi)
|
||||
|
||||
assert expint(y, x*exp_polar(2*I*pi)) == \
|
||||
x**(y - 1)*(exp(2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x)
|
||||
assert expint(y, x*exp_polar(-2*I*pi)) == \
|
||||
x**(y - 1)*(exp(-2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x)
|
||||
assert expint(2, x*exp_polar(2*I*pi)) == 2*I*pi*x + expint(2, x)
|
||||
assert expint(2, x*exp_polar(-2*I*pi)) == -2*I*pi*x + expint(2, x)
|
||||
assert expint(1, x).rewrite(Ei).rewrite(expint) == expint(1, x)
|
||||
assert expint(x, y).rewrite(Ei) == expint(x, y)
|
||||
assert expint(x, y).rewrite(Ci) == expint(x, y)
|
||||
|
||||
assert mytn(E1(x), E1(x).rewrite(Shi), Shi(x) - Chi(x), x)
|
||||
assert mytn(E1(polar_lift(I)*x), E1(polar_lift(I)*x).rewrite(Si),
|
||||
-Ci(x) + I*Si(x) - I*pi/2, x)
|
||||
|
||||
assert mytn(expint(2, x), expint(2, x).rewrite(Ei).rewrite(expint),
|
||||
-x*E1(x) + exp(-x), x)
|
||||
assert mytn(expint(3, x), expint(3, x).rewrite(Ei).rewrite(expint),
|
||||
x**2*E1(x)/2 + (1 - x)*exp(-x)/2, x)
|
||||
|
||||
assert expint(Rational(3, 2), z).nseries(z) == \
|
||||
2 + 2*z - z**2/3 + z**3/15 - z**4/84 + z**5/540 - \
|
||||
2*sqrt(pi)*sqrt(z) + O(z**6)
|
||||
|
||||
assert E1(z).series(z) == -EulerGamma - log(z) + z - \
|
||||
z**2/4 + z**3/18 - z**4/96 + z**5/600 + O(z**6)
|
||||
|
||||
assert expint(4, z).series(z) == Rational(1, 3) - z/2 + z**2/2 + \
|
||||
z**3*(log(z)/6 - Rational(11, 36) + EulerGamma/6 - I*pi/6) - z**4/24 + \
|
||||
z**5/240 + O(z**6)
|
||||
|
||||
assert expint(n, x).series(x, oo, n=3) == \
|
||||
(n*(n + 1)/x**2 - n/x + 1 + O(x**(-3), (x, oo)))*exp(-x)/x
|
||||
|
||||
assert expint(z, y).series(z, 0, 2) == exp(-y)/y - z*meijerg(((), (1, 1)),
|
||||
((0, 0, 1), ()), y)/y + O(z**2)
|
||||
raises(ArgumentIndexError, lambda: expint(x, y).fdiff(3))
|
||||
|
||||
neg = Symbol('neg', negative=True)
|
||||
assert Ei(neg).rewrite(Si) == Shi(neg) + Chi(neg) - I*pi
|
||||
|
||||
|
||||
def test__eis():
|
||||
assert _eis(z).diff(z) == -_eis(z) + 1/z
|
||||
|
||||
assert _eis(1/z).series(z) == \
|
||||
z + z**2 + 2*z**3 + 6*z**4 + 24*z**5 + O(z**6)
|
||||
|
||||
assert Ei(z).rewrite('tractable') == exp(z)*_eis(z)
|
||||
assert li(z).rewrite('tractable') == z*_eis(log(z))
|
||||
|
||||
assert _eis(z).rewrite('intractable') == exp(-z)*Ei(z)
|
||||
|
||||
assert expand(li(z).rewrite('tractable').diff(z).rewrite('intractable')) \
|
||||
== li(z).diff(z)
|
||||
|
||||
assert expand(Ei(z).rewrite('tractable').diff(z).rewrite('intractable')) \
|
||||
== Ei(z).diff(z)
|
||||
|
||||
assert _eis(z).series(z, n=3) == EulerGamma + log(z) + z*(-log(z) - \
|
||||
EulerGamma + 1) + z**2*(log(z)/2 - Rational(3, 4) + EulerGamma/2)\
|
||||
+ O(z**3*log(z))
|
||||
raises(ArgumentIndexError, lambda: _eis(z).fdiff(2))
|
||||
|
||||
|
||||
def tn_arg(func):
|
||||
def test(arg, e1, e2):
|
||||
from sympy.core.random import uniform
|
||||
v = uniform(1, 5)
|
||||
v1 = func(arg*x).subs(x, v).n()
|
||||
v2 = func(e1*v + e2*1e-15).n()
|
||||
return abs(v1 - v2).n() < 1e-10
|
||||
return test(exp_polar(I*pi/2), I, 1) and \
|
||||
test(exp_polar(-I*pi/2), -I, 1) and \
|
||||
test(exp_polar(I*pi), -1, I) and \
|
||||
test(exp_polar(-I*pi), -1, -I)
|
||||
|
||||
|
||||
def test_li():
|
||||
z = Symbol("z")
|
||||
zr = Symbol("z", real=True)
|
||||
zp = Symbol("z", positive=True)
|
||||
zn = Symbol("z", negative=True)
|
||||
|
||||
assert li(0) is S.Zero
|
||||
assert li(1) is -oo
|
||||
assert li(oo) is oo
|
||||
|
||||
assert isinstance(li(z), li)
|
||||
assert unchanged(li, -zp)
|
||||
assert unchanged(li, zn)
|
||||
|
||||
assert diff(li(z), z) == 1/log(z)
|
||||
|
||||
assert conjugate(li(z)) == li(conjugate(z))
|
||||
assert conjugate(li(-zr)) == li(-zr)
|
||||
assert unchanged(conjugate, li(-zp))
|
||||
assert unchanged(conjugate, li(zn))
|
||||
|
||||
assert li(z).rewrite(Li) == Li(z) + li(2)
|
||||
assert li(z).rewrite(Ei) == Ei(log(z))
|
||||
assert li(z).rewrite(uppergamma) == (-log(1/log(z))/2 - log(-log(z)) +
|
||||
log(log(z))/2 - expint(1, -log(z)))
|
||||
assert li(z).rewrite(Si) == (-log(I*log(z)) - log(1/log(z))/2 +
|
||||
log(log(z))/2 + Ci(I*log(z)) + Shi(log(z)))
|
||||
assert li(z).rewrite(Ci) == (-log(I*log(z)) - log(1/log(z))/2 +
|
||||
log(log(z))/2 + Ci(I*log(z)) + Shi(log(z)))
|
||||
assert li(z).rewrite(Shi) == (-log(1/log(z))/2 + log(log(z))/2 +
|
||||
Chi(log(z)) - Shi(log(z)))
|
||||
assert li(z).rewrite(Chi) == (-log(1/log(z))/2 + log(log(z))/2 +
|
||||
Chi(log(z)) - Shi(log(z)))
|
||||
assert li(z).rewrite(hyper) ==(log(z)*hyper((1, 1), (2, 2), log(z)) -
|
||||
log(1/log(z))/2 + log(log(z))/2 + EulerGamma)
|
||||
assert li(z).rewrite(meijerg) == (-log(1/log(z))/2 - log(-log(z)) + log(log(z))/2 -
|
||||
meijerg(((), (1,)), ((0, 0), ()), -log(z)))
|
||||
|
||||
assert gruntz(1/li(z), z, oo) is S.Zero
|
||||
assert li(z).series(z) == log(z)**5/600 + log(z)**4/96 + log(z)**3/18 + log(z)**2/4 + \
|
||||
log(z) + log(log(z)) + EulerGamma
|
||||
raises(ArgumentIndexError, lambda: li(z).fdiff(2))
|
||||
|
||||
|
||||
def test_Li():
|
||||
assert Li(2) is S.Zero
|
||||
assert Li(oo) is oo
|
||||
|
||||
assert isinstance(Li(z), Li)
|
||||
|
||||
assert diff(Li(z), z) == 1/log(z)
|
||||
|
||||
assert gruntz(1/Li(z), z, oo) is S.Zero
|
||||
assert Li(z).rewrite(li) == li(z) - li(2)
|
||||
assert Li(z).series(z) == \
|
||||
log(z)**5/600 + log(z)**4/96 + log(z)**3/18 + log(z)**2/4 + log(z) + log(log(z)) - li(2) + EulerGamma
|
||||
raises(ArgumentIndexError, lambda: Li(z).fdiff(2))
|
||||
|
||||
|
||||
def test_si():
|
||||
assert Si(I*x) == I*Shi(x)
|
||||
assert Shi(I*x) == I*Si(x)
|
||||
assert Si(-I*x) == -I*Shi(x)
|
||||
assert Shi(-I*x) == -I*Si(x)
|
||||
assert Si(-x) == -Si(x)
|
||||
assert Shi(-x) == -Shi(x)
|
||||
assert Si(exp_polar(2*pi*I)*x) == Si(x)
|
||||
assert Si(exp_polar(-2*pi*I)*x) == Si(x)
|
||||
assert Shi(exp_polar(2*pi*I)*x) == Shi(x)
|
||||
assert Shi(exp_polar(-2*pi*I)*x) == Shi(x)
|
||||
|
||||
assert Si(oo) == pi/2
|
||||
assert Si(-oo) == -pi/2
|
||||
assert Shi(oo) is oo
|
||||
assert Shi(-oo) is -oo
|
||||
|
||||
assert mytd(Si(x), sin(x)/x, x)
|
||||
assert mytd(Shi(x), sinh(x)/x, x)
|
||||
|
||||
assert mytn(Si(x), Si(x).rewrite(Ei),
|
||||
-I*(-Ei(x*exp_polar(-I*pi/2))/2
|
||||
+ Ei(x*exp_polar(I*pi/2))/2 - I*pi) + pi/2, x)
|
||||
assert mytn(Si(x), Si(x).rewrite(expint),
|
||||
-I*(-expint(1, x*exp_polar(-I*pi/2))/2 +
|
||||
expint(1, x*exp_polar(I*pi/2))/2) + pi/2, x)
|
||||
assert mytn(Shi(x), Shi(x).rewrite(Ei),
|
||||
Ei(x)/2 - Ei(x*exp_polar(I*pi))/2 + I*pi/2, x)
|
||||
assert mytn(Shi(x), Shi(x).rewrite(expint),
|
||||
expint(1, x)/2 - expint(1, x*exp_polar(I*pi))/2 - I*pi/2, x)
|
||||
|
||||
assert tn_arg(Si)
|
||||
assert tn_arg(Shi)
|
||||
|
||||
assert Si(x)._eval_as_leading_term(x, None, 1) == x
|
||||
assert Si(2*x)._eval_as_leading_term(x, None, 1) == 2*x
|
||||
assert Si(sin(x))._eval_as_leading_term(x, None, 1) == x
|
||||
assert Si(x + 1)._eval_as_leading_term(x, None, 1) == Si(1)
|
||||
assert Si(1/x)._eval_as_leading_term(x, None, 1) == \
|
||||
Si(1/x)._eval_as_leading_term(x, None, -1) == Si(1/x)
|
||||
|
||||
assert Si(x).nseries(x, n=8) == \
|
||||
x - x**3/18 + x**5/600 - x**7/35280 + O(x**8)
|
||||
assert Shi(x).nseries(x, n=8) == \
|
||||
x + x**3/18 + x**5/600 + x**7/35280 + O(x**8)
|
||||
assert Si(sin(x)).nseries(x, n=5) == x - 2*x**3/9 + O(x**5)
|
||||
assert Si(x).nseries(x, 1, n=3) == \
|
||||
Si(1) + (x - 1)*sin(1) + (x - 1)**2*(-sin(1)/2 + cos(1)/2) + O((x - 1)**3, (x, 1))
|
||||
|
||||
assert Si(x).series(x, oo) == -sin(x)*(-6/x**4 + x**(-2) + O(x**(-6), (x, oo))) - \
|
||||
cos(x)*(24/x**5 - 2/x**3 + 1/x + O(x**(-6), (x, oo))) + pi/2
|
||||
|
||||
t = Symbol('t', Dummy=True)
|
||||
assert Si(x).rewrite(sinc).dummy_eq(Integral(sinc(t), (t, 0, x)))
|
||||
|
||||
assert limit(Shi(x), x, S.Infinity) == S.Infinity
|
||||
assert limit(Shi(x), x, S.NegativeInfinity) == S.NegativeInfinity
|
||||
|
||||
|
||||
def test_ci():
|
||||
m1 = exp_polar(I*pi)
|
||||
m1_ = exp_polar(-I*pi)
|
||||
pI = exp_polar(I*pi/2)
|
||||
mI = exp_polar(-I*pi/2)
|
||||
|
||||
assert Ci(m1*x) == Ci(x) + I*pi
|
||||
assert Ci(m1_*x) == Ci(x) - I*pi
|
||||
assert Ci(pI*x) == Chi(x) + I*pi/2
|
||||
assert Ci(mI*x) == Chi(x) - I*pi/2
|
||||
assert Chi(m1*x) == Chi(x) + I*pi
|
||||
assert Chi(m1_*x) == Chi(x) - I*pi
|
||||
assert Chi(pI*x) == Ci(x) + I*pi/2
|
||||
assert Chi(mI*x) == Ci(x) - I*pi/2
|
||||
assert Ci(exp_polar(2*I*pi)*x) == Ci(x) + 2*I*pi
|
||||
assert Chi(exp_polar(-2*I*pi)*x) == Chi(x) - 2*I*pi
|
||||
assert Chi(exp_polar(2*I*pi)*x) == Chi(x) + 2*I*pi
|
||||
assert Ci(exp_polar(-2*I*pi)*x) == Ci(x) - 2*I*pi
|
||||
|
||||
assert Ci(oo) is S.Zero
|
||||
assert Ci(-oo) == I*pi
|
||||
assert Chi(oo) is oo
|
||||
assert Chi(-oo) is oo
|
||||
|
||||
assert mytd(Ci(x), cos(x)/x, x)
|
||||
assert mytd(Chi(x), cosh(x)/x, x)
|
||||
|
||||
assert mytn(Ci(x), Ci(x).rewrite(Ei),
|
||||
Ei(x*exp_polar(-I*pi/2))/2 + Ei(x*exp_polar(I*pi/2))/2, x)
|
||||
assert mytn(Chi(x), Chi(x).rewrite(Ei),
|
||||
Ei(x)/2 + Ei(x*exp_polar(I*pi))/2 - I*pi/2, x)
|
||||
|
||||
assert tn_arg(Ci)
|
||||
assert tn_arg(Chi)
|
||||
|
||||
assert Ci(x).nseries(x, n=4) == \
|
||||
EulerGamma + log(x) - x**2/4 + O(x**4)
|
||||
assert Chi(x).nseries(x, n=4) == \
|
||||
EulerGamma + log(x) + x**2/4 + O(x**4)
|
||||
|
||||
assert Ci(x).series(x, oo) == -cos(x)*(-6/x**4 + x**(-2) + O(x**(-6), (x, oo))) + \
|
||||
sin(x)*(24/x**5 - 2/x**3 + 1/x + O(x**(-6), (x, oo)))
|
||||
|
||||
assert Ci(x).series(x, -oo) == -cos(x)*(-6/x**4 + x**(-2) + O(x**(-6), (x, -oo))) + \
|
||||
sin(x)*(24/x**5 - 2/x**3 + 1/x + O(x**(-6), (x, -oo))) + I*pi
|
||||
|
||||
assert limit(log(x) - Ci(2*x), x, 0) == -log(2) - EulerGamma
|
||||
assert Ci(x).rewrite(uppergamma) == -expint(1, x*exp_polar(-I*pi/2))/2 -\
|
||||
expint(1, x*exp_polar(I*pi/2))/2
|
||||
assert Ci(x).rewrite(expint) == -expint(1, x*exp_polar(-I*pi/2))/2 -\
|
||||
expint(1, x*exp_polar(I*pi/2))/2
|
||||
raises(ArgumentIndexError, lambda: Ci(x).fdiff(2))
|
||||
|
||||
|
||||
def test_fresnel():
|
||||
assert fresnels(0) is S.Zero
|
||||
assert fresnels(oo) is S.Half
|
||||
assert fresnels(-oo) == Rational(-1, 2)
|
||||
assert fresnels(I*oo) == -I*S.Half
|
||||
|
||||
assert unchanged(fresnels, z)
|
||||
assert fresnels(-z) == -fresnels(z)
|
||||
assert fresnels(I*z) == -I*fresnels(z)
|
||||
assert fresnels(-I*z) == I*fresnels(z)
|
||||
|
||||
assert conjugate(fresnels(z)) == fresnels(conjugate(z))
|
||||
|
||||
assert fresnels(z).diff(z) == sin(pi*z**2/2)
|
||||
|
||||
assert fresnels(z).rewrite(erf) == (S.One + I)/4 * (
|
||||
erf((S.One + I)/2*sqrt(pi)*z) - I*erf((S.One - I)/2*sqrt(pi)*z))
|
||||
|
||||
assert fresnels(z).rewrite(hyper) == \
|
||||
pi*z**3/6 * hyper([Rational(3, 4)], [Rational(3, 2), Rational(7, 4)], -pi**2*z**4/16)
|
||||
|
||||
assert fresnels(z).series(z, n=15) == \
|
||||
pi*z**3/6 - pi**3*z**7/336 + pi**5*z**11/42240 + O(z**15)
|
||||
|
||||
assert fresnels(w).is_extended_real is True
|
||||
assert fresnels(w).is_finite is True
|
||||
|
||||
assert fresnels(z).is_extended_real is None
|
||||
assert fresnels(z).is_finite is None
|
||||
|
||||
assert fresnels(z).as_real_imag() == (fresnels(re(z) - I*im(z))/2 +
|
||||
fresnels(re(z) + I*im(z))/2,
|
||||
-I*(-fresnels(re(z) - I*im(z)) + fresnels(re(z) + I*im(z)))/2)
|
||||
|
||||
assert fresnels(z).as_real_imag(deep=False) == (fresnels(re(z) - I*im(z))/2 +
|
||||
fresnels(re(z) + I*im(z))/2,
|
||||
-I*(-fresnels(re(z) - I*im(z)) + fresnels(re(z) + I*im(z)))/2)
|
||||
|
||||
assert fresnels(w).as_real_imag() == (fresnels(w), 0)
|
||||
assert fresnels(w).as_real_imag(deep=True) == (fresnels(w), 0)
|
||||
|
||||
assert fresnels(2 + 3*I).as_real_imag() == (
|
||||
fresnels(2 + 3*I)/2 + fresnels(2 - 3*I)/2,
|
||||
-I*(fresnels(2 + 3*I) - fresnels(2 - 3*I))/2
|
||||
)
|
||||
|
||||
assert expand_func(integrate(fresnels(z), z)) == \
|
||||
z*fresnels(z) + cos(pi*z**2/2)/pi
|
||||
|
||||
assert fresnels(z).rewrite(meijerg) == sqrt(2)*pi*z**Rational(9, 4) * \
|
||||
meijerg(((), (1,)), ((Rational(3, 4),),
|
||||
(Rational(1, 4), 0)), -pi**2*z**4/16)/(2*(-z)**Rational(3, 4)*(z**2)**Rational(3, 4))
|
||||
|
||||
assert fresnelc(0) is S.Zero
|
||||
assert fresnelc(oo) == S.Half
|
||||
assert fresnelc(-oo) == Rational(-1, 2)
|
||||
assert fresnelc(I*oo) == I*S.Half
|
||||
|
||||
assert unchanged(fresnelc, z)
|
||||
assert fresnelc(-z) == -fresnelc(z)
|
||||
assert fresnelc(I*z) == I*fresnelc(z)
|
||||
assert fresnelc(-I*z) == -I*fresnelc(z)
|
||||
|
||||
assert conjugate(fresnelc(z)) == fresnelc(conjugate(z))
|
||||
|
||||
assert fresnelc(z).diff(z) == cos(pi*z**2/2)
|
||||
|
||||
assert fresnelc(z).rewrite(erf) == (S.One - I)/4 * (
|
||||
erf((S.One + I)/2*sqrt(pi)*z) + I*erf((S.One - I)/2*sqrt(pi)*z))
|
||||
|
||||
assert fresnelc(z).rewrite(hyper) == \
|
||||
z * hyper([Rational(1, 4)], [S.Half, Rational(5, 4)], -pi**2*z**4/16)
|
||||
|
||||
assert fresnelc(w).is_extended_real is True
|
||||
|
||||
assert fresnelc(z).as_real_imag() == \
|
||||
(fresnelc(re(z) - I*im(z))/2 + fresnelc(re(z) + I*im(z))/2,
|
||||
-I*(-fresnelc(re(z) - I*im(z)) + fresnelc(re(z) + I*im(z)))/2)
|
||||
|
||||
assert fresnelc(z).as_real_imag(deep=False) == \
|
||||
(fresnelc(re(z) - I*im(z))/2 + fresnelc(re(z) + I*im(z))/2,
|
||||
-I*(-fresnelc(re(z) - I*im(z)) + fresnelc(re(z) + I*im(z)))/2)
|
||||
|
||||
assert fresnelc(2 + 3*I).as_real_imag() == (
|
||||
fresnelc(2 - 3*I)/2 + fresnelc(2 + 3*I)/2,
|
||||
-I*(fresnelc(2 + 3*I) - fresnelc(2 - 3*I))/2
|
||||
)
|
||||
|
||||
assert expand_func(integrate(fresnelc(z), z)) == \
|
||||
z*fresnelc(z) - sin(pi*z**2/2)/pi
|
||||
|
||||
assert fresnelc(z).rewrite(meijerg) == sqrt(2)*pi*z**Rational(3, 4) * \
|
||||
meijerg(((), (1,)), ((Rational(1, 4),),
|
||||
(Rational(3, 4), 0)), -pi**2*z**4/16)/(2*(-z)**Rational(1, 4)*(z**2)**Rational(1, 4))
|
||||
|
||||
from sympy.core.random import verify_numerically
|
||||
|
||||
verify_numerically(re(fresnels(z)), fresnels(z).as_real_imag()[0], z)
|
||||
verify_numerically(im(fresnels(z)), fresnels(z).as_real_imag()[1], z)
|
||||
verify_numerically(fresnels(z), fresnels(z).rewrite(hyper), z)
|
||||
verify_numerically(fresnels(z), fresnels(z).rewrite(meijerg), z)
|
||||
|
||||
verify_numerically(re(fresnelc(z)), fresnelc(z).as_real_imag()[0], z)
|
||||
verify_numerically(im(fresnelc(z)), fresnelc(z).as_real_imag()[1], z)
|
||||
verify_numerically(fresnelc(z), fresnelc(z).rewrite(hyper), z)
|
||||
verify_numerically(fresnelc(z), fresnelc(z).rewrite(meijerg), z)
|
||||
|
||||
raises(ArgumentIndexError, lambda: fresnels(z).fdiff(2))
|
||||
raises(ArgumentIndexError, lambda: fresnelc(z).fdiff(2))
|
||||
|
||||
assert fresnels(x).taylor_term(-1, x) is S.Zero
|
||||
assert fresnelc(x).taylor_term(-1, x) is S.Zero
|
||||
assert fresnelc(x).taylor_term(1, x) == -pi**2*x**5/40
|
||||
|
||||
|
||||
def test_fresnel_series():
|
||||
assert fresnelc(z).series(z, n=15) == \
|
||||
z - pi**2*z**5/40 + pi**4*z**9/3456 - pi**6*z**13/599040 + O(z**15)
|
||||
|
||||
# issues 6510, 10102
|
||||
fs = (S.Half - sin(pi*z**2/2)/(pi**2*z**3)
|
||||
+ (-1/(pi*z) + 3/(pi**3*z**5))*cos(pi*z**2/2))
|
||||
fc = (S.Half - cos(pi*z**2/2)/(pi**2*z**3)
|
||||
+ (1/(pi*z) - 3/(pi**3*z**5))*sin(pi*z**2/2))
|
||||
assert fresnels(z).series(z, oo) == fs + O(z**(-6), (z, oo))
|
||||
assert fresnelc(z).series(z, oo) == fc + O(z**(-6), (z, oo))
|
||||
assert (fresnels(z).series(z, -oo) + fs.subs(z, -z)).expand().is_Order
|
||||
assert (fresnelc(z).series(z, -oo) + fc.subs(z, -z)).expand().is_Order
|
||||
assert (fresnels(1/z).series(z) - fs.subs(z, 1/z)).expand().is_Order
|
||||
assert (fresnelc(1/z).series(z) - fc.subs(z, 1/z)).expand().is_Order
|
||||
assert ((2*fresnels(3*z)).series(z, oo) - 2*fs.subs(z, 3*z)).expand().is_Order
|
||||
assert ((3*fresnelc(2*z)).series(z, oo) - 3*fc.subs(z, 2*z)).expand().is_Order
|
||||
|
||||
|
||||
def test_integral_rewrites(): #issues 26134, 26144, 26306
|
||||
assert expint(n, x).rewrite(Integral).dummy_eq(Integral(t**-n * exp(-t*x), (t, 1, oo)))
|
||||
assert Si(x).rewrite(Integral).dummy_eq(Integral(sinc(t), (t, 0, x)))
|
||||
assert Ci(x).rewrite(Integral).dummy_eq(log(x) - Integral((1 - cos(t))/t, (t, 0, x)) + EulerGamma)
|
||||
assert fresnels(x).rewrite(Integral).dummy_eq(Integral(sin(pi*t**2/2), (t, 0, x)))
|
||||
assert fresnelc(x).rewrite(Integral).dummy_eq(Integral(cos(pi*t**2/2), (t, 0, x)))
|
||||
assert Ei(x).rewrite(Integral).dummy_eq(Integral(exp(t)/t, (t, -oo, x)))
|
||||
assert fresnels(x).diff(x) == fresnels(x).rewrite(Integral).diff(x)
|
||||
assert fresnelc(x).diff(x) == fresnelc(x).rewrite(Integral).diff(x)
|
||||
+741
@@ -0,0 +1,741 @@
|
||||
from sympy.core.function import expand_func, Subs
|
||||
from sympy.core import EulerGamma
|
||||
from sympy.core.numbers import (I, Rational, nan, oo, pi, zoo)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, Symbol)
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.combinatorial.numbers import harmonic
|
||||
from sympy.functions.elementary.complexes import (Abs, conjugate, im, re)
|
||||
from sympy.functions.elementary.exponential import (exp, exp_polar, log)
|
||||
from sympy.functions.elementary.hyperbolic import tanh
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin, atan)
|
||||
from sympy.functions.special.error_functions import (Ei, erf, erfc)
|
||||
from sympy.functions.special.gamma_functions import (digamma, gamma, loggamma, lowergamma, multigamma, polygamma, trigamma, uppergamma)
|
||||
from sympy.functions.special.zeta_functions import zeta
|
||||
from sympy.series.order import O
|
||||
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.random import (test_derivative_numerically as td,
|
||||
random_complex_number as randcplx,
|
||||
verify_numerically as tn)
|
||||
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
n = Symbol('n', integer=True)
|
||||
w = Symbol('w', real=True)
|
||||
|
||||
def test_gamma():
|
||||
assert gamma(nan) is nan
|
||||
assert gamma(oo) is oo
|
||||
|
||||
assert gamma(-100) is zoo
|
||||
assert gamma(0) is zoo
|
||||
assert gamma(-100.0) is zoo
|
||||
|
||||
assert gamma(1) == 1
|
||||
assert gamma(2) == 1
|
||||
assert gamma(3) == 2
|
||||
|
||||
assert gamma(102) == factorial(101)
|
||||
|
||||
assert gamma(S.Half) == sqrt(pi)
|
||||
|
||||
assert gamma(Rational(3, 2)) == sqrt(pi)*S.Half
|
||||
assert gamma(Rational(5, 2)) == sqrt(pi)*Rational(3, 4)
|
||||
assert gamma(Rational(7, 2)) == sqrt(pi)*Rational(15, 8)
|
||||
|
||||
assert gamma(Rational(-1, 2)) == -2*sqrt(pi)
|
||||
assert gamma(Rational(-3, 2)) == sqrt(pi)*Rational(4, 3)
|
||||
assert gamma(Rational(-5, 2)) == sqrt(pi)*Rational(-8, 15)
|
||||
|
||||
assert gamma(Rational(-15, 2)) == sqrt(pi)*Rational(256, 2027025)
|
||||
|
||||
assert gamma(Rational(
|
||||
-11, 8)).expand(func=True) == Rational(64, 33)*gamma(Rational(5, 8))
|
||||
assert gamma(Rational(
|
||||
-10, 3)).expand(func=True) == Rational(81, 280)*gamma(Rational(2, 3))
|
||||
assert gamma(Rational(
|
||||
14, 3)).expand(func=True) == Rational(880, 81)*gamma(Rational(2, 3))
|
||||
assert gamma(Rational(
|
||||
17, 7)).expand(func=True) == Rational(30, 49)*gamma(Rational(3, 7))
|
||||
assert gamma(Rational(
|
||||
19, 8)).expand(func=True) == Rational(33, 64)*gamma(Rational(3, 8))
|
||||
|
||||
assert gamma(x).diff(x) == gamma(x)*polygamma(0, x)
|
||||
|
||||
assert gamma(x - 1).expand(func=True) == gamma(x)/(x - 1)
|
||||
assert gamma(x + 2).expand(func=True, mul=False) == x*(x + 1)*gamma(x)
|
||||
|
||||
assert conjugate(gamma(x)) == gamma(conjugate(x))
|
||||
|
||||
assert expand_func(gamma(x + Rational(3, 2))) == \
|
||||
(x + S.Half)*gamma(x + S.Half)
|
||||
|
||||
assert expand_func(gamma(x - S.Half)) == \
|
||||
gamma(S.Half + x)/(x - S.Half)
|
||||
|
||||
# Test a bug:
|
||||
assert expand_func(gamma(x + Rational(3, 4))) == gamma(x + Rational(3, 4))
|
||||
|
||||
# XXX: Not sure about these tests. I can fix them by defining e.g.
|
||||
# exp_polar.is_integer but I'm not sure if that makes sense.
|
||||
assert gamma(3*exp_polar(I*pi)/4).is_nonnegative is False
|
||||
assert gamma(3*exp_polar(I*pi)/4).is_extended_nonpositive is True
|
||||
|
||||
y = Symbol('y', nonpositive=True, integer=True)
|
||||
assert gamma(y).is_real == False
|
||||
y = Symbol('y', positive=True, noninteger=True)
|
||||
assert gamma(y).is_real == True
|
||||
|
||||
assert gamma(-1.0, evaluate=False).is_real == False
|
||||
assert gamma(0, evaluate=False).is_real == False
|
||||
assert gamma(-2, evaluate=False).is_real == False
|
||||
|
||||
|
||||
def test_gamma_rewrite():
|
||||
assert gamma(n).rewrite(factorial) == factorial(n - 1)
|
||||
|
||||
|
||||
def test_gamma_series():
|
||||
assert gamma(x + 1).series(x, 0, 3) == \
|
||||
1 - EulerGamma*x + x**2*(EulerGamma**2/2 + pi**2/12) + O(x**3)
|
||||
assert gamma(x).series(x, -1, 3) == \
|
||||
-1/(x + 1) + EulerGamma - 1 + (x + 1)*(-1 - pi**2/12 - EulerGamma**2/2 + \
|
||||
EulerGamma) + (x + 1)**2*(-1 - pi**2/12 - EulerGamma**2/2 + EulerGamma**3/6 - \
|
||||
polygamma(2, 1)/6 + EulerGamma*pi**2/12 + EulerGamma) + O((x + 1)**3, (x, -1))
|
||||
|
||||
|
||||
def tn_branch(s, func):
|
||||
from sympy.core.random import uniform
|
||||
c = uniform(1, 5)
|
||||
expr = func(s, c*exp_polar(I*pi)) - func(s, c*exp_polar(-I*pi))
|
||||
eps = 1e-15
|
||||
expr2 = func(s + eps, -c + eps*I) - func(s + eps, -c - eps*I)
|
||||
return abs(expr.n() - expr2.n()).n() < 1e-10
|
||||
|
||||
|
||||
def test_lowergamma():
|
||||
from sympy.functions.special.error_functions import expint
|
||||
from sympy.functions.special.hyper import meijerg
|
||||
assert lowergamma(x, 0) == 0
|
||||
assert lowergamma(x, y).diff(y) == y**(x - 1)*exp(-y)
|
||||
assert td(lowergamma(randcplx(), y), y)
|
||||
assert td(lowergamma(x, randcplx()), x)
|
||||
assert lowergamma(x, y).diff(x) == \
|
||||
gamma(x)*digamma(x) - uppergamma(x, y)*log(y) \
|
||||
- meijerg([], [1, 1], [0, 0, x], [], y)
|
||||
|
||||
assert lowergamma(S.Half, x) == sqrt(pi)*erf(sqrt(x))
|
||||
assert not lowergamma(S.Half - 3, x).has(lowergamma)
|
||||
assert not lowergamma(S.Half + 3, x).has(lowergamma)
|
||||
assert lowergamma(S.Half, x, evaluate=False).has(lowergamma)
|
||||
assert tn(lowergamma(S.Half + 3, x, evaluate=False),
|
||||
lowergamma(S.Half + 3, x), x)
|
||||
assert tn(lowergamma(S.Half - 3, x, evaluate=False),
|
||||
lowergamma(S.Half - 3, x), x)
|
||||
|
||||
assert tn_branch(-3, lowergamma)
|
||||
assert tn_branch(-4, lowergamma)
|
||||
assert tn_branch(Rational(1, 3), lowergamma)
|
||||
assert tn_branch(pi, lowergamma)
|
||||
assert lowergamma(3, exp_polar(4*pi*I)*x) == lowergamma(3, x)
|
||||
assert lowergamma(y, exp_polar(5*pi*I)*x) == \
|
||||
exp(4*I*pi*y)*lowergamma(y, x*exp_polar(pi*I))
|
||||
assert lowergamma(-2, exp_polar(5*pi*I)*x) == \
|
||||
lowergamma(-2, x*exp_polar(I*pi)) + 2*pi*I
|
||||
|
||||
assert conjugate(lowergamma(x, y)) == lowergamma(conjugate(x), conjugate(y))
|
||||
assert conjugate(lowergamma(x, 0)) == 0
|
||||
assert unchanged(conjugate, lowergamma(x, -oo))
|
||||
|
||||
assert lowergamma(0, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(S(1)/3, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(1, x, evaluate=False)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(x, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(x + 1, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(1/x, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(0, x + 1)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(S(1)/3, x + 1)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(1, x + 1, evaluate=False)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(x, x + 1)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(x + 1, x + 1)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(1/x, x + 1)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(0, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(S(1)/3, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(1, 1/x, evaluate=False)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(x, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(x + 1, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(1/x, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
|
||||
assert lowergamma(x, 2).series(x, oo, 3) == \
|
||||
2**x*(1 + 2/(x + 1))*exp(-2)/x + O(exp(x*log(2))/x**3, (x, oo))
|
||||
|
||||
assert lowergamma(
|
||||
x, y).rewrite(expint) == -y**x*expint(-x + 1, y) + gamma(x)
|
||||
k = Symbol('k', integer=True)
|
||||
assert lowergamma(
|
||||
k, y).rewrite(expint) == -y**k*expint(-k + 1, y) + gamma(k)
|
||||
k = Symbol('k', integer=True, positive=False)
|
||||
assert lowergamma(k, y).rewrite(expint) == lowergamma(k, y)
|
||||
assert lowergamma(x, y).rewrite(uppergamma) == gamma(x) - uppergamma(x, y)
|
||||
|
||||
assert lowergamma(70, 6) == factorial(69) - 69035724522603011058660187038367026272747334489677105069435923032634389419656200387949342530805432320 * exp(-6)
|
||||
assert (lowergamma(S(77) / 2, 6) - lowergamma(S(77) / 2, 6, evaluate=False)).evalf() < 1e-16
|
||||
assert (lowergamma(-S(77) / 2, 6) - lowergamma(-S(77) / 2, 6, evaluate=False)).evalf() < 1e-16
|
||||
|
||||
|
||||
def test_uppergamma():
|
||||
from sympy.functions.special.error_functions import expint
|
||||
from sympy.functions.special.hyper import meijerg
|
||||
assert uppergamma(4, 0) == 6
|
||||
assert uppergamma(x, y).diff(y) == -y**(x - 1)*exp(-y)
|
||||
assert td(uppergamma(randcplx(), y), y)
|
||||
assert uppergamma(x, y).diff(x) == \
|
||||
uppergamma(x, y)*log(y) + meijerg([], [1, 1], [0, 0, x], [], y)
|
||||
assert td(uppergamma(x, randcplx()), x)
|
||||
|
||||
p = Symbol('p', positive=True)
|
||||
assert uppergamma(0, p) == -Ei(-p)
|
||||
assert uppergamma(p, 0) == gamma(p)
|
||||
assert uppergamma(S.Half, x) == sqrt(pi)*erfc(sqrt(x))
|
||||
assert not uppergamma(S.Half - 3, x).has(uppergamma)
|
||||
assert not uppergamma(S.Half + 3, x).has(uppergamma)
|
||||
assert uppergamma(S.Half, x, evaluate=False).has(uppergamma)
|
||||
assert tn(uppergamma(S.Half + 3, x, evaluate=False),
|
||||
uppergamma(S.Half + 3, x), x)
|
||||
assert tn(uppergamma(S.Half - 3, x, evaluate=False),
|
||||
uppergamma(S.Half - 3, x), x)
|
||||
|
||||
assert unchanged(uppergamma, x, -oo)
|
||||
assert unchanged(uppergamma, x, 0)
|
||||
|
||||
assert tn_branch(-3, uppergamma)
|
||||
assert tn_branch(-4, uppergamma)
|
||||
assert tn_branch(Rational(1, 3), uppergamma)
|
||||
assert tn_branch(pi, uppergamma)
|
||||
assert uppergamma(3, exp_polar(4*pi*I)*x) == uppergamma(3, x)
|
||||
assert uppergamma(y, exp_polar(5*pi*I)*x) == \
|
||||
exp(4*I*pi*y)*uppergamma(y, x*exp_polar(pi*I)) + \
|
||||
gamma(y)*(1 - exp(4*pi*I*y))
|
||||
assert uppergamma(-2, exp_polar(5*pi*I)*x) == \
|
||||
uppergamma(-2, x*exp_polar(I*pi)) - 2*pi*I
|
||||
|
||||
assert uppergamma(-2, x) == expint(3, x)/x**2
|
||||
|
||||
assert conjugate(uppergamma(x, y)) == uppergamma(conjugate(x), conjugate(y))
|
||||
assert unchanged(conjugate, uppergamma(x, -oo))
|
||||
|
||||
assert uppergamma(x, y).rewrite(expint) == y**x*expint(-x + 1, y)
|
||||
assert uppergamma(x, y).rewrite(lowergamma) == gamma(x) - lowergamma(x, y)
|
||||
|
||||
assert uppergamma(70, 6) == 69035724522603011058660187038367026272747334489677105069435923032634389419656200387949342530805432320*exp(-6)
|
||||
assert (uppergamma(S(77) / 2, 6) - uppergamma(S(77) / 2, 6, evaluate=False)).evalf() < 1e-16
|
||||
assert (uppergamma(-S(77) / 2, 6) - uppergamma(-S(77) / 2, 6, evaluate=False)).evalf() < 1e-16
|
||||
|
||||
|
||||
def test_polygamma():
|
||||
assert polygamma(n, nan) is nan
|
||||
|
||||
assert polygamma(0, oo) is oo
|
||||
assert polygamma(0, -oo) is oo
|
||||
assert polygamma(0, I*oo) is oo
|
||||
assert polygamma(0, -I*oo) is oo
|
||||
assert polygamma(1, oo) == 0
|
||||
assert polygamma(5, oo) == 0
|
||||
|
||||
assert polygamma(0, -9) is zoo
|
||||
|
||||
assert polygamma(0, -9) is zoo
|
||||
assert polygamma(0, -1) is zoo
|
||||
assert polygamma(Rational(3, 2), -1) is zoo
|
||||
|
||||
assert polygamma(0, 0) is zoo
|
||||
|
||||
assert polygamma(0, 1) == -EulerGamma
|
||||
assert polygamma(0, 7) == Rational(49, 20) - EulerGamma
|
||||
|
||||
assert polygamma(1, 1) == pi**2/6
|
||||
assert polygamma(1, 2) == pi**2/6 - 1
|
||||
assert polygamma(1, 3) == pi**2/6 - Rational(5, 4)
|
||||
assert polygamma(3, 1) == pi**4 / 15
|
||||
assert polygamma(3, 5) == 6*(Rational(-22369, 20736) + pi**4/90)
|
||||
assert polygamma(5, 1) == 8 * pi**6 / 63
|
||||
|
||||
assert polygamma(1, S.Half) == pi**2 / 2
|
||||
assert polygamma(2, S.Half) == -14*zeta(3)
|
||||
assert polygamma(11, S.Half) == 176896*pi**12
|
||||
|
||||
def t(m, n):
|
||||
x = S(m)/n
|
||||
r = polygamma(0, x)
|
||||
if r.has(polygamma):
|
||||
return False
|
||||
return abs(polygamma(0, x.n()).n() - r.n()).n() < 1e-10
|
||||
assert t(1, 2)
|
||||
assert t(3, 2)
|
||||
assert t(-1, 2)
|
||||
assert t(1, 4)
|
||||
assert t(-3, 4)
|
||||
assert t(1, 3)
|
||||
assert t(4, 3)
|
||||
assert t(3, 4)
|
||||
assert t(2, 3)
|
||||
assert t(123, 5)
|
||||
|
||||
assert polygamma(0, x).rewrite(zeta) == polygamma(0, x)
|
||||
assert polygamma(1, x).rewrite(zeta) == zeta(2, x)
|
||||
assert polygamma(2, x).rewrite(zeta) == -2*zeta(3, x)
|
||||
assert polygamma(I, 2).rewrite(zeta) == polygamma(I, 2)
|
||||
n1 = Symbol('n1')
|
||||
n2 = Symbol('n2', real=True)
|
||||
n3 = Symbol('n3', integer=True)
|
||||
n4 = Symbol('n4', positive=True)
|
||||
n5 = Symbol('n5', positive=True, integer=True)
|
||||
assert polygamma(n1, x).rewrite(zeta) == polygamma(n1, x)
|
||||
assert polygamma(n2, x).rewrite(zeta) == polygamma(n2, x)
|
||||
assert polygamma(n3, x).rewrite(zeta) == polygamma(n3, x)
|
||||
assert polygamma(n4, x).rewrite(zeta) == polygamma(n4, x)
|
||||
assert polygamma(n5, x).rewrite(zeta) == (-1)**(n5 + 1) * factorial(n5) * zeta(n5 + 1, x)
|
||||
|
||||
assert polygamma(3, 7*x).diff(x) == 7*polygamma(4, 7*x)
|
||||
|
||||
assert polygamma(0, x).rewrite(harmonic) == harmonic(x - 1) - EulerGamma
|
||||
assert polygamma(2, x).rewrite(harmonic) == 2*harmonic(x - 1, 3) - 2*zeta(3)
|
||||
ni = Symbol("n", integer=True)
|
||||
assert polygamma(ni, x).rewrite(harmonic) == (-1)**(ni + 1)*(-harmonic(x - 1, ni + 1)
|
||||
+ zeta(ni + 1))*factorial(ni)
|
||||
|
||||
# Polygamma of non-negative integer order is unbranched:
|
||||
k = Symbol('n', integer=True, nonnegative=True)
|
||||
assert polygamma(k, exp_polar(2*I*pi)*x) == polygamma(k, x)
|
||||
|
||||
# but negative integers are branched!
|
||||
k = Symbol('n', integer=True)
|
||||
assert polygamma(k, exp_polar(2*I*pi)*x).args == (k, exp_polar(2*I*pi)*x)
|
||||
|
||||
# Polygamma of order -1 is loggamma:
|
||||
assert polygamma(-1, x) == loggamma(x) - log(2*pi) / 2
|
||||
|
||||
# But smaller orders are iterated integrals and don't have a special name
|
||||
assert polygamma(-2, x).func is polygamma
|
||||
|
||||
# Test a bug
|
||||
assert polygamma(0, -x).expand(func=True) == polygamma(0, -x)
|
||||
|
||||
assert polygamma(2, 2.5).is_positive == False
|
||||
assert polygamma(2, -2.5).is_positive == False
|
||||
assert polygamma(3, 2.5).is_positive == True
|
||||
assert polygamma(3, -2.5).is_positive is True
|
||||
assert polygamma(-2, -2.5).is_positive is None
|
||||
assert polygamma(-3, -2.5).is_positive is None
|
||||
|
||||
assert polygamma(2, 2.5).is_negative == True
|
||||
assert polygamma(3, 2.5).is_negative == False
|
||||
assert polygamma(3, -2.5).is_negative == False
|
||||
assert polygamma(2, -2.5).is_negative is True
|
||||
assert polygamma(-2, -2.5).is_negative is None
|
||||
assert polygamma(-3, -2.5).is_negative is None
|
||||
|
||||
assert polygamma(I, 2).is_positive is None
|
||||
assert polygamma(I, 3).is_negative is None
|
||||
|
||||
# issue 17350
|
||||
assert (I*polygamma(I, pi)).as_real_imag() == \
|
||||
(-im(polygamma(I, pi)), re(polygamma(I, pi)))
|
||||
assert (tanh(polygamma(I, 1))).rewrite(exp) == \
|
||||
(exp(polygamma(I, 1)) - exp(-polygamma(I, 1)))/(exp(polygamma(I, 1)) + exp(-polygamma(I, 1)))
|
||||
assert (I / polygamma(I, 4)).rewrite(exp) == \
|
||||
I*exp(-I*atan(im(polygamma(I, 4))/re(polygamma(I, 4))))/Abs(polygamma(I, 4))
|
||||
|
||||
# issue 12569
|
||||
assert unchanged(im, polygamma(0, I))
|
||||
assert polygamma(Symbol('a', positive=True), Symbol('b', positive=True)).is_real is True
|
||||
assert polygamma(0, I).is_real is None
|
||||
|
||||
assert str(polygamma(pi, 3).evalf(n=10)) == "0.1169314564"
|
||||
assert str(polygamma(2.3, 1.0).evalf(n=10)) == "-3.003302909"
|
||||
assert str(polygamma(-1, 1).evalf(n=10)) == "-0.9189385332" # not zero
|
||||
assert str(polygamma(I, 1).evalf(n=10)) == "-3.109856569 + 1.89089016*I"
|
||||
assert str(polygamma(1, I).evalf(n=10)) == "-0.5369999034 - 0.7942335428*I"
|
||||
assert str(polygamma(I, I).evalf(n=10)) == "6.332362889 + 45.92828268*I"
|
||||
|
||||
|
||||
def test_polygamma_expand_func():
|
||||
assert polygamma(0, x).expand(func=True) == polygamma(0, x)
|
||||
assert polygamma(0, 2*x).expand(func=True) == \
|
||||
polygamma(0, x)/2 + polygamma(0, S.Half + x)/2 + log(2)
|
||||
assert polygamma(1, 2*x).expand(func=True) == \
|
||||
polygamma(1, x)/4 + polygamma(1, S.Half + x)/4
|
||||
assert polygamma(2, x).expand(func=True) == \
|
||||
polygamma(2, x)
|
||||
assert polygamma(0, -1 + x).expand(func=True) == \
|
||||
polygamma(0, x) - 1/(x - 1)
|
||||
assert polygamma(0, 1 + x).expand(func=True) == \
|
||||
1/x + polygamma(0, x )
|
||||
assert polygamma(0, 2 + x).expand(func=True) == \
|
||||
1/x + 1/(1 + x) + polygamma(0, x)
|
||||
assert polygamma(0, 3 + x).expand(func=True) == \
|
||||
polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x)
|
||||
assert polygamma(0, 4 + x).expand(func=True) == \
|
||||
polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) + 1/(3 + x)
|
||||
assert polygamma(1, 1 + x).expand(func=True) == \
|
||||
polygamma(1, x) - 1/x**2
|
||||
assert polygamma(1, 2 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2
|
||||
assert polygamma(1, 3 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - 1/(2 + x)**2
|
||||
assert polygamma(1, 4 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - \
|
||||
1/(2 + x)**2 - 1/(3 + x)**2
|
||||
assert polygamma(0, x + y).expand(func=True) == \
|
||||
polygamma(0, x + y)
|
||||
assert polygamma(1, x + y).expand(func=True) == \
|
||||
polygamma(1, x + y)
|
||||
assert polygamma(1, 3 + 4*x + y).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, y + 4*x) - 1/(y + 4*x)**2 - \
|
||||
1/(1 + y + 4*x)**2 - 1/(2 + y + 4*x)**2
|
||||
assert polygamma(3, 3 + 4*x + y).expand(func=True, multinomial=False) == \
|
||||
polygamma(3, y + 4*x) - 6/(y + 4*x)**4 - \
|
||||
6/(1 + y + 4*x)**4 - 6/(2 + y + 4*x)**4
|
||||
assert polygamma(3, 4*x + y + 1).expand(func=True, multinomial=False) == \
|
||||
polygamma(3, y + 4*x) - 6/(y + 4*x)**4
|
||||
e = polygamma(3, 4*x + y + Rational(3, 2))
|
||||
assert e.expand(func=True) == e
|
||||
e = polygamma(3, x + y + Rational(3, 4))
|
||||
assert e.expand(func=True, basic=False) == e
|
||||
|
||||
assert polygamma(-1, x, evaluate=False).expand(func=True) == \
|
||||
loggamma(x) - log(pi)/2 - log(2)/2
|
||||
p2 = polygamma(-2, x).expand(func=True) + x**2/2 - x/2 + S(1)/12
|
||||
assert isinstance(p2, Subs)
|
||||
assert p2.point == (-1,)
|
||||
|
||||
|
||||
def test_digamma():
|
||||
assert digamma(nan) == nan
|
||||
|
||||
assert digamma(oo) == oo
|
||||
assert digamma(-oo) == oo
|
||||
assert digamma(I*oo) == oo
|
||||
assert digamma(-I*oo) == oo
|
||||
|
||||
assert digamma(-9) == zoo
|
||||
|
||||
assert digamma(-9) == zoo
|
||||
assert digamma(-1) == zoo
|
||||
|
||||
assert digamma(0) == zoo
|
||||
|
||||
assert digamma(1) == -EulerGamma
|
||||
assert digamma(7) == Rational(49, 20) - EulerGamma
|
||||
|
||||
def t(m, n):
|
||||
x = S(m)/n
|
||||
r = digamma(x)
|
||||
if r.has(digamma):
|
||||
return False
|
||||
return abs(digamma(x.n()).n() - r.n()).n() < 1e-10
|
||||
assert t(1, 2)
|
||||
assert t(3, 2)
|
||||
assert t(-1, 2)
|
||||
assert t(1, 4)
|
||||
assert t(-3, 4)
|
||||
assert t(1, 3)
|
||||
assert t(4, 3)
|
||||
assert t(3, 4)
|
||||
assert t(2, 3)
|
||||
assert t(123, 5)
|
||||
|
||||
assert digamma(x).rewrite(zeta) == polygamma(0, x)
|
||||
|
||||
assert digamma(x).rewrite(harmonic) == harmonic(x - 1) - EulerGamma
|
||||
|
||||
assert digamma(I).is_real is None
|
||||
|
||||
assert digamma(x,evaluate=False).fdiff() == polygamma(1, x)
|
||||
|
||||
assert digamma(x,evaluate=False).is_real is None
|
||||
|
||||
assert digamma(x,evaluate=False).is_positive is None
|
||||
|
||||
assert digamma(x,evaluate=False).is_negative is None
|
||||
|
||||
assert digamma(x,evaluate=False).rewrite(polygamma) == polygamma(0, x)
|
||||
|
||||
|
||||
def test_digamma_expand_func():
|
||||
assert digamma(x).expand(func=True) == polygamma(0, x)
|
||||
assert digamma(2*x).expand(func=True) == \
|
||||
polygamma(0, x)/2 + polygamma(0, Rational(1, 2) + x)/2 + log(2)
|
||||
assert digamma(-1 + x).expand(func=True) == \
|
||||
polygamma(0, x) - 1/(x - 1)
|
||||
assert digamma(1 + x).expand(func=True) == \
|
||||
1/x + polygamma(0, x )
|
||||
assert digamma(2 + x).expand(func=True) == \
|
||||
1/x + 1/(1 + x) + polygamma(0, x)
|
||||
assert digamma(3 + x).expand(func=True) == \
|
||||
polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x)
|
||||
assert digamma(4 + x).expand(func=True) == \
|
||||
polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) + 1/(3 + x)
|
||||
assert digamma(x + y).expand(func=True) == \
|
||||
polygamma(0, x + y)
|
||||
|
||||
def test_trigamma():
|
||||
assert trigamma(nan) == nan
|
||||
|
||||
assert trigamma(oo) == 0
|
||||
|
||||
assert trigamma(1) == pi**2/6
|
||||
assert trigamma(2) == pi**2/6 - 1
|
||||
assert trigamma(3) == pi**2/6 - Rational(5, 4)
|
||||
|
||||
assert trigamma(x, evaluate=False).rewrite(zeta) == zeta(2, x)
|
||||
assert trigamma(x, evaluate=False).rewrite(harmonic) == \
|
||||
trigamma(x).rewrite(polygamma).rewrite(harmonic)
|
||||
|
||||
assert trigamma(x,evaluate=False).fdiff() == polygamma(2, x)
|
||||
|
||||
assert trigamma(x,evaluate=False).is_real is None
|
||||
|
||||
assert trigamma(x,evaluate=False).is_positive is None
|
||||
|
||||
assert trigamma(x,evaluate=False).is_negative is None
|
||||
|
||||
assert trigamma(x,evaluate=False).rewrite(polygamma) == polygamma(1, x)
|
||||
|
||||
def test_trigamma_expand_func():
|
||||
assert trigamma(2*x).expand(func=True) == \
|
||||
polygamma(1, x)/4 + polygamma(1, Rational(1, 2) + x)/4
|
||||
assert trigamma(1 + x).expand(func=True) == \
|
||||
polygamma(1, x) - 1/x**2
|
||||
assert trigamma(2 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2
|
||||
assert trigamma(3 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - 1/(2 + x)**2
|
||||
assert trigamma(4 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - \
|
||||
1/(2 + x)**2 - 1/(3 + x)**2
|
||||
assert trigamma(x + y).expand(func=True) == \
|
||||
polygamma(1, x + y)
|
||||
assert trigamma(3 + 4*x + y).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, y + 4*x) - 1/(y + 4*x)**2 - \
|
||||
1/(1 + y + 4*x)**2 - 1/(2 + y + 4*x)**2
|
||||
|
||||
def test_loggamma():
|
||||
raises(TypeError, lambda: loggamma(2, 3))
|
||||
raises(ArgumentIndexError, lambda: loggamma(x).fdiff(2))
|
||||
|
||||
assert loggamma(-1) is oo
|
||||
assert loggamma(-2) is oo
|
||||
assert loggamma(0) is oo
|
||||
assert loggamma(1) == 0
|
||||
assert loggamma(2) == 0
|
||||
assert loggamma(3) == log(2)
|
||||
assert loggamma(4) == log(6)
|
||||
|
||||
n = Symbol("n", integer=True, positive=True)
|
||||
assert loggamma(n) == log(gamma(n))
|
||||
assert loggamma(-n) is oo
|
||||
assert loggamma(n/2) == log(2**(-n + 1)*sqrt(pi)*gamma(n)/gamma(n/2 + S.Half))
|
||||
|
||||
assert loggamma(oo) is oo
|
||||
assert loggamma(-oo) is zoo
|
||||
assert loggamma(I*oo) is zoo
|
||||
assert loggamma(-I*oo) is zoo
|
||||
assert loggamma(zoo) is zoo
|
||||
assert loggamma(nan) is nan
|
||||
|
||||
L = loggamma(Rational(16, 3))
|
||||
E = -5*log(3) + loggamma(Rational(1, 3)) + log(4) + log(7) + log(10) + log(13)
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
L = loggamma(Rational(19, 4))
|
||||
E = -4*log(4) + loggamma(Rational(3, 4)) + log(3) + log(7) + log(11) + log(15)
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
L = loggamma(Rational(23, 7))
|
||||
E = -3*log(7) + log(2) + loggamma(Rational(2, 7)) + log(9) + log(16)
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
L = loggamma(Rational(19, 4) - 7)
|
||||
E = -log(9) - log(5) + loggamma(Rational(3, 4)) + 3*log(4) - 3*I*pi
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
L = loggamma(Rational(23, 7) - 6)
|
||||
E = -log(19) - log(12) - log(5) + loggamma(Rational(2, 7)) + 3*log(7) - 3*I*pi
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
assert loggamma(x).diff(x) == polygamma(0, x)
|
||||
s1 = loggamma(1/(x + sin(x)) + cos(x)).nseries(x, n=4)
|
||||
s2 = (-log(2*x) - 1)/(2*x) - log(x/pi)/2 + (4 - log(2*x))*x/24 + O(x**2) + \
|
||||
log(x)*x**2/2
|
||||
assert (s1 - s2).expand(force=True).removeO() == 0
|
||||
s1 = loggamma(1/x).series(x)
|
||||
s2 = (1/x - S.Half)*log(1/x) - 1/x + log(2*pi)/2 + \
|
||||
x/12 - x**3/360 + x**5/1260 + O(x**7)
|
||||
assert ((s1 - s2).expand(force=True)).removeO() == 0
|
||||
|
||||
assert loggamma(x).rewrite('intractable') == log(gamma(x))
|
||||
|
||||
s1 = loggamma(x).series(x).cancel()
|
||||
assert s1 == -log(x) - EulerGamma*x + pi**2*x**2/12 + x**3*polygamma(2, 1)/6 + \
|
||||
pi**4*x**4/360 + x**5*polygamma(4, 1)/120 + O(x**6)
|
||||
assert s1 == loggamma(x).rewrite('intractable').series(x).cancel()
|
||||
|
||||
assert conjugate(loggamma(x)) == loggamma(conjugate(x))
|
||||
assert conjugate(loggamma(0)) is oo
|
||||
assert conjugate(loggamma(1)) == loggamma(conjugate(1))
|
||||
assert conjugate(loggamma(-oo)) == conjugate(zoo)
|
||||
|
||||
assert loggamma(Symbol('v', positive=True)).is_real is True
|
||||
assert loggamma(Symbol('v', zero=True)).is_real is False
|
||||
assert loggamma(Symbol('v', negative=True)).is_real is False
|
||||
assert loggamma(Symbol('v', nonpositive=True)).is_real is False
|
||||
assert loggamma(Symbol('v', nonnegative=True)).is_real is None
|
||||
assert loggamma(Symbol('v', imaginary=True)).is_real is None
|
||||
assert loggamma(Symbol('v', real=True)).is_real is None
|
||||
assert loggamma(Symbol('v')).is_real is None
|
||||
|
||||
assert loggamma(S.Half).is_real is True
|
||||
assert loggamma(0).is_real is False
|
||||
assert loggamma(Rational(-1, 2)).is_real is False
|
||||
assert loggamma(I).is_real is None
|
||||
assert loggamma(2 + 3*I).is_real is None
|
||||
|
||||
def tN(N, M):
|
||||
assert loggamma(1/x)._eval_nseries(x, n=N).getn() == M
|
||||
tN(0, 0)
|
||||
tN(1, 1)
|
||||
tN(2, 2)
|
||||
tN(3, 3)
|
||||
tN(4, 4)
|
||||
tN(5, 5)
|
||||
|
||||
|
||||
def test_polygamma_expansion():
|
||||
# A. & S., pa. 259 and 260
|
||||
assert polygamma(0, 1/x).nseries(x, n=3) == \
|
||||
-log(x) - x/2 - x**2/12 + O(x**3)
|
||||
assert polygamma(1, 1/x).series(x, n=5) == \
|
||||
x + x**2/2 + x**3/6 + O(x**5)
|
||||
assert polygamma(3, 1/x).nseries(x, n=11) == \
|
||||
2*x**3 + 3*x**4 + 2*x**5 - x**7 + 4*x**9/3 + O(x**11)
|
||||
|
||||
|
||||
def test_polygamma_leading_term():
|
||||
expr = -log(1/x) + polygamma(0, 1 + 1/x) + S.EulerGamma
|
||||
assert expr.as_leading_term(x, logx=-y) == S.EulerGamma
|
||||
|
||||
|
||||
def test_issue_8657():
|
||||
n = Symbol('n', negative=True, integer=True)
|
||||
m = Symbol('m', integer=True)
|
||||
o = Symbol('o', positive=True)
|
||||
p = Symbol('p', negative=True, integer=False)
|
||||
assert gamma(n).is_real is False
|
||||
assert gamma(m).is_real is None
|
||||
assert gamma(o).is_real is True
|
||||
assert gamma(p).is_real is True
|
||||
assert gamma(w).is_real is None
|
||||
|
||||
|
||||
def test_issue_8524():
|
||||
x = Symbol('x', positive=True)
|
||||
y = Symbol('y', negative=True)
|
||||
z = Symbol('z', positive=False)
|
||||
p = Symbol('p', negative=False)
|
||||
q = Symbol('q', integer=True)
|
||||
r = Symbol('r', integer=False)
|
||||
e = Symbol('e', even=True, negative=True)
|
||||
assert gamma(x).is_positive is True
|
||||
assert gamma(y).is_positive is None
|
||||
assert gamma(z).is_positive is None
|
||||
assert gamma(p).is_positive is None
|
||||
assert gamma(q).is_positive is None
|
||||
assert gamma(r).is_positive is None
|
||||
assert gamma(e + S.Half).is_positive is True
|
||||
assert gamma(e - S.Half).is_positive is False
|
||||
|
||||
def test_issue_14450():
|
||||
assert uppergamma(Rational(3, 8), x).evalf() == uppergamma(Rational(3, 8), x)
|
||||
assert lowergamma(x, Rational(3, 8)).evalf() == lowergamma(x, Rational(3, 8))
|
||||
# some values from Wolfram Alpha for comparison
|
||||
assert abs(uppergamma(Rational(3, 8), 2).evalf() - 0.07105675881) < 1e-9
|
||||
assert abs(lowergamma(Rational(3, 8), 2).evalf() - 2.2993794256) < 1e-9
|
||||
|
||||
def test_issue_14528():
|
||||
k = Symbol('k', integer=True, nonpositive=True)
|
||||
assert isinstance(gamma(k), gamma)
|
||||
|
||||
def test_multigamma():
|
||||
from sympy.concrete.products import Product
|
||||
p = Symbol('p')
|
||||
_k = Dummy('_k')
|
||||
|
||||
assert multigamma(x, p).dummy_eq(pi**(p*(p - 1)/4)*\
|
||||
Product(gamma(x + (1 - _k)/2), (_k, 1, p)))
|
||||
|
||||
assert conjugate(multigamma(x, p)).dummy_eq(pi**((conjugate(p) - 1)*\
|
||||
conjugate(p)/4)*Product(gamma(conjugate(x) + (1-conjugate(_k))/2), (_k, 1, p)))
|
||||
assert conjugate(multigamma(x, 1)) == gamma(conjugate(x))
|
||||
|
||||
p = Symbol('p', positive=True)
|
||||
assert conjugate(multigamma(x, p)).dummy_eq(pi**((p - 1)*p/4)*\
|
||||
Product(gamma(conjugate(x) + (1-conjugate(_k))/2), (_k, 1, p)))
|
||||
|
||||
assert multigamma(nan, 1) is nan
|
||||
assert multigamma(oo, 1).doit() is oo
|
||||
|
||||
assert multigamma(1, 1) == 1
|
||||
assert multigamma(2, 1) == 1
|
||||
assert multigamma(3, 1) == 2
|
||||
|
||||
assert multigamma(102, 1) == factorial(101)
|
||||
assert multigamma(S.Half, 1) == sqrt(pi)
|
||||
|
||||
assert multigamma(1, 2) == pi
|
||||
assert multigamma(2, 2) == pi/2
|
||||
|
||||
assert multigamma(1, 3) is zoo
|
||||
assert multigamma(2, 3) == pi**2/2
|
||||
assert multigamma(3, 3) == 3*pi**2/2
|
||||
|
||||
assert multigamma(x, 1).diff(x) == gamma(x)*polygamma(0, x)
|
||||
assert multigamma(x, 2).diff(x) == sqrt(pi)*gamma(x)*gamma(x - S.Half)*\
|
||||
polygamma(0, x) + sqrt(pi)*gamma(x)*gamma(x - S.Half)*polygamma(0, x - S.Half)
|
||||
|
||||
assert multigamma(x - 1, 1).expand(func=True) == gamma(x)/(x - 1)
|
||||
assert multigamma(x + 2, 1).expand(func=True, mul=False) == x*(x + 1)*\
|
||||
gamma(x)
|
||||
assert multigamma(x - 1, 2).expand(func=True) == sqrt(pi)*gamma(x)*\
|
||||
gamma(x + S.Half)/(x**3 - 3*x**2 + x*Rational(11, 4) - Rational(3, 4))
|
||||
assert multigamma(x - 1, 3).expand(func=True) == pi**Rational(3, 2)*gamma(x)**2*\
|
||||
gamma(x + S.Half)/(x**5 - 6*x**4 + 55*x**3/4 - 15*x**2 + x*Rational(31, 4) - Rational(3, 2))
|
||||
|
||||
assert multigamma(n, 1).rewrite(factorial) == factorial(n - 1)
|
||||
assert multigamma(n, 2).rewrite(factorial) == sqrt(pi)*\
|
||||
factorial(n - Rational(3, 2))*factorial(n - 1)
|
||||
assert multigamma(n, 3).rewrite(factorial) == pi**Rational(3, 2)*\
|
||||
factorial(n - 2)*factorial(n - Rational(3, 2))*factorial(n - 1)
|
||||
|
||||
assert multigamma(Rational(-1, 2), 3, evaluate=False).is_real == False
|
||||
assert multigamma(S.Half, 3, evaluate=False).is_real == False
|
||||
assert multigamma(0, 1, evaluate=False).is_real == False
|
||||
assert multigamma(1, 3, evaluate=False).is_real == False
|
||||
assert multigamma(-1.0, 3, evaluate=False).is_real == False
|
||||
assert multigamma(0.7, 3, evaluate=False).is_real == True
|
||||
assert multigamma(3, 3, evaluate=False).is_real == True
|
||||
|
||||
def test_gamma_as_leading_term():
|
||||
assert gamma(x).as_leading_term(x) == 1/x
|
||||
assert gamma(2 + x).as_leading_term(x) == S(1)
|
||||
assert gamma(cos(x)).as_leading_term(x) == S(1)
|
||||
assert gamma(sin(x)).as_leading_term(x) == 1/x
|
||||
@@ -0,0 +1,403 @@
|
||||
from sympy.core.containers import Tuple
|
||||
from sympy.core.function import Derivative
|
||||
from sympy.core.numbers import (I, Rational, oo, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.exponential import (exp, log)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import cos
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.functions.special.hyper import (appellf1, hyper, meijerg)
|
||||
from sympy.series.order import O
|
||||
from sympy.abc import x, z, k
|
||||
from sympy.series.limits import limit
|
||||
from sympy.testing.pytest import raises, slow
|
||||
from sympy.core.random import (
|
||||
random_complex_number as randcplx,
|
||||
verify_numerically as tn,
|
||||
test_derivative_numerically as td)
|
||||
|
||||
|
||||
def test_TupleParametersBase():
|
||||
# test that our implementation of the chain rule works
|
||||
p = hyper((), (), z**2)
|
||||
assert p.diff(z) == p*2*z
|
||||
|
||||
|
||||
def test_hyper():
|
||||
raises(TypeError, lambda: hyper(1, 2, z))
|
||||
|
||||
assert hyper((2, 1), (1,), z) == hyper(Tuple(1, 2), Tuple(1), z)
|
||||
assert hyper((2, 1, 2), (1, 2, 1, 3), z) == hyper((2,), (1, 3), z)
|
||||
u = hyper((2, 1, 2), (1, 2, 1, 3), z, evaluate=False)
|
||||
assert u.ap == Tuple(1, 2, 2)
|
||||
assert u.bq == Tuple(1, 1, 2, 3)
|
||||
|
||||
h = hyper((1, 2), (3, 4, 5), z)
|
||||
assert h.ap == Tuple(1, 2)
|
||||
assert h.bq == Tuple(3, 4, 5)
|
||||
assert h.argument == z
|
||||
assert h.is_commutative is True
|
||||
h = hyper((2, 1), (4, 3, 5), z)
|
||||
assert h.ap == Tuple(1, 2)
|
||||
assert h.bq == Tuple(3, 4, 5)
|
||||
assert h.argument == z
|
||||
assert h.is_commutative is True
|
||||
|
||||
# just a few checks to make sure that all arguments go where they should
|
||||
assert tn(hyper(Tuple(), Tuple(), z), exp(z), z)
|
||||
assert tn(z*hyper((1, 1), Tuple(2), -z), log(1 + z), z)
|
||||
|
||||
# differentiation
|
||||
h = hyper(
|
||||
(randcplx(), randcplx(), randcplx()), (randcplx(), randcplx()), z)
|
||||
assert td(h, z)
|
||||
|
||||
a1, a2, b1, b2, b3 = symbols('a1:3, b1:4')
|
||||
assert hyper((a1, a2), (b1, b2, b3), z).diff(z) == \
|
||||
a1*a2/(b1*b2*b3) * hyper((a1 + 1, a2 + 1), (b1 + 1, b2 + 1, b3 + 1), z)
|
||||
|
||||
# differentiation wrt parameters is not supported
|
||||
assert hyper([z], [], z).diff(z) == Derivative(hyper([z], [], z), z)
|
||||
|
||||
# hyper is unbranched wrt parameters
|
||||
from sympy.functions.elementary.complexes import polar_lift
|
||||
assert hyper([polar_lift(z)], [polar_lift(k)], polar_lift(x)) == \
|
||||
hyper([z], [k], polar_lift(x))
|
||||
|
||||
# hyper does not automatically evaluate anyway, but the test is to make
|
||||
# sure that the evaluate keyword is accepted
|
||||
assert hyper((1, 2), (1,), z, evaluate=False).func is hyper
|
||||
|
||||
|
||||
def test_expand_func():
|
||||
# evaluation at 1 of Gauss' hypergeometric function:
|
||||
from sympy.abc import a, b, c
|
||||
from sympy.core.function import expand_func
|
||||
a1, b1, c1 = randcplx(), randcplx(), randcplx() + 5
|
||||
assert expand_func(hyper([a, b], [c], 1)) == \
|
||||
gamma(c)*gamma(-a - b + c)/(gamma(-a + c)*gamma(-b + c))
|
||||
assert abs(expand_func(hyper([a1, b1], [c1], 1)).n()
|
||||
- hyper([a1, b1], [c1], 1).n()) < 1e-10
|
||||
|
||||
# hyperexpand wrapper for hyper:
|
||||
assert expand_func(hyper([], [], z)) == exp(z)
|
||||
assert expand_func(hyper([1, 2, 3], [], z)) == hyper([1, 2, 3], [], z)
|
||||
assert expand_func(meijerg([[1, 1], []], [[1], [0]], z)) == log(z + 1)
|
||||
assert expand_func(meijerg([[1, 1], []], [[], []], z)) == \
|
||||
meijerg([[1, 1], []], [[], []], z)
|
||||
|
||||
|
||||
def replace_dummy(expr, sym):
|
||||
from sympy.core.symbol import Dummy
|
||||
dum = expr.atoms(Dummy)
|
||||
if not dum:
|
||||
return expr
|
||||
assert len(dum) == 1
|
||||
return expr.xreplace({dum.pop(): sym})
|
||||
|
||||
|
||||
def test_hyper_rewrite_sum():
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.symbol import Dummy
|
||||
from sympy.functions.combinatorial.factorials import (RisingFactorial, factorial)
|
||||
_k = Dummy("k")
|
||||
assert replace_dummy(hyper((1, 2), (1, 3), x).rewrite(Sum), _k) == \
|
||||
Sum(x**_k / factorial(_k) * RisingFactorial(2, _k) /
|
||||
RisingFactorial(3, _k), (_k, 0, oo))
|
||||
|
||||
assert hyper((1, 2, 3), (-1, 3), z).rewrite(Sum) == \
|
||||
hyper((1, 2, 3), (-1, 3), z)
|
||||
|
||||
|
||||
def test_radius_of_convergence():
|
||||
assert hyper((1, 2), [3], z).radius_of_convergence == 1
|
||||
assert hyper((1, 2), [3, 4], z).radius_of_convergence is oo
|
||||
assert hyper((1, 2, 3), [4], z).radius_of_convergence == 0
|
||||
assert hyper((0, 1, 2), [4], z).radius_of_convergence is oo
|
||||
assert hyper((-1, 1, 2), [-4], z).radius_of_convergence == 0
|
||||
assert hyper((-1, -2, 2), [-1], z).radius_of_convergence is oo
|
||||
assert hyper((-1, 2), [-1, -2], z).radius_of_convergence == 0
|
||||
assert hyper([-1, 1, 3], [-2, 2], z).radius_of_convergence == 1
|
||||
assert hyper([-1, 1], [-2, 2], z).radius_of_convergence is oo
|
||||
assert hyper([-1, 1, 3], [-2], z).radius_of_convergence == 0
|
||||
assert hyper((-1, 2, 3, 4), [], z).radius_of_convergence is oo
|
||||
|
||||
assert hyper([1, 1], [3], 1).convergence_statement == True
|
||||
assert hyper([1, 1], [2], 1).convergence_statement == False
|
||||
assert hyper([1, 1], [2], -1).convergence_statement == True
|
||||
assert hyper([1, 1], [1], -1).convergence_statement == False
|
||||
|
||||
|
||||
def test_meijer():
|
||||
raises(TypeError, lambda: meijerg(1, z))
|
||||
raises(TypeError, lambda: meijerg(((1,), (2,)), (3,), (4,), z))
|
||||
|
||||
assert meijerg(((1, 2), (3,)), ((4,), (5,)), z) == \
|
||||
meijerg(Tuple(1, 2), Tuple(3), Tuple(4), Tuple(5), z)
|
||||
|
||||
g = meijerg((1, 2), (3, 4, 5), (6, 7, 8, 9), (10, 11, 12, 13, 14), z)
|
||||
assert g.an == Tuple(1, 2)
|
||||
assert g.ap == Tuple(1, 2, 3, 4, 5)
|
||||
assert g.aother == Tuple(3, 4, 5)
|
||||
assert g.bm == Tuple(6, 7, 8, 9)
|
||||
assert g.bq == Tuple(6, 7, 8, 9, 10, 11, 12, 13, 14)
|
||||
assert g.bother == Tuple(10, 11, 12, 13, 14)
|
||||
assert g.argument == z
|
||||
assert g.nu == 75
|
||||
assert g.delta == -1
|
||||
assert g.is_commutative is True
|
||||
assert g.is_number is False
|
||||
#issue 13071
|
||||
assert meijerg([[],[]], [[S.Half],[0]], 1).is_number is True
|
||||
|
||||
assert meijerg([1, 2], [3], [4], [5], z).delta == S.Half
|
||||
|
||||
# just a few checks to make sure that all arguments go where they should
|
||||
assert tn(meijerg(Tuple(), Tuple(), Tuple(0), Tuple(), -z), exp(z), z)
|
||||
assert tn(sqrt(pi)*meijerg(Tuple(), Tuple(),
|
||||
Tuple(0), Tuple(S.Half), z**2/4), cos(z), z)
|
||||
assert tn(meijerg(Tuple(1, 1), Tuple(), Tuple(1), Tuple(0), z),
|
||||
log(1 + z), z)
|
||||
|
||||
# test exceptions
|
||||
raises(ValueError, lambda: meijerg(((3, 1), (2,)), ((oo,), (2, 0)), x))
|
||||
raises(ValueError, lambda: meijerg(((3, 1), (2,)), ((1,), (2, 0)), x))
|
||||
|
||||
# differentiation
|
||||
g = meijerg((randcplx(),), (randcplx() + 2*I,), Tuple(),
|
||||
(randcplx(), randcplx()), z)
|
||||
assert td(g, z)
|
||||
|
||||
g = meijerg(Tuple(), (randcplx(),), Tuple(),
|
||||
(randcplx(), randcplx()), z)
|
||||
assert td(g, z)
|
||||
|
||||
g = meijerg(Tuple(), Tuple(), Tuple(randcplx()),
|
||||
Tuple(randcplx(), randcplx()), z)
|
||||
assert td(g, z)
|
||||
|
||||
a1, a2, b1, b2, c1, c2, d1, d2 = symbols('a1:3, b1:3, c1:3, d1:3')
|
||||
assert meijerg((a1, a2), (b1, b2), (c1, c2), (d1, d2), z).diff(z) == \
|
||||
(meijerg((a1 - 1, a2), (b1, b2), (c1, c2), (d1, d2), z)
|
||||
+ (a1 - 1)*meijerg((a1, a2), (b1, b2), (c1, c2), (d1, d2), z))/z
|
||||
|
||||
assert meijerg([z, z], [], [], [], z).diff(z) == \
|
||||
Derivative(meijerg([z, z], [], [], [], z), z)
|
||||
|
||||
# meijerg is unbranched wrt parameters
|
||||
from sympy.functions.elementary.complexes import polar_lift as pl
|
||||
assert meijerg([pl(a1)], [pl(a2)], [pl(b1)], [pl(b2)], pl(z)) == \
|
||||
meijerg([a1], [a2], [b1], [b2], pl(z))
|
||||
|
||||
# integrand
|
||||
from sympy.abc import a, b, c, d, s
|
||||
assert meijerg([a], [b], [c], [d], z).integrand(s) == \
|
||||
z**s*gamma(c - s)*gamma(-a + s + 1)/(gamma(b - s)*gamma(-d + s + 1))
|
||||
|
||||
|
||||
def test_meijerg_derivative():
|
||||
assert meijerg([], [1, 1], [0, 0, x], [], z).diff(x) == \
|
||||
log(z)*meijerg([], [1, 1], [0, 0, x], [], z) \
|
||||
+ 2*meijerg([], [1, 1, 1], [0, 0, x, 0], [], z)
|
||||
|
||||
y = randcplx()
|
||||
a = 5 # mpmath chokes with non-real numbers, and Mod1 with floats
|
||||
assert td(meijerg([x], [], [], [], y), x)
|
||||
assert td(meijerg([x**2], [], [], [], y), x)
|
||||
assert td(meijerg([], [x], [], [], y), x)
|
||||
assert td(meijerg([], [], [x], [], y), x)
|
||||
assert td(meijerg([], [], [], [x], y), x)
|
||||
assert td(meijerg([x], [a], [a + 1], [], y), x)
|
||||
assert td(meijerg([x], [a + 1], [a], [], y), x)
|
||||
assert td(meijerg([x, a], [], [], [a + 1], y), x)
|
||||
assert td(meijerg([x, a + 1], [], [], [a], y), x)
|
||||
b = Rational(3, 2)
|
||||
assert td(meijerg([a + 2], [b], [b - 3, x], [a], y), x)
|
||||
|
||||
|
||||
def test_meijerg_period():
|
||||
assert meijerg([], [1], [0], [], x).get_period() == 2*pi
|
||||
assert meijerg([1], [], [], [0], x).get_period() == 2*pi
|
||||
assert meijerg([], [], [0], [], x).get_period() == 2*pi # exp(x)
|
||||
assert meijerg(
|
||||
[], [], [0], [S.Half], x).get_period() == 2*pi # cos(sqrt(x))
|
||||
assert meijerg(
|
||||
[], [], [S.Half], [0], x).get_period() == 4*pi # sin(sqrt(x))
|
||||
assert meijerg([1, 1], [], [1], [0], x).get_period() is oo # log(1 + x)
|
||||
|
||||
|
||||
def test_hyper_unpolarify():
|
||||
from sympy.functions.elementary.exponential import exp_polar
|
||||
a = exp_polar(2*pi*I)*x
|
||||
b = x
|
||||
assert hyper([], [], a).argument == b
|
||||
assert hyper([0], [], a).argument == a
|
||||
assert hyper([0], [0], a).argument == b
|
||||
assert hyper([0, 1], [0], a).argument == a
|
||||
assert hyper([0, 1], [0], exp_polar(2*pi*I)).argument == 1
|
||||
|
||||
|
||||
@slow
|
||||
def test_hyperrep():
|
||||
from sympy.functions.special.hyper import (HyperRep, HyperRep_atanh,
|
||||
HyperRep_power1, HyperRep_power2, HyperRep_log1, HyperRep_asin1,
|
||||
HyperRep_asin2, HyperRep_sqrts1, HyperRep_sqrts2, HyperRep_log2,
|
||||
HyperRep_cosasin, HyperRep_sinasin)
|
||||
# First test the base class works.
|
||||
from sympy.functions.elementary.exponential import exp_polar
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
a, b, c, d, z = symbols('a b c d z')
|
||||
|
||||
class myrep(HyperRep):
|
||||
@classmethod
|
||||
def _expr_small(cls, x):
|
||||
return a
|
||||
|
||||
@classmethod
|
||||
def _expr_small_minus(cls, x):
|
||||
return b
|
||||
|
||||
@classmethod
|
||||
def _expr_big(cls, x, n):
|
||||
return c*n
|
||||
|
||||
@classmethod
|
||||
def _expr_big_minus(cls, x, n):
|
||||
return d*n
|
||||
assert myrep(z).rewrite('nonrep') == Piecewise((0, abs(z) > 1), (a, True))
|
||||
assert myrep(exp_polar(I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((0, abs(z) > 1), (b, True))
|
||||
assert myrep(exp_polar(2*I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((c, abs(z) > 1), (a, True))
|
||||
assert myrep(exp_polar(3*I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((d, abs(z) > 1), (b, True))
|
||||
assert myrep(exp_polar(4*I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((2*c, abs(z) > 1), (a, True))
|
||||
assert myrep(exp_polar(5*I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((2*d, abs(z) > 1), (b, True))
|
||||
assert myrep(z).rewrite('nonrepsmall') == a
|
||||
assert myrep(exp_polar(I*pi)*z).rewrite('nonrepsmall') == b
|
||||
|
||||
def t(func, hyp, z):
|
||||
""" Test that func is a valid representation of hyp. """
|
||||
# First test that func agrees with hyp for small z
|
||||
if not tn(func.rewrite('nonrepsmall'), hyp, z,
|
||||
a=Rational(-1, 2), b=Rational(-1, 2), c=S.Half, d=S.Half):
|
||||
return False
|
||||
# Next check that the two small representations agree.
|
||||
if not tn(
|
||||
func.rewrite('nonrepsmall').subs(
|
||||
z, exp_polar(I*pi)*z).replace(exp_polar, exp),
|
||||
func.subs(z, exp_polar(I*pi)*z).rewrite('nonrepsmall'),
|
||||
z, a=Rational(-1, 2), b=Rational(-1, 2), c=S.Half, d=S.Half):
|
||||
return False
|
||||
# Next check continuity along exp_polar(I*pi)*t
|
||||
expr = func.subs(z, exp_polar(I*pi)*z).rewrite('nonrep')
|
||||
if abs(expr.subs(z, 1 + 1e-15).n() - expr.subs(z, 1 - 1e-15).n()) > 1e-10:
|
||||
return False
|
||||
# Finally check continuity of the big reps.
|
||||
|
||||
def dosubs(func, a, b):
|
||||
rv = func.subs(z, exp_polar(a)*z).rewrite('nonrep')
|
||||
return rv.subs(z, exp_polar(b)*z).replace(exp_polar, exp)
|
||||
for n in [0, 1, 2, 3, 4, -1, -2, -3, -4]:
|
||||
expr1 = dosubs(func, 2*I*pi*n, I*pi/2)
|
||||
expr2 = dosubs(func, 2*I*pi*n + I*pi, -I*pi/2)
|
||||
if not tn(expr1, expr2, z):
|
||||
return False
|
||||
expr1 = dosubs(func, 2*I*pi*(n + 1), -I*pi/2)
|
||||
expr2 = dosubs(func, 2*I*pi*n + I*pi, I*pi/2)
|
||||
if not tn(expr1, expr2, z):
|
||||
return False
|
||||
return True
|
||||
|
||||
# Now test the various representatives.
|
||||
a = Rational(1, 3)
|
||||
assert t(HyperRep_atanh(z), hyper([S.Half, 1], [Rational(3, 2)], z), z)
|
||||
assert t(HyperRep_power1(a, z), hyper([-a], [], z), z)
|
||||
assert t(HyperRep_power2(a, z), hyper([a, a - S.Half], [2*a], z), z)
|
||||
assert t(HyperRep_log1(z), -z*hyper([1, 1], [2], z), z)
|
||||
assert t(HyperRep_asin1(z), hyper([S.Half, S.Half], [Rational(3, 2)], z), z)
|
||||
assert t(HyperRep_asin2(z), hyper([1, 1], [Rational(3, 2)], z), z)
|
||||
assert t(HyperRep_sqrts1(a, z), hyper([-a, S.Half - a], [S.Half], z), z)
|
||||
assert t(HyperRep_sqrts2(a, z),
|
||||
-2*z/(2*a + 1)*hyper([-a - S.Half, -a], [S.Half], z).diff(z), z)
|
||||
assert t(HyperRep_log2(z), -z/4*hyper([Rational(3, 2), 1, 1], [2, 2], z), z)
|
||||
assert t(HyperRep_cosasin(a, z), hyper([-a, a], [S.Half], z), z)
|
||||
assert t(HyperRep_sinasin(a, z), 2*a*z*hyper([1 - a, 1 + a], [Rational(3, 2)], z), z)
|
||||
|
||||
|
||||
@slow
|
||||
def test_meijerg_eval():
|
||||
from sympy.functions.elementary.exponential import exp_polar
|
||||
from sympy.functions.special.bessel import besseli
|
||||
from sympy.abc import l
|
||||
a = randcplx()
|
||||
arg = x*exp_polar(k*pi*I)
|
||||
expr1 = pi*meijerg([[], [(a + 1)/2]], [[a/2], [-a/2, (a + 1)/2]], arg**2/4)
|
||||
expr2 = besseli(a, arg)
|
||||
|
||||
# Test that the two expressions agree for all arguments.
|
||||
for x_ in [0.5, 1.5]:
|
||||
for k_ in [0.0, 0.1, 0.3, 0.5, 0.8, 1, 5.751, 15.3]:
|
||||
assert abs((expr1 - expr2).n(subs={x: x_, k: k_})) < 1e-10
|
||||
assert abs((expr1 - expr2).n(subs={x: x_, k: -k_})) < 1e-10
|
||||
|
||||
# Test continuity independently
|
||||
eps = 1e-13
|
||||
expr2 = expr1.subs(k, l)
|
||||
for x_ in [0.5, 1.5]:
|
||||
for k_ in [0.5, Rational(1, 3), 0.25, 0.75, Rational(2, 3), 1.0, 1.5]:
|
||||
assert abs((expr1 - expr2).n(
|
||||
subs={x: x_, k: k_ + eps, l: k_ - eps})) < 1e-10
|
||||
assert abs((expr1 - expr2).n(
|
||||
subs={x: x_, k: -k_ + eps, l: -k_ - eps})) < 1e-10
|
||||
|
||||
expr = (meijerg(((0.5,), ()), ((0.5, 0, 0.5), ()), exp_polar(-I*pi)/4)
|
||||
+ meijerg(((0.5,), ()), ((0.5, 0, 0.5), ()), exp_polar(I*pi)/4)) \
|
||||
/(2*sqrt(pi))
|
||||
assert (expr - pi/exp(1)).n(chop=True) == 0
|
||||
|
||||
|
||||
def test_limits():
|
||||
k, x = symbols('k, x')
|
||||
assert hyper((1,), (Rational(4, 3), Rational(5, 3)), k**2).series(k) == \
|
||||
1 + 9*k**2/20 + 81*k**4/1120 + O(k**6) # issue 6350
|
||||
|
||||
# https://github.com/sympy/sympy/issues/11465
|
||||
assert limit(1/hyper((1, ), (1, ), x), x, 0) == 1
|
||||
|
||||
|
||||
def test_appellf1():
|
||||
a, b1, b2, c, x, y = symbols('a b1 b2 c x y')
|
||||
assert appellf1(a, b2, b1, c, y, x) == appellf1(a, b1, b2, c, x, y)
|
||||
assert appellf1(a, b1, b1, c, y, x) == appellf1(a, b1, b1, c, x, y)
|
||||
assert appellf1(a, b1, b2, c, S.Zero, S.Zero) is S.One
|
||||
|
||||
f = appellf1(a, b1, b2, c, S.Zero, S.Zero, evaluate=False)
|
||||
assert f.func is appellf1
|
||||
assert f.doit() is S.One
|
||||
|
||||
|
||||
def test_derivative_appellf1():
|
||||
from sympy.core.function import diff
|
||||
a, b1, b2, c, x, y, z = symbols('a b1 b2 c x y z')
|
||||
assert diff(appellf1(a, b1, b2, c, x, y), x) == a*b1*appellf1(a + 1, b2, b1 + 1, c + 1, y, x)/c
|
||||
assert diff(appellf1(a, b1, b2, c, x, y), y) == a*b2*appellf1(a + 1, b1, b2 + 1, c + 1, x, y)/c
|
||||
assert diff(appellf1(a, b1, b2, c, x, y), z) == 0
|
||||
assert diff(appellf1(a, b1, b2, c, x, y), a) == Derivative(appellf1(a, b1, b2, c, x, y), a)
|
||||
|
||||
|
||||
def test_eval_nseries():
|
||||
a1, b1, a2, b2 = symbols('a1 b1 a2 b2')
|
||||
assert hyper((1,2), (1,2,3), x**2)._eval_nseries(x, 7, None) == \
|
||||
1 + x**2/3 + x**4/24 + x**6/360 + O(x**7)
|
||||
assert exp(x)._eval_nseries(x,7,None) == \
|
||||
hyper((a1, b1), (a1, b1), x)._eval_nseries(x, 7, None)
|
||||
assert hyper((a1, a2), (b1, b2), x)._eval_nseries(z, 7, None) ==\
|
||||
hyper((a1, a2), (b1, b2), x) + O(z**7)
|
||||
assert hyper((-S(1)/2, S(1)/2), (1,), 4*x/(x + 1)).nseries(x) == \
|
||||
1 - x + x**2/4 - 3*x**3/4 - 15*x**4/64 - 93*x**5/64 + O(x**6)
|
||||
assert (pi/2*hyper((-S(1)/2, S(1)/2), (1,), 4*x/(x + 1))).nseries(x) == \
|
||||
pi/2 - pi*x/2 + pi*x**2/8 - 3*pi*x**3/8 - 15*pi*x**4/128 - 93*pi*x**5/128 + O(x**6)
|
||||
@@ -0,0 +1,29 @@
|
||||
from sympy.core.function import diff
|
||||
from sympy.functions.elementary.complexes import conjugate
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||||
from sympy.functions.special.mathieu_functions import (mathieuc, mathieucprime, mathieus, mathieusprime)
|
||||
|
||||
from sympy.abc import a, q, z
|
||||
|
||||
|
||||
def test_mathieus():
|
||||
assert isinstance(mathieus(a, q, z), mathieus)
|
||||
assert mathieus(a, 0, z) == sin(sqrt(a)*z)
|
||||
assert conjugate(mathieus(a, q, z)) == mathieus(conjugate(a), conjugate(q), conjugate(z))
|
||||
assert diff(mathieus(a, q, z), z) == mathieusprime(a, q, z)
|
||||
|
||||
def test_mathieuc():
|
||||
assert isinstance(mathieuc(a, q, z), mathieuc)
|
||||
assert mathieuc(a, 0, z) == cos(sqrt(a)*z)
|
||||
assert diff(mathieuc(a, q, z), z) == mathieucprime(a, q, z)
|
||||
|
||||
def test_mathieusprime():
|
||||
assert isinstance(mathieusprime(a, q, z), mathieusprime)
|
||||
assert mathieusprime(a, 0, z) == sqrt(a)*cos(sqrt(a)*z)
|
||||
assert diff(mathieusprime(a, q, z), z) == (-a + 2*q*cos(2*z))*mathieus(a, q, z)
|
||||
|
||||
def test_mathieucprime():
|
||||
assert isinstance(mathieucprime(a, q, z), mathieucprime)
|
||||
assert mathieucprime(a, 0, z) == -sqrt(a)*sin(sqrt(a)*z)
|
||||
assert diff(mathieucprime(a, q, z), z) == (-a + 2*q*cos(2*z))*mathieuc(a, q, z)
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
from sympy.core.function import (Derivative, diff)
|
||||
from sympy.core.numbers import (Float, I, nan, oo, pi)
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.special.delta_functions import (DiracDelta, Heaviside)
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
from sympy.series.order import O
|
||||
|
||||
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
x, y, a, n = symbols('x y a n')
|
||||
|
||||
|
||||
def test_fdiff():
|
||||
assert SingularityFunction(x, 4, 5).fdiff() == 5*SingularityFunction(x, 4, 4)
|
||||
assert SingularityFunction(x, 4, -1).fdiff() == SingularityFunction(x, 4, -2)
|
||||
assert SingularityFunction(x, 4, -2).fdiff() == SingularityFunction(x, 4, -3)
|
||||
assert SingularityFunction(x, 4, -3).fdiff() == SingularityFunction(x, 4, -4)
|
||||
assert SingularityFunction(x, 4, 0).fdiff() == SingularityFunction(x, 4, -1)
|
||||
|
||||
assert SingularityFunction(y, 6, 2).diff(y) == 2*SingularityFunction(y, 6, 1)
|
||||
assert SingularityFunction(y, -4, -1).diff(y) == SingularityFunction(y, -4, -2)
|
||||
assert SingularityFunction(y, 4, 0).diff(y) == SingularityFunction(y, 4, -1)
|
||||
assert SingularityFunction(y, 4, 0).diff(y, 2) == SingularityFunction(y, 4, -2)
|
||||
|
||||
n = Symbol('n', positive=True)
|
||||
assert SingularityFunction(x, a, n).fdiff() == n*SingularityFunction(x, a, n - 1)
|
||||
assert SingularityFunction(y, a, n).diff(y) == n*SingularityFunction(y, a, n - 1)
|
||||
|
||||
expr_in = 4*SingularityFunction(x, a, n) + 3*SingularityFunction(x, a, -1) + -10*SingularityFunction(x, a, 0)
|
||||
expr_out = n*4*SingularityFunction(x, a, n - 1) + 3*SingularityFunction(x, a, -2) - 10*SingularityFunction(x, a, -1)
|
||||
assert diff(expr_in, x) == expr_out
|
||||
|
||||
assert SingularityFunction(x, -10, 5).diff(evaluate=False) == (
|
||||
Derivative(SingularityFunction(x, -10, 5), x))
|
||||
|
||||
raises(ArgumentIndexError, lambda: SingularityFunction(x, 4, 5).fdiff(2))
|
||||
|
||||
|
||||
def test_eval():
|
||||
assert SingularityFunction(x, a, n).func == SingularityFunction
|
||||
assert unchanged(SingularityFunction, x, 5, n)
|
||||
assert SingularityFunction(5, 3, 2) == 4
|
||||
assert SingularityFunction(3, 5, 1) == 0
|
||||
assert SingularityFunction(3, 3, 0) == 1
|
||||
assert SingularityFunction(3, 3, 1) == 0
|
||||
assert SingularityFunction(Symbol('z', zero=True), 0, 1) == 0 # like sin(z) == 0
|
||||
assert SingularityFunction(4, 4, -1) is oo
|
||||
assert SingularityFunction(4, 2, -1) == 0
|
||||
assert SingularityFunction(4, 7, -1) == 0
|
||||
assert SingularityFunction(5, 6, -2) == 0
|
||||
assert SingularityFunction(4, 2, -2) == 0
|
||||
assert SingularityFunction(4, 4, -2) is oo
|
||||
assert SingularityFunction(4, 2, -3) == 0
|
||||
assert SingularityFunction(8, 8, -3) is oo
|
||||
assert SingularityFunction(4, 2, -4) == 0
|
||||
assert SingularityFunction(8, 8, -4) is oo
|
||||
assert (SingularityFunction(6.1, 4, 5)).evalf(5) == Float('40.841', '5')
|
||||
assert SingularityFunction(6.1, pi, 2) == (-pi + 6.1)**2
|
||||
assert SingularityFunction(x, a, nan) is nan
|
||||
assert SingularityFunction(x, nan, 1) is nan
|
||||
assert SingularityFunction(nan, a, n) is nan
|
||||
|
||||
raises(ValueError, lambda: SingularityFunction(x, a, I))
|
||||
raises(ValueError, lambda: SingularityFunction(2*I, I, n))
|
||||
raises(ValueError, lambda: SingularityFunction(x, a, -5))
|
||||
|
||||
|
||||
def test_leading_term():
|
||||
l = Symbol('l', positive=True)
|
||||
assert SingularityFunction(x, 3, 2).as_leading_term(x) == 0
|
||||
assert SingularityFunction(x, -2, 1).as_leading_term(x) == 2
|
||||
assert SingularityFunction(x, 0, 0).as_leading_term(x) == 1
|
||||
assert SingularityFunction(x, 0, 0).as_leading_term(x, cdir=-1) == 0
|
||||
assert SingularityFunction(x, 0, -1).as_leading_term(x) == 0
|
||||
assert SingularityFunction(x, 0, -2).as_leading_term(x) == 0
|
||||
assert SingularityFunction(x, 0, -3).as_leading_term(x) == 0
|
||||
assert SingularityFunction(x, 0, -4).as_leading_term(x) == 0
|
||||
assert (SingularityFunction(x + l, 0, 1)/2\
|
||||
- SingularityFunction(x + l, l/2, 1)\
|
||||
+ SingularityFunction(x + l, l, 1)/2).as_leading_term(x) == -x/2
|
||||
|
||||
|
||||
def test_series():
|
||||
l = Symbol('l', positive=True)
|
||||
assert SingularityFunction(x, -3, 2).series(x) == x**2 + 6*x + 9
|
||||
assert SingularityFunction(x, -2, 1).series(x) == x + 2
|
||||
assert SingularityFunction(x, 0, 0).series(x) == 1
|
||||
assert SingularityFunction(x, 0, 0).series(x, dir='-') == 0
|
||||
assert SingularityFunction(x, 0, -1).series(x) == 0
|
||||
assert SingularityFunction(x, 0, -2).series(x) == 0
|
||||
assert SingularityFunction(x, 0, -3).series(x) == 0
|
||||
assert SingularityFunction(x, 0, -4).series(x) == 0
|
||||
assert (SingularityFunction(x + l, 0, 1)/2\
|
||||
- SingularityFunction(x + l, l/2, 1)\
|
||||
+ SingularityFunction(x + l, l, 1)/2).nseries(x) == -x/2 + O(x**6)
|
||||
|
||||
|
||||
def test_rewrite():
|
||||
assert SingularityFunction(x, 4, 5).rewrite(Piecewise) == (
|
||||
Piecewise(((x - 4)**5, x - 4 >= 0), (0, True)))
|
||||
assert SingularityFunction(x, -10, 0).rewrite(Piecewise) == (
|
||||
Piecewise((1, x + 10 >= 0), (0, True)))
|
||||
assert SingularityFunction(x, 2, -1).rewrite(Piecewise) == (
|
||||
Piecewise((oo, Eq(x - 2, 0)), (0, True)))
|
||||
assert SingularityFunction(x, 0, -2).rewrite(Piecewise) == (
|
||||
Piecewise((oo, Eq(x, 0)), (0, True)))
|
||||
|
||||
n = Symbol('n', nonnegative=True)
|
||||
p = SingularityFunction(x, a, n).rewrite(Piecewise)
|
||||
assert p == (
|
||||
Piecewise(((x - a)**n, x - a >= 0), (0, True)))
|
||||
assert p.subs(x, a).subs(n, 0) == 1
|
||||
|
||||
expr_in = SingularityFunction(x, 4, 5) + SingularityFunction(x, -3, -1) - SingularityFunction(x, 0, -2)
|
||||
expr_out = (x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
|
||||
assert expr_in.rewrite(Heaviside) == expr_out
|
||||
assert expr_in.rewrite(DiracDelta) == expr_out
|
||||
assert expr_in.rewrite('HeavisideDiracDelta') == expr_out
|
||||
|
||||
expr_in = SingularityFunction(x, a, n) + SingularityFunction(x, a, -1) - SingularityFunction(x, a, -2)
|
||||
expr_out = (x - a)**n*Heaviside(x - a, 1) + DiracDelta(x - a) + DiracDelta(a - x, 1)
|
||||
assert expr_in.rewrite(Heaviside) == expr_out
|
||||
assert expr_in.rewrite(DiracDelta) == expr_out
|
||||
assert expr_in.rewrite('HeavisideDiracDelta') == expr_out
|
||||
+475
@@ -0,0 +1,475 @@
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.function import (Derivative, diff)
|
||||
from sympy.core.numbers import (Rational, oo, pi, zoo)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, Symbol)
|
||||
from sympy.functions.combinatorial.factorials import (RisingFactorial, binomial, factorial)
|
||||
from sympy.functions.elementary.complexes import conjugate
|
||||
from sympy.functions.elementary.exponential import exp
|
||||
from sympy.functions.elementary.integers import floor
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import cos
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.functions.special.hyper import hyper
|
||||
from sympy.functions.special.polynomials import (assoc_laguerre, assoc_legendre, chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root, gegenbauer, hermite, hermite_prob, jacobi, jacobi_normalized, laguerre, legendre)
|
||||
from sympy.polys.orthopolys import laguerre_poly
|
||||
from sympy.polys.polyroots import roots
|
||||
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
x = Symbol('x')
|
||||
|
||||
|
||||
def test_jacobi():
|
||||
n = Symbol("n")
|
||||
a = Symbol("a")
|
||||
b = Symbol("b")
|
||||
|
||||
assert jacobi(0, a, b, x) == 1
|
||||
assert jacobi(1, a, b, x) == a/2 - b/2 + x*(a/2 + b/2 + 1)
|
||||
|
||||
assert jacobi(n, a, a, x) == RisingFactorial(
|
||||
a + 1, n)*gegenbauer(n, a + S.Half, x)/RisingFactorial(2*a + 1, n)
|
||||
assert jacobi(n, a, -a, x) == ((-1)**a*(-x + 1)**(-a/2)*(x + 1)**(a/2)*assoc_legendre(n, a, x)*
|
||||
factorial(-a + n)*gamma(a + n + 1)/(factorial(a + n)*gamma(n + 1)))
|
||||
assert jacobi(n, -b, b, x) == ((-x + 1)**(b/2)*(x + 1)**(-b/2)*assoc_legendre(n, b, x)*
|
||||
gamma(-b + n + 1)/gamma(n + 1))
|
||||
assert jacobi(n, 0, 0, x) == legendre(n, x)
|
||||
assert jacobi(n, S.Half, S.Half, x) == RisingFactorial(
|
||||
Rational(3, 2), n)*chebyshevu(n, x)/factorial(n + 1)
|
||||
assert jacobi(n, Rational(-1, 2), Rational(-1, 2), x) == RisingFactorial(
|
||||
S.Half, n)*chebyshevt(n, x)/factorial(n)
|
||||
|
||||
X = jacobi(n, a, b, x)
|
||||
assert isinstance(X, jacobi)
|
||||
|
||||
assert jacobi(n, a, b, -x) == (-1)**n*jacobi(n, b, a, x)
|
||||
assert jacobi(n, a, b, 0) == 2**(-n)*gamma(a + n + 1)*hyper(
|
||||
(-b - n, -n), (a + 1,), -1)/(factorial(n)*gamma(a + 1))
|
||||
assert jacobi(n, a, b, 1) == RisingFactorial(a + 1, n)/factorial(n)
|
||||
|
||||
m = Symbol("m", positive=True)
|
||||
assert jacobi(m, a, b, oo) == oo*RisingFactorial(a + b + m + 1, m)
|
||||
assert unchanged(jacobi, n, a, b, oo)
|
||||
|
||||
assert conjugate(jacobi(m, a, b, x)) == \
|
||||
jacobi(m, conjugate(a), conjugate(b), conjugate(x))
|
||||
|
||||
_k = Dummy('k')
|
||||
assert diff(jacobi(n, a, b, x), n) == Derivative(jacobi(n, a, b, x), n)
|
||||
assert diff(jacobi(n, a, b, x), a).dummy_eq(Sum((jacobi(n, a, b, x) +
|
||||
(2*_k + a + b + 1)*RisingFactorial(_k + b + 1, -_k + n)*jacobi(_k, a,
|
||||
b, x)/((-_k + n)*RisingFactorial(_k + a + b + 1, -_k + n)))/(_k + a
|
||||
+ b + n + 1), (_k, 0, n - 1)))
|
||||
assert diff(jacobi(n, a, b, x), b).dummy_eq(Sum(((-1)**(-_k + n)*(2*_k +
|
||||
a + b + 1)*RisingFactorial(_k + a + 1, -_k + n)*jacobi(_k, a, b, x)/
|
||||
((-_k + n)*RisingFactorial(_k + a + b + 1, -_k + n)) + jacobi(n, a,
|
||||
b, x))/(_k + a + b + n + 1), (_k, 0, n - 1)))
|
||||
assert diff(jacobi(n, a, b, x), x) == \
|
||||
(a/2 + b/2 + n/2 + S.Half)*jacobi(n - 1, a + 1, b + 1, x)
|
||||
|
||||
assert jacobi_normalized(n, a, b, x) == \
|
||||
(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))))
|
||||
|
||||
raises(ValueError, lambda: jacobi(-2.1, a, b, x))
|
||||
raises(ValueError, lambda: jacobi(Dummy(positive=True, integer=True), 1, 2, oo))
|
||||
|
||||
assert jacobi(n, a, b, x).rewrite(Sum).dummy_eq(Sum((S.Half - x/2)
|
||||
**_k*RisingFactorial(-n, _k)*RisingFactorial(_k + a + 1, -_k + n)*
|
||||
RisingFactorial(a + b + n + 1, _k)/factorial(_k), (_k, 0, n))/factorial(n))
|
||||
assert jacobi(n, a, b, x).rewrite("polynomial").dummy_eq(Sum((S.Half - x/2)
|
||||
**_k*RisingFactorial(-n, _k)*RisingFactorial(_k + a + 1, -_k + n)*
|
||||
RisingFactorial(a + b + n + 1, _k)/factorial(_k), (_k, 0, n))/factorial(n))
|
||||
raises(ArgumentIndexError, lambda: jacobi(n, a, b, x).fdiff(5))
|
||||
|
||||
|
||||
def test_gegenbauer():
|
||||
n = Symbol("n")
|
||||
a = Symbol("a")
|
||||
|
||||
assert gegenbauer(0, a, x) == 1
|
||||
assert gegenbauer(1, a, x) == 2*a*x
|
||||
assert gegenbauer(2, a, x) == -a + x**2*(2*a**2 + 2*a)
|
||||
assert gegenbauer(3, a, x) == \
|
||||
x**3*(4*a**3/3 + 4*a**2 + a*Rational(8, 3)) + x*(-2*a**2 - 2*a)
|
||||
|
||||
assert gegenbauer(-1, a, x) == 0
|
||||
assert gegenbauer(n, S.Half, x) == legendre(n, x)
|
||||
assert gegenbauer(n, 1, x) == chebyshevu(n, x)
|
||||
assert gegenbauer(n, -1, x) == 0
|
||||
|
||||
X = gegenbauer(n, a, x)
|
||||
assert isinstance(X, gegenbauer)
|
||||
|
||||
assert gegenbauer(n, a, -x) == (-1)**n*gegenbauer(n, a, x)
|
||||
assert gegenbauer(n, a, 0) == 2**n*sqrt(pi) * \
|
||||
gamma(a + n/2)/(gamma(a)*gamma(-n/2 + S.Half)*gamma(n + 1))
|
||||
assert gegenbauer(n, a, 1) == gamma(2*a + n)/(gamma(2*a)*gamma(n + 1))
|
||||
|
||||
assert gegenbauer(n, Rational(3, 4), -1) is zoo
|
||||
assert gegenbauer(n, Rational(1, 4), -1) == (sqrt(2)*cos(pi*(n + S.One/4))*
|
||||
gamma(n + S.Half)/(sqrt(pi)*gamma(n + 1)))
|
||||
|
||||
m = Symbol("m", positive=True)
|
||||
assert gegenbauer(m, a, oo) == oo*RisingFactorial(a, m)
|
||||
assert unchanged(gegenbauer, n, a, oo)
|
||||
|
||||
assert conjugate(gegenbauer(n, a, x)) == gegenbauer(n, conjugate(a), conjugate(x))
|
||||
|
||||
_k = Dummy('k')
|
||||
|
||||
assert diff(gegenbauer(n, a, x), n) == Derivative(gegenbauer(n, a, x), n)
|
||||
assert diff(gegenbauer(n, a, x), a).dummy_eq(Sum((2*(-1)**(-_k + n) + 2)*
|
||||
(_k + a)*gegenbauer(_k, a, x)/((-_k + n)*(_k + 2*a + n)) + ((2*_k +
|
||||
2)/((_k + 2*a)*(2*_k + 2*a + 1)) + 2/(_k + 2*a + n))*gegenbauer(n, a
|
||||
, x), (_k, 0, n - 1)))
|
||||
assert diff(gegenbauer(n, a, x), x) == 2*a*gegenbauer(n - 1, a + 1, x)
|
||||
|
||||
assert gegenbauer(n, a, x).rewrite(Sum).dummy_eq(
|
||||
Sum((-1)**_k*(2*x)**(-2*_k + n)*RisingFactorial(a, -_k + n)
|
||||
/(factorial(_k)*factorial(-2*_k + n)), (_k, 0, floor(n/2))))
|
||||
assert gegenbauer(n, a, x).rewrite("polynomial").dummy_eq(
|
||||
Sum((-1)**_k*(2*x)**(-2*_k + n)*RisingFactorial(a, -_k + n)
|
||||
/(factorial(_k)*factorial(-2*_k + n)), (_k, 0, floor(n/2))))
|
||||
|
||||
raises(ArgumentIndexError, lambda: gegenbauer(n, a, x).fdiff(4))
|
||||
|
||||
|
||||
def test_legendre():
|
||||
assert legendre(0, x) == 1
|
||||
assert legendre(1, x) == x
|
||||
assert legendre(2, x) == ((3*x**2 - 1)/2).expand()
|
||||
assert legendre(3, x) == ((5*x**3 - 3*x)/2).expand()
|
||||
assert legendre(4, x) == ((35*x**4 - 30*x**2 + 3)/8).expand()
|
||||
assert legendre(5, x) == ((63*x**5 - 70*x**3 + 15*x)/8).expand()
|
||||
assert legendre(6, x) == ((231*x**6 - 315*x**4 + 105*x**2 - 5)/16).expand()
|
||||
|
||||
assert legendre(10, -1) == 1
|
||||
assert legendre(11, -1) == -1
|
||||
assert legendre(10, 1) == 1
|
||||
assert legendre(11, 1) == 1
|
||||
assert legendre(10, 0) != 0
|
||||
assert legendre(11, 0) == 0
|
||||
|
||||
assert legendre(-1, x) == 1
|
||||
k = Symbol('k')
|
||||
assert legendre(5 - k, x).subs(k, 2) == ((5*x**3 - 3*x)/2).expand()
|
||||
|
||||
assert roots(legendre(4, x), x) == {
|
||||
sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1,
|
||||
-sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1,
|
||||
sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1,
|
||||
-sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1,
|
||||
}
|
||||
|
||||
n = Symbol("n")
|
||||
|
||||
X = legendre(n, x)
|
||||
assert isinstance(X, legendre)
|
||||
assert unchanged(legendre, n, x)
|
||||
|
||||
assert legendre(n, 0) == sqrt(pi)/(gamma(S.Half - n/2)*gamma(n/2 + 1))
|
||||
assert legendre(n, 1) == 1
|
||||
assert legendre(n, oo) is oo
|
||||
assert legendre(-n, x) == legendre(n - 1, x)
|
||||
assert legendre(n, -x) == (-1)**n*legendre(n, x)
|
||||
assert unchanged(legendre, -n + k, x)
|
||||
|
||||
assert conjugate(legendre(n, x)) == legendre(n, conjugate(x))
|
||||
|
||||
assert diff(legendre(n, x), x) == \
|
||||
n*(x*legendre(n, x) - legendre(n - 1, x))/(x**2 - 1)
|
||||
assert diff(legendre(n, x), n) == Derivative(legendre(n, x), n)
|
||||
|
||||
_k = Dummy('k')
|
||||
assert legendre(n, x).rewrite(Sum).dummy_eq(Sum((-1)**_k*(S.Half -
|
||||
x/2)**_k*(x/2 + S.Half)**(-_k + n)*binomial(n, _k)**2, (_k, 0, n)))
|
||||
assert legendre(n, x).rewrite("polynomial").dummy_eq(Sum((-1)**_k*(S.Half -
|
||||
x/2)**_k*(x/2 + S.Half)**(-_k + n)*binomial(n, _k)**2, (_k, 0, n)))
|
||||
raises(ArgumentIndexError, lambda: legendre(n, x).fdiff(1))
|
||||
raises(ArgumentIndexError, lambda: legendre(n, x).fdiff(3))
|
||||
|
||||
|
||||
def test_assoc_legendre():
|
||||
Plm = assoc_legendre
|
||||
Q = sqrt(1 - x**2)
|
||||
|
||||
assert Plm(0, 0, x) == 1
|
||||
assert Plm(1, 0, x) == x
|
||||
assert Plm(1, 1, x) == -Q
|
||||
assert Plm(2, 0, x) == (3*x**2 - 1)/2
|
||||
assert Plm(2, 1, x) == -3*x*Q
|
||||
assert Plm(2, 2, x) == 3*Q**2
|
||||
assert Plm(3, 0, x) == (5*x**3 - 3*x)/2
|
||||
assert Plm(3, 1, x).expand() == (( 3*(1 - 5*x**2)/2 ).expand() * Q).expand()
|
||||
assert Plm(3, 2, x) == 15*x * Q**2
|
||||
assert Plm(3, 3, x) == -15 * Q**3
|
||||
|
||||
# negative m
|
||||
assert Plm(1, -1, x) == -Plm(1, 1, x)/2
|
||||
assert Plm(2, -2, x) == Plm(2, 2, x)/24
|
||||
assert Plm(2, -1, x) == -Plm(2, 1, x)/6
|
||||
assert Plm(3, -3, x) == -Plm(3, 3, x)/720
|
||||
assert Plm(3, -2, x) == Plm(3, 2, x)/120
|
||||
assert Plm(3, -1, x) == -Plm(3, 1, x)/12
|
||||
|
||||
n = Symbol("n")
|
||||
m = Symbol("m")
|
||||
X = Plm(n, m, x)
|
||||
assert isinstance(X, assoc_legendre)
|
||||
|
||||
assert Plm(n, 0, x) == legendre(n, x)
|
||||
assert Plm(n, m, 0) == 2**m*sqrt(pi)/(gamma(-m/2 - n/2 +
|
||||
S.Half)*gamma(-m/2 + n/2 + 1))
|
||||
|
||||
assert diff(Plm(m, n, x), x) == (m*x*assoc_legendre(m, n, x) -
|
||||
(m + n)*assoc_legendre(m - 1, n, x))/(x**2 - 1)
|
||||
|
||||
_k = Dummy('k')
|
||||
assert Plm(m, n, x).rewrite(Sum).dummy_eq(
|
||||
(1 - x**2)**(n/2)*Sum((-1)**_k*2**(-m)*x**(-2*_k + m - n)*factorial
|
||||
(-2*_k + 2*m)/(factorial(_k)*factorial(-_k + m)*factorial(-2*_k + m
|
||||
- n)), (_k, 0, floor(m/2 - n/2))))
|
||||
assert Plm(m, n, x).rewrite("polynomial").dummy_eq(
|
||||
(1 - x**2)**(n/2)*Sum((-1)**_k*2**(-m)*x**(-2*_k + m - n)*factorial
|
||||
(-2*_k + 2*m)/(factorial(_k)*factorial(-_k + m)*factorial(-2*_k + m
|
||||
- n)), (_k, 0, floor(m/2 - n/2))))
|
||||
assert conjugate(assoc_legendre(n, m, x)) == \
|
||||
assoc_legendre(n, conjugate(m), conjugate(x))
|
||||
raises(ValueError, lambda: Plm(0, 1, x))
|
||||
raises(ValueError, lambda: Plm(-1, 1, x))
|
||||
raises(ArgumentIndexError, lambda: Plm(n, m, x).fdiff(1))
|
||||
raises(ArgumentIndexError, lambda: Plm(n, m, x).fdiff(2))
|
||||
raises(ArgumentIndexError, lambda: Plm(n, m, x).fdiff(4))
|
||||
|
||||
|
||||
def test_chebyshev():
|
||||
assert chebyshevt(0, x) == 1
|
||||
assert chebyshevt(1, x) == x
|
||||
assert chebyshevt(2, x) == 2*x**2 - 1
|
||||
assert chebyshevt(3, x) == 4*x**3 - 3*x
|
||||
|
||||
for n in range(1, 4):
|
||||
for k in range(n):
|
||||
z = chebyshevt_root(n, k)
|
||||
assert chebyshevt(n, z) == 0
|
||||
raises(ValueError, lambda: chebyshevt_root(n, n))
|
||||
|
||||
for n in range(1, 4):
|
||||
for k in range(n):
|
||||
z = chebyshevu_root(n, k)
|
||||
assert chebyshevu(n, z) == 0
|
||||
raises(ValueError, lambda: chebyshevu_root(n, n))
|
||||
|
||||
n = Symbol("n")
|
||||
X = chebyshevt(n, x)
|
||||
assert isinstance(X, chebyshevt)
|
||||
assert unchanged(chebyshevt, n, x)
|
||||
assert chebyshevt(n, -x) == (-1)**n*chebyshevt(n, x)
|
||||
assert chebyshevt(-n, x) == chebyshevt(n, x)
|
||||
|
||||
assert chebyshevt(n, 0) == cos(pi*n/2)
|
||||
assert chebyshevt(n, 1) == 1
|
||||
assert chebyshevt(n, oo) is oo
|
||||
|
||||
assert conjugate(chebyshevt(n, x)) == chebyshevt(n, conjugate(x))
|
||||
|
||||
assert diff(chebyshevt(n, x), x) == n*chebyshevu(n - 1, x)
|
||||
|
||||
X = chebyshevu(n, x)
|
||||
assert isinstance(X, chebyshevu)
|
||||
|
||||
y = Symbol('y')
|
||||
assert chebyshevu(n, -x) == (-1)**n*chebyshevu(n, x)
|
||||
assert chebyshevu(-n, x) == -chebyshevu(n - 2, x)
|
||||
assert unchanged(chebyshevu, -n + y, x)
|
||||
|
||||
assert chebyshevu(n, 0) == cos(pi*n/2)
|
||||
assert chebyshevu(n, 1) == n + 1
|
||||
assert chebyshevu(n, oo) is oo
|
||||
|
||||
assert conjugate(chebyshevu(n, x)) == chebyshevu(n, conjugate(x))
|
||||
|
||||
assert diff(chebyshevu(n, x), x) == \
|
||||
(-x*chebyshevu(n, x) + (n + 1)*chebyshevt(n + 1, x))/(x**2 - 1)
|
||||
|
||||
_k = Dummy('k')
|
||||
assert chebyshevt(n, x).rewrite(Sum).dummy_eq(Sum(x**(-2*_k + n)
|
||||
*(x**2 - 1)**_k*binomial(n, 2*_k), (_k, 0, floor(n/2))))
|
||||
assert chebyshevt(n, x).rewrite("polynomial").dummy_eq(Sum(x**(-2*_k + n)
|
||||
*(x**2 - 1)**_k*binomial(n, 2*_k), (_k, 0, floor(n/2))))
|
||||
assert chebyshevu(n, x).rewrite(Sum).dummy_eq(Sum((-1)**_k*(2*x)
|
||||
**(-2*_k + n)*factorial(-_k + n)/(factorial(_k)*
|
||||
factorial(-2*_k + n)), (_k, 0, floor(n/2))))
|
||||
assert chebyshevu(n, x).rewrite("polynomial").dummy_eq(Sum((-1)**_k*(2*x)
|
||||
**(-2*_k + n)*factorial(-_k + n)/(factorial(_k)*
|
||||
factorial(-2*_k + n)), (_k, 0, floor(n/2))))
|
||||
raises(ArgumentIndexError, lambda: chebyshevt(n, x).fdiff(1))
|
||||
raises(ArgumentIndexError, lambda: chebyshevt(n, x).fdiff(3))
|
||||
raises(ArgumentIndexError, lambda: chebyshevu(n, x).fdiff(1))
|
||||
raises(ArgumentIndexError, lambda: chebyshevu(n, x).fdiff(3))
|
||||
|
||||
|
||||
def test_hermite():
|
||||
assert hermite(0, x) == 1
|
||||
assert hermite(1, x) == 2*x
|
||||
assert hermite(2, x) == 4*x**2 - 2
|
||||
assert hermite(3, x) == 8*x**3 - 12*x
|
||||
assert hermite(4, x) == 16*x**4 - 48*x**2 + 12
|
||||
assert hermite(6, x) == 64*x**6 - 480*x**4 + 720*x**2 - 120
|
||||
|
||||
n = Symbol("n")
|
||||
assert unchanged(hermite, n, x)
|
||||
assert hermite(n, -x) == (-1)**n*hermite(n, x)
|
||||
assert unchanged(hermite, -n, x)
|
||||
|
||||
assert hermite(n, 0) == 2**n*sqrt(pi)/gamma(S.Half - n/2)
|
||||
assert hermite(n, oo) is oo
|
||||
|
||||
assert conjugate(hermite(n, x)) == hermite(n, conjugate(x))
|
||||
|
||||
_k = Dummy('k')
|
||||
assert hermite(n, x).rewrite(Sum).dummy_eq(factorial(n)*Sum((-1)
|
||||
**_k*(2*x)**(-2*_k + n)/(factorial(_k)*factorial(-2*_k + n)), (_k,
|
||||
0, floor(n/2))))
|
||||
assert hermite(n, x).rewrite("polynomial").dummy_eq(factorial(n)*Sum((-1)
|
||||
**_k*(2*x)**(-2*_k + n)/(factorial(_k)*factorial(-2*_k + n)), (_k,
|
||||
0, floor(n/2))))
|
||||
|
||||
assert diff(hermite(n, x), x) == 2*n*hermite(n - 1, x)
|
||||
assert diff(hermite(n, x), n) == Derivative(hermite(n, x), n)
|
||||
raises(ArgumentIndexError, lambda: hermite(n, x).fdiff(3))
|
||||
|
||||
assert hermite(n, x).rewrite(hermite_prob) == \
|
||||
sqrt(2)**n * hermite_prob(n, x*sqrt(2))
|
||||
|
||||
|
||||
def test_hermite_prob():
|
||||
assert hermite_prob(0, x) == 1
|
||||
assert hermite_prob(1, x) == x
|
||||
assert hermite_prob(2, x) == x**2 - 1
|
||||
assert hermite_prob(3, x) == x**3 - 3*x
|
||||
assert hermite_prob(4, x) == x**4 - 6*x**2 + 3
|
||||
assert hermite_prob(6, x) == x**6 - 15*x**4 + 45*x**2 - 15
|
||||
|
||||
n = Symbol("n")
|
||||
assert unchanged(hermite_prob, n, x)
|
||||
assert hermite_prob(n, -x) == (-1)**n*hermite_prob(n, x)
|
||||
assert unchanged(hermite_prob, -n, x)
|
||||
|
||||
assert hermite_prob(n, 0) == sqrt(pi)/gamma(S.Half - n/2)
|
||||
assert hermite_prob(n, oo) is oo
|
||||
|
||||
assert conjugate(hermite_prob(n, x)) == hermite_prob(n, conjugate(x))
|
||||
|
||||
_k = Dummy('k')
|
||||
assert hermite_prob(n, x).rewrite(Sum).dummy_eq(factorial(n) *
|
||||
Sum((-S.Half)**_k * x**(n-2*_k) / (factorial(_k) * factorial(n-2*_k)),
|
||||
(_k, 0, floor(n/2))))
|
||||
assert hermite_prob(n, x).rewrite("polynomial").dummy_eq(factorial(n) *
|
||||
Sum((-S.Half)**_k * x**(n-2*_k) / (factorial(_k) * factorial(n-2*_k)),
|
||||
(_k, 0, floor(n/2))))
|
||||
|
||||
assert diff(hermite_prob(n, x), x) == n*hermite_prob(n-1, x)
|
||||
assert diff(hermite_prob(n, x), n) == Derivative(hermite_prob(n, x), n)
|
||||
raises(ArgumentIndexError, lambda: hermite_prob(n, x).fdiff(3))
|
||||
|
||||
assert hermite_prob(n, x).rewrite(hermite) == \
|
||||
sqrt(2)**(-n) * hermite(n, x/sqrt(2))
|
||||
|
||||
|
||||
def test_laguerre():
|
||||
n = Symbol("n")
|
||||
m = Symbol("m", negative=True)
|
||||
|
||||
# Laguerre polynomials:
|
||||
assert laguerre(0, x) == 1
|
||||
assert laguerre(1, x) == -x + 1
|
||||
assert laguerre(2, x) == x**2/2 - 2*x + 1
|
||||
assert laguerre(3, x) == -x**3/6 + 3*x**2/2 - 3*x + 1
|
||||
assert laguerre(-2, x) == (x + 1)*exp(x)
|
||||
|
||||
X = laguerre(n, x)
|
||||
assert isinstance(X, laguerre)
|
||||
|
||||
assert laguerre(n, 0) == 1
|
||||
assert laguerre(n, oo) == (-1)**n*oo
|
||||
assert laguerre(n, -oo) is oo
|
||||
|
||||
assert conjugate(laguerre(n, x)) == laguerre(n, conjugate(x))
|
||||
|
||||
_k = Dummy('k')
|
||||
|
||||
assert laguerre(n, x).rewrite(Sum).dummy_eq(
|
||||
Sum(x**_k*RisingFactorial(-n, _k)/factorial(_k)**2, (_k, 0, n)))
|
||||
assert laguerre(n, x).rewrite("polynomial").dummy_eq(
|
||||
Sum(x**_k*RisingFactorial(-n, _k)/factorial(_k)**2, (_k, 0, n)))
|
||||
assert laguerre(m, x).rewrite(Sum).dummy_eq(
|
||||
exp(x)*Sum((-x)**_k*RisingFactorial(m + 1, _k)/factorial(_k)**2,
|
||||
(_k, 0, -m - 1)))
|
||||
assert laguerre(m, x).rewrite("polynomial").dummy_eq(
|
||||
exp(x)*Sum((-x)**_k*RisingFactorial(m + 1, _k)/factorial(_k)**2,
|
||||
(_k, 0, -m - 1)))
|
||||
|
||||
assert diff(laguerre(n, x), x) == -assoc_laguerre(n - 1, 1, x)
|
||||
|
||||
k = Symbol('k')
|
||||
assert laguerre(-n, x) == exp(x)*laguerre(n - 1, -x)
|
||||
assert laguerre(-3, x) == exp(x)*laguerre(2, -x)
|
||||
assert unchanged(laguerre, -n + k, x)
|
||||
|
||||
raises(ValueError, lambda: laguerre(-2.1, x))
|
||||
raises(ValueError, lambda: laguerre(Rational(5, 2), x))
|
||||
raises(ArgumentIndexError, lambda: laguerre(n, x).fdiff(1))
|
||||
raises(ArgumentIndexError, lambda: laguerre(n, x).fdiff(3))
|
||||
|
||||
|
||||
def test_assoc_laguerre():
|
||||
n = Symbol("n")
|
||||
m = Symbol("m")
|
||||
alpha = Symbol("alpha")
|
||||
|
||||
# generalized Laguerre polynomials:
|
||||
assert assoc_laguerre(0, alpha, x) == 1
|
||||
assert assoc_laguerre(1, alpha, x) == -x + alpha + 1
|
||||
assert assoc_laguerre(2, alpha, x).expand() == \
|
||||
(x**2/2 - (alpha + 2)*x + (alpha + 2)*(alpha + 1)/2).expand()
|
||||
assert assoc_laguerre(3, alpha, x).expand() == \
|
||||
(-x**3/6 + (alpha + 3)*x**2/2 - (alpha + 2)*(alpha + 3)*x/2 +
|
||||
(alpha + 1)*(alpha + 2)*(alpha + 3)/6).expand()
|
||||
|
||||
# Test the lowest 10 polynomials with laguerre_poly, to make sure it works:
|
||||
for i in range(10):
|
||||
assert assoc_laguerre(i, 0, x).expand() == laguerre_poly(i, x)
|
||||
|
||||
X = assoc_laguerre(n, m, x)
|
||||
assert isinstance(X, assoc_laguerre)
|
||||
|
||||
assert assoc_laguerre(n, 0, x) == laguerre(n, x)
|
||||
assert assoc_laguerre(n, alpha, 0) == binomial(alpha + n, alpha)
|
||||
p = Symbol("p", positive=True)
|
||||
assert assoc_laguerre(p, alpha, oo) == (-1)**p*oo
|
||||
assert assoc_laguerre(p, alpha, -oo) is oo
|
||||
|
||||
assert diff(assoc_laguerre(n, alpha, x), x) == \
|
||||
-assoc_laguerre(n - 1, alpha + 1, x)
|
||||
_k = Dummy('k')
|
||||
assert diff(assoc_laguerre(n, alpha, x), alpha).dummy_eq(
|
||||
Sum(assoc_laguerre(_k, alpha, x)/(-alpha + n), (_k, 0, n - 1)))
|
||||
|
||||
assert conjugate(assoc_laguerre(n, alpha, x)) == \
|
||||
assoc_laguerre(n, conjugate(alpha), conjugate(x))
|
||||
|
||||
assert assoc_laguerre(n, alpha, x).rewrite(Sum).dummy_eq(
|
||||
gamma(alpha + n + 1)*Sum(x**_k*RisingFactorial(-n, _k)/
|
||||
(factorial(_k)*gamma(_k + alpha + 1)), (_k, 0, n))/factorial(n))
|
||||
assert assoc_laguerre(n, alpha, x).rewrite("polynomial").dummy_eq(
|
||||
gamma(alpha + n + 1)*Sum(x**_k*RisingFactorial(-n, _k)/
|
||||
(factorial(_k)*gamma(_k + alpha + 1)), (_k, 0, n))/factorial(n))
|
||||
raises(ValueError, lambda: assoc_laguerre(-2.1, alpha, x))
|
||||
raises(ArgumentIndexError, lambda: assoc_laguerre(n, alpha, x).fdiff(1))
|
||||
raises(ArgumentIndexError, lambda: assoc_laguerre(n, alpha, x).fdiff(4))
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
from sympy.core.function import diff
|
||||
from sympy.core.numbers import (I, pi)
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.elementary.complexes import conjugate
|
||||
from sympy.functions.elementary.exponential import exp
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, cot, sin)
|
||||
from sympy.functions.special.spherical_harmonics import Ynm, Znm, Ynm_c
|
||||
|
||||
|
||||
def test_Ynm():
|
||||
# https://en.wikipedia.org/wiki/Spherical_harmonics
|
||||
th, ph = Symbol("theta", real=True), Symbol("phi", real=True)
|
||||
from sympy.abc import n,m
|
||||
|
||||
assert Ynm(0, 0, th, ph).expand(func=True) == 1/(2*sqrt(pi))
|
||||
assert Ynm(1, -1, th, ph) == -exp(-2*I*ph)*Ynm(1, 1, th, ph)
|
||||
assert Ynm(1, -1, th, ph).expand(func=True) == sqrt(6)*sin(th)*exp(-I*ph)/(4*sqrt(pi))
|
||||
assert Ynm(1, 0, th, ph).expand(func=True) == sqrt(3)*cos(th)/(2*sqrt(pi))
|
||||
assert Ynm(1, 1, th, ph).expand(func=True) == -sqrt(6)*sin(th)*exp(I*ph)/(4*sqrt(pi))
|
||||
assert Ynm(2, 0, th, ph).expand(func=True) == 3*sqrt(5)*cos(th)**2/(4*sqrt(pi)) - sqrt(5)/(4*sqrt(pi))
|
||||
assert Ynm(2, 1, th, ph).expand(func=True) == -sqrt(30)*sin(th)*exp(I*ph)*cos(th)/(4*sqrt(pi))
|
||||
assert Ynm(2, -2, th, ph).expand(func=True) == (-sqrt(30)*exp(-2*I*ph)*cos(th)**2/(8*sqrt(pi))
|
||||
+ sqrt(30)*exp(-2*I*ph)/(8*sqrt(pi)))
|
||||
assert Ynm(2, 2, th, ph).expand(func=True) == (-sqrt(30)*exp(2*I*ph)*cos(th)**2/(8*sqrt(pi))
|
||||
+ sqrt(30)*exp(2*I*ph)/(8*sqrt(pi)))
|
||||
|
||||
assert diff(Ynm(n, m, th, ph), th) == (m*cot(th)*Ynm(n, m, th, ph)
|
||||
+ sqrt((-m + n)*(m + n + 1))*exp(-I*ph)*Ynm(n, m + 1, th, ph))
|
||||
assert diff(Ynm(n, m, th, ph), ph) == I*m*Ynm(n, m, th, ph)
|
||||
|
||||
assert conjugate(Ynm(n, m, th, ph)) == (-1)**(2*m)*exp(-2*I*m*ph)*Ynm(n, m, th, ph)
|
||||
|
||||
assert Ynm(n, m, -th, ph) == Ynm(n, m, th, ph)
|
||||
assert Ynm(n, m, th, -ph) == exp(-2*I*m*ph)*Ynm(n, m, th, ph)
|
||||
assert Ynm(n, -m, th, ph) == (-1)**m*exp(-2*I*m*ph)*Ynm(n, m, th, ph)
|
||||
|
||||
|
||||
def test_Ynm_c():
|
||||
th, ph = Symbol("theta", real=True), Symbol("phi", real=True)
|
||||
from sympy.abc import n,m
|
||||
|
||||
assert Ynm_c(n, m, th, ph) == (-1)**(2*m)*exp(-2*I*m*ph)*Ynm(n, m, th, ph)
|
||||
|
||||
|
||||
def test_Znm():
|
||||
# https://en.wikipedia.org/wiki/Solid_harmonics#List_of_lowest_functions
|
||||
th, ph = Symbol("theta", real=True), Symbol("phi", real=True)
|
||||
|
||||
assert Znm(0, 0, th, ph) == Ynm(0, 0, th, ph)
|
||||
assert Znm(1, -1, th, ph) == (-sqrt(2)*I*(Ynm(1, 1, th, ph)
|
||||
- exp(-2*I*ph)*Ynm(1, 1, th, ph))/2)
|
||||
assert Znm(1, 0, th, ph) == Ynm(1, 0, th, ph)
|
||||
assert Znm(1, 1, th, ph) == (sqrt(2)*(Ynm(1, 1, th, ph)
|
||||
+ exp(-2*I*ph)*Ynm(1, 1, th, ph))/2)
|
||||
assert Znm(0, 0, th, ph).expand(func=True) == 1/(2*sqrt(pi))
|
||||
assert Znm(1, -1, th, ph).expand(func=True) == (sqrt(3)*I*sin(th)*exp(I*ph)/(4*sqrt(pi))
|
||||
- sqrt(3)*I*sin(th)*exp(-I*ph)/(4*sqrt(pi)))
|
||||
assert Znm(1, 0, th, ph).expand(func=True) == sqrt(3)*cos(th)/(2*sqrt(pi))
|
||||
assert Znm(1, 1, th, ph).expand(func=True) == (-sqrt(3)*sin(th)*exp(I*ph)/(4*sqrt(pi))
|
||||
- sqrt(3)*sin(th)*exp(-I*ph)/(4*sqrt(pi)))
|
||||
assert Znm(2, -1, th, ph).expand(func=True) == (sqrt(15)*I*sin(th)*exp(I*ph)*cos(th)/(4*sqrt(pi))
|
||||
- sqrt(15)*I*sin(th)*exp(-I*ph)*cos(th)/(4*sqrt(pi)))
|
||||
assert Znm(2, 0, th, ph).expand(func=True) == 3*sqrt(5)*cos(th)**2/(4*sqrt(pi)) - sqrt(5)/(4*sqrt(pi))
|
||||
assert Znm(2, 1, th, ph).expand(func=True) == (-sqrt(15)*sin(th)*exp(I*ph)*cos(th)/(4*sqrt(pi))
|
||||
- sqrt(15)*sin(th)*exp(-I*ph)*cos(th)/(4*sqrt(pi)))
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
from sympy.core.relational import Ne
|
||||
from sympy.core.symbol import (Dummy, Symbol, symbols)
|
||||
from sympy.functions.elementary.complexes import (adjoint, conjugate, transpose)
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.special.tensor_functions import (Eijk, KroneckerDelta, LeviCivita)
|
||||
|
||||
from sympy.physics.secondquant import evaluate_deltas, F
|
||||
|
||||
x, y = symbols('x y')
|
||||
|
||||
|
||||
def test_levicivita():
|
||||
assert Eijk(1, 2, 3) == LeviCivita(1, 2, 3)
|
||||
assert LeviCivita(1, 2, 3) == 1
|
||||
assert LeviCivita(int(1), int(2), int(3)) == 1
|
||||
assert LeviCivita(1, 3, 2) == -1
|
||||
assert LeviCivita(1, 2, 2) == 0
|
||||
i, j, k = symbols('i j k')
|
||||
assert LeviCivita(i, j, k) == LeviCivita(i, j, k, evaluate=False)
|
||||
assert LeviCivita(i, j, i) == 0
|
||||
assert LeviCivita(1, i, i) == 0
|
||||
assert LeviCivita(i, j, k).doit() == (j - i)*(k - i)*(k - j)/2
|
||||
assert LeviCivita(1, 2, 3, 1) == 0
|
||||
assert LeviCivita(4, 5, 1, 2, 3) == 1
|
||||
assert LeviCivita(4, 5, 2, 1, 3) == -1
|
||||
|
||||
assert LeviCivita(i, j, k).is_integer is True
|
||||
|
||||
assert adjoint(LeviCivita(i, j, k)) == LeviCivita(i, j, k)
|
||||
assert conjugate(LeviCivita(i, j, k)) == LeviCivita(i, j, k)
|
||||
assert transpose(LeviCivita(i, j, k)) == LeviCivita(i, j, k)
|
||||
|
||||
|
||||
def test_kronecker_delta():
|
||||
i, j = symbols('i j')
|
||||
k = Symbol('k', nonzero=True)
|
||||
assert KroneckerDelta(1, 1) == 1
|
||||
assert KroneckerDelta(1, 2) == 0
|
||||
assert KroneckerDelta(k, 0) == 0
|
||||
assert KroneckerDelta(x, x) == 1
|
||||
assert KroneckerDelta(x**2 - y**2, x**2 - y**2) == 1
|
||||
assert KroneckerDelta(i, i) == 1
|
||||
assert KroneckerDelta(i, i + 1) == 0
|
||||
assert KroneckerDelta(0, 0) == 1
|
||||
assert KroneckerDelta(0, 1) == 0
|
||||
assert KroneckerDelta(i + k, i) == 0
|
||||
assert KroneckerDelta(i + k, i + k) == 1
|
||||
assert KroneckerDelta(i + k, i + 1 + k) == 0
|
||||
assert KroneckerDelta(i, j).subs({"i": 1, "j": 0}) == 0
|
||||
assert KroneckerDelta(i, j).subs({"i": 3, "j": 3}) == 1
|
||||
|
||||
assert KroneckerDelta(i, j)**0 == 1
|
||||
for n in range(1, 10):
|
||||
assert KroneckerDelta(i, j)**n == KroneckerDelta(i, j)
|
||||
assert KroneckerDelta(i, j)**-n == 1/KroneckerDelta(i, j)
|
||||
|
||||
assert KroneckerDelta(i, j).is_integer is True
|
||||
|
||||
assert adjoint(KroneckerDelta(i, j)) == KroneckerDelta(i, j)
|
||||
assert conjugate(KroneckerDelta(i, j)) == KroneckerDelta(i, j)
|
||||
assert transpose(KroneckerDelta(i, j)) == KroneckerDelta(i, j)
|
||||
# to test if canonical
|
||||
assert (KroneckerDelta(i, j) == KroneckerDelta(j, i)) == True
|
||||
|
||||
assert KroneckerDelta(i, j).rewrite(Piecewise) == Piecewise((0, Ne(i, j)), (1, True))
|
||||
|
||||
# Tests with range:
|
||||
assert KroneckerDelta(i, j, (0, i)).args == (i, j, (0, i))
|
||||
assert KroneckerDelta(i, j, (-j, i)).delta_range == (-j, i)
|
||||
|
||||
# If index is out of range, return zero:
|
||||
assert KroneckerDelta(i, j, (0, i-1)) == 0
|
||||
assert KroneckerDelta(-1, j, (0, i-1)) == 0
|
||||
assert KroneckerDelta(j, -1, (0, i-1)) == 0
|
||||
assert KroneckerDelta(j, i, (0, i-1)) == 0
|
||||
|
||||
|
||||
def test_kronecker_delta_secondquant():
|
||||
"""secondquant-specific methods"""
|
||||
D = KroneckerDelta
|
||||
i, j, v, w = symbols('i j v w', below_fermi=True, cls=Dummy)
|
||||
a, b, t, u = symbols('a b t u', above_fermi=True, cls=Dummy)
|
||||
p, q, r, s = symbols('p q r s', cls=Dummy)
|
||||
|
||||
assert D(i, a) == 0
|
||||
assert D(i, t) == 0
|
||||
|
||||
assert D(i, j).is_above_fermi is False
|
||||
assert D(a, b).is_above_fermi is True
|
||||
assert D(p, q).is_above_fermi is True
|
||||
assert D(i, q).is_above_fermi is False
|
||||
assert D(q, i).is_above_fermi is False
|
||||
assert D(q, v).is_above_fermi is False
|
||||
assert D(a, q).is_above_fermi is True
|
||||
|
||||
assert D(i, j).is_below_fermi is True
|
||||
assert D(a, b).is_below_fermi is False
|
||||
assert D(p, q).is_below_fermi is True
|
||||
assert D(p, j).is_below_fermi is True
|
||||
assert D(q, b).is_below_fermi is False
|
||||
|
||||
assert D(i, j).is_only_above_fermi is False
|
||||
assert D(a, b).is_only_above_fermi is True
|
||||
assert D(p, q).is_only_above_fermi is False
|
||||
assert D(i, q).is_only_above_fermi is False
|
||||
assert D(q, i).is_only_above_fermi is False
|
||||
assert D(a, q).is_only_above_fermi is True
|
||||
|
||||
assert D(i, j).is_only_below_fermi is True
|
||||
assert D(a, b).is_only_below_fermi is False
|
||||
assert D(p, q).is_only_below_fermi is False
|
||||
assert D(p, j).is_only_below_fermi is True
|
||||
assert D(q, b).is_only_below_fermi is False
|
||||
|
||||
assert not D(i, q).indices_contain_equal_information
|
||||
assert not D(a, q).indices_contain_equal_information
|
||||
assert D(p, q).indices_contain_equal_information
|
||||
assert D(a, b).indices_contain_equal_information
|
||||
assert D(i, j).indices_contain_equal_information
|
||||
|
||||
assert D(q, b).preferred_index == b
|
||||
assert D(q, b).killable_index == q
|
||||
assert D(q, t).preferred_index == t
|
||||
assert D(q, t).killable_index == q
|
||||
assert D(q, i).preferred_index == i
|
||||
assert D(q, i).killable_index == q
|
||||
assert D(q, v).preferred_index == v
|
||||
assert D(q, v).killable_index == q
|
||||
assert D(q, p).preferred_index == p
|
||||
assert D(q, p).killable_index == q
|
||||
|
||||
EV = evaluate_deltas
|
||||
assert EV(D(a, q)*F(q)) == F(a)
|
||||
assert EV(D(i, q)*F(q)) == F(i)
|
||||
assert EV(D(a, q)*F(a)) == D(a, q)*F(a)
|
||||
assert EV(D(i, q)*F(i)) == D(i, q)*F(i)
|
||||
assert EV(D(a, b)*F(a)) == F(b)
|
||||
assert EV(D(a, b)*F(b)) == F(a)
|
||||
assert EV(D(i, j)*F(i)) == F(j)
|
||||
assert EV(D(i, j)*F(j)) == F(i)
|
||||
assert EV(D(p, q)*F(q)) == F(p)
|
||||
assert EV(D(p, q)*F(p)) == F(q)
|
||||
assert EV(D(p, j)*D(p, i)*F(i)) == F(j)
|
||||
assert EV(D(p, j)*D(p, i)*F(j)) == F(i)
|
||||
assert EV(D(p, q)*D(p, i))*F(i) == D(q, i)*F(i)
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.function import expand_func
|
||||
from sympy.core.numbers import (Float, I, Rational, nan, oo, pi, zoo)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.elementary.complexes import (Abs, polar_lift)
|
||||
from sympy.functions.elementary.exponential import (exp, exp_polar, log)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.special.zeta_functions import (dirichlet_eta, lerchphi, polylog, riemann_xi, stieltjes, zeta)
|
||||
from sympy.series.order import O
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.functions.combinatorial.numbers import bernoulli, factorial, genocchi, harmonic
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.random import (test_derivative_numerically as td,
|
||||
random_complex_number as randcplx, verify_numerically)
|
||||
|
||||
x = Symbol('x')
|
||||
a = Symbol('a')
|
||||
b = Symbol('b', negative=True)
|
||||
z = Symbol('z')
|
||||
s = Symbol('s')
|
||||
|
||||
|
||||
def test_zeta_eval():
|
||||
|
||||
assert zeta(nan) is nan
|
||||
assert zeta(x, nan) is nan
|
||||
|
||||
assert zeta(0) == Rational(-1, 2)
|
||||
assert zeta(0, x) == S.Half - x
|
||||
assert zeta(0, b) == S.Half - b
|
||||
|
||||
assert zeta(1) is zoo
|
||||
assert zeta(1, 2) is zoo
|
||||
assert zeta(1, -7) is zoo
|
||||
assert zeta(1, x) is zoo
|
||||
|
||||
assert zeta(2, 1) == pi**2/6
|
||||
assert zeta(3, 1) == zeta(3)
|
||||
|
||||
assert zeta(2) == pi**2/6
|
||||
assert zeta(4) == pi**4/90
|
||||
assert zeta(6) == pi**6/945
|
||||
|
||||
assert zeta(4, 3) == pi**4/90 - Rational(17, 16)
|
||||
assert zeta(7, 4) == zeta(7) - Rational(282251, 279936)
|
||||
assert zeta(S.Half, 2).func == zeta
|
||||
assert expand_func(zeta(S.Half, 2)) == zeta(S.Half) - 1
|
||||
assert zeta(x, 3).func == zeta
|
||||
assert expand_func(zeta(x, 3)) == zeta(x) - 1 - 1/2**x
|
||||
|
||||
assert zeta(2, 0) is nan
|
||||
assert zeta(3, -1) is nan
|
||||
assert zeta(4, -2) is nan
|
||||
|
||||
assert zeta(oo) == 1
|
||||
|
||||
assert zeta(-1) == Rational(-1, 12)
|
||||
assert zeta(-2) == 0
|
||||
assert zeta(-3) == Rational(1, 120)
|
||||
assert zeta(-4) == 0
|
||||
assert zeta(-5) == Rational(-1, 252)
|
||||
|
||||
assert zeta(-1, 3) == Rational(-37, 12)
|
||||
assert zeta(-1, 7) == Rational(-253, 12)
|
||||
assert zeta(-1, -4) == Rational(-121, 12)
|
||||
assert zeta(-1, -9) == Rational(-541, 12)
|
||||
|
||||
assert zeta(-4, 3) == -17
|
||||
assert zeta(-4, -8) == 8772
|
||||
|
||||
assert zeta(0, 1) == Rational(-1, 2)
|
||||
assert zeta(0, -1) == Rational(3, 2)
|
||||
|
||||
assert zeta(0, 2) == Rational(-3, 2)
|
||||
assert zeta(0, -2) == Rational(5, 2)
|
||||
|
||||
assert zeta(
|
||||
3).evalf(20).epsilon_eq(Float("1.2020569031595942854", 20), 1e-19)
|
||||
|
||||
|
||||
def test_zeta_series():
|
||||
assert zeta(x, a).series(a, z, 2) == \
|
||||
zeta(x, z) - x*(a-z)*zeta(x+1, z) + O((a-z)**2, (a, z))
|
||||
|
||||
|
||||
def test_dirichlet_eta_eval():
|
||||
assert dirichlet_eta(0) == S.Half
|
||||
assert dirichlet_eta(-1) == Rational(1, 4)
|
||||
assert dirichlet_eta(1) == log(2)
|
||||
assert dirichlet_eta(1, S.Half).simplify() == pi/2
|
||||
assert dirichlet_eta(1, 2) == 1 - log(2)
|
||||
assert dirichlet_eta(2) == pi**2/12
|
||||
assert dirichlet_eta(4) == pi**4*Rational(7, 720)
|
||||
assert str(dirichlet_eta(I).evalf(n=10)) == '0.5325931818 + 0.2293848577*I'
|
||||
assert str(dirichlet_eta(I, I).evalf(n=10)) == '3.462349253 + 0.220285771*I'
|
||||
|
||||
|
||||
def test_riemann_xi_eval():
|
||||
assert riemann_xi(2) == pi/6
|
||||
assert riemann_xi(0) == Rational(1, 2)
|
||||
assert riemann_xi(1) == Rational(1, 2)
|
||||
assert riemann_xi(3).rewrite(zeta) == 3*zeta(3)/(2*pi)
|
||||
assert riemann_xi(4) == pi**2/15
|
||||
|
||||
|
||||
def test_rewriting():
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
assert isinstance(dirichlet_eta(x).rewrite(zeta), Piecewise)
|
||||
assert isinstance(dirichlet_eta(x).rewrite(genocchi), Piecewise)
|
||||
assert zeta(x).rewrite(dirichlet_eta) == dirichlet_eta(x)/(1 - 2**(1 - x))
|
||||
assert zeta(x).rewrite(dirichlet_eta, a=2) == zeta(x)
|
||||
assert verify_numerically(dirichlet_eta(x), dirichlet_eta(x).rewrite(zeta), x)
|
||||
assert verify_numerically(dirichlet_eta(x), dirichlet_eta(x).rewrite(genocchi), x)
|
||||
assert verify_numerically(zeta(x), zeta(x).rewrite(dirichlet_eta), x)
|
||||
|
||||
assert zeta(x, a).rewrite(lerchphi) == lerchphi(1, x, a)
|
||||
assert polylog(s, z).rewrite(lerchphi) == lerchphi(z, s, 1)*z
|
||||
|
||||
assert lerchphi(1, x, a).rewrite(zeta) == zeta(x, a)
|
||||
assert z*lerchphi(z, s, 1).rewrite(polylog) == polylog(s, z)
|
||||
|
||||
|
||||
def test_derivatives():
|
||||
from sympy.core.function import Derivative
|
||||
assert zeta(x, a).diff(x) == Derivative(zeta(x, a), x)
|
||||
assert zeta(x, a).diff(a) == -x*zeta(x + 1, a)
|
||||
assert lerchphi(
|
||||
z, s, a).diff(z) == (lerchphi(z, s - 1, a) - a*lerchphi(z, s, a))/z
|
||||
assert lerchphi(z, s, a).diff(a) == -s*lerchphi(z, s + 1, a)
|
||||
assert polylog(s, z).diff(z) == polylog(s - 1, z)/z
|
||||
|
||||
b = randcplx()
|
||||
c = randcplx()
|
||||
assert td(zeta(b, x), x)
|
||||
assert td(polylog(b, z), z)
|
||||
assert td(lerchphi(c, b, x), x)
|
||||
assert td(lerchphi(x, b, c), x)
|
||||
raises(ArgumentIndexError, lambda: lerchphi(c, b, x).fdiff(2))
|
||||
raises(ArgumentIndexError, lambda: lerchphi(c, b, x).fdiff(4))
|
||||
raises(ArgumentIndexError, lambda: polylog(b, z).fdiff(1))
|
||||
raises(ArgumentIndexError, lambda: polylog(b, z).fdiff(3))
|
||||
|
||||
|
||||
def myexpand(func, target):
|
||||
expanded = expand_func(func)
|
||||
if target is not None:
|
||||
return expanded == target
|
||||
if expanded == func: # it didn't expand
|
||||
return False
|
||||
|
||||
# check to see that the expanded and original evaluate to the same value
|
||||
subs = {}
|
||||
for a in func.free_symbols:
|
||||
subs[a] = randcplx()
|
||||
return abs(func.subs(subs).n()
|
||||
- expanded.replace(exp_polar, exp).subs(subs).n()) < 1e-10
|
||||
|
||||
|
||||
def test_polylog_expansion():
|
||||
assert polylog(s, 0) == 0
|
||||
assert polylog(s, 1) == zeta(s)
|
||||
assert polylog(s, -1) == -dirichlet_eta(s)
|
||||
assert polylog(s, exp_polar(I*pi*Rational(4, 3))) == polylog(s, exp(I*pi*Rational(4, 3)))
|
||||
assert polylog(s, exp_polar(I*pi)/3) == polylog(s, exp(I*pi)/3)
|
||||
|
||||
assert myexpand(polylog(1, z), -log(1 - z))
|
||||
assert myexpand(polylog(0, z), z/(1 - z))
|
||||
assert myexpand(polylog(-1, z), z/(1 - z)**2)
|
||||
assert ((1-z)**3 * expand_func(polylog(-2, z))).simplify() == z*(1 + z)
|
||||
assert myexpand(polylog(-5, z), None)
|
||||
|
||||
|
||||
def test_polylog_series():
|
||||
assert polylog(1, z).series(z, n=5) == z + z**2/2 + z**3/3 + z**4/4 + O(z**5)
|
||||
assert polylog(1, sqrt(z)).series(z, n=3) == z/2 + z**2/4 + sqrt(z)\
|
||||
+ z**(S(3)/2)/3 + z**(S(5)/2)/5 + O(z**3)
|
||||
|
||||
# https://github.com/sympy/sympy/issues/9497
|
||||
assert polylog(S(3)/2, -z).series(z, 0, 5) == -z + sqrt(2)*z**2/4\
|
||||
- sqrt(3)*z**3/9 + z**4/8 + O(z**5)
|
||||
|
||||
|
||||
def test_issue_8404():
|
||||
i = Symbol('i', integer=True)
|
||||
assert Abs(Sum(1/(3*i + 1)**2, (i, 0, S.Infinity)).doit().n(4)
|
||||
- 1.122) < 0.001
|
||||
|
||||
|
||||
def test_polylog_values():
|
||||
assert polylog(2, 2) == pi**2/4 - I*pi*log(2)
|
||||
assert polylog(2, S.Half) == pi**2/12 - log(2)**2/2
|
||||
for z in [S.Half, 2, (sqrt(5)-1)/2, -(sqrt(5)-1)/2, -(sqrt(5)+1)/2, (3-sqrt(5))/2]:
|
||||
assert Abs(polylog(2, z).evalf() - polylog(2, z, evaluate=False).evalf()) < 1e-15
|
||||
z = Symbol("z")
|
||||
for s in [-1, 0]:
|
||||
for _ in range(10):
|
||||
assert verify_numerically(polylog(s, z), polylog(s, z, evaluate=False),
|
||||
z, a=-3, b=-2, c=S.Half, d=2)
|
||||
assert verify_numerically(polylog(s, z), polylog(s, z, evaluate=False),
|
||||
z, a=2, b=-2, c=5, d=2)
|
||||
|
||||
from sympy.integrals.integrals import Integral
|
||||
assert polylog(0, Integral(1, (x, 0, 1))) == -S.Half
|
||||
|
||||
|
||||
def test_lerchphi_expansion():
|
||||
assert myexpand(lerchphi(1, s, a), zeta(s, a))
|
||||
assert myexpand(lerchphi(z, s, 1), polylog(s, z)/z)
|
||||
|
||||
# direct summation
|
||||
assert myexpand(lerchphi(z, -1, a), a/(1 - z) + z/(1 - z)**2)
|
||||
assert myexpand(lerchphi(z, -3, a), None)
|
||||
# polylog reduction
|
||||
assert myexpand(lerchphi(z, s, S.Half),
|
||||
2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z)
|
||||
- polylog(s, polar_lift(-1)*sqrt(z))/sqrt(z)))
|
||||
assert myexpand(lerchphi(z, s, 2), -1/z + polylog(s, z)/z**2)
|
||||
assert myexpand(lerchphi(z, s, Rational(3, 2)), None)
|
||||
assert myexpand(lerchphi(z, s, Rational(7, 3)), None)
|
||||
assert myexpand(lerchphi(z, s, Rational(-1, 3)), None)
|
||||
assert myexpand(lerchphi(z, s, Rational(-5, 2)), None)
|
||||
|
||||
# hurwitz zeta reduction
|
||||
assert myexpand(lerchphi(-1, s, a),
|
||||
2**(-s)*zeta(s, a/2) - 2**(-s)*zeta(s, (a + 1)/2))
|
||||
assert myexpand(lerchphi(I, s, a), None)
|
||||
assert myexpand(lerchphi(-I, s, a), None)
|
||||
assert myexpand(lerchphi(exp(I*pi*Rational(2, 5)), s, a), None)
|
||||
|
||||
|
||||
def test_stieltjes():
|
||||
assert isinstance(stieltjes(x), stieltjes)
|
||||
assert isinstance(stieltjes(x, a), stieltjes)
|
||||
|
||||
# Zero'th constant EulerGamma
|
||||
assert stieltjes(0) == S.EulerGamma
|
||||
assert stieltjes(0, 1) == S.EulerGamma
|
||||
|
||||
# Not defined
|
||||
assert stieltjes(nan) is nan
|
||||
assert stieltjes(0, nan) is nan
|
||||
assert stieltjes(-1) is S.ComplexInfinity
|
||||
assert stieltjes(1.5) is S.ComplexInfinity
|
||||
assert stieltjes(z, 0) is S.ComplexInfinity
|
||||
assert stieltjes(z, -1) is S.ComplexInfinity
|
||||
|
||||
|
||||
def test_stieltjes_evalf():
|
||||
assert abs(stieltjes(0).evalf() - 0.577215664) < 1E-9
|
||||
assert abs(stieltjes(0, 0.5).evalf() - 1.963510026) < 1E-9
|
||||
assert abs(stieltjes(1, 2).evalf() + 0.072815845) < 1E-9
|
||||
|
||||
|
||||
def test_issue_10475():
|
||||
a = Symbol('a', extended_real=True)
|
||||
b = Symbol('b', extended_positive=True)
|
||||
s = Symbol('s', zero=False)
|
||||
|
||||
assert zeta(2 + I).is_finite
|
||||
assert zeta(1).is_finite is False
|
||||
assert zeta(x).is_finite is None
|
||||
assert zeta(x + I).is_finite is None
|
||||
assert zeta(a).is_finite is None
|
||||
assert zeta(b).is_finite is None
|
||||
assert zeta(-b).is_finite is True
|
||||
assert zeta(b**2 - 2*b + 1).is_finite is None
|
||||
assert zeta(a + I).is_finite is True
|
||||
assert zeta(b + 1).is_finite is True
|
||||
assert zeta(s + 1).is_finite is True
|
||||
|
||||
|
||||
def test_issue_14177():
|
||||
n = Symbol('n', nonnegative=True, integer=True)
|
||||
|
||||
assert zeta(-n).rewrite(bernoulli) == bernoulli(n+1) / (-n-1)
|
||||
assert zeta(-n, a).rewrite(bernoulli) == bernoulli(n+1, a) / (-n-1)
|
||||
z2n = -(2*I*pi)**(2*n)*bernoulli(2*n) / (2*factorial(2*n))
|
||||
assert zeta(2*n).rewrite(bernoulli) == z2n
|
||||
assert expand_func(zeta(s, n+1)) == zeta(s) - harmonic(n, s)
|
||||
assert expand_func(zeta(-b, -n)) is nan
|
||||
assert expand_func(zeta(-b, n)) == zeta(-b, n)
|
||||
|
||||
n = Symbol('n')
|
||||
|
||||
assert zeta(2*n) == zeta(2*n) # As sign of z (= 2*n) is not determined
|
||||
@@ -0,0 +1,786 @@
|
||||
""" Riemann zeta and related function. """
|
||||
|
||||
from sympy.core.add import Add
|
||||
from sympy.core.cache import cacheit
|
||||
from sympy.core.function import ArgumentIndexError, expand_mul, DefinedFunction
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.core.numbers import pi, I, Integer
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Dummy
|
||||
from sympy.core.sympify import sympify
|
||||
from sympy.functions.combinatorial.numbers import bernoulli, factorial, genocchi, harmonic
|
||||
from sympy.functions.elementary.complexes import re, unpolarify, Abs, polar_lift
|
||||
from sympy.functions.elementary.exponential import log, exp_polar, exp
|
||||
from sympy.functions.elementary.integers import ceiling, floor
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.polys.polytools import Poly
|
||||
|
||||
###############################################################################
|
||||
###################### LERCH TRANSCENDENT #####################################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class lerchphi(DefinedFunction):
|
||||
r"""
|
||||
Lerch transcendent (Lerch phi function).
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For $\operatorname{Re}(a) > 0$, $|z| < 1$ and $s \in \mathbb{C}$, the
|
||||
Lerch transcendent is defined as
|
||||
|
||||
.. math :: \Phi(z, s, a) = \sum_{n=0}^\infty \frac{z^n}{(n + a)^s},
|
||||
|
||||
where the standard branch of the argument is used for $n + a$,
|
||||
and by analytic continuation for other values of the parameters.
|
||||
|
||||
A commonly used related function is the Lerch zeta function, defined by
|
||||
|
||||
.. math:: L(q, s, a) = \Phi(e^{2\pi i q}, s, a).
|
||||
|
||||
**Analytic Continuation and Branching Behavior**
|
||||
|
||||
It can be shown that
|
||||
|
||||
.. math:: \Phi(z, s, a) = z\Phi(z, s, a+1) + a^{-s}.
|
||||
|
||||
This provides the analytic continuation to $\operatorname{Re}(a) \le 0$.
|
||||
|
||||
Assume now $\operatorname{Re}(a) > 0$. The integral representation
|
||||
|
||||
.. math:: \Phi_0(z, s, a) = \int_0^\infty \frac{t^{s-1} e^{-at}}{1 - ze^{-t}}
|
||||
\frac{\mathrm{d}t}{\Gamma(s)}
|
||||
|
||||
provides an analytic continuation to $\mathbb{C} - [1, \infty)$.
|
||||
Finally, for $x \in (1, \infty)$ we find
|
||||
|
||||
.. math:: \lim_{\epsilon \to 0^+} \Phi_0(x + i\epsilon, s, a)
|
||||
-\lim_{\epsilon \to 0^+} \Phi_0(x - i\epsilon, s, a)
|
||||
= \frac{2\pi i \log^{s-1}{x}}{x^a \Gamma(s)},
|
||||
|
||||
using the standard branch for both $\log{x}$ and
|
||||
$\log{\log{x}}$ (a branch of $\log{\log{x}}$ is needed to
|
||||
evaluate $\log{x}^{s-1}$).
|
||||
This concludes the analytic continuation. The Lerch transcendent is thus
|
||||
branched at $z \in \{0, 1, \infty\}$ and
|
||||
$a \in \mathbb{Z}_{\le 0}$. For fixed $z, a$ outside these
|
||||
branch points, it is an entire function of $s$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The Lerch transcendent is a fairly general function, for this reason it does
|
||||
not automatically evaluate to simpler functions. Use ``expand_func()`` to
|
||||
achieve this.
|
||||
|
||||
If $z=1$, the Lerch transcendent reduces to the Hurwitz zeta function:
|
||||
|
||||
>>> from sympy import lerchphi, expand_func
|
||||
>>> from sympy.abc import z, s, a
|
||||
>>> expand_func(lerchphi(1, s, a))
|
||||
zeta(s, a)
|
||||
|
||||
More generally, if $z$ is a root of unity, the Lerch transcendent
|
||||
reduces to a sum of Hurwitz zeta functions:
|
||||
|
||||
>>> expand_func(lerchphi(-1, s, a))
|
||||
zeta(s, a/2)/2**s - zeta(s, a/2 + 1/2)/2**s
|
||||
|
||||
If $a=1$, the Lerch transcendent reduces to the polylogarithm:
|
||||
|
||||
>>> expand_func(lerchphi(z, s, 1))
|
||||
polylog(s, z)/z
|
||||
|
||||
More generally, if $a$ is rational, the Lerch transcendent reduces
|
||||
to a sum of polylogarithms:
|
||||
|
||||
>>> from sympy import S
|
||||
>>> expand_func(lerchphi(z, s, S(1)/2))
|
||||
2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) -
|
||||
polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z))
|
||||
>>> expand_func(lerchphi(z, s, S(3)/2))
|
||||
-2**s/z + 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) -
|
||||
polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z))/z
|
||||
|
||||
The derivatives with respect to $z$ and $a$ can be computed in
|
||||
closed form:
|
||||
|
||||
>>> lerchphi(z, s, a).diff(z)
|
||||
(-a*lerchphi(z, s, a) + lerchphi(z, s - 1, a))/z
|
||||
>>> lerchphi(z, s, a).diff(a)
|
||||
-s*lerchphi(z, s + 1, a)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
polylog, zeta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Bateman, H.; Erdelyi, A. (1953), Higher Transcendental Functions,
|
||||
Vol. I, New York: McGraw-Hill. Section 1.11.
|
||||
.. [2] https://dlmf.nist.gov/25.14
|
||||
.. [3] https://en.wikipedia.org/wiki/Lerch_transcendent
|
||||
|
||||
"""
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
z, s, a = self.args
|
||||
if z == 1:
|
||||
return zeta(s, a)
|
||||
if s.is_Integer and s <= 0:
|
||||
t = Dummy('t')
|
||||
p = Poly((t + a)**(-s), t)
|
||||
start = 1/(1 - t)
|
||||
res = S.Zero
|
||||
for c in reversed(p.all_coeffs()):
|
||||
res += c*start
|
||||
start = t*start.diff(t)
|
||||
return res.subs(t, z)
|
||||
|
||||
if a.is_Rational:
|
||||
# See section 18 of
|
||||
# Kelly B. Roach. Hypergeometric Function Representations.
|
||||
# In: Proceedings of the 1997 International Symposium on Symbolic and
|
||||
# Algebraic Computation, pages 205-211, New York, 1997. ACM.
|
||||
# TODO should something be polarified here?
|
||||
add = S.Zero
|
||||
mul = S.One
|
||||
# First reduce a to the interaval (0, 1]
|
||||
if a > 1:
|
||||
n = floor(a)
|
||||
if n == a:
|
||||
n -= 1
|
||||
a -= n
|
||||
mul = z**(-n)
|
||||
add = Add(*[-z**(k - n)/(a + k)**s for k in range(n)])
|
||||
elif a <= 0:
|
||||
n = floor(-a) + 1
|
||||
a += n
|
||||
mul = z**n
|
||||
add = Add(*[z**(n - 1 - k)/(a - k - 1)**s for k in range(n)])
|
||||
|
||||
m, n = S([a.p, a.q])
|
||||
zet = exp_polar(2*pi*I/n)
|
||||
root = z**(1/n)
|
||||
up_zet = unpolarify(zet)
|
||||
addargs = []
|
||||
for k in range(n):
|
||||
p = polylog(s, zet**k*root)
|
||||
if isinstance(p, polylog):
|
||||
p = p._eval_expand_func(**hints)
|
||||
addargs.append(p/(up_zet**k*root)**m)
|
||||
return add + mul*n**(s - 1)*Add(*addargs)
|
||||
|
||||
# TODO use minpoly instead of ad-hoc methods when issue 5888 is fixed
|
||||
if isinstance(z, exp) and (z.args[0]/(pi*I)).is_Rational or z in [-1, I, -I]:
|
||||
# TODO reference?
|
||||
if z == -1:
|
||||
p, q = S([1, 2])
|
||||
elif z == I:
|
||||
p, q = S([1, 4])
|
||||
elif z == -I:
|
||||
p, q = S([-1, 4])
|
||||
else:
|
||||
arg = z.args[0]/(2*pi*I)
|
||||
p, q = S([arg.p, arg.q])
|
||||
return Add(*[exp(2*pi*I*k*p/q)/q**s*zeta(s, (k + a)/q)
|
||||
for k in range(q)])
|
||||
|
||||
return lerchphi(z, s, a)
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
z, s, a = self.args
|
||||
if argindex == 3:
|
||||
return -s*lerchphi(z, s + 1, a)
|
||||
elif argindex == 1:
|
||||
return (lerchphi(z, s - 1, a) - a*lerchphi(z, s, a))/z
|
||||
else:
|
||||
raise ArgumentIndexError
|
||||
|
||||
def _eval_rewrite_helper(self, target):
|
||||
res = self._eval_expand_func()
|
||||
if res.has(target):
|
||||
return res
|
||||
else:
|
||||
return self
|
||||
|
||||
def _eval_rewrite_as_zeta(self, z, s, a, **kwargs):
|
||||
return self._eval_rewrite_helper(zeta)
|
||||
|
||||
def _eval_rewrite_as_polylog(self, z, s, a, **kwargs):
|
||||
return self._eval_rewrite_helper(polylog)
|
||||
|
||||
###############################################################################
|
||||
###################### POLYLOGARITHM ##########################################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class polylog(DefinedFunction):
|
||||
r"""
|
||||
Polylogarithm function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For $|z| < 1$ and $s \in \mathbb{C}$, the polylogarithm is
|
||||
defined by
|
||||
|
||||
.. math:: \operatorname{Li}_s(z) = \sum_{n=1}^\infty \frac{z^n}{n^s},
|
||||
|
||||
where the standard branch of the argument is used for $n$. It admits
|
||||
an analytic continuation which is branched at $z=1$ (notably not on the
|
||||
sheet of initial definition), $z=0$ and $z=\infty$.
|
||||
|
||||
The name polylogarithm comes from the fact that for $s=1$, the
|
||||
polylogarithm is related to the ordinary logarithm (see examples), and that
|
||||
|
||||
.. math:: \operatorname{Li}_{s+1}(z) =
|
||||
\int_0^z \frac{\operatorname{Li}_s(t)}{t} \mathrm{d}t.
|
||||
|
||||
The polylogarithm is a special case of the Lerch transcendent:
|
||||
|
||||
.. math:: \operatorname{Li}_{s}(z) = z \Phi(z, s, 1).
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For $z \in \{0, 1, -1\}$, the polylogarithm is automatically expressed
|
||||
using other functions:
|
||||
|
||||
>>> from sympy import polylog
|
||||
>>> from sympy.abc import s
|
||||
>>> polylog(s, 0)
|
||||
0
|
||||
>>> polylog(s, 1)
|
||||
zeta(s)
|
||||
>>> polylog(s, -1)
|
||||
-dirichlet_eta(s)
|
||||
|
||||
If $s$ is a negative integer, $0$ or $1$, the polylogarithm can be
|
||||
expressed using elementary functions. This can be done using
|
||||
``expand_func()``:
|
||||
|
||||
>>> from sympy import expand_func
|
||||
>>> from sympy.abc import z
|
||||
>>> expand_func(polylog(1, z))
|
||||
-log(1 - z)
|
||||
>>> expand_func(polylog(0, z))
|
||||
z/(1 - z)
|
||||
|
||||
The derivative with respect to $z$ can be computed in closed form:
|
||||
|
||||
>>> polylog(s, z).diff(z)
|
||||
polylog(s - 1, z)/z
|
||||
|
||||
The polylogarithm can be expressed in terms of the lerch transcendent:
|
||||
|
||||
>>> from sympy import lerchphi
|
||||
>>> polylog(s, z).rewrite(lerchphi)
|
||||
z*lerchphi(z, s, 1)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
zeta, lerchphi
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, s, z):
|
||||
if z.is_number:
|
||||
if z is S.One:
|
||||
return zeta(s)
|
||||
elif z is S.NegativeOne:
|
||||
return -dirichlet_eta(s)
|
||||
elif z is S.Zero:
|
||||
return S.Zero
|
||||
elif s == 2:
|
||||
dilogtable = _dilogtable()
|
||||
if z in dilogtable:
|
||||
return dilogtable[z]
|
||||
|
||||
if z.is_zero:
|
||||
return S.Zero
|
||||
|
||||
# Make an effort to determine if z is 1 to avoid replacing into
|
||||
# expression with singularity
|
||||
zone = z.equals(S.One)
|
||||
|
||||
if zone:
|
||||
return zeta(s)
|
||||
elif zone is False:
|
||||
# For s = 0 or -1 use explicit formulas to evaluate, but
|
||||
# automatically expanding polylog(1, z) to -log(1-z) seems
|
||||
# undesirable for summation methods based on hypergeometric
|
||||
# functions
|
||||
if s is S.Zero:
|
||||
return z/(1 - z)
|
||||
elif s is S.NegativeOne:
|
||||
return z/(1 - z)**2
|
||||
if s.is_zero:
|
||||
return z/(1 - z)
|
||||
|
||||
# polylog is branched, but not over the unit disk
|
||||
if z.has(exp_polar, polar_lift) and (zone or (Abs(z) <= S.One) == True):
|
||||
return cls(s, unpolarify(z))
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
s, z = self.args
|
||||
if argindex == 2:
|
||||
return polylog(s - 1, z)/z
|
||||
raise ArgumentIndexError
|
||||
|
||||
def _eval_rewrite_as_lerchphi(self, s, z, **kwargs):
|
||||
return z*lerchphi(z, s, 1)
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
s, z = self.args
|
||||
if s == 1:
|
||||
return -log(1 - z)
|
||||
if s.is_Integer and s <= 0:
|
||||
u = Dummy('u')
|
||||
start = u/(1 - u)
|
||||
for _ in range(-s):
|
||||
start = u*start.diff(u)
|
||||
return expand_mul(start).subs(u, z)
|
||||
return polylog(s, z)
|
||||
|
||||
def _eval_is_zero(self):
|
||||
z = self.args[1]
|
||||
if z.is_zero:
|
||||
return True
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
from sympy.series.order import Order
|
||||
nu, z = self.args
|
||||
|
||||
z0 = z.subs(x, 0)
|
||||
if z0 is S.NaN:
|
||||
z0 = z.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
|
||||
|
||||
if z0.is_zero:
|
||||
# In case of powers less than 1, number of terms need to be computed
|
||||
# separately to avoid repeated callings of _eval_nseries with wrong n
|
||||
try:
|
||||
_, exp = z.leadterm(x)
|
||||
except (ValueError, NotImplementedError):
|
||||
return self
|
||||
|
||||
if exp.is_positive:
|
||||
newn = ceiling(n/exp)
|
||||
o = Order(x**n, x)
|
||||
r = z._eval_nseries(x, n, logx, cdir).removeO()
|
||||
if r is S.Zero:
|
||||
return o
|
||||
|
||||
term = r
|
||||
s = [term]
|
||||
for k in range(2, newn):
|
||||
term *= r
|
||||
s.append(term/k**nu)
|
||||
return Add(*s) + o
|
||||
|
||||
return super(polylog, self)._eval_nseries(x, n, logx, cdir)
|
||||
|
||||
###############################################################################
|
||||
###################### HURWITZ GENERALIZED ZETA FUNCTION ######################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class zeta(DefinedFunction):
|
||||
r"""
|
||||
Hurwitz zeta function (or Riemann zeta function).
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For $\operatorname{Re}(a) > 0$ and $\operatorname{Re}(s) > 1$, this
|
||||
function is defined as
|
||||
|
||||
.. math:: \zeta(s, a) = \sum_{n=0}^\infty \frac{1}{(n + a)^s},
|
||||
|
||||
where the standard choice of argument for $n + a$ is used. For fixed
|
||||
$a$ not a nonpositive integer the Hurwitz zeta function admits a
|
||||
meromorphic continuation to all of $\mathbb{C}$; it is an unbranched
|
||||
function with a simple pole at $s = 1$.
|
||||
|
||||
The Hurwitz zeta function is a special case of the Lerch transcendent:
|
||||
|
||||
.. math:: \zeta(s, a) = \Phi(1, s, a).
|
||||
|
||||
This formula defines an analytic continuation for all possible values of
|
||||
$s$ and $a$ (also $\operatorname{Re}(a) < 0$), see the documentation of
|
||||
:class:`lerchphi` for a description of the branching behavior.
|
||||
|
||||
If no value is passed for $a$ a default value of $a = 1$ is assumed,
|
||||
yielding the Riemann zeta function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For $a = 1$ the Hurwitz zeta function reduces to the famous Riemann
|
||||
zeta function:
|
||||
|
||||
.. math:: \zeta(s, 1) = \zeta(s) = \sum_{n=1}^\infty \frac{1}{n^s}.
|
||||
|
||||
>>> from sympy import zeta
|
||||
>>> from sympy.abc import s
|
||||
>>> zeta(s, 1)
|
||||
zeta(s)
|
||||
>>> zeta(s)
|
||||
zeta(s)
|
||||
|
||||
The Riemann zeta function can also be expressed using the Dirichlet eta
|
||||
function:
|
||||
|
||||
>>> from sympy import dirichlet_eta
|
||||
>>> zeta(s).rewrite(dirichlet_eta)
|
||||
dirichlet_eta(s)/(1 - 2**(1 - s))
|
||||
|
||||
The Riemann zeta function at nonnegative even and negative integer
|
||||
values is related to the Bernoulli numbers and polynomials:
|
||||
|
||||
>>> zeta(2)
|
||||
pi**2/6
|
||||
>>> zeta(4)
|
||||
pi**4/90
|
||||
>>> zeta(0)
|
||||
-1/2
|
||||
>>> zeta(-1)
|
||||
-1/12
|
||||
>>> zeta(-4)
|
||||
0
|
||||
|
||||
The specific formulae are:
|
||||
|
||||
.. math:: \zeta(2n) = -\frac{(2\pi i)^{2n} B_{2n}}{2(2n)!}
|
||||
.. math:: \zeta(-n,a) = -\frac{B_{n+1}(a)}{n+1}
|
||||
|
||||
No closed-form expressions are known at positive odd integers, but
|
||||
numerical evaluation is possible:
|
||||
|
||||
>>> zeta(3).n()
|
||||
1.20205690315959
|
||||
|
||||
The derivative of $\zeta(s, a)$ with respect to $a$ can be computed:
|
||||
|
||||
>>> from sympy.abc import a
|
||||
>>> zeta(s, a).diff(a)
|
||||
-s*zeta(s + 1, a)
|
||||
|
||||
However the derivative with respect to $s$ has no useful closed form
|
||||
expression:
|
||||
|
||||
>>> zeta(s, a).diff(s)
|
||||
Derivative(zeta(s, a), s)
|
||||
|
||||
The Hurwitz zeta function can be expressed in terms of the Lerch
|
||||
transcendent, :class:`~.lerchphi`:
|
||||
|
||||
>>> from sympy import lerchphi
|
||||
>>> zeta(s, a).rewrite(lerchphi)
|
||||
lerchphi(1, s, a)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
dirichlet_eta, lerchphi, polylog
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://dlmf.nist.gov/25.11
|
||||
.. [2] https://en.wikipedia.org/wiki/Hurwitz_zeta_function
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, s, a=None):
|
||||
if a is S.One:
|
||||
return cls(s)
|
||||
elif s is S.NaN or a is S.NaN:
|
||||
return S.NaN
|
||||
elif s is S.One:
|
||||
return S.ComplexInfinity
|
||||
elif s is S.Infinity:
|
||||
return S.One
|
||||
elif a is S.Infinity:
|
||||
return S.Zero
|
||||
|
||||
sint = s.is_Integer
|
||||
if a is None:
|
||||
a = S.One
|
||||
if sint and s.is_nonpositive:
|
||||
return bernoulli(1-s, a) / (s-1)
|
||||
elif a is S.One:
|
||||
if sint and s.is_even:
|
||||
return -(2*pi*I)**s * bernoulli(s) / (2*factorial(s))
|
||||
elif sint and a.is_Integer and a.is_positive:
|
||||
return cls(s) - harmonic(a-1, s)
|
||||
elif a.is_Integer and a.is_nonpositive and \
|
||||
(s.is_integer is False or s.is_nonpositive is False):
|
||||
return S.NaN
|
||||
|
||||
def _eval_rewrite_as_bernoulli(self, s, a=1, **kwargs):
|
||||
if a == 1 and s.is_integer and s.is_nonnegative and s.is_even:
|
||||
return -(2*pi*I)**s * bernoulli(s) / (2*factorial(s))
|
||||
return bernoulli(1-s, a) / (s-1)
|
||||
|
||||
def _eval_rewrite_as_dirichlet_eta(self, s, a=1, **kwargs):
|
||||
if a != 1:
|
||||
return self
|
||||
s = self.args[0]
|
||||
return dirichlet_eta(s)/(1 - 2**(1 - s))
|
||||
|
||||
def _eval_rewrite_as_lerchphi(self, s, a=1, **kwargs):
|
||||
return lerchphi(1, s, a)
|
||||
|
||||
def _eval_is_finite(self):
|
||||
return fuzzy_not((self.args[0] - 1).is_zero)
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
s = self.args[0]
|
||||
a = self.args[1] if len(self.args) > 1 else S.One
|
||||
if a.is_integer:
|
||||
if a.is_positive:
|
||||
return zeta(s) - harmonic(a-1, s)
|
||||
if a.is_nonpositive and (s.is_integer is False or
|
||||
s.is_nonpositive is False):
|
||||
return S.NaN
|
||||
return self
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if len(self.args) == 2:
|
||||
s, a = self.args
|
||||
else:
|
||||
s, a = self.args + (1,)
|
||||
if argindex == 2:
|
||||
return -s*zeta(s + 1, a)
|
||||
else:
|
||||
raise ArgumentIndexError
|
||||
|
||||
def _eval_as_leading_term(self, x, logx, cdir):
|
||||
if len(self.args) == 2:
|
||||
s, a = self.args
|
||||
else:
|
||||
s, a = self.args + (S.One,)
|
||||
|
||||
try:
|
||||
c, e = a.leadterm(x)
|
||||
except NotImplementedError:
|
||||
return self
|
||||
|
||||
if e.is_negative and not s.is_positive:
|
||||
raise NotImplementedError
|
||||
|
||||
return super(zeta, self)._eval_as_leading_term(x, logx=logx, cdir=cdir)
|
||||
|
||||
|
||||
class dirichlet_eta(DefinedFunction):
|
||||
r"""
|
||||
Dirichlet eta function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For $\operatorname{Re}(s) > 0$ and $0 < x \le 1$, this function is defined as
|
||||
|
||||
.. math:: \eta(s, a) = \sum_{n=0}^\infty \frac{(-1)^n}{(n+a)^s}.
|
||||
|
||||
It admits a unique analytic continuation to all of $\mathbb{C}$ for any
|
||||
fixed $a$ not a nonpositive integer. It is an entire, unbranched function.
|
||||
|
||||
It can be expressed using the Hurwitz zeta function as
|
||||
|
||||
.. math:: \eta(s, a) = \zeta(s,a) - 2^{1-s} \zeta\left(s, \frac{a+1}{2}\right)
|
||||
|
||||
and using the generalized Genocchi function as
|
||||
|
||||
.. math:: \eta(s, a) = \frac{G(1-s, a)}{2(s-1)}.
|
||||
|
||||
In both cases the limiting value of $\log2 - \psi(a) + \psi\left(\frac{a+1}{2}\right)$
|
||||
is used when $s = 1$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import dirichlet_eta, zeta
|
||||
>>> from sympy.abc import s
|
||||
>>> dirichlet_eta(s).rewrite(zeta)
|
||||
Piecewise((log(2), Eq(s, 1)), ((1 - 2**(1 - s))*zeta(s), True))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
zeta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Dirichlet_eta_function
|
||||
.. [2] Peter Luschny, "An introduction to the Bernoulli function",
|
||||
https://arxiv.org/abs/2009.06743
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, s, a=None):
|
||||
if a is S.One:
|
||||
return cls(s)
|
||||
if a is None:
|
||||
if s == 1:
|
||||
return log(2)
|
||||
z = zeta(s)
|
||||
if not z.has(zeta):
|
||||
return (1 - 2**(1-s)) * z
|
||||
return
|
||||
elif s == 1:
|
||||
from sympy.functions.special.gamma_functions import digamma
|
||||
return log(2) - digamma(a) + digamma((a+1)/2)
|
||||
z1 = zeta(s, a)
|
||||
z2 = zeta(s, (a+1)/2)
|
||||
if not z1.has(zeta) and not z2.has(zeta):
|
||||
return z1 - 2**(1-s) * z2
|
||||
|
||||
def _eval_rewrite_as_zeta(self, s, a=1, **kwargs):
|
||||
from sympy.functions.special.gamma_functions import digamma
|
||||
if a == 1:
|
||||
return Piecewise((log(2), Eq(s, 1)), ((1 - 2**(1-s)) * zeta(s), True))
|
||||
return Piecewise((log(2) - digamma(a) + digamma((a+1)/2), Eq(s, 1)),
|
||||
(zeta(s, a) - 2**(1-s) * zeta(s, (a+1)/2), True))
|
||||
|
||||
def _eval_rewrite_as_genocchi(self, s, a=S.One, **kwargs):
|
||||
from sympy.functions.special.gamma_functions import digamma
|
||||
return Piecewise((log(2) - digamma(a) + digamma((a+1)/2), Eq(s, 1)),
|
||||
(genocchi(1-s, a) / (2 * (s-1)), True))
|
||||
|
||||
def _eval_evalf(self, prec):
|
||||
if all(i.is_number for i in self.args):
|
||||
return self.rewrite(zeta)._eval_evalf(prec)
|
||||
|
||||
|
||||
class riemann_xi(DefinedFunction):
|
||||
r"""
|
||||
Riemann Xi function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The Riemann Xi function is closely related to the Riemann zeta function.
|
||||
The zeros of Riemann Xi function are precisely the non-trivial zeros
|
||||
of the zeta function.
|
||||
|
||||
>>> from sympy import riemann_xi, zeta
|
||||
>>> from sympy.abc import s
|
||||
>>> riemann_xi(s).rewrite(zeta)
|
||||
s*(s - 1)*gamma(s/2)*zeta(s)/(2*pi**(s/2))
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Riemann_Xi_function
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@classmethod
|
||||
def eval(cls, s):
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
z = zeta(s)
|
||||
if s in (S.Zero, S.One):
|
||||
return S.Half
|
||||
|
||||
if not isinstance(z, zeta):
|
||||
return s*(s - 1)*gamma(s/2)*z/(2*pi**(s/2))
|
||||
|
||||
def _eval_rewrite_as_zeta(self, s, **kwargs):
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
return s*(s - 1)*gamma(s/2)*zeta(s)/(2*pi**(s/2))
|
||||
|
||||
|
||||
class stieltjes(DefinedFunction):
|
||||
r"""
|
||||
Represents Stieltjes constants, $\gamma_{k}$ that occur in
|
||||
Laurent Series expansion of the Riemann zeta function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import stieltjes
|
||||
>>> from sympy.abc import n, m
|
||||
>>> stieltjes(n)
|
||||
stieltjes(n)
|
||||
|
||||
The zero'th stieltjes constant:
|
||||
|
||||
>>> stieltjes(0)
|
||||
EulerGamma
|
||||
>>> stieltjes(0, 1)
|
||||
EulerGamma
|
||||
|
||||
For generalized stieltjes constants:
|
||||
|
||||
>>> stieltjes(n, m)
|
||||
stieltjes(n, m)
|
||||
|
||||
Constants are only defined for integers >= 0:
|
||||
|
||||
>>> stieltjes(-1)
|
||||
zoo
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Stieltjes_constants
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, n, a=None):
|
||||
if a is not None:
|
||||
a = sympify(a)
|
||||
if a is S.NaN:
|
||||
return S.NaN
|
||||
if a.is_Integer and a.is_nonpositive:
|
||||
return S.ComplexInfinity
|
||||
|
||||
if n.is_Number:
|
||||
if n is S.NaN:
|
||||
return S.NaN
|
||||
elif n < 0:
|
||||
return S.ComplexInfinity
|
||||
elif not n.is_Integer:
|
||||
return S.ComplexInfinity
|
||||
elif n is S.Zero and a in [None, 1]:
|
||||
return S.EulerGamma
|
||||
|
||||
if n.is_extended_negative:
|
||||
return S.ComplexInfinity
|
||||
|
||||
if n.is_zero and a in [None, 1]:
|
||||
return S.EulerGamma
|
||||
|
||||
if n.is_integer == False:
|
||||
return S.ComplexInfinity
|
||||
|
||||
|
||||
@cacheit
|
||||
def _dilogtable():
|
||||
return {
|
||||
S.Half: pi**2/12 - log(2)**2/2,
|
||||
Integer(2) : pi**2/4 - I*pi*log(2),
|
||||
-(sqrt(5) - 1)/2 : -pi**2/15 + log((sqrt(5)-1)/2)**2/2,
|
||||
-(sqrt(5) + 1)/2 : -pi**2/10 - log((sqrt(5)+1)/2)**2,
|
||||
(3 - sqrt(5))/2 : pi**2/15 - log((sqrt(5)-1)/2)**2,
|
||||
(sqrt(5) - 1)/2 : pi**2/10 - log((sqrt(5)-1)/2)**2,
|
||||
I : I*S.Catalan - pi**2/48,
|
||||
-I : -I*S.Catalan - pi**2/48,
|
||||
1 - I : pi**2/16 - I*S.Catalan - pi*I/4*log(2),
|
||||
1 + I : pi**2/16 + I*S.Catalan + pi*I/4*log(2),
|
||||
(1 - I)/2 : -log(2)**2/8 + pi*I*log(2)/8 + 5*pi**2/96 - I*S.Catalan
|
||||
}
|
||||
Reference in New Issue
Block a user