I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -0,0 +1 @@
# Stub __init__.py for the sympy.functions.special package

View File

@ -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

View File

@ -0,0 +1,389 @@
from sympy.core import S
from sympy.core.function import Function, 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(Function):
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(Function):
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(Function):
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 Function.__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)

View File

@ -0,0 +1,351 @@
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
ival = [_ivl(c, x) for c in intervals]
com = zip(ival, intervals)
com = sorted(com, key=lambda x: x[0])
intervals = [y for x, y in com]
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)

View File

@ -0,0 +1,664 @@
from sympy.core import S, diff
from sympy.core.function import Function, 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(Function):
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(Function):
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.'''))

View File

@ -0,0 +1,445 @@
""" Elliptic Integrals. """
from sympy.core import S, pi, I, Rational
from sympy.core.function import Function, 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(Function):
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(Function):
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(Function):
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(Function):
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:
n, z, m = n, 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

View File

@ -0,0 +1,269 @@
""" This module contains the Mathieu functions.
"""
from sympy.core.function import Function, ArgumentIndexError
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import sin, cos
class MathieuBase(Function):
"""
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

View File

@ -0,0 +1,235 @@
from sympy.core import S, oo, diff
from sympy.core.function import Function, 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(Function):
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=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 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

View File

@ -0,0 +1,334 @@
from sympy.core.expr import Expr
from sympy.core.function import Function, 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(Function):
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(Function):
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

View File

@ -0,0 +1,474 @@
from math import prod
from sympy.core import S, Integer
from sympy.core.function import Function
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(Function):
"""
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(Function):
"""
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))

View File

@ -0,0 +1,765 @@
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))
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)
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(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)
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)

View File

@ -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

View File

@ -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)))

View File

@ -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

View File

@ -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)))

View File

@ -0,0 +1,837 @@
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
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
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(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 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) == x
assert Si(2*x)._eval_as_leading_term(x) == 2*x
assert Si(sin(x))._eval_as_leading_term(x) == x
assert Si(x + 1)._eval_as_leading_term(x) == Si(1)
assert Si(1/x)._eval_as_leading_term(x, cdir=1) == \
Si(1/x)._eval_as_leading_term(x, cdir=-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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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))

View File

@ -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)))

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,787 @@
""" 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, Function
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(Function):
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(Function):
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(Function):
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):
arg_is_one = (self.args[0] - 1).is_zero
if arg_is_one is not None:
return not arg_is_one
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=None, cdir=0):
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, cdir)
class dirichlet_eta(Function):
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(Function):
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(Function):
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
}