Initialisation du repository de Beta
This commit is contained in:
commit
14985f6dbb
9469 changed files with 1903273 additions and 0 deletions
|
|
@ -0,0 +1 @@
|
|||
# Stub __init__.py for the sympy.functions.special package
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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)
|
||||
2208
venv/lib/python3.12/site-packages/sympy/functions/special/bessel.py
Normal file
2208
venv/lib/python3.12/site-packages/sympy/functions/special/bessel.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,389 @@
|
|||
from sympy.core import S
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.symbol import Dummy, uniquely_named_symbol
|
||||
from sympy.functions.special.gamma_functions import gamma, digamma
|
||||
from sympy.functions.combinatorial.numbers import catalan
|
||||
from sympy.functions.elementary.complexes import conjugate
|
||||
|
||||
# See mpmath #569 and SymPy #20569
|
||||
def betainc_mpmath_fix(a, b, x1, x2, reg=0):
|
||||
from mpmath import betainc, mpf
|
||||
if x1 == x2:
|
||||
return mpf(0)
|
||||
else:
|
||||
return betainc(a, b, x1, x2, reg)
|
||||
|
||||
###############################################################################
|
||||
############################ COMPLETE BETA FUNCTION ##########################
|
||||
###############################################################################
|
||||
|
||||
class beta(DefinedFunction):
|
||||
r"""
|
||||
The beta integral is called the Eulerian integral of the first kind by
|
||||
Legendre:
|
||||
|
||||
.. math::
|
||||
\mathrm{B}(x,y) \int^{1}_{0} t^{x-1} (1-t)^{y-1} \mathrm{d}t.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Beta function or Euler's first integral is closely associated
|
||||
with the gamma function. The Beta function is often used in probability
|
||||
theory and mathematical statistics. It satisfies properties like:
|
||||
|
||||
.. math::
|
||||
\mathrm{B}(a,1) = \frac{1}{a} \\
|
||||
\mathrm{B}(a,b) = \mathrm{B}(b,a) \\
|
||||
\mathrm{B}(a,b) = \frac{\Gamma(a) \Gamma(b)}{\Gamma(a+b)}
|
||||
|
||||
Therefore for integral values of $a$ and $b$:
|
||||
|
||||
.. math::
|
||||
\mathrm{B} = \frac{(a-1)! (b-1)!}{(a+b-1)!}
|
||||
|
||||
A special case of the Beta function when `x = y` is the
|
||||
Central Beta function. It satisfies properties like:
|
||||
|
||||
.. math::
|
||||
\mathrm{B}(x) = 2^{1 - 2x}\mathrm{B}(x, \frac{1}{2})
|
||||
\mathrm{B}(x) = 2^{1 - 2x} cos(\pi x) \mathrm{B}(\frac{1}{2} - x, x)
|
||||
\mathrm{B}(x) = \int_{0}^{1} \frac{t^x}{(1 + t)^{2x}} dt
|
||||
\mathrm{B}(x) = \frac{2}{x} \prod_{n = 1}^{\infty} \frac{n(n + 2x)}{(n + x)^2}
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import I, pi
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
The Beta function obeys the mirror symmetry:
|
||||
|
||||
>>> from sympy import beta, conjugate
|
||||
>>> conjugate(beta(x, y))
|
||||
beta(conjugate(x), conjugate(y))
|
||||
|
||||
Differentiation with respect to both $x$ and $y$ is supported:
|
||||
|
||||
>>> from sympy import beta, diff
|
||||
>>> diff(beta(x, y), x)
|
||||
(polygamma(0, x) - polygamma(0, x + y))*beta(x, y)
|
||||
|
||||
>>> diff(beta(x, y), y)
|
||||
(polygamma(0, y) - polygamma(0, x + y))*beta(x, y)
|
||||
|
||||
>>> diff(beta(x), x)
|
||||
2*(polygamma(0, x) - polygamma(0, 2*x))*beta(x, x)
|
||||
|
||||
We can numerically evaluate the Beta function to
|
||||
arbitrary precision for any complex numbers x and y:
|
||||
|
||||
>>> from sympy import beta
|
||||
>>> beta(pi).evalf(40)
|
||||
0.02671848900111377452242355235388489324562
|
||||
|
||||
>>> beta(1 + I).evalf(20)
|
||||
-0.2112723729365330143 - 0.7655283165378005676*I
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gamma: Gamma function.
|
||||
uppergamma: Upper incomplete gamma function.
|
||||
lowergamma: Lower incomplete gamma function.
|
||||
polygamma: Polygamma function.
|
||||
loggamma: Log Gamma function.
|
||||
digamma: Digamma function.
|
||||
trigamma: Trigamma function.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Beta_function
|
||||
.. [2] https://mathworld.wolfram.com/BetaFunction.html
|
||||
.. [3] https://dlmf.nist.gov/5.12
|
||||
|
||||
"""
|
||||
unbranched = True
|
||||
|
||||
def fdiff(self, argindex):
|
||||
x, y = self.args
|
||||
if argindex == 1:
|
||||
# Diff wrt x
|
||||
return beta(x, y)*(digamma(x) - digamma(x + y))
|
||||
elif argindex == 2:
|
||||
# Diff wrt y
|
||||
return beta(x, y)*(digamma(y) - digamma(x + y))
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, x, y=None):
|
||||
if y is None:
|
||||
return beta(x, x)
|
||||
if x.is_Number and y.is_Number:
|
||||
return beta(x, y, evaluate=False).doit()
|
||||
|
||||
def doit(self, **hints):
|
||||
x = xold = self.args[0]
|
||||
# Deal with unevaluated single argument beta
|
||||
single_argument = len(self.args) == 1
|
||||
y = yold = self.args[0] if single_argument else self.args[1]
|
||||
if hints.get('deep', True):
|
||||
x = x.doit(**hints)
|
||||
y = y.doit(**hints)
|
||||
if y.is_zero or x.is_zero:
|
||||
return S.ComplexInfinity
|
||||
if y is S.One:
|
||||
return 1/x
|
||||
if x is S.One:
|
||||
return 1/y
|
||||
if y == x + 1:
|
||||
return 1/(x*y*catalan(x))
|
||||
s = x + y
|
||||
if (s.is_integer and s.is_negative and x.is_integer is False and
|
||||
y.is_integer is False):
|
||||
return S.Zero
|
||||
if x == xold and y == yold and not single_argument:
|
||||
return self
|
||||
return beta(x, y)
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
x, y = self.args
|
||||
return gamma(x)*gamma(y) / gamma(x + y)
|
||||
|
||||
def _eval_is_real(self):
|
||||
return self.args[0].is_real and self.args[1].is_real
|
||||
|
||||
def _eval_conjugate(self):
|
||||
return self.func(self.args[0].conjugate(), self.args[1].conjugate())
|
||||
|
||||
def _eval_rewrite_as_gamma(self, x, y, piecewise=True, **kwargs):
|
||||
return self._eval_expand_func(**kwargs)
|
||||
|
||||
def _eval_rewrite_as_Integral(self, x, y, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', [x, y]).name)
|
||||
return Integral(t**(x - 1)*(1 - t)**(y - 1), (t, 0, 1))
|
||||
|
||||
###############################################################################
|
||||
########################## INCOMPLETE BETA FUNCTION ###########################
|
||||
###############################################################################
|
||||
|
||||
class betainc(DefinedFunction):
|
||||
r"""
|
||||
The Generalized Incomplete Beta function is defined as
|
||||
|
||||
.. math::
|
||||
\mathrm{B}_{(x_1, x_2)}(a, b) = \int_{x_1}^{x_2} t^{a - 1} (1 - t)^{b - 1} dt
|
||||
|
||||
The Incomplete Beta function is a special case
|
||||
of the Generalized Incomplete Beta function :
|
||||
|
||||
.. math:: \mathrm{B}_z (a, b) = \mathrm{B}_{(0, z)}(a, b)
|
||||
|
||||
The Incomplete Beta function satisfies :
|
||||
|
||||
.. math:: \mathrm{B}_z (a, b) = (-1)^a \mathrm{B}_{\frac{z}{z - 1}} (a, 1 - a - b)
|
||||
|
||||
The Beta function is a special case of the Incomplete Beta function :
|
||||
|
||||
.. math:: \mathrm{B}(a, b) = \mathrm{B}_{1}(a, b)
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import betainc, symbols, conjugate
|
||||
>>> a, b, x, x1, x2 = symbols('a b x x1 x2')
|
||||
|
||||
The Generalized Incomplete Beta function is given by:
|
||||
|
||||
>>> betainc(a, b, x1, x2)
|
||||
betainc(a, b, x1, x2)
|
||||
|
||||
The Incomplete Beta function can be obtained as follows:
|
||||
|
||||
>>> betainc(a, b, 0, x)
|
||||
betainc(a, b, 0, x)
|
||||
|
||||
The Incomplete Beta function obeys the mirror symmetry:
|
||||
|
||||
>>> conjugate(betainc(a, b, x1, x2))
|
||||
betainc(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
|
||||
|
||||
We can numerically evaluate the Incomplete Beta function to
|
||||
arbitrary precision for any complex numbers a, b, x1 and x2:
|
||||
|
||||
>>> from sympy import betainc, I
|
||||
>>> betainc(2, 3, 4, 5).evalf(10)
|
||||
56.08333333
|
||||
>>> betainc(0.75, 1 - 4*I, 0, 2 + 3*I).evalf(25)
|
||||
0.2241657956955709603655887 + 0.3619619242700451992411724*I
|
||||
|
||||
The Generalized Incomplete Beta function can be expressed
|
||||
in terms of the Generalized Hypergeometric function.
|
||||
|
||||
>>> from sympy import hyper
|
||||
>>> betainc(a, b, x1, x2).rewrite(hyper)
|
||||
(-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/a
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
beta: Beta function
|
||||
hyper: Generalized Hypergeometric function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
|
||||
.. [2] https://dlmf.nist.gov/8.17
|
||||
.. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
|
||||
.. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
|
||||
|
||||
"""
|
||||
nargs = 4
|
||||
unbranched = True
|
||||
|
||||
def fdiff(self, argindex):
|
||||
a, b, x1, x2 = self.args
|
||||
if argindex == 3:
|
||||
# Diff wrt x1
|
||||
return -(1 - x1)**(b - 1)*x1**(a - 1)
|
||||
elif argindex == 4:
|
||||
# Diff wrt x2
|
||||
return (1 - x2)**(b - 1)*x2**(a - 1)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_mpmath(self):
|
||||
return betainc_mpmath_fix, self.args
|
||||
|
||||
def _eval_is_real(self):
|
||||
if all(arg.is_real for arg in self.args):
|
||||
return True
|
||||
|
||||
def _eval_conjugate(self):
|
||||
return self.func(*map(conjugate, self.args))
|
||||
|
||||
def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', [a, b, x1, x2]).name)
|
||||
return Integral(t**(a - 1)*(1 - t)**(b - 1), (t, x1, x2))
|
||||
|
||||
def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.functions.special.hyper import hyper
|
||||
return (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
|
||||
|
||||
###############################################################################
|
||||
#################### REGULARIZED INCOMPLETE BETA FUNCTION #####################
|
||||
###############################################################################
|
||||
|
||||
class betainc_regularized(DefinedFunction):
|
||||
r"""
|
||||
The Generalized Regularized Incomplete Beta function is given by
|
||||
|
||||
.. math::
|
||||
\mathrm{I}_{(x_1, x_2)}(a, b) = \frac{\mathrm{B}_{(x_1, x_2)}(a, b)}{\mathrm{B}(a, b)}
|
||||
|
||||
The Regularized Incomplete Beta function is a special case
|
||||
of the Generalized Regularized Incomplete Beta function :
|
||||
|
||||
.. math:: \mathrm{I}_z (a, b) = \mathrm{I}_{(0, z)}(a, b)
|
||||
|
||||
The Regularized Incomplete Beta function is the cumulative distribution
|
||||
function of the beta distribution.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import betainc_regularized, symbols, conjugate
|
||||
>>> a, b, x, x1, x2 = symbols('a b x x1 x2')
|
||||
|
||||
The Generalized Regularized Incomplete Beta
|
||||
function is given by:
|
||||
|
||||
>>> betainc_regularized(a, b, x1, x2)
|
||||
betainc_regularized(a, b, x1, x2)
|
||||
|
||||
The Regularized Incomplete Beta function
|
||||
can be obtained as follows:
|
||||
|
||||
>>> betainc_regularized(a, b, 0, x)
|
||||
betainc_regularized(a, b, 0, x)
|
||||
|
||||
The Regularized Incomplete Beta function
|
||||
obeys the mirror symmetry:
|
||||
|
||||
>>> conjugate(betainc_regularized(a, b, x1, x2))
|
||||
betainc_regularized(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
|
||||
|
||||
We can numerically evaluate the Regularized Incomplete Beta function
|
||||
to arbitrary precision for any complex numbers a, b, x1 and x2:
|
||||
|
||||
>>> from sympy import betainc_regularized, pi, E
|
||||
>>> betainc_regularized(1, 2, 0, 0.25).evalf(10)
|
||||
0.4375000000
|
||||
>>> betainc_regularized(pi, E, 0, 1).evalf(5)
|
||||
1.00000
|
||||
|
||||
The Generalized Regularized Incomplete Beta function can be
|
||||
expressed in terms of the Generalized Hypergeometric function.
|
||||
|
||||
>>> from sympy import hyper
|
||||
>>> betainc_regularized(a, b, x1, x2).rewrite(hyper)
|
||||
(-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/(a*beta(a, b))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
beta: Beta function
|
||||
hyper: Generalized Hypergeometric function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
|
||||
.. [2] https://dlmf.nist.gov/8.17
|
||||
.. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
|
||||
.. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
|
||||
|
||||
"""
|
||||
nargs = 4
|
||||
unbranched = True
|
||||
|
||||
def __new__(cls, a, b, x1, x2):
|
||||
return super().__new__(cls, a, b, x1, x2)
|
||||
|
||||
def _eval_mpmath(self):
|
||||
return betainc_mpmath_fix, (*self.args, S(1))
|
||||
|
||||
def fdiff(self, argindex):
|
||||
a, b, x1, x2 = self.args
|
||||
if argindex == 3:
|
||||
# Diff wrt x1
|
||||
return -(1 - x1)**(b - 1)*x1**(a - 1) / beta(a, b)
|
||||
elif argindex == 4:
|
||||
# Diff wrt x2
|
||||
return (1 - x2)**(b - 1)*x2**(a - 1) / beta(a, b)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_is_real(self):
|
||||
if all(arg.is_real for arg in self.args):
|
||||
return True
|
||||
|
||||
def _eval_conjugate(self):
|
||||
return self.func(*map(conjugate, self.args))
|
||||
|
||||
def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', [a, b, x1, x2]).name)
|
||||
integrand = t**(a - 1)*(1 - t)**(b - 1)
|
||||
expr = Integral(integrand, (t, x1, x2))
|
||||
return expr / Integral(integrand, (t, 0, 1))
|
||||
|
||||
def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.functions.special.hyper import hyper
|
||||
expr = (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
|
||||
return expr / beta(a, b)
|
||||
|
|
@ -0,0 +1,348 @@
|
|||
from sympy.core import S, sympify
|
||||
from sympy.core.symbol import (Dummy, symbols)
|
||||
from sympy.functions import Piecewise, piecewise_fold
|
||||
from sympy.logic.boolalg import And
|
||||
from sympy.sets.sets import Interval
|
||||
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
def _ivl(cond, x):
|
||||
"""return the interval corresponding to the condition
|
||||
|
||||
Conditions in spline's Piecewise give the range over
|
||||
which an expression is valid like (lo <= x) & (x <= hi).
|
||||
This function returns (lo, hi).
|
||||
"""
|
||||
if isinstance(cond, And) and len(cond.args) == 2:
|
||||
a, b = cond.args
|
||||
if a.lts == x:
|
||||
a, b = b, a
|
||||
return a.lts, b.gts
|
||||
raise TypeError('unexpected cond type: %s' % cond)
|
||||
|
||||
|
||||
def _add_splines(c, b1, d, b2, x):
|
||||
"""Construct c*b1 + d*b2."""
|
||||
|
||||
if S.Zero in (b1, c):
|
||||
rv = piecewise_fold(d * b2)
|
||||
elif S.Zero in (b2, d):
|
||||
rv = piecewise_fold(c * b1)
|
||||
else:
|
||||
new_args = []
|
||||
# Just combining the Piecewise without any fancy optimization
|
||||
p1 = piecewise_fold(c * b1)
|
||||
p2 = piecewise_fold(d * b2)
|
||||
|
||||
# Search all Piecewise arguments except (0, True)
|
||||
p2args = list(p2.args[:-1])
|
||||
|
||||
# This merging algorithm assumes the conditions in
|
||||
# p1 and p2 are sorted
|
||||
for arg in p1.args[:-1]:
|
||||
expr = arg.expr
|
||||
cond = arg.cond
|
||||
|
||||
lower = _ivl(cond, x)[0]
|
||||
|
||||
# Check p2 for matching conditions that can be merged
|
||||
for i, arg2 in enumerate(p2args):
|
||||
expr2 = arg2.expr
|
||||
cond2 = arg2.cond
|
||||
|
||||
lower_2, upper_2 = _ivl(cond2, x)
|
||||
if cond2 == cond:
|
||||
# Conditions match, join expressions
|
||||
expr += expr2
|
||||
# Remove matching element
|
||||
del p2args[i]
|
||||
# No need to check the rest
|
||||
break
|
||||
elif lower_2 < lower and upper_2 <= lower:
|
||||
# Check if arg2 condition smaller than arg1,
|
||||
# add to new_args by itself (no match expected
|
||||
# in p1)
|
||||
new_args.append(arg2)
|
||||
del p2args[i]
|
||||
break
|
||||
|
||||
# Checked all, add expr and cond
|
||||
new_args.append((expr, cond))
|
||||
|
||||
# Add remaining items from p2args
|
||||
new_args.extend(p2args)
|
||||
|
||||
# Add final (0, True)
|
||||
new_args.append((0, True))
|
||||
|
||||
rv = Piecewise(*new_args, evaluate=False)
|
||||
|
||||
return rv.expand()
|
||||
|
||||
|
||||
@lru_cache(maxsize=128)
|
||||
def bspline_basis(d, knots, n, x):
|
||||
"""
|
||||
The $n$-th B-spline at $x$ of degree $d$ with knots.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
B-Splines are piecewise polynomials of degree $d$. They are defined on a
|
||||
set of knots, which is a sequence of integers or floats.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The 0th degree splines have a value of 1 on a single interval:
|
||||
|
||||
>>> from sympy import bspline_basis
|
||||
>>> from sympy.abc import x
|
||||
>>> d = 0
|
||||
>>> knots = tuple(range(5))
|
||||
>>> bspline_basis(d, knots, 0, x)
|
||||
Piecewise((1, (x >= 0) & (x <= 1)), (0, True))
|
||||
|
||||
For a given ``(d, knots)`` there are ``len(knots)-d-1`` B-splines
|
||||
defined, that are indexed by ``n`` (starting at 0).
|
||||
|
||||
Here is an example of a cubic B-spline:
|
||||
|
||||
>>> bspline_basis(3, tuple(range(5)), 0, x)
|
||||
Piecewise((x**3/6, (x >= 0) & (x <= 1)),
|
||||
(-x**3/2 + 2*x**2 - 2*x + 2/3,
|
||||
(x >= 1) & (x <= 2)),
|
||||
(x**3/2 - 4*x**2 + 10*x - 22/3,
|
||||
(x >= 2) & (x <= 3)),
|
||||
(-x**3/6 + 2*x**2 - 8*x + 32/3,
|
||||
(x >= 3) & (x <= 4)),
|
||||
(0, True))
|
||||
|
||||
By repeating knot points, you can introduce discontinuities in the
|
||||
B-splines and their derivatives:
|
||||
|
||||
>>> d = 1
|
||||
>>> knots = (0, 0, 2, 3, 4)
|
||||
>>> bspline_basis(d, knots, 0, x)
|
||||
Piecewise((1 - x/2, (x >= 0) & (x <= 2)), (0, True))
|
||||
|
||||
It is quite time consuming to construct and evaluate B-splines. If
|
||||
you need to evaluate a B-spline many times, it is best to lambdify them
|
||||
first:
|
||||
|
||||
>>> from sympy import lambdify
|
||||
>>> d = 3
|
||||
>>> knots = tuple(range(10))
|
||||
>>> b0 = bspline_basis(d, knots, 0, x)
|
||||
>>> f = lambdify(x, b0)
|
||||
>>> y = f(0.5)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
d : integer
|
||||
degree of bspline
|
||||
|
||||
knots : list of integer values
|
||||
list of knots points of bspline
|
||||
|
||||
n : integer
|
||||
$n$-th B-spline
|
||||
|
||||
x : symbol
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
bspline_basis_set
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/B-spline
|
||||
|
||||
"""
|
||||
# make sure x has no assumptions so conditions don't evaluate
|
||||
xvar = x
|
||||
x = Dummy()
|
||||
|
||||
knots = tuple(sympify(k) for k in knots)
|
||||
d = int(d)
|
||||
n = int(n)
|
||||
n_knots = len(knots)
|
||||
n_intervals = n_knots - 1
|
||||
if n + d + 1 > n_intervals:
|
||||
raise ValueError("n + d + 1 must not exceed len(knots) - 1")
|
||||
if d == 0:
|
||||
result = Piecewise(
|
||||
(S.One, Interval(knots[n], knots[n + 1]).contains(x)), (0, True)
|
||||
)
|
||||
elif d > 0:
|
||||
denom = knots[n + d + 1] - knots[n + 1]
|
||||
if denom != S.Zero:
|
||||
B = (knots[n + d + 1] - x) / denom
|
||||
b2 = bspline_basis(d - 1, knots, n + 1, x)
|
||||
else:
|
||||
b2 = B = S.Zero
|
||||
|
||||
denom = knots[n + d] - knots[n]
|
||||
if denom != S.Zero:
|
||||
A = (x - knots[n]) / denom
|
||||
b1 = bspline_basis(d - 1, knots, n, x)
|
||||
else:
|
||||
b1 = A = S.Zero
|
||||
|
||||
result = _add_splines(A, b1, B, b2, x)
|
||||
else:
|
||||
raise ValueError("degree must be non-negative: %r" % n)
|
||||
|
||||
# return result with user-given x
|
||||
return result.xreplace({x: xvar})
|
||||
|
||||
|
||||
def bspline_basis_set(d, knots, x):
|
||||
"""
|
||||
Return the ``len(knots)-d-1`` B-splines at *x* of degree *d*
|
||||
with *knots*.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function returns a list of piecewise polynomials that are the
|
||||
``len(knots)-d-1`` B-splines of degree *d* for the given knots.
|
||||
This function calls ``bspline_basis(d, knots, n, x)`` for different
|
||||
values of *n*.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import bspline_basis_set
|
||||
>>> from sympy.abc import x
|
||||
>>> d = 2
|
||||
>>> knots = range(5)
|
||||
>>> splines = bspline_basis_set(d, knots, x)
|
||||
>>> splines
|
||||
[Piecewise((x**2/2, (x >= 0) & (x <= 1)),
|
||||
(-x**2 + 3*x - 3/2, (x >= 1) & (x <= 2)),
|
||||
(x**2/2 - 3*x + 9/2, (x >= 2) & (x <= 3)),
|
||||
(0, True)),
|
||||
Piecewise((x**2/2 - x + 1/2, (x >= 1) & (x <= 2)),
|
||||
(-x**2 + 5*x - 11/2, (x >= 2) & (x <= 3)),
|
||||
(x**2/2 - 4*x + 8, (x >= 3) & (x <= 4)),
|
||||
(0, True))]
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
d : integer
|
||||
degree of bspline
|
||||
|
||||
knots : list of integers
|
||||
list of knots points of bspline
|
||||
|
||||
x : symbol
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
bspline_basis
|
||||
|
||||
"""
|
||||
n_splines = len(knots) - d - 1
|
||||
return [bspline_basis(d, tuple(knots), i, x) for i in range(n_splines)]
|
||||
|
||||
|
||||
def interpolating_spline(d, x, X, Y):
|
||||
"""
|
||||
Return spline of degree *d*, passing through the given *X*
|
||||
and *Y* values.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function returns a piecewise function such that each part is
|
||||
a polynomial of degree not greater than *d*. The value of *d*
|
||||
must be 1 or greater and the values of *X* must be strictly
|
||||
increasing.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import interpolating_spline
|
||||
>>> from sympy.abc import x
|
||||
>>> interpolating_spline(1, x, [1, 2, 4, 7], [3, 6, 5, 7])
|
||||
Piecewise((3*x, (x >= 1) & (x <= 2)),
|
||||
(7 - x/2, (x >= 2) & (x <= 4)),
|
||||
(2*x/3 + 7/3, (x >= 4) & (x <= 7)))
|
||||
>>> interpolating_spline(3, x, [-2, 0, 1, 3, 4], [4, 2, 1, 1, 3])
|
||||
Piecewise((7*x**3/117 + 7*x**2/117 - 131*x/117 + 2, (x >= -2) & (x <= 1)),
|
||||
(10*x**3/117 - 2*x**2/117 - 122*x/117 + 77/39, (x >= 1) & (x <= 4)))
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
d : integer
|
||||
Degree of Bspline strictly greater than equal to one
|
||||
|
||||
x : symbol
|
||||
|
||||
X : list of strictly increasing real values
|
||||
list of X coordinates through which the spline passes
|
||||
|
||||
Y : list of real values
|
||||
list of corresponding Y coordinates through which the spline passes
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
bspline_basis_set, interpolating_poly
|
||||
|
||||
"""
|
||||
from sympy.solvers.solveset import linsolve
|
||||
from sympy.matrices.dense import Matrix
|
||||
|
||||
# Input sanitization
|
||||
d = sympify(d)
|
||||
if not (d.is_Integer and d.is_positive):
|
||||
raise ValueError("Spline degree must be a positive integer, not %s." % d)
|
||||
if len(X) != len(Y):
|
||||
raise ValueError("Number of X and Y coordinates must be the same.")
|
||||
if len(X) < d + 1:
|
||||
raise ValueError("Degree must be less than the number of control points.")
|
||||
if not all(a < b for a, b in zip(X, X[1:])):
|
||||
raise ValueError("The x-coordinates must be strictly increasing.")
|
||||
X = [sympify(i) for i in X]
|
||||
|
||||
# Evaluating knots value
|
||||
if d.is_odd:
|
||||
j = (d + 1) // 2
|
||||
interior_knots = X[j:-j]
|
||||
else:
|
||||
j = d // 2
|
||||
interior_knots = [
|
||||
(a + b)/2 for a, b in zip(X[j : -j - 1], X[j + 1 : -j])
|
||||
]
|
||||
|
||||
knots = [X[0]] * (d + 1) + list(interior_knots) + [X[-1]] * (d + 1)
|
||||
|
||||
basis = bspline_basis_set(d, knots, x)
|
||||
|
||||
A = [[b.subs(x, v) for b in basis] for v in X]
|
||||
|
||||
coeff = linsolve((Matrix(A), Matrix(Y)), symbols("c0:{}".format(len(X)), cls=Dummy))
|
||||
coeff = list(coeff)[0]
|
||||
intervals = {c for b in basis for (e, c) in b.args if c != True}
|
||||
|
||||
# Sorting the intervals
|
||||
# ival contains the end-points of each interval
|
||||
intervals = sorted(intervals, key=lambda c: _ivl(c, x))
|
||||
|
||||
basis_dicts = [{c: e for (e, c) in b.args} for b in basis]
|
||||
spline = []
|
||||
for i in intervals:
|
||||
piece = sum(
|
||||
[c * d.get(i, S.Zero) for (c, d) in zip(coeff, basis_dicts)], S.Zero
|
||||
)
|
||||
spline.append((piece, i))
|
||||
return Piecewise(*spline)
|
||||
|
|
@ -0,0 +1,664 @@
|
|||
from sympy.core import S, diff
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.core.relational import Eq, Ne
|
||||
from sympy.functions.elementary.complexes import im, sign
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.polys.polyerrors import PolynomialError
|
||||
from sympy.polys.polyroots import roots
|
||||
from sympy.utilities.misc import filldedent
|
||||
|
||||
|
||||
###############################################################################
|
||||
################################ DELTA FUNCTION ###############################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class DiracDelta(DefinedFunction):
|
||||
r"""
|
||||
The DiracDelta function and its derivatives.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
DiracDelta is not an ordinary function. It can be rigorously defined either
|
||||
as a distribution or as a measure.
|
||||
|
||||
DiracDelta only makes sense in definite integrals, and in particular,
|
||||
integrals of the form ``Integral(f(x)*DiracDelta(x - x0), (x, a, b))``,
|
||||
where it equals ``f(x0)`` if ``a <= x0 <= b`` and ``0`` otherwise. Formally,
|
||||
DiracDelta acts in some ways like a function that is ``0`` everywhere except
|
||||
at ``0``, but in many ways it also does not. It can often be useful to treat
|
||||
DiracDelta in formal ways, building up and manipulating expressions with
|
||||
delta functions (which may eventually be integrated), but care must be taken
|
||||
to not treat it as a real function. SymPy's ``oo`` is similar. It only
|
||||
truly makes sense formally in certain contexts (such as integration limits),
|
||||
but SymPy allows its use everywhere, and it tries to be consistent with
|
||||
operations on it (like ``1/oo``), but it is easy to get into trouble and get
|
||||
wrong results if ``oo`` is treated too much like a number. Similarly, if
|
||||
DiracDelta is treated too much like a function, it is easy to get wrong or
|
||||
nonsensical results.
|
||||
|
||||
DiracDelta function has the following properties:
|
||||
|
||||
1) $\frac{d}{d x} \theta(x) = \delta(x)$
|
||||
2) $\int_{-\infty}^\infty \delta(x - a)f(x)\, dx = f(a)$ and $\int_{a-
|
||||
\epsilon}^{a+\epsilon} \delta(x - a)f(x)\, dx = f(a)$
|
||||
3) $\delta(x) = 0$ for all $x \neq 0$
|
||||
4) $\delta(g(x)) = \sum_i \frac{\delta(x - x_i)}{\|g'(x_i)\|}$ where $x_i$
|
||||
are the roots of $g$
|
||||
5) $\delta(-x) = \delta(x)$
|
||||
|
||||
Derivatives of ``k``-th order of DiracDelta have the following properties:
|
||||
|
||||
6) $\delta(x, k) = 0$ for all $x \neq 0$
|
||||
7) $\delta(-x, k) = -\delta(x, k)$ for odd $k$
|
||||
8) $\delta(-x, k) = \delta(x, k)$ for even $k$
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, diff, pi
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> DiracDelta(x)
|
||||
DiracDelta(x)
|
||||
>>> DiracDelta(1)
|
||||
0
|
||||
>>> DiracDelta(-1)
|
||||
0
|
||||
>>> DiracDelta(pi)
|
||||
0
|
||||
>>> DiracDelta(x - 4).subs(x, 4)
|
||||
DiracDelta(0)
|
||||
>>> diff(DiracDelta(x))
|
||||
DiracDelta(x, 1)
|
||||
>>> diff(DiracDelta(x - 1), x, 2)
|
||||
DiracDelta(x - 1, 2)
|
||||
>>> diff(DiracDelta(x**2 - 1), x, 2)
|
||||
2*(2*x**2*DiracDelta(x**2 - 1, 2) + DiracDelta(x**2 - 1, 1))
|
||||
>>> DiracDelta(3*x).is_simple(x)
|
||||
True
|
||||
>>> DiracDelta(x**2).is_simple(x)
|
||||
False
|
||||
>>> DiracDelta((x**2 - 1)*y).expand(diracdelta=True, wrt=x)
|
||||
DiracDelta(x - 1)/(2*Abs(y)) + DiracDelta(x + 1)/(2*Abs(y))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Heaviside
|
||||
sympy.simplify.simplify.simplify, is_simple
|
||||
sympy.functions.special.tensor_functions.KroneckerDelta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://mathworld.wolfram.com/DeltaFunction.html
|
||||
|
||||
"""
|
||||
|
||||
is_real = True
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
"""
|
||||
Returns the first derivative of a DiracDelta Function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the
|
||||
user-level function and ``fdiff()`` is an object method. ``fdiff()`` is
|
||||
a convenience method available in the ``Function`` class. It returns
|
||||
the derivative of the function without considering the chain rule.
|
||||
``diff(function, x)`` calls ``Function._eval_derivative`` which in turn
|
||||
calls ``fdiff()`` internally to compute the derivative of the function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, diff
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> DiracDelta(x).fdiff()
|
||||
DiracDelta(x, 1)
|
||||
|
||||
>>> DiracDelta(x, 1).fdiff()
|
||||
DiracDelta(x, 2)
|
||||
|
||||
>>> DiracDelta(x**2 - 1).fdiff()
|
||||
DiracDelta(x**2 - 1, 1)
|
||||
|
||||
>>> diff(DiracDelta(x, 1)).fdiff()
|
||||
DiracDelta(x, 3)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
argindex : integer
|
||||
degree of derivative
|
||||
|
||||
"""
|
||||
if argindex == 1:
|
||||
#I didn't know if there is a better way to handle default arguments
|
||||
k = 0
|
||||
if len(self.args) > 1:
|
||||
k = self.args[1]
|
||||
return self.func(self.args[0], k + 1)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg, k=S.Zero):
|
||||
"""
|
||||
Returns a simplified form or a value of DiracDelta depending on the
|
||||
argument passed by the DiracDelta object.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The ``eval()`` method is automatically called when the ``DiracDelta``
|
||||
class is about to be instantiated and it returns either some simplified
|
||||
instance or the unevaluated instance depending on the argument passed.
|
||||
In other words, ``eval()`` method is not needed to be called explicitly,
|
||||
it is being called and evaluated once the object is called.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, S
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> DiracDelta(x)
|
||||
DiracDelta(x)
|
||||
|
||||
>>> DiracDelta(-x, 1)
|
||||
-DiracDelta(x, 1)
|
||||
|
||||
>>> DiracDelta(1)
|
||||
0
|
||||
|
||||
>>> DiracDelta(5, 1)
|
||||
0
|
||||
|
||||
>>> DiracDelta(0)
|
||||
DiracDelta(0)
|
||||
|
||||
>>> DiracDelta(-1)
|
||||
0
|
||||
|
||||
>>> DiracDelta(S.NaN)
|
||||
nan
|
||||
|
||||
>>> DiracDelta(x - 100).subs(x, 5)
|
||||
0
|
||||
|
||||
>>> DiracDelta(x - 100).subs(x, 100)
|
||||
DiracDelta(0)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
k : integer
|
||||
order of derivative
|
||||
|
||||
arg : argument passed to DiracDelta
|
||||
|
||||
"""
|
||||
if not k.is_Integer or k.is_negative:
|
||||
raise ValueError("Error: the second argument of DiracDelta must be \
|
||||
a non-negative integer, %s given instead." % (k,))
|
||||
if arg is S.NaN:
|
||||
return S.NaN
|
||||
if arg.is_nonzero:
|
||||
return S.Zero
|
||||
if fuzzy_not(im(arg).is_zero):
|
||||
raise ValueError(filldedent('''
|
||||
Function defined only for Real Values.
|
||||
Complex part: %s found in %s .''' % (
|
||||
repr(im(arg)), repr(arg))))
|
||||
c, nc = arg.args_cnc()
|
||||
if c and c[0] is S.NegativeOne:
|
||||
# keep this fast and simple instead of using
|
||||
# could_extract_minus_sign
|
||||
if k.is_odd:
|
||||
return -cls(-arg, k)
|
||||
elif k.is_even:
|
||||
return cls(-arg, k) if k else cls(-arg)
|
||||
elif k.is_zero:
|
||||
return cls(arg, evaluate=False)
|
||||
|
||||
def _eval_expand_diracdelta(self, **hints):
|
||||
"""
|
||||
Compute a simplified representation of the function using
|
||||
property number 4. Pass ``wrt`` as a hint to expand the expression
|
||||
with respect to a particular variable.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
``wrt`` is:
|
||||
|
||||
- a variable with respect to which a DiracDelta expression will
|
||||
get expanded.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> DiracDelta(x*y).expand(diracdelta=True, wrt=x)
|
||||
DiracDelta(x)/Abs(y)
|
||||
>>> DiracDelta(x*y).expand(diracdelta=True, wrt=y)
|
||||
DiracDelta(y)/Abs(x)
|
||||
|
||||
>>> DiracDelta(x**2 + x - 2).expand(diracdelta=True, wrt=x)
|
||||
DiracDelta(x - 1)/3 + DiracDelta(x + 2)/3
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_simple, Diracdelta
|
||||
|
||||
"""
|
||||
wrt = hints.get('wrt', None)
|
||||
if wrt is None:
|
||||
free = self.free_symbols
|
||||
if len(free) == 1:
|
||||
wrt = free.pop()
|
||||
else:
|
||||
raise TypeError(filldedent('''
|
||||
When there is more than 1 free symbol or variable in the expression,
|
||||
the 'wrt' keyword is required as a hint to expand when using the
|
||||
DiracDelta hint.'''))
|
||||
|
||||
if not self.args[0].has(wrt) or (len(self.args) > 1 and self.args[1] != 0 ):
|
||||
return self
|
||||
try:
|
||||
argroots = roots(self.args[0], wrt)
|
||||
result = 0
|
||||
valid = True
|
||||
darg = abs(diff(self.args[0], wrt))
|
||||
for r, m in argroots.items():
|
||||
if r.is_real is not False and m == 1:
|
||||
result += self.func(wrt - r)/darg.subs(wrt, r)
|
||||
else:
|
||||
# don't handle non-real and if m != 1 then
|
||||
# a polynomial will have a zero in the derivative (darg)
|
||||
# at r
|
||||
valid = False
|
||||
break
|
||||
if valid:
|
||||
return result
|
||||
except PolynomialError:
|
||||
pass
|
||||
return self
|
||||
|
||||
def is_simple(self, x):
|
||||
"""
|
||||
Tells whether the argument(args[0]) of DiracDelta is a linear
|
||||
expression in *x*.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, cos
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> DiracDelta(x*y).is_simple(x)
|
||||
True
|
||||
>>> DiracDelta(x*y).is_simple(y)
|
||||
True
|
||||
|
||||
>>> DiracDelta(x**2 + x - 2).is_simple(x)
|
||||
False
|
||||
|
||||
>>> DiracDelta(cos(x)).is_simple(x)
|
||||
False
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
x : can be a symbol
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.simplify.simplify.simplify, DiracDelta
|
||||
|
||||
"""
|
||||
p = self.args[0].as_poly(x)
|
||||
if p:
|
||||
return p.degree() == 1
|
||||
return False
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
|
||||
"""
|
||||
Represents DiracDelta in a piecewise form.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, Piecewise, Symbol
|
||||
>>> x = Symbol('x')
|
||||
|
||||
>>> DiracDelta(x).rewrite(Piecewise)
|
||||
Piecewise((DiracDelta(0), Eq(x, 0)), (0, True))
|
||||
|
||||
>>> DiracDelta(x - 5).rewrite(Piecewise)
|
||||
Piecewise((DiracDelta(0), Eq(x, 5)), (0, True))
|
||||
|
||||
>>> DiracDelta(x**2 - 5).rewrite(Piecewise)
|
||||
Piecewise((DiracDelta(0), Eq(x**2, 5)), (0, True))
|
||||
|
||||
>>> DiracDelta(x - 5, 4).rewrite(Piecewise)
|
||||
DiracDelta(x - 5, 4)
|
||||
|
||||
"""
|
||||
if len(args) == 1:
|
||||
return Piecewise((DiracDelta(0), Eq(args[0], 0)), (0, True))
|
||||
|
||||
def _eval_rewrite_as_SingularityFunction(self, *args, **kwargs):
|
||||
"""
|
||||
Returns the DiracDelta expression written in the form of Singularity
|
||||
Functions.
|
||||
|
||||
"""
|
||||
from sympy.solvers import solve
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
if self == DiracDelta(0):
|
||||
return SingularityFunction(0, 0, -1)
|
||||
if self == DiracDelta(0, 1):
|
||||
return SingularityFunction(0, 0, -2)
|
||||
free = self.free_symbols
|
||||
if len(free) == 1:
|
||||
x = (free.pop())
|
||||
if len(args) == 1:
|
||||
return SingularityFunction(x, solve(args[0], x)[0], -1)
|
||||
return SingularityFunction(x, solve(args[0], x)[0], -args[1] - 1)
|
||||
else:
|
||||
# I don't know how to handle the case for DiracDelta expressions
|
||||
# having arguments with more than one variable.
|
||||
raise TypeError(filldedent('''
|
||||
rewrite(SingularityFunction) does not support
|
||||
arguments with more that one variable.'''))
|
||||
|
||||
|
||||
###############################################################################
|
||||
############################## HEAVISIDE FUNCTION #############################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class Heaviside(DefinedFunction):
|
||||
r"""
|
||||
Heaviside step function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Heaviside step function has the following properties:
|
||||
|
||||
1) $\frac{d}{d x} \theta(x) = \delta(x)$
|
||||
2) $\theta(x) = \begin{cases} 0 & \text{for}\: x < 0 \\ \frac{1}{2} &
|
||||
\text{for}\: x = 0 \\1 & \text{for}\: x > 0 \end{cases}$
|
||||
3) $\frac{d}{d x} \max(x, 0) = \theta(x)$
|
||||
|
||||
Heaviside(x) is printed as $\theta(x)$ with the SymPy LaTeX printer.
|
||||
|
||||
The value at 0 is set differently in different fields. SymPy uses 1/2,
|
||||
which is a convention from electronics and signal processing, and is
|
||||
consistent with solving improper integrals by Fourier transform and
|
||||
convolution.
|
||||
|
||||
To specify a different value of Heaviside at ``x=0``, a second argument
|
||||
can be given. Using ``Heaviside(x, nan)`` gives an expression that will
|
||||
evaluate to nan for x=0.
|
||||
|
||||
.. versionchanged:: 1.9 ``Heaviside(0)`` now returns 1/2 (before: undefined)
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, nan
|
||||
>>> from sympy.abc import x
|
||||
>>> Heaviside(9)
|
||||
1
|
||||
>>> Heaviside(-9)
|
||||
0
|
||||
>>> Heaviside(0)
|
||||
1/2
|
||||
>>> Heaviside(0, nan)
|
||||
nan
|
||||
>>> (Heaviside(x) + 1).replace(Heaviside(x), Heaviside(x, 1))
|
||||
Heaviside(x, 1) + 1
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
DiracDelta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://mathworld.wolfram.com/HeavisideStepFunction.html
|
||||
.. [2] https://dlmf.nist.gov/1.16#iv
|
||||
|
||||
"""
|
||||
|
||||
is_real = True
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
"""
|
||||
Returns the first derivative of a Heaviside Function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, diff
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> Heaviside(x).fdiff()
|
||||
DiracDelta(x)
|
||||
|
||||
>>> Heaviside(x**2 - 1).fdiff()
|
||||
DiracDelta(x**2 - 1)
|
||||
|
||||
>>> diff(Heaviside(x)).fdiff()
|
||||
DiracDelta(x, 1)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
argindex : integer
|
||||
order of derivative
|
||||
|
||||
"""
|
||||
if argindex == 1:
|
||||
return DiracDelta(self.args[0])
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def __new__(cls, arg, H0=S.Half, **options):
|
||||
if isinstance(H0, Heaviside) and len(H0.args) == 1:
|
||||
H0 = S.Half
|
||||
return super(cls, cls).__new__(cls, arg, H0, **options)
|
||||
|
||||
@property
|
||||
def pargs(self):
|
||||
"""Args without default S.Half"""
|
||||
args = self.args
|
||||
if args[1] is S.Half:
|
||||
args = args[:1]
|
||||
return args
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg, H0=S.Half):
|
||||
"""
|
||||
Returns a simplified form or a value of Heaviside depending on the
|
||||
argument passed by the Heaviside object.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The ``eval()`` method is automatically called when the ``Heaviside``
|
||||
class is about to be instantiated and it returns either some simplified
|
||||
instance or the unevaluated instance depending on the argument passed.
|
||||
In other words, ``eval()`` method is not needed to be called explicitly,
|
||||
it is being called and evaluated once the object is called.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, S
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> Heaviside(x)
|
||||
Heaviside(x)
|
||||
|
||||
>>> Heaviside(19)
|
||||
1
|
||||
|
||||
>>> Heaviside(0)
|
||||
1/2
|
||||
|
||||
>>> Heaviside(0, 1)
|
||||
1
|
||||
|
||||
>>> Heaviside(-5)
|
||||
0
|
||||
|
||||
>>> Heaviside(S.NaN)
|
||||
nan
|
||||
|
||||
>>> Heaviside(x - 100).subs(x, 5)
|
||||
0
|
||||
|
||||
>>> Heaviside(x - 100).subs(x, 105)
|
||||
1
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
arg : argument passed by Heaviside object
|
||||
|
||||
H0 : value of Heaviside(0)
|
||||
|
||||
"""
|
||||
if arg.is_extended_negative:
|
||||
return S.Zero
|
||||
elif arg.is_extended_positive:
|
||||
return S.One
|
||||
elif arg.is_zero:
|
||||
return H0
|
||||
elif arg is S.NaN:
|
||||
return S.NaN
|
||||
elif fuzzy_not(im(arg).is_zero):
|
||||
raise ValueError("Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)) )
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, arg, H0=None, **kwargs):
|
||||
"""
|
||||
Represents Heaviside in a Piecewise form.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, Piecewise, Symbol, nan
|
||||
>>> x = Symbol('x')
|
||||
|
||||
>>> Heaviside(x).rewrite(Piecewise)
|
||||
Piecewise((0, x < 0), (1/2, Eq(x, 0)), (1, True))
|
||||
|
||||
>>> Heaviside(x,nan).rewrite(Piecewise)
|
||||
Piecewise((0, x < 0), (nan, Eq(x, 0)), (1, True))
|
||||
|
||||
>>> Heaviside(x - 5).rewrite(Piecewise)
|
||||
Piecewise((0, x < 5), (1/2, Eq(x, 5)), (1, True))
|
||||
|
||||
>>> Heaviside(x**2 - 1).rewrite(Piecewise)
|
||||
Piecewise((0, x**2 < 1), (1/2, Eq(x**2, 1)), (1, True))
|
||||
|
||||
"""
|
||||
if H0 == 0:
|
||||
return Piecewise((0, arg <= 0), (1, True))
|
||||
if H0 == 1:
|
||||
return Piecewise((0, arg < 0), (1, True))
|
||||
return Piecewise((0, arg < 0), (H0, Eq(arg, 0)), (1, True))
|
||||
|
||||
def _eval_rewrite_as_sign(self, arg, H0=S.Half, **kwargs):
|
||||
"""
|
||||
Represents the Heaviside function in the form of sign function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The value of Heaviside(0) must be 1/2 for rewriting as sign to be
|
||||
strictly equivalent. For easier usage, we also allow this rewriting
|
||||
when Heaviside(0) is undefined.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, Symbol, sign, nan
|
||||
>>> x = Symbol('x', real=True)
|
||||
>>> y = Symbol('y')
|
||||
|
||||
>>> Heaviside(x).rewrite(sign)
|
||||
sign(x)/2 + 1/2
|
||||
|
||||
>>> Heaviside(x, 0).rewrite(sign)
|
||||
Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (0, True))
|
||||
|
||||
>>> Heaviside(x, nan).rewrite(sign)
|
||||
Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (nan, True))
|
||||
|
||||
>>> Heaviside(x - 2).rewrite(sign)
|
||||
sign(x - 2)/2 + 1/2
|
||||
|
||||
>>> Heaviside(x**2 - 2*x + 1).rewrite(sign)
|
||||
sign(x**2 - 2*x + 1)/2 + 1/2
|
||||
|
||||
>>> Heaviside(y).rewrite(sign)
|
||||
Heaviside(y)
|
||||
|
||||
>>> Heaviside(y**2 - 2*y + 1).rewrite(sign)
|
||||
Heaviside(y**2 - 2*y + 1)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sign
|
||||
|
||||
"""
|
||||
if arg.is_extended_real:
|
||||
pw1 = Piecewise(
|
||||
((sign(arg) + 1)/2, Ne(arg, 0)),
|
||||
(Heaviside(0, H0=H0), True))
|
||||
pw2 = Piecewise(
|
||||
((sign(arg) + 1)/2, Eq(Heaviside(0, H0=H0), S.Half)),
|
||||
(pw1, True))
|
||||
return pw2
|
||||
|
||||
def _eval_rewrite_as_SingularityFunction(self, args, H0=S.Half, **kwargs):
|
||||
"""
|
||||
Returns the Heaviside expression written in the form of Singularity
|
||||
Functions.
|
||||
|
||||
"""
|
||||
from sympy.solvers import solve
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
if self == Heaviside(0):
|
||||
return SingularityFunction(0, 0, 0)
|
||||
free = self.free_symbols
|
||||
if len(free) == 1:
|
||||
x = (free.pop())
|
||||
return SingularityFunction(x, solve(args, x)[0], 0)
|
||||
# TODO
|
||||
# ((x - 5)**3*Heaviside(x - 5)).rewrite(SingularityFunction) should output
|
||||
# SingularityFunction(x, 5, 0) instead of (x - 5)**3*SingularityFunction(x, 5, 0)
|
||||
else:
|
||||
# I don't know how to handle the case for Heaviside expressions
|
||||
# having arguments with more than one variable.
|
||||
raise TypeError(filldedent('''
|
||||
rewrite(SingularityFunction) does not
|
||||
support arguments with more that one variable.'''))
|
||||
|
|
@ -0,0 +1,445 @@
|
|||
""" Elliptic Integrals. """
|
||||
|
||||
from sympy.core import S, pi, I, Rational
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.symbol import Dummy,uniquely_named_symbol
|
||||
from sympy.functions.elementary.complexes import sign
|
||||
from sympy.functions.elementary.hyperbolic import atanh
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import sin, tan
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.functions.special.hyper import hyper, meijerg
|
||||
|
||||
class elliptic_k(DefinedFunction):
|
||||
r"""
|
||||
The complete elliptic integral of the first kind, defined by
|
||||
|
||||
.. math:: K(m) = F\left(\tfrac{\pi}{2}\middle| m\right)
|
||||
|
||||
where $F\left(z\middle| m\right)$ is the Legendre incomplete
|
||||
elliptic integral of the first kind.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The function $K(m)$ is a single-valued function on the complex
|
||||
plane with branch cut along the interval $(1, \infty)$.
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_k, I
|
||||
>>> from sympy.abc import m
|
||||
>>> elliptic_k(0)
|
||||
pi/2
|
||||
>>> elliptic_k(1.0 + I)
|
||||
1.50923695405127 + 0.625146415202697*I
|
||||
>>> elliptic_k(m).series(n=3)
|
||||
pi/2 + pi*m/8 + 9*pi*m**2/128 + O(m**3)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
elliptic_f
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticK
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, m):
|
||||
if m.is_zero:
|
||||
return pi*S.Half
|
||||
elif m is S.Half:
|
||||
return 8*pi**Rational(3, 2)/gamma(Rational(-1, 4))**2
|
||||
elif m is S.One:
|
||||
return S.ComplexInfinity
|
||||
elif m is S.NegativeOne:
|
||||
return gamma(Rational(1, 4))**2/(4*sqrt(2*pi))
|
||||
elif m in (S.Infinity, S.NegativeInfinity, I*S.Infinity,
|
||||
I*S.NegativeInfinity, S.ComplexInfinity):
|
||||
return S.Zero
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
m = self.args[0]
|
||||
return (elliptic_e(m) - (1 - m)*elliptic_k(m))/(2*m*(1 - m))
|
||||
|
||||
def _eval_conjugate(self):
|
||||
m = self.args[0]
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(m.conjugate())
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
from sympy.simplify import hyperexpand
|
||||
return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx))
|
||||
|
||||
def _eval_rewrite_as_hyper(self, m, **kwargs):
|
||||
return pi*S.Half*hyper((S.Half, S.Half), (S.One,), m)
|
||||
|
||||
def _eval_rewrite_as_meijerg(self, m, **kwargs):
|
||||
return meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -m)/2
|
||||
|
||||
def _eval_is_zero(self):
|
||||
m = self.args[0]
|
||||
if m.is_infinite:
|
||||
return True
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
m = self.args[0]
|
||||
return Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, pi/2))
|
||||
|
||||
|
||||
class elliptic_f(DefinedFunction):
|
||||
r"""
|
||||
The Legendre incomplete elliptic integral of the first
|
||||
kind, defined by
|
||||
|
||||
.. math:: F\left(z\middle| m\right) =
|
||||
\int_0^z \frac{dt}{\sqrt{1 - m \sin^2 t}}
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function reduces to a complete elliptic integral of
|
||||
the first kind, $K(m)$, when $z = \pi/2$.
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_f, I
|
||||
>>> from sympy.abc import z, m
|
||||
>>> elliptic_f(z, m).series(z)
|
||||
z + z**5*(3*m**2/40 - m/30) + m*z**3/6 + O(z**6)
|
||||
>>> elliptic_f(3.0 + I/2, 1.0 + I)
|
||||
2.909449841483 + 1.74720545502474*I
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
elliptic_k
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticF
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, z, m):
|
||||
if z.is_zero:
|
||||
return S.Zero
|
||||
if m.is_zero:
|
||||
return z
|
||||
k = 2*z/pi
|
||||
if k.is_integer:
|
||||
return k*elliptic_k(m)
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif z.could_extract_minus_sign():
|
||||
return -elliptic_f(-z, m)
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
z, m = self.args
|
||||
fm = sqrt(1 - m*sin(z)**2)
|
||||
if argindex == 1:
|
||||
return 1/fm
|
||||
elif argindex == 2:
|
||||
return (elliptic_e(z, m)/(2*m*(1 - m)) - elliptic_f(z, m)/(2*m) -
|
||||
sin(2*z)/(4*(1 - m)*fm))
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_conjugate(self):
|
||||
z, m = self.args
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(z.conjugate(), m.conjugate())
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
z, m = self.args[0], self.args[1]
|
||||
return Integral(1/(sqrt(1 - m*sin(t)**2)), (t, 0, z))
|
||||
|
||||
def _eval_is_zero(self):
|
||||
z, m = self.args
|
||||
if z.is_zero:
|
||||
return True
|
||||
if m.is_extended_real and m.is_infinite:
|
||||
return True
|
||||
|
||||
|
||||
class elliptic_e(DefinedFunction):
|
||||
r"""
|
||||
Called with two arguments $z$ and $m$, evaluates the
|
||||
incomplete elliptic integral of the second kind, defined by
|
||||
|
||||
.. math:: E\left(z\middle| m\right) = \int_0^z \sqrt{1 - m \sin^2 t} dt
|
||||
|
||||
Called with a single argument $m$, evaluates the Legendre complete
|
||||
elliptic integral of the second kind
|
||||
|
||||
.. math:: E(m) = E\left(\tfrac{\pi}{2}\middle| m\right)
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The function $E(m)$ is a single-valued function on the complex
|
||||
plane with branch cut along the interval $(1, \infty)$.
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_e, I
|
||||
>>> from sympy.abc import z, m
|
||||
>>> elliptic_e(z, m).series(z)
|
||||
z + z**5*(-m**2/40 + m/30) - m*z**3/6 + O(z**6)
|
||||
>>> elliptic_e(m).series(n=4)
|
||||
pi/2 - pi*m/8 - 3*pi*m**2/128 - 5*pi*m**3/512 + O(m**4)
|
||||
>>> elliptic_e(1 + I, 2 - I/2).n()
|
||||
1.55203744279187 + 0.290764986058437*I
|
||||
>>> elliptic_e(0)
|
||||
pi/2
|
||||
>>> elliptic_e(2.0 - I)
|
||||
0.991052601328069 + 0.81879421395609*I
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticE2
|
||||
.. [3] https://functions.wolfram.com/EllipticIntegrals/EllipticE
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, m, z=None):
|
||||
if z is not None:
|
||||
z, m = m, z
|
||||
k = 2*z/pi
|
||||
if m.is_zero:
|
||||
return z
|
||||
if z.is_zero:
|
||||
return S.Zero
|
||||
elif k.is_integer:
|
||||
return k*elliptic_e(m)
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.ComplexInfinity
|
||||
elif z.could_extract_minus_sign():
|
||||
return -elliptic_e(-z, m)
|
||||
else:
|
||||
if m.is_zero:
|
||||
return pi/2
|
||||
elif m is S.One:
|
||||
return S.One
|
||||
elif m is S.Infinity:
|
||||
return I*S.Infinity
|
||||
elif m is S.NegativeInfinity:
|
||||
return S.Infinity
|
||||
elif m is S.ComplexInfinity:
|
||||
return S.ComplexInfinity
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if len(self.args) == 2:
|
||||
z, m = self.args
|
||||
if argindex == 1:
|
||||
return sqrt(1 - m*sin(z)**2)
|
||||
elif argindex == 2:
|
||||
return (elliptic_e(z, m) - elliptic_f(z, m))/(2*m)
|
||||
else:
|
||||
m = self.args[0]
|
||||
if argindex == 1:
|
||||
return (elliptic_e(m) - elliptic_k(m))/(2*m)
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_conjugate(self):
|
||||
if len(self.args) == 2:
|
||||
z, m = self.args
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(z.conjugate(), m.conjugate())
|
||||
else:
|
||||
m = self.args[0]
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(m.conjugate())
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
from sympy.simplify import hyperexpand
|
||||
if len(self.args) == 1:
|
||||
return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx))
|
||||
return super()._eval_nseries(x, n=n, logx=logx)
|
||||
|
||||
def _eval_rewrite_as_hyper(self, *args, **kwargs):
|
||||
if len(args) == 1:
|
||||
m = args[0]
|
||||
return (pi/2)*hyper((Rational(-1, 2), S.Half), (S.One,), m)
|
||||
|
||||
def _eval_rewrite_as_meijerg(self, *args, **kwargs):
|
||||
if len(args) == 1:
|
||||
m = args[0]
|
||||
return -meijerg(((S.Half, Rational(3, 2)), []), \
|
||||
((S.Zero,), (S.Zero,)), -m)/4
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
z, m = (pi/2, self.args[0]) if len(self.args) == 1 else self.args
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
return Integral(sqrt(1 - m*sin(t)**2), (t, 0, z))
|
||||
|
||||
|
||||
class elliptic_pi(DefinedFunction):
|
||||
r"""
|
||||
Called with three arguments $n$, $z$ and $m$, evaluates the
|
||||
Legendre incomplete elliptic integral of the third kind, defined by
|
||||
|
||||
.. math:: \Pi\left(n; z\middle| m\right) = \int_0^z \frac{dt}
|
||||
{\left(1 - n \sin^2 t\right) \sqrt{1 - m \sin^2 t}}
|
||||
|
||||
Called with two arguments $n$ and $m$, evaluates the complete
|
||||
elliptic integral of the third kind:
|
||||
|
||||
.. math:: \Pi\left(n\middle| m\right) =
|
||||
\Pi\left(n; \tfrac{\pi}{2}\middle| m\right)
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_pi, I
|
||||
>>> from sympy.abc import z, n, m
|
||||
>>> elliptic_pi(n, z, m).series(z, n=4)
|
||||
z + z**3*(m/6 + n/3) + O(z**4)
|
||||
>>> elliptic_pi(0.5 + I, 1.0 - I, 1.2)
|
||||
2.50232379629182 - 0.760939574180767*I
|
||||
>>> elliptic_pi(0, 0)
|
||||
pi/2
|
||||
>>> elliptic_pi(1.0 - I/3, 2.0 + I)
|
||||
3.29136443417283 + 0.32555634906645*I
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticPi3
|
||||
.. [3] https://functions.wolfram.com/EllipticIntegrals/EllipticPi
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, n, m, z=None):
|
||||
if z is not None:
|
||||
z, m = m, z
|
||||
if n.is_zero:
|
||||
return elliptic_f(z, m)
|
||||
elif n is S.One:
|
||||
return (elliptic_f(z, m) +
|
||||
(sqrt(1 - m*sin(z)**2)*tan(z) -
|
||||
elliptic_e(z, m))/(1 - m))
|
||||
k = 2*z/pi
|
||||
if k.is_integer:
|
||||
return k*elliptic_pi(n, m)
|
||||
elif m.is_zero:
|
||||
return atanh(sqrt(n - 1)*tan(z))/sqrt(n - 1)
|
||||
elif n == m:
|
||||
return (elliptic_f(z, n) - elliptic_pi(1, z, n) +
|
||||
tan(z)/sqrt(1 - n*sin(z)**2))
|
||||
elif n in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif z.could_extract_minus_sign():
|
||||
return -elliptic_pi(n, -z, m)
|
||||
if n.is_zero:
|
||||
return elliptic_f(z, m)
|
||||
if m.is_extended_real and m.is_infinite or \
|
||||
n.is_extended_real and n.is_infinite:
|
||||
return S.Zero
|
||||
else:
|
||||
if n.is_zero:
|
||||
return elliptic_k(m)
|
||||
elif n is S.One:
|
||||
return S.ComplexInfinity
|
||||
elif m.is_zero:
|
||||
return pi/(2*sqrt(1 - n))
|
||||
elif m == S.One:
|
||||
return S.NegativeInfinity/sign(n - 1)
|
||||
elif n == m:
|
||||
return elliptic_e(n)/(1 - n)
|
||||
elif n in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
if n.is_zero:
|
||||
return elliptic_k(m)
|
||||
if m.is_extended_real and m.is_infinite or \
|
||||
n.is_extended_real and n.is_infinite:
|
||||
return S.Zero
|
||||
|
||||
def _eval_conjugate(self):
|
||||
if len(self.args) == 3:
|
||||
n, z, m = self.args
|
||||
if (n.is_real and (n - 1).is_positive) is False and \
|
||||
(m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(n.conjugate(), z.conjugate(), m.conjugate())
|
||||
else:
|
||||
n, m = self.args
|
||||
return self.func(n.conjugate(), m.conjugate())
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if len(self.args) == 3:
|
||||
n, z, m = self.args
|
||||
fm, fn = sqrt(1 - m*sin(z)**2), 1 - n*sin(z)**2
|
||||
if argindex == 1:
|
||||
return (elliptic_e(z, m) + (m - n)*elliptic_f(z, m)/n +
|
||||
(n**2 - m)*elliptic_pi(n, z, m)/n -
|
||||
n*fm*sin(2*z)/(2*fn))/(2*(m - n)*(n - 1))
|
||||
elif argindex == 2:
|
||||
return 1/(fm*fn)
|
||||
elif argindex == 3:
|
||||
return (elliptic_e(z, m)/(m - 1) +
|
||||
elliptic_pi(n, z, m) -
|
||||
m*sin(2*z)/(2*(m - 1)*fm))/(2*(n - m))
|
||||
else:
|
||||
n, m = self.args
|
||||
if argindex == 1:
|
||||
return (elliptic_e(m) + (m - n)*elliptic_k(m)/n +
|
||||
(n**2 - m)*elliptic_pi(n, m)/n)/(2*(m - n)*(n - 1))
|
||||
elif argindex == 2:
|
||||
return (elliptic_e(m)/(m - 1) + elliptic_pi(n, m))/(2*(n - m))
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
if len(self.args) == 2:
|
||||
n, m, z = self.args[0], self.args[1], pi/2
|
||||
else:
|
||||
n, z, m = self.args
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
return Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, z))
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1185
venv/lib/python3.12/site-packages/sympy/functions/special/hyper.py
Normal file
1185
venv/lib/python3.12/site-packages/sympy/functions/special/hyper.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,269 @@
|
|||
""" This module contains the Mathieu functions.
|
||||
"""
|
||||
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import sin, cos
|
||||
|
||||
|
||||
class MathieuBase(DefinedFunction):
|
||||
"""
|
||||
Abstract base class for Mathieu functions.
|
||||
|
||||
This class is meant to reduce code duplication.
|
||||
|
||||
"""
|
||||
|
||||
unbranched = True
|
||||
|
||||
def _eval_conjugate(self):
|
||||
a, q, z = self.args
|
||||
return self.func(a.conjugate(), q.conjugate(), z.conjugate())
|
||||
|
||||
|
||||
class mathieus(MathieuBase):
|
||||
r"""
|
||||
The Mathieu Sine function $S(a,q,z)$.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Cosine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieus
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieus(a, q, z)
|
||||
mathieus(a, q, z)
|
||||
|
||||
>>> mathieus(a, 0, z)
|
||||
sin(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieus(a, q, z), z)
|
||||
mathieusprime(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieuc: Mathieu cosine function.
|
||||
mathieusprime: Derivative of Mathieu sine function.
|
||||
mathieucprime: Derivative of Mathieu cosine function.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuS/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return mathieusprime(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return sin(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return -cls(a, q, -z)
|
||||
|
||||
|
||||
class mathieuc(MathieuBase):
|
||||
r"""
|
||||
The Mathieu Cosine function $C(a,q,z)$.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Sine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieuc
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieuc(a, q, z)
|
||||
mathieuc(a, q, z)
|
||||
|
||||
>>> mathieuc(a, 0, z)
|
||||
cos(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieuc(a, q, z), z)
|
||||
mathieucprime(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieus: Mathieu sine function
|
||||
mathieusprime: Derivative of Mathieu sine function
|
||||
mathieucprime: Derivative of Mathieu cosine function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuC/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return mathieucprime(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return cos(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return cls(a, q, -z)
|
||||
|
||||
|
||||
class mathieusprime(MathieuBase):
|
||||
r"""
|
||||
The derivative $S^{\prime}(a,q,z)$ of the Mathieu Sine function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Cosine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieusprime
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieusprime(a, q, z)
|
||||
mathieusprime(a, q, z)
|
||||
|
||||
>>> mathieusprime(a, 0, z)
|
||||
sqrt(a)*cos(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieusprime(a, q, z), z)
|
||||
(-a + 2*q*cos(2*z))*mathieus(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieus: Mathieu sine function
|
||||
mathieuc: Mathieu cosine function
|
||||
mathieucprime: Derivative of Mathieu cosine function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuSPrime/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return (2*q*cos(2*z) - a)*mathieus(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return sqrt(a)*cos(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return cls(a, q, -z)
|
||||
|
||||
|
||||
class mathieucprime(MathieuBase):
|
||||
r"""
|
||||
The derivative $C^{\prime}(a,q,z)$ of the Mathieu Cosine function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Sine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieucprime
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieucprime(a, q, z)
|
||||
mathieucprime(a, q, z)
|
||||
|
||||
>>> mathieucprime(a, 0, z)
|
||||
-sqrt(a)*sin(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieucprime(a, q, z), z)
|
||||
(-a + 2*q*cos(2*z))*mathieuc(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieus: Mathieu sine function
|
||||
mathieuc: Mathieu cosine function
|
||||
mathieusprime: Derivative of Mathieu sine function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuCPrime/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return (2*q*cos(2*z) - a)*mathieuc(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return -sqrt(a)*sin(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return -cls(a, q, -z)
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,235 @@
|
|||
from sympy.core import S, oo, diff
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.functions.elementary.complexes import im
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.special.delta_functions import Heaviside
|
||||
|
||||
###############################################################################
|
||||
############################# SINGULARITY FUNCTION ############################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class SingularityFunction(DefinedFunction):
|
||||
r"""
|
||||
Singularity functions are a class of discontinuous functions.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Singularity functions take a variable, an offset, and an exponent as
|
||||
arguments. These functions are represented using Macaulay brackets as:
|
||||
|
||||
SingularityFunction(x, a, n) := <x - a>^n
|
||||
|
||||
The singularity function will automatically evaluate to
|
||||
``Derivative(DiracDelta(x - a), x, -n - 1)`` if ``n < 0``
|
||||
and ``(x - a)**n*Heaviside(x - a, 1)`` if ``n >= 0``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import SingularityFunction, diff, Piecewise, DiracDelta, Heaviside, Symbol
|
||||
>>> from sympy.abc import x, a, n
|
||||
>>> SingularityFunction(x, a, n)
|
||||
SingularityFunction(x, a, n)
|
||||
>>> y = Symbol('y', positive=True)
|
||||
>>> n = Symbol('n', nonnegative=True)
|
||||
>>> SingularityFunction(y, -10, n)
|
||||
(y + 10)**n
|
||||
>>> y = Symbol('y', negative=True)
|
||||
>>> SingularityFunction(y, 10, n)
|
||||
0
|
||||
>>> SingularityFunction(x, 4, -1).subs(x, 4)
|
||||
oo
|
||||
>>> SingularityFunction(x, 10, -2).subs(x, 10)
|
||||
oo
|
||||
>>> SingularityFunction(4, 1, 5)
|
||||
243
|
||||
>>> diff(SingularityFunction(x, 1, 5) + SingularityFunction(x, 1, 4), x)
|
||||
4*SingularityFunction(x, 1, 3) + 5*SingularityFunction(x, 1, 4)
|
||||
>>> diff(SingularityFunction(x, 4, 0), x, 2)
|
||||
SingularityFunction(x, 4, -2)
|
||||
>>> SingularityFunction(x, 4, 5).rewrite(Piecewise)
|
||||
Piecewise(((x - 4)**5, x >= 4), (0, True))
|
||||
>>> expr = SingularityFunction(x, a, n)
|
||||
>>> y = Symbol('y', positive=True)
|
||||
>>> n = Symbol('n', nonnegative=True)
|
||||
>>> expr.subs({x: y, a: -10, n: n})
|
||||
(y + 10)**n
|
||||
|
||||
The methods ``rewrite(DiracDelta)``, ``rewrite(Heaviside)``, and
|
||||
``rewrite('HeavisideDiracDelta')`` returns the same output. One can use any
|
||||
of these methods according to their choice.
|
||||
|
||||
>>> expr = SingularityFunction(x, 4, 5) + SingularityFunction(x, -3, -1) - SingularityFunction(x, 0, -2)
|
||||
>>> expr.rewrite(Heaviside)
|
||||
(x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
|
||||
>>> expr.rewrite(DiracDelta)
|
||||
(x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
|
||||
>>> expr.rewrite('HeavisideDiracDelta')
|
||||
(x - 4)**5*Heaviside(x - 4, 1) + DiracDelta(x + 3) - DiracDelta(x, 1)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
DiracDelta, Heaviside
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Singularity_function
|
||||
|
||||
"""
|
||||
|
||||
is_real = True
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
"""
|
||||
Returns the first derivative of a DiracDelta Function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the
|
||||
user-level function and ``fdiff()`` is an object method. ``fdiff()`` is
|
||||
a convenience method available in the ``Function`` class. It returns
|
||||
the derivative of the function without considering the chain rule.
|
||||
``diff(function, x)`` calls ``Function._eval_derivative`` which in turn
|
||||
calls ``fdiff()`` internally to compute the derivative of the function.
|
||||
|
||||
"""
|
||||
|
||||
if argindex == 1:
|
||||
x, a, n = self.args
|
||||
if n in (S.Zero, S.NegativeOne, S(-2), S(-3)):
|
||||
return self.func(x, a, n-1)
|
||||
elif n.is_positive:
|
||||
return n*self.func(x, a, n-1)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, variable, offset, exponent):
|
||||
"""
|
||||
Returns a simplified form or a value of Singularity Function depending
|
||||
on the argument passed by the object.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The ``eval()`` method is automatically called when the
|
||||
``SingularityFunction`` class is about to be instantiated and it
|
||||
returns either some simplified instance or the unevaluated instance
|
||||
depending on the argument passed. In other words, ``eval()`` method is
|
||||
not needed to be called explicitly, it is being called and evaluated
|
||||
once the object is called.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import SingularityFunction, Symbol, nan
|
||||
>>> from sympy.abc import x, a, n
|
||||
>>> SingularityFunction(x, a, n)
|
||||
SingularityFunction(x, a, n)
|
||||
>>> SingularityFunction(5, 3, 2)
|
||||
4
|
||||
>>> SingularityFunction(x, a, nan)
|
||||
nan
|
||||
>>> SingularityFunction(x, 3, 0).subs(x, 3)
|
||||
1
|
||||
>>> SingularityFunction(4, 1, 5)
|
||||
243
|
||||
>>> x = Symbol('x', positive = True)
|
||||
>>> a = Symbol('a', negative = True)
|
||||
>>> n = Symbol('n', nonnegative = True)
|
||||
>>> SingularityFunction(x, a, n)
|
||||
(-a + x)**n
|
||||
>>> x = Symbol('x', negative = True)
|
||||
>>> a = Symbol('a', positive = True)
|
||||
>>> SingularityFunction(x, a, n)
|
||||
0
|
||||
|
||||
"""
|
||||
|
||||
x = variable
|
||||
a = offset
|
||||
n = exponent
|
||||
shift = (x - a)
|
||||
|
||||
if fuzzy_not(im(shift).is_zero):
|
||||
raise ValueError("Singularity Functions are defined only for Real Numbers.")
|
||||
if fuzzy_not(im(n).is_zero):
|
||||
raise ValueError("Singularity Functions are not defined for imaginary exponents.")
|
||||
if shift is S.NaN or n is S.NaN:
|
||||
return S.NaN
|
||||
if (n + 4).is_negative:
|
||||
raise ValueError("Singularity Functions are not defined for exponents less than -4.")
|
||||
if shift.is_extended_negative:
|
||||
return S.Zero
|
||||
if n.is_nonnegative:
|
||||
if shift.is_zero: # use literal 0 in case of Symbol('z', zero=True)
|
||||
return S.Zero**n
|
||||
if shift.is_extended_nonnegative:
|
||||
return shift**n
|
||||
if n in (S.NegativeOne, -2, -3, -4):
|
||||
if shift.is_negative or shift.is_extended_positive:
|
||||
return S.Zero
|
||||
if shift.is_zero:
|
||||
return oo
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
|
||||
'''
|
||||
Converts a Singularity Function expression into its Piecewise form.
|
||||
|
||||
'''
|
||||
x, a, n = self.args
|
||||
|
||||
if n in (S.NegativeOne, S(-2), S(-3), S(-4)):
|
||||
return Piecewise((oo, Eq(x - a, 0)), (0, True))
|
||||
elif n.is_nonnegative:
|
||||
return Piecewise(((x - a)**n, x - a >= 0), (0, True))
|
||||
|
||||
def _eval_rewrite_as_Heaviside(self, *args, **kwargs):
|
||||
'''
|
||||
Rewrites a Singularity Function expression using Heavisides and DiracDeltas.
|
||||
|
||||
'''
|
||||
x, a, n = self.args
|
||||
|
||||
if n == -4:
|
||||
return diff(Heaviside(x - a), x.free_symbols.pop(), 4)
|
||||
if n == -3:
|
||||
return diff(Heaviside(x - a), x.free_symbols.pop(), 3)
|
||||
if n == -2:
|
||||
return diff(Heaviside(x - a), x.free_symbols.pop(), 2)
|
||||
if n == -1:
|
||||
return diff(Heaviside(x - a), x.free_symbols.pop(), 1)
|
||||
if n.is_nonnegative:
|
||||
return (x - a)**n*Heaviside(x - a, 1)
|
||||
|
||||
def _eval_as_leading_term(self, x, logx, cdir):
|
||||
z, a, n = self.args
|
||||
shift = (z - a).subs(x, 0)
|
||||
if n < 0:
|
||||
return S.Zero
|
||||
elif n.is_zero and shift.is_zero:
|
||||
return S.Zero if cdir == -1 else S.One
|
||||
elif shift.is_positive:
|
||||
return shift**n
|
||||
return S.Zero
|
||||
|
||||
def _eval_nseries(self, x, n, logx=None, cdir=0):
|
||||
z, a, n = self.args
|
||||
shift = (z - a).subs(x, 0)
|
||||
if n < 0:
|
||||
return S.Zero
|
||||
elif n.is_zero and shift.is_zero:
|
||||
return S.Zero if cdir == -1 else S.One
|
||||
elif shift.is_positive:
|
||||
return ((z - a)**n)._eval_nseries(x, n, logx=logx, cdir=cdir)
|
||||
return S.Zero
|
||||
|
||||
_eval_rewrite_as_DiracDelta = _eval_rewrite_as_Heaviside
|
||||
_eval_rewrite_as_HeavisideDiracDelta = _eval_rewrite_as_Heaviside
|
||||
|
|
@ -0,0 +1,334 @@
|
|||
from sympy.core.expr import Expr
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.numbers import I, pi
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Dummy
|
||||
from sympy.functions import assoc_legendre
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.elementary.complexes import Abs, conjugate
|
||||
from sympy.functions.elementary.exponential import exp
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import sin, cos, cot
|
||||
|
||||
_x = Dummy("x")
|
||||
|
||||
class Ynm(DefinedFunction):
|
||||
r"""
|
||||
Spherical harmonics defined as
|
||||
|
||||
.. math::
|
||||
Y_n^m(\theta, \varphi) := \sqrt{\frac{(2n+1)(n-m)!}{4\pi(n+m)!}}
|
||||
\exp(i m \varphi)
|
||||
\mathrm{P}_n^m\left(\cos(\theta)\right)
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
``Ynm()`` gives the spherical harmonic function of order $n$ and $m$
|
||||
in $\theta$ and $\varphi$, $Y_n^m(\theta, \varphi)$. The four
|
||||
parameters are as follows: $n \geq 0$ an integer and $m$ an integer
|
||||
such that $-n \leq m \leq n$ holds. The two angles are real-valued
|
||||
with $\theta \in [0, \pi]$ and $\varphi \in [0, 2\pi]$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Ynm, Symbol, simplify
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
|
||||
>>> Ynm(n, m, theta, phi)
|
||||
Ynm(n, m, theta, phi)
|
||||
|
||||
Several symmetries are known, for the order:
|
||||
|
||||
>>> Ynm(n, -m, theta, phi)
|
||||
(-1)**m*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
|
||||
As well as for the angles:
|
||||
|
||||
>>> Ynm(n, m, -theta, phi)
|
||||
Ynm(n, m, theta, phi)
|
||||
|
||||
>>> Ynm(n, m, theta, -phi)
|
||||
exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
|
||||
For specific integers $n$ and $m$ we can evaluate the harmonics
|
||||
to more useful expressions:
|
||||
|
||||
>>> simplify(Ynm(0, 0, theta, phi).expand(func=True))
|
||||
1/(2*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(1, -1, theta, phi).expand(func=True))
|
||||
sqrt(6)*exp(-I*phi)*sin(theta)/(4*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(1, 0, theta, phi).expand(func=True))
|
||||
sqrt(3)*cos(theta)/(2*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(1, 1, theta, phi).expand(func=True))
|
||||
-sqrt(6)*exp(I*phi)*sin(theta)/(4*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, -2, theta, phi).expand(func=True))
|
||||
sqrt(30)*exp(-2*I*phi)*sin(theta)**2/(8*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, -1, theta, phi).expand(func=True))
|
||||
sqrt(30)*exp(-I*phi)*sin(2*theta)/(8*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, 0, theta, phi).expand(func=True))
|
||||
sqrt(5)*(3*cos(theta)**2 - 1)/(4*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, 1, theta, phi).expand(func=True))
|
||||
-sqrt(30)*exp(I*phi)*sin(2*theta)/(8*sqrt(pi))
|
||||
|
||||
>>> simplify(Ynm(2, 2, theta, phi).expand(func=True))
|
||||
sqrt(30)*exp(2*I*phi)*sin(theta)**2/(8*sqrt(pi))
|
||||
|
||||
We can differentiate the functions with respect
|
||||
to both angles:
|
||||
|
||||
>>> from sympy import Ynm, Symbol, diff
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
|
||||
>>> diff(Ynm(n, m, theta, phi), theta)
|
||||
m*cot(theta)*Ynm(n, m, theta, phi) + sqrt((-m + n)*(m + n + 1))*exp(-I*phi)*Ynm(n, m + 1, theta, phi)
|
||||
|
||||
>>> diff(Ynm(n, m, theta, phi), phi)
|
||||
I*m*Ynm(n, m, theta, phi)
|
||||
|
||||
Further we can compute the complex conjugation:
|
||||
|
||||
>>> from sympy import Ynm, Symbol, conjugate
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
|
||||
>>> conjugate(Ynm(n, m, theta, phi))
|
||||
(-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
|
||||
To get back the well known expressions in spherical
|
||||
coordinates, we use full expansion:
|
||||
|
||||
>>> from sympy import Ynm, Symbol, expand_func
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
|
||||
>>> expand_func(Ynm(n, m, theta, phi))
|
||||
sqrt((2*n + 1)*factorial(-m + n)/factorial(m + n))*exp(I*m*phi)*assoc_legendre(n, m, cos(theta))/(2*sqrt(pi))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Ynm_c, Znm
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Spherical_harmonics
|
||||
.. [2] https://mathworld.wolfram.com/SphericalHarmonic.html
|
||||
.. [3] https://functions.wolfram.com/Polynomials/SphericalHarmonicY/
|
||||
.. [4] https://dlmf.nist.gov/14.30
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, n, m, theta, phi):
|
||||
# Handle negative index m and arguments theta, phi
|
||||
if m.could_extract_minus_sign():
|
||||
m = -m
|
||||
return S.NegativeOne**m * exp(-2*I*m*phi) * Ynm(n, m, theta, phi)
|
||||
if theta.could_extract_minus_sign():
|
||||
theta = -theta
|
||||
return Ynm(n, m, theta, phi)
|
||||
if phi.could_extract_minus_sign():
|
||||
phi = -phi
|
||||
return exp(-2*I*m*phi) * Ynm(n, m, theta, phi)
|
||||
|
||||
# TODO Add more simplififcation here
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
n, m, theta, phi = self.args
|
||||
rv = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) *
|
||||
exp(I*m*phi) * assoc_legendre(n, m, cos(theta)))
|
||||
# We can do this because of the range of theta
|
||||
return rv.subs(sqrt(-cos(theta)**2 + 1), sin(theta))
|
||||
|
||||
def fdiff(self, argindex=4):
|
||||
if argindex == 1:
|
||||
# Diff wrt n
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
elif argindex == 2:
|
||||
# Diff wrt m
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
elif argindex == 3:
|
||||
# Diff wrt theta
|
||||
n, m, theta, phi = self.args
|
||||
return (m * cot(theta) * Ynm(n, m, theta, phi) +
|
||||
sqrt((n - m)*(n + m + 1)) * exp(-I*phi) * Ynm(n, m + 1, theta, phi))
|
||||
elif argindex == 4:
|
||||
# Diff wrt phi
|
||||
n, m, theta, phi = self.args
|
||||
return I * m * Ynm(n, m, theta, phi)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_rewrite_as_polynomial(self, n, m, theta, phi, **kwargs):
|
||||
# TODO: Make sure n \in N
|
||||
# TODO: Assert |m| <= n ortherwise we should return 0
|
||||
return self.expand(func=True)
|
||||
|
||||
def _eval_rewrite_as_sin(self, n, m, theta, phi, **kwargs):
|
||||
return self.rewrite(cos)
|
||||
|
||||
def _eval_rewrite_as_cos(self, n, m, theta, phi, **kwargs):
|
||||
# This method can be expensive due to extensive use of simplification!
|
||||
from sympy.simplify import simplify, trigsimp
|
||||
# TODO: Make sure n \in N
|
||||
# TODO: Assert |m| <= n ortherwise we should return 0
|
||||
term = simplify(self.expand(func=True))
|
||||
# We can do this because of the range of theta
|
||||
term = term.xreplace({Abs(sin(theta)):sin(theta)})
|
||||
return simplify(trigsimp(term))
|
||||
|
||||
def _eval_conjugate(self):
|
||||
# TODO: Make sure theta \in R and phi \in R
|
||||
n, m, theta, phi = self.args
|
||||
return S.NegativeOne**m * self.func(n, -m, theta, phi)
|
||||
|
||||
def as_real_imag(self, deep=True, **hints):
|
||||
# TODO: Handle deep and hints
|
||||
n, m, theta, phi = self.args
|
||||
re = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) *
|
||||
cos(m*phi) * assoc_legendre(n, m, cos(theta)))
|
||||
im = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) *
|
||||
sin(m*phi) * assoc_legendre(n, m, cos(theta)))
|
||||
return (re, im)
|
||||
|
||||
def _eval_evalf(self, prec):
|
||||
# Note: works without this function by just calling
|
||||
# mpmath for Legendre polynomials. But using
|
||||
# the dedicated function directly is cleaner.
|
||||
from mpmath import mp, workprec
|
||||
n = self.args[0]._to_mpmath(prec)
|
||||
m = self.args[1]._to_mpmath(prec)
|
||||
theta = self.args[2]._to_mpmath(prec)
|
||||
phi = self.args[3]._to_mpmath(prec)
|
||||
with workprec(prec):
|
||||
res = mp.spherharm(n, m, theta, phi)
|
||||
return Expr._from_mpmath(res, prec)
|
||||
|
||||
|
||||
def Ynm_c(n, m, theta, phi):
|
||||
r"""
|
||||
Conjugate spherical harmonics defined as
|
||||
|
||||
.. math::
|
||||
\overline{Y_n^m(\theta, \varphi)} := (-1)^m Y_n^{-m}(\theta, \varphi).
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Ynm_c, Symbol, simplify
|
||||
>>> from sympy.abc import n,m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
>>> Ynm_c(n, m, theta, phi)
|
||||
(-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
>>> Ynm_c(n, m, -theta, phi)
|
||||
(-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi)
|
||||
|
||||
For specific integers $n$ and $m$ we can evaluate the harmonics
|
||||
to more useful expressions:
|
||||
|
||||
>>> simplify(Ynm_c(0, 0, theta, phi).expand(func=True))
|
||||
1/(2*sqrt(pi))
|
||||
>>> simplify(Ynm_c(1, -1, theta, phi).expand(func=True))
|
||||
sqrt(6)*exp(I*(-phi + 2*conjugate(phi)))*sin(theta)/(4*sqrt(pi))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Ynm, Znm
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Spherical_harmonics
|
||||
.. [2] https://mathworld.wolfram.com/SphericalHarmonic.html
|
||||
.. [3] https://functions.wolfram.com/Polynomials/SphericalHarmonicY/
|
||||
|
||||
"""
|
||||
return conjugate(Ynm(n, m, theta, phi))
|
||||
|
||||
|
||||
class Znm(DefinedFunction):
|
||||
r"""
|
||||
Real spherical harmonics defined as
|
||||
|
||||
.. math::
|
||||
|
||||
Z_n^m(\theta, \varphi) :=
|
||||
\begin{cases}
|
||||
\frac{Y_n^m(\theta, \varphi) + \overline{Y_n^m(\theta, \varphi)}}{\sqrt{2}} &\quad m > 0 \\
|
||||
Y_n^m(\theta, \varphi) &\quad m = 0 \\
|
||||
\frac{Y_n^m(\theta, \varphi) - \overline{Y_n^m(\theta, \varphi)}}{i \sqrt{2}} &\quad m < 0 \\
|
||||
\end{cases}
|
||||
|
||||
which gives in simplified form
|
||||
|
||||
.. math::
|
||||
|
||||
Z_n^m(\theta, \varphi) =
|
||||
\begin{cases}
|
||||
\frac{Y_n^m(\theta, \varphi) + (-1)^m Y_n^{-m}(\theta, \varphi)}{\sqrt{2}} &\quad m > 0 \\
|
||||
Y_n^m(\theta, \varphi) &\quad m = 0 \\
|
||||
\frac{Y_n^m(\theta, \varphi) - (-1)^m Y_n^{-m}(\theta, \varphi)}{i \sqrt{2}} &\quad m < 0 \\
|
||||
\end{cases}
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Znm, Symbol, simplify
|
||||
>>> from sympy.abc import n, m
|
||||
>>> theta = Symbol("theta")
|
||||
>>> phi = Symbol("phi")
|
||||
>>> Znm(n, m, theta, phi)
|
||||
Znm(n, m, theta, phi)
|
||||
|
||||
For specific integers n and m we can evaluate the harmonics
|
||||
to more useful expressions:
|
||||
|
||||
>>> simplify(Znm(0, 0, theta, phi).expand(func=True))
|
||||
1/(2*sqrt(pi))
|
||||
>>> simplify(Znm(1, 1, theta, phi).expand(func=True))
|
||||
-sqrt(3)*sin(theta)*cos(phi)/(2*sqrt(pi))
|
||||
>>> simplify(Znm(2, 1, theta, phi).expand(func=True))
|
||||
-sqrt(15)*sin(2*theta)*cos(phi)/(4*sqrt(pi))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Ynm, Ynm_c
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Spherical_harmonics
|
||||
.. [2] https://mathworld.wolfram.com/SphericalHarmonic.html
|
||||
.. [3] https://functions.wolfram.com/Polynomials/SphericalHarmonicY/
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, n, m, theta, phi):
|
||||
if m.is_positive:
|
||||
zz = (Ynm(n, m, theta, phi) + Ynm_c(n, m, theta, phi)) / sqrt(2)
|
||||
return zz
|
||||
elif m.is_zero:
|
||||
return Ynm(n, m, theta, phi)
|
||||
elif m.is_negative:
|
||||
zz = (Ynm(n, m, theta, phi) - Ynm_c(n, m, theta, phi)) / (sqrt(2)*I)
|
||||
return zz
|
||||
|
|
@ -0,0 +1,474 @@
|
|||
from math import prod
|
||||
|
||||
from sympy.core import S, Integer
|
||||
from sympy.core.function import DefinedFunction
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.core.relational import Ne
|
||||
from sympy.core.sorting import default_sort_key
|
||||
from sympy.external.gmpy import SYMPY_INTS
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.utilities.iterables import has_dups
|
||||
|
||||
###############################################################################
|
||||
###################### Kronecker Delta, Levi-Civita etc. ######################
|
||||
###############################################################################
|
||||
|
||||
|
||||
def Eijk(*args, **kwargs):
|
||||
"""
|
||||
Represent the Levi-Civita symbol.
|
||||
|
||||
This is a compatibility wrapper to ``LeviCivita()``.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
LeviCivita
|
||||
|
||||
"""
|
||||
return LeviCivita(*args, **kwargs)
|
||||
|
||||
|
||||
def eval_levicivita(*args):
|
||||
"""Evaluate Levi-Civita symbol."""
|
||||
n = len(args)
|
||||
return prod(
|
||||
prod(args[j] - args[i] for j in range(i + 1, n))
|
||||
/ factorial(i) for i in range(n))
|
||||
# converting factorial(i) to int is slightly faster
|
||||
|
||||
|
||||
class LeviCivita(DefinedFunction):
|
||||
"""
|
||||
Represent the Levi-Civita symbol.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For even permutations of indices it returns 1, for odd permutations -1, and
|
||||
for everything else (a repeated index) it returns 0.
|
||||
|
||||
Thus it represents an alternating pseudotensor.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import LeviCivita
|
||||
>>> from sympy.abc import i, j, k
|
||||
>>> LeviCivita(1, 2, 3)
|
||||
1
|
||||
>>> LeviCivita(1, 3, 2)
|
||||
-1
|
||||
>>> LeviCivita(1, 2, 2)
|
||||
0
|
||||
>>> LeviCivita(i, j, k)
|
||||
LeviCivita(i, j, k)
|
||||
>>> LeviCivita(i, j, i)
|
||||
0
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Eijk
|
||||
|
||||
"""
|
||||
|
||||
is_integer = True
|
||||
|
||||
@classmethod
|
||||
def eval(cls, *args):
|
||||
if all(isinstance(a, (SYMPY_INTS, Integer)) for a in args):
|
||||
return eval_levicivita(*args)
|
||||
if has_dups(args):
|
||||
return S.Zero
|
||||
|
||||
def doit(self, **hints):
|
||||
return eval_levicivita(*self.args)
|
||||
|
||||
|
||||
class KroneckerDelta(DefinedFunction):
|
||||
"""
|
||||
The discrete, or Kronecker, delta function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
A function that takes in two integers $i$ and $j$. It returns $0$ if $i$
|
||||
and $j$ are not equal, or it returns $1$ if $i$ and $j$ are equal.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
An example with integer indices:
|
||||
|
||||
>>> from sympy import KroneckerDelta
|
||||
>>> KroneckerDelta(1, 2)
|
||||
0
|
||||
>>> KroneckerDelta(3, 3)
|
||||
1
|
||||
|
||||
Symbolic indices:
|
||||
|
||||
>>> from sympy.abc import i, j, k
|
||||
>>> KroneckerDelta(i, j)
|
||||
KroneckerDelta(i, j)
|
||||
>>> KroneckerDelta(i, i)
|
||||
1
|
||||
>>> KroneckerDelta(i, i + 1)
|
||||
0
|
||||
>>> KroneckerDelta(i, i + 1 + k)
|
||||
KroneckerDelta(i, i + k + 1)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
i : Number, Symbol
|
||||
The first index of the delta function.
|
||||
j : Number, Symbol
|
||||
The second index of the delta function.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
eval
|
||||
DiracDelta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Kronecker_delta
|
||||
|
||||
"""
|
||||
|
||||
is_integer = True
|
||||
|
||||
@classmethod
|
||||
def eval(cls, i, j, delta_range=None):
|
||||
"""
|
||||
Evaluates the discrete delta function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta
|
||||
>>> from sympy.abc import i, j, k
|
||||
|
||||
>>> KroneckerDelta(i, j)
|
||||
KroneckerDelta(i, j)
|
||||
>>> KroneckerDelta(i, i)
|
||||
1
|
||||
>>> KroneckerDelta(i, i + 1)
|
||||
0
|
||||
>>> KroneckerDelta(i, i + 1 + k)
|
||||
KroneckerDelta(i, i + k + 1)
|
||||
|
||||
# indirect doctest
|
||||
|
||||
"""
|
||||
|
||||
if delta_range is not None:
|
||||
dinf, dsup = delta_range
|
||||
if (dinf - i > 0) == True:
|
||||
return S.Zero
|
||||
if (dinf - j > 0) == True:
|
||||
return S.Zero
|
||||
if (dsup - i < 0) == True:
|
||||
return S.Zero
|
||||
if (dsup - j < 0) == True:
|
||||
return S.Zero
|
||||
|
||||
diff = i - j
|
||||
if diff.is_zero:
|
||||
return S.One
|
||||
elif fuzzy_not(diff.is_zero):
|
||||
return S.Zero
|
||||
|
||||
if i.assumptions0.get("below_fermi") and \
|
||||
j.assumptions0.get("above_fermi"):
|
||||
return S.Zero
|
||||
if j.assumptions0.get("below_fermi") and \
|
||||
i.assumptions0.get("above_fermi"):
|
||||
return S.Zero
|
||||
# to make KroneckerDelta canonical
|
||||
# following lines will check if inputs are in order
|
||||
# if not, will return KroneckerDelta with correct order
|
||||
if default_sort_key(j) < default_sort_key(i):
|
||||
if delta_range:
|
||||
return cls(j, i, delta_range)
|
||||
else:
|
||||
return cls(j, i)
|
||||
|
||||
@property
|
||||
def delta_range(self):
|
||||
if len(self.args) > 2:
|
||||
return self.args[2]
|
||||
|
||||
def _eval_power(self, expt):
|
||||
if expt.is_positive:
|
||||
return self
|
||||
if expt.is_negative and expt is not S.NegativeOne:
|
||||
return 1/self
|
||||
|
||||
@property
|
||||
def is_above_fermi(self):
|
||||
"""
|
||||
True if Delta can be non-zero above fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, a).is_above_fermi
|
||||
True
|
||||
>>> KroneckerDelta(p, i).is_above_fermi
|
||||
False
|
||||
>>> KroneckerDelta(p, q).is_above_fermi
|
||||
True
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_below_fermi, is_only_below_fermi, is_only_above_fermi
|
||||
|
||||
"""
|
||||
if self.args[0].assumptions0.get("below_fermi"):
|
||||
return False
|
||||
if self.args[1].assumptions0.get("below_fermi"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_below_fermi(self):
|
||||
"""
|
||||
True if Delta can be non-zero below fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, a).is_below_fermi
|
||||
False
|
||||
>>> KroneckerDelta(p, i).is_below_fermi
|
||||
True
|
||||
>>> KroneckerDelta(p, q).is_below_fermi
|
||||
True
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_above_fermi, is_only_above_fermi, is_only_below_fermi
|
||||
|
||||
"""
|
||||
if self.args[0].assumptions0.get("above_fermi"):
|
||||
return False
|
||||
if self.args[1].assumptions0.get("above_fermi"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_only_above_fermi(self):
|
||||
"""
|
||||
True if Delta is restricted to above fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, a).is_only_above_fermi
|
||||
True
|
||||
>>> KroneckerDelta(p, q).is_only_above_fermi
|
||||
False
|
||||
>>> KroneckerDelta(p, i).is_only_above_fermi
|
||||
False
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_above_fermi, is_below_fermi, is_only_below_fermi
|
||||
|
||||
"""
|
||||
return ( self.args[0].assumptions0.get("above_fermi")
|
||||
or
|
||||
self.args[1].assumptions0.get("above_fermi")
|
||||
) or False
|
||||
|
||||
@property
|
||||
def is_only_below_fermi(self):
|
||||
"""
|
||||
True if Delta is restricted to below fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, i).is_only_below_fermi
|
||||
True
|
||||
>>> KroneckerDelta(p, q).is_only_below_fermi
|
||||
False
|
||||
>>> KroneckerDelta(p, a).is_only_below_fermi
|
||||
False
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_above_fermi, is_below_fermi, is_only_above_fermi
|
||||
|
||||
"""
|
||||
return ( self.args[0].assumptions0.get("below_fermi")
|
||||
or
|
||||
self.args[1].assumptions0.get("below_fermi")
|
||||
) or False
|
||||
|
||||
@property
|
||||
def indices_contain_equal_information(self):
|
||||
"""
|
||||
Returns True if indices are either both above or below fermi.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> q = Symbol('q')
|
||||
>>> KroneckerDelta(p, q).indices_contain_equal_information
|
||||
True
|
||||
>>> KroneckerDelta(p, q+1).indices_contain_equal_information
|
||||
True
|
||||
>>> KroneckerDelta(i, p).indices_contain_equal_information
|
||||
False
|
||||
|
||||
"""
|
||||
if (self.args[0].assumptions0.get("below_fermi") and
|
||||
self.args[1].assumptions0.get("below_fermi")):
|
||||
return True
|
||||
if (self.args[0].assumptions0.get("above_fermi")
|
||||
and self.args[1].assumptions0.get("above_fermi")):
|
||||
return True
|
||||
|
||||
# if both indices are general we are True, else false
|
||||
return self.is_below_fermi and self.is_above_fermi
|
||||
|
||||
@property
|
||||
def preferred_index(self):
|
||||
"""
|
||||
Returns the index which is preferred to keep in the final expression.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The preferred index is the index with more information regarding fermi
|
||||
level. If indices contain the same information, 'a' is preferred before
|
||||
'b'.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> j = Symbol('j', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> KroneckerDelta(p, i).preferred_index
|
||||
i
|
||||
>>> KroneckerDelta(p, a).preferred_index
|
||||
a
|
||||
>>> KroneckerDelta(i, j).preferred_index
|
||||
i
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
killable_index
|
||||
|
||||
"""
|
||||
if self._get_preferred_index():
|
||||
return self.args[1]
|
||||
else:
|
||||
return self.args[0]
|
||||
|
||||
@property
|
||||
def killable_index(self):
|
||||
"""
|
||||
Returns the index which is preferred to substitute in the final
|
||||
expression.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The index to substitute is the index with less information regarding
|
||||
fermi level. If indices contain the same information, 'a' is preferred
|
||||
before 'b'.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import KroneckerDelta, Symbol
|
||||
>>> a = Symbol('a', above_fermi=True)
|
||||
>>> i = Symbol('i', below_fermi=True)
|
||||
>>> j = Symbol('j', below_fermi=True)
|
||||
>>> p = Symbol('p')
|
||||
>>> KroneckerDelta(p, i).killable_index
|
||||
p
|
||||
>>> KroneckerDelta(p, a).killable_index
|
||||
p
|
||||
>>> KroneckerDelta(i, j).killable_index
|
||||
j
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
preferred_index
|
||||
|
||||
"""
|
||||
if self._get_preferred_index():
|
||||
return self.args[0]
|
||||
else:
|
||||
return self.args[1]
|
||||
|
||||
def _get_preferred_index(self):
|
||||
"""
|
||||
Returns the index which is preferred to keep in the final expression.
|
||||
|
||||
The preferred index is the index with more information regarding fermi
|
||||
level. If indices contain the same information, index 0 is returned.
|
||||
|
||||
"""
|
||||
if not self.is_above_fermi:
|
||||
if self.args[0].assumptions0.get("below_fermi"):
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
elif not self.is_below_fermi:
|
||||
if self.args[0].assumptions0.get("above_fermi"):
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def indices(self):
|
||||
return self.args[0:2]
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
|
||||
i, j = args
|
||||
return Piecewise((0, Ne(i, j)), (1, True))
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,807 @@
|
|||
from itertools import product
|
||||
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.function import (diff, expand_func)
|
||||
from sympy.core.numbers import (I, Rational, oo, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.elementary.complexes import (conjugate, polar_lift)
|
||||
from sympy.functions.elementary.exponential import (exp, exp_polar, log)
|
||||
from sympy.functions.elementary.hyperbolic import (cosh, sinh)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||||
from sympy.functions.special.bessel import (besseli, besselj, besselk, bessely, hankel1, hankel2, hn1, hn2, jn, jn_zeros, yn)
|
||||
from sympy.functions.special.gamma_functions import (gamma, uppergamma)
|
||||
from sympy.functions.special.hyper import hyper
|
||||
from sympy.integrals.integrals import Integral
|
||||
from sympy.series.order import O
|
||||
from sympy.series.series import series
|
||||
from sympy.functions.special.bessel import (airyai, airybi,
|
||||
airyaiprime, airybiprime, marcumq)
|
||||
from sympy.core.random import (random_complex_number as randcplx,
|
||||
verify_numerically as tn,
|
||||
test_derivative_numerically as td,
|
||||
_randint)
|
||||
from sympy.simplify import besselsimp
|
||||
from sympy.testing.pytest import raises, slow
|
||||
|
||||
from sympy.abc import z, n, k, x
|
||||
|
||||
randint = _randint()
|
||||
|
||||
|
||||
def test_bessel_rand():
|
||||
for f in [besselj, bessely, besseli, besselk, hankel1, hankel2]:
|
||||
assert td(f(randcplx(), z), z)
|
||||
|
||||
for f in [jn, yn, hn1, hn2]:
|
||||
assert td(f(randint(-10, 10), z), z)
|
||||
|
||||
|
||||
def test_bessel_twoinputs():
|
||||
for f in [besselj, bessely, besseli, besselk, hankel1, hankel2, jn, yn]:
|
||||
raises(TypeError, lambda: f(1))
|
||||
raises(TypeError, lambda: f(1, 2, 3))
|
||||
|
||||
|
||||
def test_besselj_leading_term():
|
||||
assert besselj(0, x).as_leading_term(x) == 1
|
||||
assert besselj(1, sin(x)).as_leading_term(x) == x/2
|
||||
assert besselj(1, 2*sqrt(x)).as_leading_term(x) == sqrt(x)
|
||||
|
||||
# https://github.com/sympy/sympy/issues/21701
|
||||
assert (besselj(z, x)/x**z).as_leading_term(x) == 1/(2**z*gamma(z + 1))
|
||||
|
||||
|
||||
def test_bessely_leading_term():
|
||||
assert bessely(0, x).as_leading_term(x) == (2*log(x) - 2*log(2) + 2*S.EulerGamma)/pi
|
||||
assert bessely(1, sin(x)).as_leading_term(x) == -2/(pi*x)
|
||||
assert bessely(1, 2*sqrt(x)).as_leading_term(x) == -1/(pi*sqrt(x))
|
||||
|
||||
|
||||
def test_besseli_leading_term():
|
||||
assert besseli(0, x).as_leading_term(x) == 1
|
||||
assert besseli(1, sin(x)).as_leading_term(x) == x/2
|
||||
assert besseli(1, 2*sqrt(x)).as_leading_term(x) == sqrt(x)
|
||||
|
||||
|
||||
def test_besselk_leading_term():
|
||||
assert besselk(0, x).as_leading_term(x) == -log(x) - S.EulerGamma + log(2)
|
||||
assert besselk(1, sin(x)).as_leading_term(x) == 1/x
|
||||
assert besselk(1, 2*sqrt(x)).as_leading_term(x) == 1/(2*sqrt(x))
|
||||
assert besselk(S(5)/3, x).as_leading_term(x) == 2**(S(2)/3)*gamma(S(5)/3)/x**(S(5)/3)
|
||||
assert besselk(S(2)/3, x).as_leading_term(x) == besselk(-S(2)/3, x).as_leading_term(x)
|
||||
assert besselk(1,cos(x)).as_leading_term(x) == besselk(1,1)
|
||||
assert besselk(3,1/x).as_leading_term(x) == sqrt(pi)*exp(-(1/x))/sqrt(2/x)
|
||||
assert besselk(3,1/sin(x)).as_leading_term(x) == sqrt(pi)*exp(-(1/x))/sqrt(2/x)
|
||||
|
||||
nz = Symbol("nz", nonzero=True)
|
||||
assert besselk(nz, x).as_leading_term(x).subs({nz:S(5)/7}) == besselk(S(5)/7, x).series(x).as_leading_term(x)
|
||||
assert besselk(nz, x).as_leading_term(x).subs({nz:S(-15)/7}) == besselk(S(-15)/7, x).series(x).as_leading_term(x)
|
||||
assert besselk(nz, x).as_leading_term(x).subs({nz:3}) == besselk(3, x).series(x).as_leading_term(x)
|
||||
assert besselk(nz, x).as_leading_term(x).subs({nz:-2}) == besselk(-2, x).series(x).as_leading_term(x)
|
||||
|
||||
|
||||
def test_besselj_series():
|
||||
assert besselj(0, x).series(x) == 1 - x**2/4 + x**4/64 + O(x**6)
|
||||
assert besselj(0, x**(1.1)).series(x) == 1 + x**4.4/64 - x**2.2/4 + O(x**6)
|
||||
assert besselj(0, x**2 + x).series(x) == 1 - x**2/4 - x**3/2\
|
||||
- 15*x**4/64 + x**5/16 + O(x**6)
|
||||
assert besselj(0, sqrt(x) + x).series(x, n=4) == 1 - x/4 - 15*x**2/64\
|
||||
+ 215*x**3/2304 - x**Rational(3, 2)/2 + x**Rational(5, 2)/16\
|
||||
+ 23*x**Rational(7, 2)/384 + O(x**4)
|
||||
assert besselj(0, x/(1 - x)).series(x) == 1 - x**2/4 - x**3/2 - 47*x**4/64\
|
||||
- 15*x**5/16 + O(x**6)
|
||||
assert besselj(0, log(1 + x)).series(x) == 1 - x**2/4 + x**3/4\
|
||||
- 41*x**4/192 + 17*x**5/96 + O(x**6)
|
||||
assert besselj(1, sin(x)).series(x) == x/2 - 7*x**3/48 + 73*x**5/1920 + O(x**6)
|
||||
assert besselj(1, 2*sqrt(x)).series(x) == sqrt(x) - x**Rational(3, 2)/2\
|
||||
+ x**Rational(5, 2)/12 - x**Rational(7, 2)/144 + x**Rational(9, 2)/2880\
|
||||
- x**Rational(11, 2)/86400 + O(x**6)
|
||||
assert besselj(-2, sin(x)).series(x, n=4) == besselj(2, sin(x)).series(x, n=4)
|
||||
|
||||
|
||||
def test_bessely_series():
|
||||
const = 2*S.EulerGamma/pi - 2*log(2)/pi + 2*log(x)/pi
|
||||
assert bessely(0, x).series(x, n=4) == const + x**2*(-log(x)/(2*pi)\
|
||||
+ (2 - 2*S.EulerGamma)/(4*pi) + log(2)/(2*pi)) + O(x**4*log(x))
|
||||
assert bessely(1, x).series(x, n=4) == -2/(pi*x) + x*(log(x)/pi - log(2)/pi - \
|
||||
(1 - 2*S.EulerGamma)/(2*pi)) + x**3*(-log(x)/(8*pi) + \
|
||||
(S(5)/2 - 2*S.EulerGamma)/(16*pi) + log(2)/(8*pi)) + O(x**4*log(x))
|
||||
assert bessely(2, x).series(x, n=4) == -4/(pi*x**2) - 1/pi + x**2*(log(x)/(4*pi) - \
|
||||
log(2)/(4*pi) - (S(3)/2 - 2*S.EulerGamma)/(8*pi)) + O(x**4*log(x))
|
||||
assert bessely(3, x).series(x, n=4) == -16/(pi*x**3) - 2/(pi*x) - \
|
||||
x/(4*pi) + x**3*(log(x)/(24*pi) - log(2)/(24*pi) - \
|
||||
(S(11)/6 - 2*S.EulerGamma)/(48*pi)) + O(x**4*log(x))
|
||||
assert bessely(0, x**(1.1)).series(x, n=4) == 2*S.EulerGamma/pi\
|
||||
- 2*log(2)/pi + 2.2*log(x)/pi + x**2.2*(-0.55*log(x)/pi\
|
||||
+ (2 - 2*S.EulerGamma)/(4*pi) + log(2)/(2*pi)) + O(x**4*log(x))
|
||||
assert bessely(0, x**2 + x).series(x, n=4) == \
|
||||
const - (2 - 2*S.EulerGamma)*(-x**3/(2*pi) - x**2/(4*pi)) + 2*x/pi\
|
||||
+ x**2*(-log(x)/(2*pi) - 1/pi + log(2)/(2*pi))\
|
||||
+ x**3*(-log(x)/pi + 1/(6*pi) + log(2)/pi) + O(x**4*log(x))
|
||||
assert bessely(0, x/(1 - x)).series(x, n=3) == const\
|
||||
+ 2*x/pi + x**2*(-log(x)/(2*pi) + (2 - 2*S.EulerGamma)/(4*pi)\
|
||||
+ log(2)/(2*pi) + 1/pi) + O(x**3*log(x))
|
||||
assert bessely(0, log(1 + x)).series(x, n=3) == const\
|
||||
- x/pi + x**2*(-log(x)/(2*pi) + (2 - 2*S.EulerGamma)/(4*pi)\
|
||||
+ log(2)/(2*pi) + 5/(12*pi)) + O(x**3*log(x))
|
||||
assert bessely(1, sin(x)).series(x, n=4) == -1/(pi*(-x**3/12 + x/2)) - \
|
||||
(1 - 2*S.EulerGamma)*(-x**3/12 + x/2)/pi + x*(log(x)/pi - log(2)/pi) + \
|
||||
x**3*(-7*log(x)/(24*pi) - 1/(6*pi) + (S(5)/2 - 2*S.EulerGamma)/(16*pi) +
|
||||
7*log(2)/(24*pi)) + O(x**4*log(x))
|
||||
assert bessely(1, 2*sqrt(x)).series(x, n=3) == -1/(pi*sqrt(x)) + \
|
||||
sqrt(x)*(log(x)/pi - (1 - 2*S.EulerGamma)/pi) + x**(S(3)/2)*(-log(x)/(2*pi) + \
|
||||
(S(5)/2 - 2*S.EulerGamma)/(2*pi)) + x**(S(5)/2)*(log(x)/(12*pi) - \
|
||||
(S(10)/3 - 2*S.EulerGamma)/(12*pi)) + O(x**3*log(x))
|
||||
assert bessely(-2, sin(x)).series(x, n=4) == bessely(2, sin(x)).series(x, n=4)
|
||||
|
||||
|
||||
def test_besseli_series():
|
||||
assert besseli(0, x).series(x) == 1 + x**2/4 + x**4/64 + O(x**6)
|
||||
assert besseli(0, x**(1.1)).series(x) == 1 + x**4.4/64 + x**2.2/4 + O(x**6)
|
||||
assert besseli(0, x**2 + x).series(x) == 1 + x**2/4 + x**3/2 + 17*x**4/64 + \
|
||||
x**5/16 + O(x**6)
|
||||
assert besseli(0, sqrt(x) + x).series(x, n=4) == 1 + x/4 + 17*x**2/64 + \
|
||||
217*x**3/2304 + x**(S(3)/2)/2 + x**(S(5)/2)/16 + 25*x**(S(7)/2)/384 + O(x**4)
|
||||
assert besseli(0, x/(1 - x)).series(x) == 1 + x**2/4 + x**3/2 + 49*x**4/64 + \
|
||||
17*x**5/16 + O(x**6)
|
||||
assert besseli(0, log(1 + x)).series(x) == 1 + x**2/4 - x**3/4 + 47*x**4/192 - \
|
||||
23*x**5/96 + O(x**6)
|
||||
assert besseli(1, sin(x)).series(x) == x/2 - x**3/48 - 47*x**5/1920 + O(x**6)
|
||||
assert besseli(1, 2*sqrt(x)).series(x) == sqrt(x) + x**(S(3)/2)/2 + x**(S(5)/2)/12 + \
|
||||
x**(S(7)/2)/144 + x**(S(9)/2)/2880 + x**(S(11)/2)/86400 + O(x**6)
|
||||
assert besseli(-2, sin(x)).series(x, n=4) == besseli(2, sin(x)).series(x, n=4)
|
||||
|
||||
#test for aseries
|
||||
assert besseli(0,x).series(x, oo, n=4) == sqrt(2)*(sqrt(1/x) - (1/x)**(S(3)/2)/8 - \
|
||||
3*(1/x)**(S(5)/2)/128 - 15*(1/x)**(S(7)/2)/1024 + O((1/x)**(S(9)/2), (x, oo)))*exp(x)/(2*sqrt(pi))
|
||||
assert besseli(0,x).series(x,-oo, n=4) == sqrt(2)*(sqrt(-1/x) - (-1/x)**(S(3)/2)/8 - 3*(-1/x)**(S(5)/2)/128 - \
|
||||
15*(-1/x)**(S(7)/2)/1024 + O((-1/x)**(S(9)/2), (x, -oo)))*exp(-x)/(2*sqrt(pi))
|
||||
|
||||
|
||||
def test_besselk_series():
|
||||
const = log(2) - S.EulerGamma - log(x)
|
||||
assert besselk(0, x).series(x, n=4) == const + \
|
||||
x**2*(-log(x)/4 - S.EulerGamma/4 + log(2)/4 + S(1)/4) + O(x**4*log(x))
|
||||
assert besselk(1, x).series(x, n=4) == 1/x + x*(log(x)/2 - log(2)/2 - \
|
||||
S(1)/4 + S.EulerGamma/2) + x**3*(log(x)/16 - S(5)/64 - log(2)/16 + \
|
||||
S.EulerGamma/16) + O(x**4*log(x))
|
||||
assert besselk(2, x).series(x, n=4) == 2/x**2 - S(1)/2 + x**2*(-log(x)/8 - \
|
||||
S.EulerGamma/8 + log(2)/8 + S(3)/32) + O(x**4*log(x))
|
||||
assert besselk(2, x).series(x, n=1) == 2/x**2 - S(1)/2 + O(x) #edge case for series truncation
|
||||
assert besselk(0, x**(1.1)).series(x, n=4) == log(2) - S.EulerGamma - \
|
||||
1.1*log(x) + x**2.2*(-0.275*log(x) - S.EulerGamma/4 + \
|
||||
log(2)/4 + S(1)/4) + O(x**4*log(x))
|
||||
assert besselk(0, x**2 + x).series(x, n=4) == const + \
|
||||
(2 - 2*S.EulerGamma)*(x**3/4 + x**2/8) - x + x**2*(-log(x)/4 + \
|
||||
log(2)/4 + S(1)/2) + x**3*(-log(x)/2 - S(7)/12 + log(2)/2) + O(x**4*log(x))
|
||||
assert besselk(0, x/(1 - x)).series(x, n=3) == const - x + x**2*(-log(x)/4 - \
|
||||
S(1)/4 - S.EulerGamma/4 + log(2)/4) + O(x**3*log(x))
|
||||
assert besselk(0, log(1 + x)).series(x, n=3) == const + x/2 + \
|
||||
x**2*(-log(x)/4 - S.EulerGamma/4 + S(1)/24 + log(2)/4) + O(x**3*log(x))
|
||||
assert besselk(1, 2*sqrt(x)).series(x, n=3) == 1/(2*sqrt(x)) + \
|
||||
sqrt(x)*(log(x)/2 - S(1)/2 + S.EulerGamma) + x**(S(3)/2)*(log(x)/4 - S(5)/8 + \
|
||||
S.EulerGamma/2) + x**(S(5)/2)*(log(x)/24 - S(5)/36 + S.EulerGamma/12) + O(x**3*log(x))
|
||||
assert besselk(-2, sin(x)).series(x, n=4) == besselk(2, sin(x)).series(x, n=4)
|
||||
assert besselk(2, x**2).series(x, n=2) == 2/x**4 - S(1)/2 + O(x**2) #edge case for series truncation
|
||||
assert besselk(2, x**2).series(x, n=6) == 2/x**4 - S(1)/2 + x**4*(-log(x)/4 - S.EulerGamma/8 + log(2)/8 + S(3)/32) + O(x**6*log(x))
|
||||
assert (x**2*besselk(2, x)).series(x, n=2) == 2 + O(x**2)
|
||||
|
||||
#test for aseries
|
||||
assert besselk(0,x).series(x, oo, n=4) == sqrt(2)*sqrt(pi)*(sqrt(1/x) + (1/x)**(S(3)/2)/8 - \
|
||||
3*(1/x)**(S(5)/2)/128 + 15*(1/x)**(S(7)/2)/1024 + O((1/x)**(S(9)/2), (x, oo)))*exp(-x)/2
|
||||
assert besselk(0,x).series(x, -oo, n=4) == sqrt(2)*sqrt(pi)*(-I*sqrt(-1/x) + I*(-1/x)**(S(3)/2)/8 + \
|
||||
3*I*(-1/x)**(S(5)/2)/128 + 15*I*(-1/x)**(S(7)/2)/1024 + O((-1/x)**(S(9)/2), (x, -oo)))*exp(-x)/2
|
||||
|
||||
|
||||
def test_besselk_frac_order_series():
|
||||
assert besselk(S(5)/3, x).series(x, n=2) == 2**(S(2)/3)*gamma(S(5)/3)/x**(S(5)/3) - \
|
||||
3*gamma(S(5)/3)*x**(S(1)/3)/(4*2**(S(1)/3)) + \
|
||||
gamma(-S(5)/3)*x**(S(5)/3)/(4*2**(S(2)/3)) + O(x**2)
|
||||
assert besselk(S(1)/2, x).series(x, n=2) == sqrt(pi/2)/sqrt(x) - \
|
||||
sqrt(pi*x/2) + x**(S(3)/2)*sqrt(pi/2)/2 + O(x**2)
|
||||
assert besselk(S(1)/2, sqrt(x)).series(x, n=2) == sqrt(pi/2)/x**(S(1)/4) - \
|
||||
sqrt(pi/2)*x**(S(1)/4) + sqrt(pi/2)*x**(S(3)/4)/2 - \
|
||||
sqrt(pi/2)*x**(S(5)/4)/6 + sqrt(pi/2)*x**(S(7)/4)/24 + O(x**2)
|
||||
assert besselk(S(1)/2, x**2).series(x, n=2) == sqrt(pi/2)/x \
|
||||
- sqrt(pi/2)*x + O(x**2)
|
||||
assert besselk(-S(1)/2, x).series(x) == besselk(S(1)/2, x).series(x)
|
||||
assert besselk(-S(7)/6, x).series(x) == besselk(S(7)/6, x).series(x)
|
||||
|
||||
|
||||
def test_diff():
|
||||
assert besselj(n, z).diff(z) == besselj(n - 1, z)/2 - besselj(n + 1, z)/2
|
||||
assert bessely(n, z).diff(z) == bessely(n - 1, z)/2 - bessely(n + 1, z)/2
|
||||
assert besseli(n, z).diff(z) == besseli(n - 1, z)/2 + besseli(n + 1, z)/2
|
||||
assert besselk(n, z).diff(z) == -besselk(n - 1, z)/2 - besselk(n + 1, z)/2
|
||||
assert hankel1(n, z).diff(z) == hankel1(n - 1, z)/2 - hankel1(n + 1, z)/2
|
||||
assert hankel2(n, z).diff(z) == hankel2(n - 1, z)/2 - hankel2(n + 1, z)/2
|
||||
|
||||
|
||||
def test_rewrite():
|
||||
assert besselj(n, z).rewrite(jn) == sqrt(2*z/pi)*jn(n - S.Half, z)
|
||||
assert bessely(n, z).rewrite(yn) == sqrt(2*z/pi)*yn(n - S.Half, z)
|
||||
assert besseli(n, z).rewrite(besselj) == \
|
||||
exp(-I*n*pi/2)*besselj(n, polar_lift(I)*z)
|
||||
assert besselj(n, z).rewrite(besseli) == \
|
||||
exp(I*n*pi/2)*besseli(n, polar_lift(-I)*z)
|
||||
|
||||
nu = randcplx()
|
||||
|
||||
assert tn(besselj(nu, z), besselj(nu, z).rewrite(besseli), z)
|
||||
assert tn(besselj(nu, z), besselj(nu, z).rewrite(bessely), z)
|
||||
|
||||
assert tn(besseli(nu, z), besseli(nu, z).rewrite(besselj), z)
|
||||
assert tn(besseli(nu, z), besseli(nu, z).rewrite(bessely), z)
|
||||
|
||||
assert tn(bessely(nu, z), bessely(nu, z).rewrite(besselj), z)
|
||||
assert tn(bessely(nu, z), bessely(nu, z).rewrite(besseli), z)
|
||||
|
||||
assert tn(besselk(nu, z), besselk(nu, z).rewrite(besselj), z)
|
||||
assert tn(besselk(nu, z), besselk(nu, z).rewrite(besseli), z)
|
||||
assert tn(besselk(nu, z), besselk(nu, z).rewrite(bessely), z)
|
||||
|
||||
# check that a rewrite was triggered, when the order is set to a generic
|
||||
# symbol 'nu'
|
||||
assert yn(nu, z) != yn(nu, z).rewrite(jn)
|
||||
assert hn1(nu, z) != hn1(nu, z).rewrite(jn)
|
||||
assert hn2(nu, z) != hn2(nu, z).rewrite(jn)
|
||||
assert jn(nu, z) != jn(nu, z).rewrite(yn)
|
||||
assert hn1(nu, z) != hn1(nu, z).rewrite(yn)
|
||||
assert hn2(nu, z) != hn2(nu, z).rewrite(yn)
|
||||
|
||||
# rewriting spherical bessel functions (SBFs) w.r.t. besselj, bessely is
|
||||
# not allowed if a generic symbol 'nu' is used as the order of the SBFs
|
||||
# to avoid inconsistencies (the order of bessel[jy] is allowed to be
|
||||
# complex-valued, whereas SBFs are defined only for integer orders)
|
||||
order = nu
|
||||
for f in (besselj, bessely):
|
||||
assert hn1(order, z) == hn1(order, z).rewrite(f)
|
||||
assert hn2(order, z) == hn2(order, z).rewrite(f)
|
||||
|
||||
assert jn(order, z).rewrite(besselj) == sqrt(2)*sqrt(pi)*sqrt(1/z)*besselj(order + S.Half, z)/2
|
||||
assert jn(order, z).rewrite(bessely) == (-1)**nu*sqrt(2)*sqrt(pi)*sqrt(1/z)*bessely(-order - S.Half, z)/2
|
||||
|
||||
# for integral orders rewriting SBFs w.r.t bessel[jy] is allowed
|
||||
N = Symbol('n', integer=True)
|
||||
ri = randint(-11, 10)
|
||||
for order in (ri, N):
|
||||
for f in (besselj, bessely):
|
||||
assert yn(order, z) != yn(order, z).rewrite(f)
|
||||
assert jn(order, z) != jn(order, z).rewrite(f)
|
||||
assert hn1(order, z) != hn1(order, z).rewrite(f)
|
||||
assert hn2(order, z) != hn2(order, z).rewrite(f)
|
||||
|
||||
for func, refunc in product((yn, jn, hn1, hn2),
|
||||
(jn, yn, besselj, bessely)):
|
||||
assert tn(func(ri, z), func(ri, z).rewrite(refunc), z)
|
||||
|
||||
|
||||
def test_expand():
|
||||
assert expand_func(besselj(S.Half, z).rewrite(jn)) == \
|
||||
sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z))
|
||||
assert expand_func(bessely(S.Half, z).rewrite(yn)) == \
|
||||
-sqrt(2)*cos(z)/(sqrt(pi)*sqrt(z))
|
||||
|
||||
# XXX: teach sin/cos to work around arguments like
|
||||
# x*exp_polar(I*pi*n/2). Then change besselsimp -> expand_func
|
||||
assert besselsimp(besselj(S.Half, z)) == sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(besselj(Rational(-1, 2), z)) == sqrt(2)*cos(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(besselj(Rational(5, 2), z)) == \
|
||||
-sqrt(2)*(z**2*sin(z) + 3*z*cos(z) - 3*sin(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
assert besselsimp(besselj(Rational(-5, 2), z)) == \
|
||||
-sqrt(2)*(z**2*cos(z) - 3*z*sin(z) - 3*cos(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
|
||||
assert besselsimp(bessely(S.Half, z)) == \
|
||||
-(sqrt(2)*cos(z))/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(bessely(Rational(-1, 2), z)) == sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(bessely(Rational(5, 2), z)) == \
|
||||
sqrt(2)*(z**2*cos(z) - 3*z*sin(z) - 3*cos(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
assert besselsimp(bessely(Rational(-5, 2), z)) == \
|
||||
-sqrt(2)*(z**2*sin(z) + 3*z*cos(z) - 3*sin(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
|
||||
assert besselsimp(besseli(S.Half, z)) == sqrt(2)*sinh(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(besseli(Rational(-1, 2), z)) == \
|
||||
sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z))
|
||||
assert besselsimp(besseli(Rational(5, 2), z)) == \
|
||||
sqrt(2)*(z**2*sinh(z) - 3*z*cosh(z) + 3*sinh(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
assert besselsimp(besseli(Rational(-5, 2), z)) == \
|
||||
sqrt(2)*(z**2*cosh(z) - 3*z*sinh(z) + 3*cosh(z))/(sqrt(pi)*z**Rational(5, 2))
|
||||
|
||||
assert besselsimp(besselk(S.Half, z)) == \
|
||||
besselsimp(besselk(Rational(-1, 2), z)) == sqrt(pi)*exp(-z)/(sqrt(2)*sqrt(z))
|
||||
assert besselsimp(besselk(Rational(5, 2), z)) == \
|
||||
besselsimp(besselk(Rational(-5, 2), z)) == \
|
||||
sqrt(2)*sqrt(pi)*(z**2 + 3*z + 3)*exp(-z)/(2*z**Rational(5, 2))
|
||||
|
||||
n = Symbol('n', integer=True, positive=True)
|
||||
|
||||
assert expand_func(besseli(n + 2, z)) == \
|
||||
besseli(n, z) + (-2*n - 2)*(-2*n*besseli(n, z)/z + besseli(n - 1, z))/z
|
||||
assert expand_func(besselj(n + 2, z)) == \
|
||||
-besselj(n, z) + (2*n + 2)*(2*n*besselj(n, z)/z - besselj(n - 1, z))/z
|
||||
assert expand_func(besselk(n + 2, z)) == \
|
||||
besselk(n, z) + (2*n + 2)*(2*n*besselk(n, z)/z + besselk(n - 1, z))/z
|
||||
assert expand_func(bessely(n + 2, z)) == \
|
||||
-bessely(n, z) + (2*n + 2)*(2*n*bessely(n, z)/z - bessely(n - 1, z))/z
|
||||
|
||||
assert expand_func(besseli(n + S.Half, z).rewrite(jn)) == \
|
||||
(sqrt(2)*sqrt(z)*exp(-I*pi*(n + S.Half)/2) *
|
||||
exp_polar(I*pi/4)*jn(n, z*exp_polar(I*pi/2))/sqrt(pi))
|
||||
assert expand_func(besselj(n + S.Half, z).rewrite(jn)) == \
|
||||
sqrt(2)*sqrt(z)*jn(n, z)/sqrt(pi)
|
||||
|
||||
r = Symbol('r', real=True)
|
||||
p = Symbol('p', positive=True)
|
||||
i = Symbol('i', integer=True)
|
||||
|
||||
for besselx in [besselj, bessely, besseli, besselk]:
|
||||
assert besselx(i, p).is_extended_real is True
|
||||
assert besselx(i, x).is_extended_real is None
|
||||
assert besselx(x, z).is_extended_real is None
|
||||
|
||||
for besselx in [besselj, besseli]:
|
||||
assert besselx(i, r).is_extended_real is True
|
||||
for besselx in [bessely, besselk]:
|
||||
assert besselx(i, r).is_extended_real is None
|
||||
|
||||
for besselx in [besselj, bessely, besseli, besselk]:
|
||||
assert expand_func(besselx(oo, x)) == besselx(oo, x, evaluate=False)
|
||||
assert expand_func(besselx(-oo, x)) == besselx(-oo, x, evaluate=False)
|
||||
|
||||
|
||||
# Quite varying time, but often really slow
|
||||
@slow
|
||||
def test_slow_expand():
|
||||
def check(eq, ans):
|
||||
return tn(eq, ans) and eq == ans
|
||||
|
||||
rn = randcplx(a=1, b=0, d=0, c=2)
|
||||
|
||||
for besselx in [besselj, bessely, besseli, besselk]:
|
||||
ri = S(2*randint(-11, 10) + 1) / 2 # half integer in [-21/2, 21/2]
|
||||
assert tn(besselsimp(besselx(ri, z)), besselx(ri, z))
|
||||
|
||||
assert check(expand_func(besseli(rn, x)),
|
||||
besseli(rn - 2, x) - 2*(rn - 1)*besseli(rn - 1, x)/x)
|
||||
assert check(expand_func(besseli(-rn, x)),
|
||||
besseli(-rn + 2, x) + 2*(-rn + 1)*besseli(-rn + 1, x)/x)
|
||||
|
||||
assert check(expand_func(besselj(rn, x)),
|
||||
-besselj(rn - 2, x) + 2*(rn - 1)*besselj(rn - 1, x)/x)
|
||||
assert check(expand_func(besselj(-rn, x)),
|
||||
-besselj(-rn + 2, x) + 2*(-rn + 1)*besselj(-rn + 1, x)/x)
|
||||
|
||||
assert check(expand_func(besselk(rn, x)),
|
||||
besselk(rn - 2, x) + 2*(rn - 1)*besselk(rn - 1, x)/x)
|
||||
assert check(expand_func(besselk(-rn, x)),
|
||||
besselk(-rn + 2, x) - 2*(-rn + 1)*besselk(-rn + 1, x)/x)
|
||||
|
||||
assert check(expand_func(bessely(rn, x)),
|
||||
-bessely(rn - 2, x) + 2*(rn - 1)*bessely(rn - 1, x)/x)
|
||||
assert check(expand_func(bessely(-rn, x)),
|
||||
-bessely(-rn + 2, x) + 2*(-rn + 1)*bessely(-rn + 1, x)/x)
|
||||
|
||||
|
||||
def mjn(n, z):
|
||||
return expand_func(jn(n, z))
|
||||
|
||||
|
||||
def myn(n, z):
|
||||
return expand_func(yn(n, z))
|
||||
|
||||
|
||||
def test_jn():
|
||||
z = symbols("z")
|
||||
assert jn(0, 0) == 1
|
||||
assert jn(1, 0) == 0
|
||||
assert jn(-1, 0) == S.ComplexInfinity
|
||||
assert jn(z, 0) == jn(z, 0, evaluate=False)
|
||||
assert jn(0, oo) == 0
|
||||
assert jn(0, -oo) == 0
|
||||
|
||||
assert mjn(0, z) == sin(z)/z
|
||||
assert mjn(1, z) == sin(z)/z**2 - cos(z)/z
|
||||
assert mjn(2, z) == (3/z**3 - 1/z)*sin(z) - (3/z**2) * cos(z)
|
||||
assert mjn(3, z) == (15/z**4 - 6/z**2)*sin(z) + (1/z - 15/z**3)*cos(z)
|
||||
assert mjn(4, z) == (1/z + 105/z**5 - 45/z**3)*sin(z) + \
|
||||
(-105/z**4 + 10/z**2)*cos(z)
|
||||
assert mjn(5, z) == (945/z**6 - 420/z**4 + 15/z**2)*sin(z) + \
|
||||
(-1/z - 945/z**5 + 105/z**3)*cos(z)
|
||||
assert mjn(6, z) == (-1/z + 10395/z**7 - 4725/z**5 + 210/z**3)*sin(z) + \
|
||||
(-10395/z**6 + 1260/z**4 - 21/z**2)*cos(z)
|
||||
|
||||
assert expand_func(jn(n, z)) == jn(n, z)
|
||||
|
||||
# SBFs not defined for complex-valued orders
|
||||
assert jn(2+3j, 5.2+0.3j).evalf() == jn(2+3j, 5.2+0.3j)
|
||||
|
||||
assert eq([jn(2, 5.2+0.3j).evalf(10)],
|
||||
[0.09941975672 - 0.05452508024*I])
|
||||
|
||||
|
||||
def test_yn():
|
||||
z = symbols("z")
|
||||
assert myn(0, z) == -cos(z)/z
|
||||
assert myn(1, z) == -cos(z)/z**2 - sin(z)/z
|
||||
assert myn(2, z) == -((3/z**3 - 1/z)*cos(z) + (3/z**2)*sin(z))
|
||||
assert expand_func(yn(n, z)) == yn(n, z)
|
||||
|
||||
# SBFs not defined for complex-valued orders
|
||||
assert yn(2+3j, 5.2+0.3j).evalf() == yn(2+3j, 5.2+0.3j)
|
||||
|
||||
assert eq([yn(2, 5.2+0.3j).evalf(10)],
|
||||
[0.185250342 + 0.01489557397*I])
|
||||
|
||||
|
||||
def test_sympify_yn():
|
||||
assert S(15) in myn(3, pi).atoms()
|
||||
assert myn(3, pi) == 15/pi**4 - 6/pi**2
|
||||
|
||||
|
||||
def eq(a, b, tol=1e-6):
|
||||
for u, v in zip(a, b):
|
||||
if not (abs(u - v) < tol):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def test_jn_zeros():
|
||||
assert eq(jn_zeros(0, 4), [3.141592, 6.283185, 9.424777, 12.566370])
|
||||
assert eq(jn_zeros(1, 4), [4.493409, 7.725251, 10.904121, 14.066193])
|
||||
assert eq(jn_zeros(2, 4), [5.763459, 9.095011, 12.322940, 15.514603])
|
||||
assert eq(jn_zeros(3, 4), [6.987932, 10.417118, 13.698023, 16.923621])
|
||||
assert eq(jn_zeros(4, 4), [8.182561, 11.704907, 15.039664, 18.301255])
|
||||
|
||||
|
||||
def test_bessel_eval():
|
||||
n, m, k = Symbol('n', integer=True), Symbol('m'), Symbol('k', integer=True, zero=False)
|
||||
|
||||
for f in [besselj, besseli]:
|
||||
assert f(0, 0) is S.One
|
||||
assert f(2.1, 0) is S.Zero
|
||||
assert f(-3, 0) is S.Zero
|
||||
assert f(-10.2, 0) is S.ComplexInfinity
|
||||
assert f(1 + 3*I, 0) is S.Zero
|
||||
assert f(-3 + I, 0) is S.ComplexInfinity
|
||||
assert f(-2*I, 0) is S.NaN
|
||||
assert f(n, 0) != S.One and f(n, 0) != S.Zero
|
||||
assert f(m, 0) != S.One and f(m, 0) != S.Zero
|
||||
assert f(k, 0) is S.Zero
|
||||
|
||||
assert bessely(0, 0) is S.NegativeInfinity
|
||||
assert besselk(0, 0) is S.Infinity
|
||||
for f in [bessely, besselk]:
|
||||
assert f(1 + I, 0) is S.ComplexInfinity
|
||||
assert f(I, 0) is S.NaN
|
||||
|
||||
for f in [besselj, bessely]:
|
||||
assert f(m, S.Infinity) is S.Zero
|
||||
assert f(m, S.NegativeInfinity) is S.Zero
|
||||
|
||||
for f in [besseli, besselk]:
|
||||
assert f(m, I*S.Infinity) is S.Zero
|
||||
assert f(m, I*S.NegativeInfinity) is S.Zero
|
||||
|
||||
for f in [besseli, besselk]:
|
||||
assert f(-4, z) == f(4, z)
|
||||
assert f(-3, z) == f(3, z)
|
||||
assert f(-n, z) == f(n, z)
|
||||
assert f(-m, z) != f(m, z)
|
||||
|
||||
for f in [besselj, bessely]:
|
||||
assert f(-4, z) == f(4, z)
|
||||
assert f(-3, z) == -f(3, z)
|
||||
assert f(-n, z) == (-1)**n*f(n, z)
|
||||
assert f(-m, z) != (-1)**m*f(m, z)
|
||||
|
||||
for f in [besselj, besseli]:
|
||||
assert f(m, -z) == (-z)**m*z**(-m)*f(m, z)
|
||||
|
||||
assert besseli(2, -z) == besseli(2, z)
|
||||
assert besseli(3, -z) == -besseli(3, z)
|
||||
|
||||
assert besselj(0, -z) == besselj(0, z)
|
||||
assert besselj(1, -z) == -besselj(1, z)
|
||||
|
||||
assert besseli(0, I*z) == besselj(0, z)
|
||||
assert besseli(1, I*z) == I*besselj(1, z)
|
||||
assert besselj(3, I*z) == -I*besseli(3, z)
|
||||
|
||||
|
||||
def test_bessel_nan():
|
||||
# FIXME: could have these return NaN; for now just fix infinite recursion
|
||||
for f in [besselj, bessely, besseli, besselk, hankel1, hankel2, yn, jn]:
|
||||
assert f(1, S.NaN) == f(1, S.NaN, evaluate=False)
|
||||
|
||||
|
||||
def test_meromorphic():
|
||||
assert besselj(2, x).is_meromorphic(x, 1) == True
|
||||
assert besselj(2, x).is_meromorphic(x, 0) == True
|
||||
assert besselj(2, x).is_meromorphic(x, oo) == False
|
||||
assert besselj(S(2)/3, x).is_meromorphic(x, 1) == True
|
||||
assert besselj(S(2)/3, x).is_meromorphic(x, 0) == False
|
||||
assert besselj(S(2)/3, x).is_meromorphic(x, oo) == False
|
||||
assert besselj(x, 2*x).is_meromorphic(x, 2) == False
|
||||
assert besselk(0, x).is_meromorphic(x, 1) == True
|
||||
assert besselk(2, x).is_meromorphic(x, 0) == True
|
||||
assert besseli(0, x).is_meromorphic(x, 1) == True
|
||||
assert besseli(2, x).is_meromorphic(x, 0) == True
|
||||
assert bessely(0, x).is_meromorphic(x, 1) == True
|
||||
assert bessely(0, x).is_meromorphic(x, 0) == False
|
||||
assert bessely(2, x).is_meromorphic(x, 0) == True
|
||||
assert hankel1(3, x**2 + 2*x).is_meromorphic(x, 1) == True
|
||||
assert hankel1(0, x).is_meromorphic(x, 0) == False
|
||||
assert hankel2(11, 4).is_meromorphic(x, 5) == True
|
||||
assert hn1(6, 7*x**3 + 4).is_meromorphic(x, 7) == True
|
||||
assert hn2(3, 2*x).is_meromorphic(x, 9) == True
|
||||
assert jn(5, 2*x + 7).is_meromorphic(x, 4) == True
|
||||
assert yn(8, x**2 + 11).is_meromorphic(x, 6) == True
|
||||
|
||||
|
||||
def test_conjugate():
|
||||
n = Symbol('n')
|
||||
z = Symbol('z', extended_real=False)
|
||||
x = Symbol('x', extended_real=True)
|
||||
y = Symbol('y', positive=True)
|
||||
t = Symbol('t', negative=True)
|
||||
|
||||
for f in [besseli, besselj, besselk, bessely, hankel1, hankel2]:
|
||||
assert f(n, -1).conjugate() != f(conjugate(n), -1)
|
||||
assert f(n, x).conjugate() != f(conjugate(n), x)
|
||||
assert f(n, t).conjugate() != f(conjugate(n), t)
|
||||
|
||||
rz = randcplx(b=0.5)
|
||||
|
||||
for f in [besseli, besselj, besselk, bessely]:
|
||||
assert f(n, 1 + I).conjugate() == f(conjugate(n), 1 - I)
|
||||
assert f(n, 0).conjugate() == f(conjugate(n), 0)
|
||||
assert f(n, 1).conjugate() == f(conjugate(n), 1)
|
||||
assert f(n, z).conjugate() == f(conjugate(n), conjugate(z))
|
||||
assert f(n, y).conjugate() == f(conjugate(n), y)
|
||||
assert tn(f(n, rz).conjugate(), f(conjugate(n), conjugate(rz)))
|
||||
|
||||
assert hankel1(n, 1 + I).conjugate() == hankel2(conjugate(n), 1 - I)
|
||||
assert hankel1(n, 0).conjugate() == hankel2(conjugate(n), 0)
|
||||
assert hankel1(n, 1).conjugate() == hankel2(conjugate(n), 1)
|
||||
assert hankel1(n, y).conjugate() == hankel2(conjugate(n), y)
|
||||
assert hankel1(n, z).conjugate() == hankel2(conjugate(n), conjugate(z))
|
||||
assert tn(hankel1(n, rz).conjugate(), hankel2(conjugate(n), conjugate(rz)))
|
||||
|
||||
assert hankel2(n, 1 + I).conjugate() == hankel1(conjugate(n), 1 - I)
|
||||
assert hankel2(n, 0).conjugate() == hankel1(conjugate(n), 0)
|
||||
assert hankel2(n, 1).conjugate() == hankel1(conjugate(n), 1)
|
||||
assert hankel2(n, y).conjugate() == hankel1(conjugate(n), y)
|
||||
assert hankel2(n, z).conjugate() == hankel1(conjugate(n), conjugate(z))
|
||||
assert tn(hankel2(n, rz).conjugate(), hankel1(conjugate(n), conjugate(rz)))
|
||||
|
||||
|
||||
def test_branching():
|
||||
assert besselj(polar_lift(k), x) == besselj(k, x)
|
||||
assert besseli(polar_lift(k), x) == besseli(k, x)
|
||||
|
||||
n = Symbol('n', integer=True)
|
||||
assert besselj(n, exp_polar(2*pi*I)*x) == besselj(n, x)
|
||||
assert besselj(n, polar_lift(x)) == besselj(n, x)
|
||||
assert besseli(n, exp_polar(2*pi*I)*x) == besseli(n, x)
|
||||
assert besseli(n, polar_lift(x)) == besseli(n, x)
|
||||
|
||||
def tn(func, s):
|
||||
from sympy.core.random import uniform
|
||||
c = uniform(1, 5)
|
||||
expr = func(s, c*exp_polar(I*pi)) - func(s, c*exp_polar(-I*pi))
|
||||
eps = 1e-15
|
||||
expr2 = func(s + eps, -c + eps*I) - func(s + eps, -c - eps*I)
|
||||
return abs(expr.n() - expr2.n()).n() < 1e-10
|
||||
|
||||
nu = Symbol('nu')
|
||||
assert besselj(nu, exp_polar(2*pi*I)*x) == exp(2*pi*I*nu)*besselj(nu, x)
|
||||
assert besseli(nu, exp_polar(2*pi*I)*x) == exp(2*pi*I*nu)*besseli(nu, x)
|
||||
assert tn(besselj, 2)
|
||||
assert tn(besselj, pi)
|
||||
assert tn(besselj, I)
|
||||
assert tn(besseli, 2)
|
||||
assert tn(besseli, pi)
|
||||
assert tn(besseli, I)
|
||||
|
||||
|
||||
def test_airy_base():
|
||||
z = Symbol('z')
|
||||
x = Symbol('x', real=True)
|
||||
y = Symbol('y', real=True)
|
||||
|
||||
assert conjugate(airyai(z)) == airyai(conjugate(z))
|
||||
assert airyai(x).is_extended_real
|
||||
|
||||
assert airyai(x+I*y).as_real_imag() == (
|
||||
airyai(x - I*y)/2 + airyai(x + I*y)/2,
|
||||
I*(airyai(x - I*y) - airyai(x + I*y))/2)
|
||||
|
||||
|
||||
def test_airyai():
|
||||
z = Symbol('z', real=False)
|
||||
t = Symbol('t', negative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
|
||||
assert isinstance(airyai(z), airyai)
|
||||
|
||||
assert airyai(0) == 3**Rational(1, 3)/(3*gamma(Rational(2, 3)))
|
||||
assert airyai(oo) == 0
|
||||
assert airyai(-oo) == 0
|
||||
|
||||
assert diff(airyai(z), z) == airyaiprime(z)
|
||||
|
||||
assert series(airyai(z), z, 0, 3) == (
|
||||
3**Rational(5, 6)*gamma(Rational(1, 3))/(6*pi) - 3**Rational(1, 6)*z*gamma(Rational(2, 3))/(2*pi) + O(z**3))
|
||||
|
||||
assert airyai(z).rewrite(hyper) == (
|
||||
-3**Rational(2, 3)*z*hyper((), (Rational(4, 3),), z**3/9)/(3*gamma(Rational(1, 3))) +
|
||||
3**Rational(1, 3)*hyper((), (Rational(2, 3),), z**3/9)/(3*gamma(Rational(2, 3))))
|
||||
|
||||
assert isinstance(airyai(z).rewrite(besselj), airyai)
|
||||
assert airyai(t).rewrite(besselj) == (
|
||||
sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) +
|
||||
besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3)
|
||||
assert airyai(z).rewrite(besseli) == (
|
||||
-z*besseli(Rational(1, 3), 2*z**Rational(3, 2)/3)/(3*(z**Rational(3, 2))**Rational(1, 3)) +
|
||||
(z**Rational(3, 2))**Rational(1, 3)*besseli(Rational(-1, 3), 2*z**Rational(3, 2)/3)/3)
|
||||
assert airyai(p).rewrite(besseli) == (
|
||||
sqrt(p)*(besseli(Rational(-1, 3), 2*p**Rational(3, 2)/3) -
|
||||
besseli(Rational(1, 3), 2*p**Rational(3, 2)/3))/3)
|
||||
|
||||
assert expand_func(airyai(2*(3*z**5)**Rational(1, 3))) == (
|
||||
-sqrt(3)*(-1 + (z**5)**Rational(1, 3)/z**Rational(5, 3))*airybi(2*3**Rational(1, 3)*z**Rational(5, 3))/6 +
|
||||
(1 + (z**5)**Rational(1, 3)/z**Rational(5, 3))*airyai(2*3**Rational(1, 3)*z**Rational(5, 3))/2)
|
||||
|
||||
|
||||
def test_airybi():
|
||||
z = Symbol('z', real=False)
|
||||
t = Symbol('t', negative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
|
||||
assert isinstance(airybi(z), airybi)
|
||||
|
||||
assert airybi(0) == 3**Rational(5, 6)/(3*gamma(Rational(2, 3)))
|
||||
assert airybi(oo) is oo
|
||||
assert airybi(-oo) == 0
|
||||
|
||||
assert diff(airybi(z), z) == airybiprime(z)
|
||||
|
||||
assert series(airybi(z), z, 0, 3) == (
|
||||
3**Rational(1, 3)*gamma(Rational(1, 3))/(2*pi) + 3**Rational(2, 3)*z*gamma(Rational(2, 3))/(2*pi) + O(z**3))
|
||||
|
||||
assert airybi(z).rewrite(hyper) == (
|
||||
3**Rational(1, 6)*z*hyper((), (Rational(4, 3),), z**3/9)/gamma(Rational(1, 3)) +
|
||||
3**Rational(5, 6)*hyper((), (Rational(2, 3),), z**3/9)/(3*gamma(Rational(2, 3))))
|
||||
|
||||
assert isinstance(airybi(z).rewrite(besselj), airybi)
|
||||
assert airyai(t).rewrite(besselj) == (
|
||||
sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) +
|
||||
besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3)
|
||||
assert airybi(z).rewrite(besseli) == (
|
||||
sqrt(3)*(z*besseli(Rational(1, 3), 2*z**Rational(3, 2)/3)/(z**Rational(3, 2))**Rational(1, 3) +
|
||||
(z**Rational(3, 2))**Rational(1, 3)*besseli(Rational(-1, 3), 2*z**Rational(3, 2)/3))/3)
|
||||
assert airybi(p).rewrite(besseli) == (
|
||||
sqrt(3)*sqrt(p)*(besseli(Rational(-1, 3), 2*p**Rational(3, 2)/3) +
|
||||
besseli(Rational(1, 3), 2*p**Rational(3, 2)/3))/3)
|
||||
|
||||
assert expand_func(airybi(2*(3*z**5)**Rational(1, 3))) == (
|
||||
sqrt(3)*(1 - (z**5)**Rational(1, 3)/z**Rational(5, 3))*airyai(2*3**Rational(1, 3)*z**Rational(5, 3))/2 +
|
||||
(1 + (z**5)**Rational(1, 3)/z**Rational(5, 3))*airybi(2*3**Rational(1, 3)*z**Rational(5, 3))/2)
|
||||
|
||||
|
||||
def test_airyaiprime():
|
||||
z = Symbol('z', real=False)
|
||||
t = Symbol('t', negative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
|
||||
assert isinstance(airyaiprime(z), airyaiprime)
|
||||
|
||||
assert airyaiprime(0) == -3**Rational(2, 3)/(3*gamma(Rational(1, 3)))
|
||||
assert airyaiprime(oo) == 0
|
||||
|
||||
assert diff(airyaiprime(z), z) == z*airyai(z)
|
||||
|
||||
assert series(airyaiprime(z), z, 0, 3) == (
|
||||
-3**Rational(2, 3)/(3*gamma(Rational(1, 3))) + 3**Rational(1, 3)*z**2/(6*gamma(Rational(2, 3))) + O(z**3))
|
||||
|
||||
assert airyaiprime(z).rewrite(hyper) == (
|
||||
3**Rational(1, 3)*z**2*hyper((), (Rational(5, 3),), z**3/9)/(6*gamma(Rational(2, 3))) -
|
||||
3**Rational(2, 3)*hyper((), (Rational(1, 3),), z**3/9)/(3*gamma(Rational(1, 3))))
|
||||
|
||||
assert isinstance(airyaiprime(z).rewrite(besselj), airyaiprime)
|
||||
assert airyai(t).rewrite(besselj) == (
|
||||
sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) +
|
||||
besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3)
|
||||
assert airyaiprime(z).rewrite(besseli) == (
|
||||
z**2*besseli(Rational(2, 3), 2*z**Rational(3, 2)/3)/(3*(z**Rational(3, 2))**Rational(2, 3)) -
|
||||
(z**Rational(3, 2))**Rational(2, 3)*besseli(Rational(-1, 3), 2*z**Rational(3, 2)/3)/3)
|
||||
assert airyaiprime(p).rewrite(besseli) == (
|
||||
p*(-besseli(Rational(-2, 3), 2*p**Rational(3, 2)/3) + besseli(Rational(2, 3), 2*p**Rational(3, 2)/3))/3)
|
||||
|
||||
assert expand_func(airyaiprime(2*(3*z**5)**Rational(1, 3))) == (
|
||||
sqrt(3)*(z**Rational(5, 3)/(z**5)**Rational(1, 3) - 1)*airybiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/6 +
|
||||
(z**Rational(5, 3)/(z**5)**Rational(1, 3) + 1)*airyaiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/2)
|
||||
|
||||
|
||||
def test_airybiprime():
|
||||
z = Symbol('z', real=False)
|
||||
t = Symbol('t', negative=True)
|
||||
p = Symbol('p', positive=True)
|
||||
|
||||
assert isinstance(airybiprime(z), airybiprime)
|
||||
|
||||
assert airybiprime(0) == 3**Rational(1, 6)/gamma(Rational(1, 3))
|
||||
assert airybiprime(oo) is oo
|
||||
assert airybiprime(-oo) == 0
|
||||
|
||||
assert diff(airybiprime(z), z) == z*airybi(z)
|
||||
|
||||
assert series(airybiprime(z), z, 0, 3) == (
|
||||
3**Rational(1, 6)/gamma(Rational(1, 3)) + 3**Rational(5, 6)*z**2/(6*gamma(Rational(2, 3))) + O(z**3))
|
||||
|
||||
assert airybiprime(z).rewrite(hyper) == (
|
||||
3**Rational(5, 6)*z**2*hyper((), (Rational(5, 3),), z**3/9)/(6*gamma(Rational(2, 3))) +
|
||||
3**Rational(1, 6)*hyper((), (Rational(1, 3),), z**3/9)/gamma(Rational(1, 3)))
|
||||
|
||||
assert isinstance(airybiprime(z).rewrite(besselj), airybiprime)
|
||||
assert airyai(t).rewrite(besselj) == (
|
||||
sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) +
|
||||
besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3)
|
||||
assert airybiprime(z).rewrite(besseli) == (
|
||||
sqrt(3)*(z**2*besseli(Rational(2, 3), 2*z**Rational(3, 2)/3)/(z**Rational(3, 2))**Rational(2, 3) +
|
||||
(z**Rational(3, 2))**Rational(2, 3)*besseli(Rational(-2, 3), 2*z**Rational(3, 2)/3))/3)
|
||||
assert airybiprime(p).rewrite(besseli) == (
|
||||
sqrt(3)*p*(besseli(Rational(-2, 3), 2*p**Rational(3, 2)/3) + besseli(Rational(2, 3), 2*p**Rational(3, 2)/3))/3)
|
||||
|
||||
assert expand_func(airybiprime(2*(3*z**5)**Rational(1, 3))) == (
|
||||
sqrt(3)*(z**Rational(5, 3)/(z**5)**Rational(1, 3) - 1)*airyaiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/2 +
|
||||
(z**Rational(5, 3)/(z**5)**Rational(1, 3) + 1)*airybiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/2)
|
||||
|
||||
|
||||
def test_marcumq():
|
||||
m = Symbol('m')
|
||||
a = Symbol('a')
|
||||
b = Symbol('b')
|
||||
|
||||
assert marcumq(0, 0, 0) == 0
|
||||
assert marcumq(m, 0, b) == uppergamma(m, b**2/2)/gamma(m)
|
||||
assert marcumq(2, 0, 5) == 27*exp(Rational(-25, 2))/2
|
||||
assert marcumq(0, a, 0) == 1 - exp(-a**2/2)
|
||||
assert marcumq(0, pi, 0) == 1 - exp(-pi**2/2)
|
||||
assert marcumq(1, a, a) == S.Half + exp(-a**2)*besseli(0, a**2)/2
|
||||
assert marcumq(2, a, a) == S.Half + exp(-a**2)*besseli(0, a**2)/2 + exp(-a**2)*besseli(1, a**2)
|
||||
|
||||
assert diff(marcumq(1, a, 3), a) == a*(-marcumq(1, a, 3) + marcumq(2, a, 3))
|
||||
assert diff(marcumq(2, 3, b), b) == -b**2*exp(-b**2/2 - Rational(9, 2))*besseli(1, 3*b)/3
|
||||
|
||||
x = Symbol('x')
|
||||
assert marcumq(2, 3, 4).rewrite(Integral, x=x) == \
|
||||
Integral(x**2*exp(-x**2/2 - Rational(9, 2))*besseli(1, 3*x), (x, 4, oo))/3
|
||||
assert eq([marcumq(5, -2, 3).rewrite(Integral).evalf(10)],
|
||||
[0.7905769565])
|
||||
|
||||
k = Symbol('k')
|
||||
assert marcumq(-3, -5, -7).rewrite(Sum, k=k) == \
|
||||
exp(-37)*Sum((Rational(5, 7))**k*besseli(k, 35), (k, 4, oo))
|
||||
assert eq([marcumq(1, 3, 1).rewrite(Sum).evalf(10)],
|
||||
[0.9891705502])
|
||||
|
||||
assert marcumq(1, a, a, evaluate=False).rewrite(besseli) == S.Half + exp(-a**2)*besseli(0, a**2)/2
|
||||
assert marcumq(2, a, a, evaluate=False).rewrite(besseli) == S.Half + exp(-a**2)*besseli(0, a**2)/2 + \
|
||||
exp(-a**2)*besseli(1, a**2)
|
||||
assert marcumq(3, a, a).rewrite(besseli) == (besseli(1, a**2) + besseli(2, a**2))*exp(-a**2) + \
|
||||
S.Half + exp(-a**2)*besseli(0, a**2)/2
|
||||
assert marcumq(5, 8, 8).rewrite(besseli) == exp(-64)*besseli(0, 64)/2 + \
|
||||
(besseli(4, 64) + besseli(3, 64) + besseli(2, 64) + besseli(1, 64))*exp(-64) + S.Half
|
||||
assert marcumq(m, a, a).rewrite(besseli) == marcumq(m, a, a)
|
||||
|
||||
x = Symbol('x', integer=True)
|
||||
assert marcumq(x, a, a).rewrite(besseli) == marcumq(x, a, a)
|
||||
|
||||
|
||||
def test_issue_26134():
|
||||
x = Symbol('x')
|
||||
assert marcumq(2, 3, 4).rewrite(Integral, x=x).dummy_eq(
|
||||
Integral(x**2*exp(-x**2/2 - Rational(9, 2))*besseli(1, 3*x), (x, 4, oo))/3)
|
||||
|
|
@ -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
|
||||
|
|
@ -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)))
|
||||
|
|
@ -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
|
||||
|
|
@ -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)))
|
||||
|
|
@ -0,0 +1,860 @@
|
|||
from sympy.core.function import (diff, expand, expand_func)
|
||||
from sympy.core import EulerGamma
|
||||
from sympy.core.numbers import (E, Float, I, Rational, nan, oo, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Symbol, symbols, Dummy)
|
||||
from sympy.functions.elementary.complexes import (conjugate, im, polar_lift, re)
|
||||
from sympy.functions.elementary.exponential import (exp, exp_polar, log)
|
||||
from sympy.functions.elementary.hyperbolic import (cosh, sinh)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin, sinc)
|
||||
from sympy.functions.special.error_functions import (Chi, Ci, E1, Ei, Li, Shi, Si, erf, erf2, erf2inv, erfc, erfcinv, erfi, erfinv, expint, fresnelc, fresnels, li)
|
||||
from sympy.functions.special.gamma_functions import (gamma, uppergamma)
|
||||
from sympy.functions.special.hyper import (hyper, meijerg)
|
||||
from sympy.integrals.integrals import (Integral, integrate)
|
||||
from sympy.series.gruntz import gruntz
|
||||
from sympy.series.limits import limit
|
||||
from sympy.series.order import O
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.functions.special.error_functions import _erfs, _eis
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
x, y, z = symbols('x,y,z')
|
||||
w = Symbol("w", real=True)
|
||||
n = Symbol("n", integer=True)
|
||||
t = Dummy('t')
|
||||
|
||||
|
||||
def test_erf():
|
||||
assert erf(nan) is nan
|
||||
|
||||
assert erf(oo) == 1
|
||||
assert erf(-oo) == -1
|
||||
|
||||
assert erf(0) is S.Zero
|
||||
|
||||
assert erf(I*oo) == oo*I
|
||||
assert erf(-I*oo) == -oo*I
|
||||
|
||||
assert erf(-2) == -erf(2)
|
||||
assert erf(-x*y) == -erf(x*y)
|
||||
assert erf(-x - y) == -erf(x + y)
|
||||
|
||||
assert erf(erfinv(x)) == x
|
||||
assert erf(erfcinv(x)) == 1 - x
|
||||
assert erf(erf2inv(0, x)) == x
|
||||
assert erf(erf2inv(0, x, evaluate=False)) == x # To cover code in erf
|
||||
assert erf(erf2inv(0, erf(erfcinv(1 - erf(erfinv(x)))))) == x
|
||||
|
||||
alpha = symbols('alpha', extended_real=True)
|
||||
assert erf(alpha).is_real is True
|
||||
assert erf(alpha).is_finite is True
|
||||
alpha = symbols('alpha', extended_real=False)
|
||||
assert erf(alpha).is_real is None
|
||||
assert erf(alpha).is_finite is None
|
||||
assert erf(alpha).is_zero is None
|
||||
assert erf(alpha).is_positive is None
|
||||
assert erf(alpha).is_negative is None
|
||||
alpha = symbols('alpha', extended_positive=True)
|
||||
assert erf(alpha).is_positive is True
|
||||
alpha = symbols('alpha', extended_negative=True)
|
||||
assert erf(alpha).is_negative is True
|
||||
assert erf(I).is_real is False
|
||||
assert erf(0, evaluate=False).is_real
|
||||
assert erf(0, evaluate=False).is_zero
|
||||
|
||||
assert conjugate(erf(z)) == erf(conjugate(z))
|
||||
|
||||
assert erf(x).as_leading_term(x) == 2*x/sqrt(pi)
|
||||
assert erf(x*y).as_leading_term(y) == 2*x*y/sqrt(pi)
|
||||
assert (erf(x*y)/erf(y)).as_leading_term(y) == x
|
||||
assert erf(1/x).as_leading_term(x) == S.One
|
||||
|
||||
assert erf(z).rewrite('uppergamma') == sqrt(z**2)*(1 - erfc(sqrt(z**2)))/z
|
||||
assert erf(z).rewrite('erfc') == S.One - erfc(z)
|
||||
assert erf(z).rewrite('erfi') == -I*erfi(I*z)
|
||||
assert erf(z).rewrite('fresnels') == (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 - I)/sqrt(pi)))
|
||||
assert erf(z).rewrite('fresnelc') == (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 - I)/sqrt(pi)))
|
||||
assert erf(z).rewrite('hyper') == 2*z*hyper([S.Half], [3*S.Half], -z**2)/sqrt(pi)
|
||||
assert erf(z).rewrite('meijerg') == z*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2)/sqrt(pi)
|
||||
assert erf(z).rewrite('expint') == sqrt(z**2)/z - z*expint(S.Half, z**2)/sqrt(S.Pi)
|
||||
|
||||
assert limit(exp(x)*exp(x**2)*(erf(x + 1/exp(x)) - erf(x)), x, oo) == \
|
||||
2/sqrt(pi)
|
||||
assert limit((1 - erf(z))*exp(z**2)*z, z, oo) == 1/sqrt(pi)
|
||||
assert limit((1 - erf(x))*exp(x**2)*sqrt(pi)*x, x, oo) == 1
|
||||
assert limit(((1 - erf(x))*exp(x**2)*sqrt(pi)*x - 1)*2*x**2, x, oo) == -1
|
||||
assert limit(erf(x)/x, x, 0) == 2/sqrt(pi)
|
||||
assert limit(x**(-4) - sqrt(pi)*erf(x**2) / (2*x**6), x, 0) == S(1)/3
|
||||
|
||||
assert erf(x).as_real_imag() == \
|
||||
(erf(re(x) - I*im(x))/2 + erf(re(x) + I*im(x))/2,
|
||||
-I*(-erf(re(x) - I*im(x)) + erf(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erf(x).as_real_imag(deep=False) == \
|
||||
(erf(re(x) - I*im(x))/2 + erf(re(x) + I*im(x))/2,
|
||||
-I*(-erf(re(x) - I*im(x)) + erf(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erf(w).as_real_imag() == (erf(w), 0)
|
||||
assert erf(w).as_real_imag(deep=False) == (erf(w), 0)
|
||||
# issue 13575
|
||||
assert erf(I).as_real_imag() == (0, -I*erf(I))
|
||||
|
||||
raises(ArgumentIndexError, lambda: erf(x).fdiff(2))
|
||||
|
||||
assert erf(x).inverse() == erfinv
|
||||
|
||||
|
||||
def test_erf_series():
|
||||
assert erf(x).series(x, 0, 7) == 2*x/sqrt(pi) - \
|
||||
2*x**3/3/sqrt(pi) + x**5/5/sqrt(pi) + O(x**7)
|
||||
|
||||
assert erf(x).series(x, oo) == \
|
||||
-exp(-x**2)*(3/(4*x**5) - 1/(2*x**3) + 1/x + O(x**(-6), (x, oo)))/sqrt(pi) + 1
|
||||
assert erf(x**2).series(x, oo, n=8) == \
|
||||
(-1/(2*x**6) + x**(-2) + O(x**(-8), (x, oo)))*exp(-x**4)/sqrt(pi)*-1 + 1
|
||||
assert erf(sqrt(x)).series(x, oo, n=3) == (sqrt(1/x) - (1/x)**(S(3)/2)/2\
|
||||
+ 3*(1/x)**(S(5)/2)/4 + O(x**(-3), (x, oo)))*exp(-x)/sqrt(pi)*-1 + 1
|
||||
|
||||
|
||||
def test_erf_evalf():
|
||||
assert abs( erf(Float(2.0)) - 0.995322265 ) < 1E-8 # XXX
|
||||
|
||||
|
||||
def test__erfs():
|
||||
assert _erfs(z).diff(z) == -2/sqrt(S.Pi) + 2*z*_erfs(z)
|
||||
|
||||
assert _erfs(1/z).series(z) == \
|
||||
z/sqrt(pi) - z**3/(2*sqrt(pi)) + 3*z**5/(4*sqrt(pi)) + O(z**6)
|
||||
|
||||
assert expand(erf(z).rewrite('tractable').diff(z).rewrite('intractable')) \
|
||||
== erf(z).diff(z)
|
||||
assert _erfs(z).rewrite("intractable") == (-erf(z) + 1)*exp(z**2)
|
||||
raises(ArgumentIndexError, lambda: _erfs(z).fdiff(2))
|
||||
|
||||
|
||||
def test_erfc():
|
||||
assert erfc(nan) is nan
|
||||
|
||||
assert erfc(oo) is S.Zero
|
||||
assert erfc(-oo) == 2
|
||||
|
||||
assert erfc(0) == 1
|
||||
|
||||
assert erfc(I*oo) == -oo*I
|
||||
assert erfc(-I*oo) == oo*I
|
||||
|
||||
assert erfc(-x) == S(2) - erfc(x)
|
||||
assert erfc(erfcinv(x)) == x
|
||||
|
||||
alpha = symbols('alpha', extended_real=True)
|
||||
assert erfc(alpha).is_real is True
|
||||
alpha = symbols('alpha', extended_real=False)
|
||||
assert erfc(alpha).is_real is None
|
||||
assert erfc(I).is_real is False
|
||||
assert erfc(0, evaluate=False).is_real
|
||||
assert erfc(0, evaluate=False).is_zero is False
|
||||
|
||||
assert erfc(erfinv(x)) == 1 - x
|
||||
|
||||
assert conjugate(erfc(z)) == erfc(conjugate(z))
|
||||
|
||||
assert erfc(x).as_leading_term(x) is S.One
|
||||
assert erfc(1/x).as_leading_term(x) == S.Zero
|
||||
|
||||
assert erfc(z).rewrite('erf') == 1 - erf(z)
|
||||
assert erfc(z).rewrite('erfi') == 1 + I*erfi(I*z)
|
||||
assert erfc(z).rewrite('fresnels') == 1 - (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 - I)/sqrt(pi)))
|
||||
assert erfc(z).rewrite('fresnelc') == 1 - (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 - I)/sqrt(pi)))
|
||||
assert erfc(z).rewrite('hyper') == 1 - 2*z*hyper([S.Half], [3*S.Half], -z**2)/sqrt(pi)
|
||||
assert erfc(z).rewrite('meijerg') == 1 - z*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2)/sqrt(pi)
|
||||
assert erfc(z).rewrite('uppergamma') == 1 - sqrt(z**2)*(1 - erfc(sqrt(z**2)))/z
|
||||
assert erfc(z).rewrite('expint') == S.One - sqrt(z**2)/z + z*expint(S.Half, z**2)/sqrt(S.Pi)
|
||||
assert erfc(z).rewrite('tractable') == _erfs(z)*exp(-z**2)
|
||||
assert expand_func(erf(x) + erfc(x)) is S.One
|
||||
|
||||
assert erfc(x).as_real_imag() == \
|
||||
(erfc(re(x) - I*im(x))/2 + erfc(re(x) + I*im(x))/2,
|
||||
-I*(-erfc(re(x) - I*im(x)) + erfc(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erfc(x).as_real_imag(deep=False) == \
|
||||
(erfc(re(x) - I*im(x))/2 + erfc(re(x) + I*im(x))/2,
|
||||
-I*(-erfc(re(x) - I*im(x)) + erfc(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erfc(w).as_real_imag() == (erfc(w), 0)
|
||||
assert erfc(w).as_real_imag(deep=False) == (erfc(w), 0)
|
||||
raises(ArgumentIndexError, lambda: erfc(x).fdiff(2))
|
||||
|
||||
assert erfc(x).inverse() == erfcinv
|
||||
|
||||
|
||||
def test_erfc_series():
|
||||
assert erfc(x).series(x, 0, 7) == 1 - 2*x/sqrt(pi) + \
|
||||
2*x**3/3/sqrt(pi) - x**5/5/sqrt(pi) + O(x**7)
|
||||
|
||||
assert erfc(x).series(x, oo) == \
|
||||
(3/(4*x**5) - 1/(2*x**3) + 1/x + O(x**(-6), (x, oo)))*exp(-x**2)/sqrt(pi)
|
||||
|
||||
|
||||
def test_erfc_evalf():
|
||||
assert abs( erfc(Float(2.0)) - 0.00467773 ) < 1E-8 # XXX
|
||||
|
||||
|
||||
def test_erfi():
|
||||
assert erfi(nan) is nan
|
||||
|
||||
assert erfi(oo) is S.Infinity
|
||||
assert erfi(-oo) is S.NegativeInfinity
|
||||
|
||||
assert erfi(0) is S.Zero
|
||||
|
||||
assert erfi(I*oo) == I
|
||||
assert erfi(-I*oo) == -I
|
||||
|
||||
assert erfi(-x) == -erfi(x)
|
||||
|
||||
assert erfi(I*erfinv(x)) == I*x
|
||||
assert erfi(I*erfcinv(x)) == I*(1 - x)
|
||||
assert erfi(I*erf2inv(0, x)) == I*x
|
||||
assert erfi(I*erf2inv(0, x, evaluate=False)) == I*x # To cover code in erfi
|
||||
|
||||
assert erfi(I).is_real is False
|
||||
assert erfi(0, evaluate=False).is_real
|
||||
assert erfi(0, evaluate=False).is_zero
|
||||
|
||||
assert conjugate(erfi(z)) == erfi(conjugate(z))
|
||||
|
||||
assert erfi(x).as_leading_term(x) == 2*x/sqrt(pi)
|
||||
assert erfi(x*y).as_leading_term(y) == 2*x*y/sqrt(pi)
|
||||
assert (erfi(x*y)/erfi(y)).as_leading_term(y) == x
|
||||
assert erfi(1/x).as_leading_term(x) == erfi(1/x)
|
||||
|
||||
assert erfi(z).rewrite('erf') == -I*erf(I*z)
|
||||
assert erfi(z).rewrite('erfc') == I*erfc(I*z) - I
|
||||
assert erfi(z).rewrite('fresnels') == (1 - I)*(fresnelc(z*(1 + I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 + I)/sqrt(pi)))
|
||||
assert erfi(z).rewrite('fresnelc') == (1 - I)*(fresnelc(z*(1 + I)/sqrt(pi)) -
|
||||
I*fresnels(z*(1 + I)/sqrt(pi)))
|
||||
assert erfi(z).rewrite('hyper') == 2*z*hyper([S.Half], [3*S.Half], z**2)/sqrt(pi)
|
||||
assert erfi(z).rewrite('meijerg') == z*meijerg([S.Half], [], [0], [Rational(-1, 2)], -z**2)/sqrt(pi)
|
||||
assert erfi(z).rewrite('uppergamma') == (sqrt(-z**2)/z*(uppergamma(S.Half,
|
||||
-z**2)/sqrt(S.Pi) - S.One))
|
||||
assert erfi(z).rewrite('expint') == sqrt(-z**2)/z - z*expint(S.Half, -z**2)/sqrt(S.Pi)
|
||||
assert erfi(z).rewrite('tractable') == -I*(-_erfs(I*z)*exp(z**2) + 1)
|
||||
assert expand_func(erfi(I*z)) == I*erf(z)
|
||||
|
||||
assert erfi(x).as_real_imag() == \
|
||||
(erfi(re(x) - I*im(x))/2 + erfi(re(x) + I*im(x))/2,
|
||||
-I*(-erfi(re(x) - I*im(x)) + erfi(re(x) + I*im(x)))/2)
|
||||
assert erfi(x).as_real_imag(deep=False) == \
|
||||
(erfi(re(x) - I*im(x))/2 + erfi(re(x) + I*im(x))/2,
|
||||
-I*(-erfi(re(x) - I*im(x)) + erfi(re(x) + I*im(x)))/2)
|
||||
|
||||
assert erfi(w).as_real_imag() == (erfi(w), 0)
|
||||
assert erfi(w).as_real_imag(deep=False) == (erfi(w), 0)
|
||||
|
||||
raises(ArgumentIndexError, lambda: erfi(x).fdiff(2))
|
||||
|
||||
|
||||
def test_erfi_series():
|
||||
assert erfi(x).series(x, 0, 7) == 2*x/sqrt(pi) + \
|
||||
2*x**3/3/sqrt(pi) + x**5/5/sqrt(pi) + O(x**7)
|
||||
|
||||
assert erfi(x).series(x, oo) == \
|
||||
(3/(4*x**5) + 1/(2*x**3) + 1/x + O(x**(-6), (x, oo)))*exp(x**2)/sqrt(pi) - I
|
||||
|
||||
|
||||
def test_erfi_evalf():
|
||||
assert abs( erfi(Float(2.0)) - 18.5648024145756 ) < 1E-13 # XXX
|
||||
|
||||
|
||||
def test_erf2():
|
||||
|
||||
assert erf2(0, 0) is S.Zero
|
||||
assert erf2(x, x) is S.Zero
|
||||
assert erf2(nan, 0) is nan
|
||||
|
||||
assert erf2(-oo, y) == erf(y) + 1
|
||||
assert erf2( oo, y) == erf(y) - 1
|
||||
assert erf2( x, oo) == 1 - erf(x)
|
||||
assert erf2( x,-oo) == -1 - erf(x)
|
||||
assert erf2(x, erf2inv(x, y)) == y
|
||||
|
||||
assert erf2(-x, -y) == -erf2(x,y)
|
||||
assert erf2(-x, y) == erf(y) + erf(x)
|
||||
assert erf2( x, -y) == -erf(y) - erf(x)
|
||||
assert erf2(x, y).rewrite('fresnels') == erf(y).rewrite(fresnels)-erf(x).rewrite(fresnels)
|
||||
assert erf2(x, y).rewrite('fresnelc') == erf(y).rewrite(fresnelc)-erf(x).rewrite(fresnelc)
|
||||
assert erf2(x, y).rewrite('hyper') == erf(y).rewrite(hyper)-erf(x).rewrite(hyper)
|
||||
assert erf2(x, y).rewrite('meijerg') == erf(y).rewrite(meijerg)-erf(x).rewrite(meijerg)
|
||||
assert erf2(x, y).rewrite('uppergamma') == erf(y).rewrite(uppergamma) - erf(x).rewrite(uppergamma)
|
||||
assert erf2(x, y).rewrite('expint') == erf(y).rewrite(expint)-erf(x).rewrite(expint)
|
||||
|
||||
assert erf2(I, 0).is_real is False
|
||||
assert erf2(0, 0, evaluate=False).is_real
|
||||
assert erf2(0, 0, evaluate=False).is_zero
|
||||
assert erf2(x, x, evaluate=False).is_zero
|
||||
assert erf2(x, y).is_zero is None
|
||||
|
||||
assert expand_func(erf(x) + erf2(x, y)) == erf(y)
|
||||
|
||||
assert conjugate(erf2(x, y)) == erf2(conjugate(x), conjugate(y))
|
||||
|
||||
assert erf2(x, y).rewrite('erf') == erf(y) - erf(x)
|
||||
assert erf2(x, y).rewrite('erfc') == erfc(x) - erfc(y)
|
||||
assert erf2(x, y).rewrite('erfi') == I*(erfi(I*x) - erfi(I*y))
|
||||
|
||||
assert erf2(x, y).diff(x) == erf2(x, y).fdiff(1)
|
||||
assert erf2(x, y).diff(y) == erf2(x, y).fdiff(2)
|
||||
assert erf2(x, y).diff(x) == -2*exp(-x**2)/sqrt(pi)
|
||||
assert erf2(x, y).diff(y) == 2*exp(-y**2)/sqrt(pi)
|
||||
raises(ArgumentIndexError, lambda: erf2(x, y).fdiff(3))
|
||||
|
||||
assert erf2(x, y).is_extended_real is None
|
||||
xr, yr = symbols('xr yr', extended_real=True)
|
||||
assert erf2(xr, yr).is_extended_real is True
|
||||
|
||||
|
||||
def test_erfinv():
|
||||
assert erfinv(0) is S.Zero
|
||||
assert erfinv(1) is S.Infinity
|
||||
assert erfinv(nan) is S.NaN
|
||||
assert erfinv(-1) is S.NegativeInfinity
|
||||
|
||||
assert erfinv(erf(w)) == w
|
||||
assert erfinv(erf(-w)) == -w
|
||||
|
||||
assert erfinv(x).diff() == sqrt(pi)*exp(erfinv(x)**2)/2
|
||||
raises(ArgumentIndexError, lambda: erfinv(x).fdiff(2))
|
||||
|
||||
assert erfinv(z).rewrite('erfcinv') == erfcinv(1-z)
|
||||
assert erfinv(z).inverse() == erf
|
||||
|
||||
|
||||
def test_erfinv_evalf():
|
||||
assert abs( erfinv(Float(0.2)) - 0.179143454621292 ) < 1E-13
|
||||
|
||||
|
||||
def test_erfcinv():
|
||||
assert erfcinv(1) is S.Zero
|
||||
assert erfcinv(0) is S.Infinity
|
||||
assert erfcinv(0, evaluate=False).is_infinite is True
|
||||
assert erfcinv(2, evaluate=False).is_infinite is True
|
||||
assert erfcinv(nan) is S.NaN
|
||||
|
||||
assert erfcinv(x).diff() == -sqrt(pi)*exp(erfcinv(x)**2)/2
|
||||
raises(ArgumentIndexError, lambda: erfcinv(x).fdiff(2))
|
||||
|
||||
assert erfcinv(z).rewrite('erfinv') == erfinv(1-z)
|
||||
assert erfcinv(z).inverse() == erfc
|
||||
|
||||
|
||||
def test_erf2inv():
|
||||
assert erf2inv(0, 0) is S.Zero
|
||||
assert erf2inv(0, 1) is S.Infinity
|
||||
assert erf2inv(1, 0) is S.One
|
||||
assert erf2inv(0, y) == erfinv(y)
|
||||
assert erf2inv(oo, y) == erfcinv(-y)
|
||||
assert erf2inv(x, 0) == x
|
||||
assert erf2inv(x, oo) == erfinv(x)
|
||||
assert erf2inv(nan, 0) is nan
|
||||
assert erf2inv(0, nan) is nan
|
||||
|
||||
assert erf2inv(x, y).diff(x) == exp(-x**2 + erf2inv(x, y)**2)
|
||||
assert erf2inv(x, y).diff(y) == sqrt(pi)*exp(erf2inv(x, y)**2)/2
|
||||
raises(ArgumentIndexError, lambda: erf2inv(x, y).fdiff(3))
|
||||
|
||||
|
||||
# NOTE we multiply by exp_polar(I*pi) and need this to be on the principal
|
||||
# branch, hence take x in the lower half plane (d=0).
|
||||
|
||||
|
||||
def mytn(expr1, expr2, expr3, x, d=0):
|
||||
from sympy.core.random import verify_numerically, random_complex_number
|
||||
subs = {}
|
||||
for a in expr1.free_symbols:
|
||||
if a != x:
|
||||
subs[a] = random_complex_number()
|
||||
return expr2 == expr3 and verify_numerically(expr1.subs(subs),
|
||||
expr2.subs(subs), x, d=d)
|
||||
|
||||
|
||||
def mytd(expr1, expr2, x):
|
||||
from sympy.core.random import test_derivative_numerically, \
|
||||
random_complex_number
|
||||
subs = {}
|
||||
for a in expr1.free_symbols:
|
||||
if a != x:
|
||||
subs[a] = random_complex_number()
|
||||
return expr1.diff(x) == expr2 and test_derivative_numerically(expr1.subs(subs), x)
|
||||
|
||||
|
||||
def tn_branch(func, s=None):
|
||||
from sympy.core.random import uniform
|
||||
|
||||
def fn(x):
|
||||
if s is None:
|
||||
return func(x)
|
||||
return func(s, x)
|
||||
c = uniform(1, 5)
|
||||
expr = fn(c*exp_polar(I*pi)) - fn(c*exp_polar(-I*pi))
|
||||
eps = 1e-15
|
||||
expr2 = fn(-c + eps*I) - fn(-c - eps*I)
|
||||
return abs(expr.n() - expr2.n()).n() < 1e-10
|
||||
|
||||
|
||||
def test_ei():
|
||||
assert Ei(0) is S.NegativeInfinity
|
||||
assert Ei(oo) is S.Infinity
|
||||
assert Ei(-oo) is S.Zero
|
||||
|
||||
assert tn_branch(Ei)
|
||||
assert mytd(Ei(x), exp(x)/x, x)
|
||||
assert mytn(Ei(x), Ei(x).rewrite(uppergamma),
|
||||
-uppergamma(0, x*polar_lift(-1)) - I*pi, x)
|
||||
assert mytn(Ei(x), Ei(x).rewrite(expint),
|
||||
-expint(1, x*polar_lift(-1)) - I*pi, x)
|
||||
assert Ei(x).rewrite(expint).rewrite(Ei) == Ei(x)
|
||||
assert Ei(x*exp_polar(2*I*pi)) == Ei(x) + 2*I*pi
|
||||
assert Ei(x*exp_polar(-2*I*pi)) == Ei(x) - 2*I*pi
|
||||
|
||||
assert mytn(Ei(x), Ei(x).rewrite(Shi), Chi(x) + Shi(x), x)
|
||||
assert mytn(Ei(x*polar_lift(I)), Ei(x*polar_lift(I)).rewrite(Si),
|
||||
Ci(x) + I*Si(x) + I*pi/2, x)
|
||||
|
||||
assert Ei(log(x)).rewrite(li) == li(x)
|
||||
assert Ei(2*log(x)).rewrite(li) == li(x**2)
|
||||
|
||||
assert gruntz(Ei(x+exp(-x))*exp(-x)*x, x, oo) == 1
|
||||
|
||||
assert Ei(x).series(x) == EulerGamma + log(x) + x + x**2/4 + \
|
||||
x**3/18 + x**4/96 + x**5/600 + O(x**6)
|
||||
assert Ei(x).series(x, 1, 3) == Ei(1) + E*(x - 1) + O((x - 1)**3, (x, 1))
|
||||
assert Ei(x).series(x, oo) == \
|
||||
(120/x**5 + 24/x**4 + 6/x**3 + 2/x**2 + 1/x + 1 + O(x**(-6), (x, oo)))*exp(x)/x
|
||||
assert Ei(x).series(x, -oo) == \
|
||||
(120/x**5 + 24/x**4 + 6/x**3 + 2/x**2 + 1/x + 1 + O(x**(-6), (x, -oo)))*exp(x)/x
|
||||
assert Ei(-x).series(x, oo) == \
|
||||
-((-120/x**5 + 24/x**4 - 6/x**3 + 2/x**2 - 1/x + 1 + O(x**(-6), (x, oo)))*exp(-x)/x)
|
||||
|
||||
assert str(Ei(cos(2)).evalf(n=10)) == '-0.6760647401'
|
||||
raises(ArgumentIndexError, lambda: Ei(x).fdiff(2))
|
||||
|
||||
|
||||
def test_expint():
|
||||
assert mytn(expint(x, y), expint(x, y).rewrite(uppergamma),
|
||||
y**(x - 1)*uppergamma(1 - x, y), x)
|
||||
assert mytd(
|
||||
expint(x, y), -y**(x - 1)*meijerg([], [1, 1], [0, 0, 1 - x], [], y), x)
|
||||
assert mytd(expint(x, y), -expint(x - 1, y), y)
|
||||
assert mytn(expint(1, x), expint(1, x).rewrite(Ei),
|
||||
-Ei(x*polar_lift(-1)) + I*pi, x)
|
||||
|
||||
assert expint(-4, x) == exp(-x)/x + 4*exp(-x)/x**2 + 12*exp(-x)/x**3 \
|
||||
+ 24*exp(-x)/x**4 + 24*exp(-x)/x**5
|
||||
assert expint(Rational(-3, 2), x) == \
|
||||
exp(-x)/x + 3*exp(-x)/(2*x**2) + 3*sqrt(pi)*erfc(sqrt(x))/(4*x**S('5/2'))
|
||||
|
||||
assert tn_branch(expint, 1)
|
||||
assert tn_branch(expint, 2)
|
||||
assert tn_branch(expint, 3)
|
||||
assert tn_branch(expint, 1.7)
|
||||
assert tn_branch(expint, pi)
|
||||
|
||||
assert expint(y, x*exp_polar(2*I*pi)) == \
|
||||
x**(y - 1)*(exp(2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x)
|
||||
assert expint(y, x*exp_polar(-2*I*pi)) == \
|
||||
x**(y - 1)*(exp(-2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x)
|
||||
assert expint(2, x*exp_polar(2*I*pi)) == 2*I*pi*x + expint(2, x)
|
||||
assert expint(2, x*exp_polar(-2*I*pi)) == -2*I*pi*x + expint(2, x)
|
||||
assert expint(1, x).rewrite(Ei).rewrite(expint) == expint(1, x)
|
||||
assert expint(x, y).rewrite(Ei) == expint(x, y)
|
||||
assert expint(x, y).rewrite(Ci) == expint(x, y)
|
||||
|
||||
assert mytn(E1(x), E1(x).rewrite(Shi), Shi(x) - Chi(x), x)
|
||||
assert mytn(E1(polar_lift(I)*x), E1(polar_lift(I)*x).rewrite(Si),
|
||||
-Ci(x) + I*Si(x) - I*pi/2, x)
|
||||
|
||||
assert mytn(expint(2, x), expint(2, x).rewrite(Ei).rewrite(expint),
|
||||
-x*E1(x) + exp(-x), x)
|
||||
assert mytn(expint(3, x), expint(3, x).rewrite(Ei).rewrite(expint),
|
||||
x**2*E1(x)/2 + (1 - x)*exp(-x)/2, x)
|
||||
|
||||
assert expint(Rational(3, 2), z).nseries(z) == \
|
||||
2 + 2*z - z**2/3 + z**3/15 - z**4/84 + z**5/540 - \
|
||||
2*sqrt(pi)*sqrt(z) + O(z**6)
|
||||
|
||||
assert E1(z).series(z) == -EulerGamma - log(z) + z - \
|
||||
z**2/4 + z**3/18 - z**4/96 + z**5/600 + O(z**6)
|
||||
|
||||
assert expint(4, z).series(z) == Rational(1, 3) - z/2 + z**2/2 + \
|
||||
z**3*(log(z)/6 - Rational(11, 36) + EulerGamma/6 - I*pi/6) - z**4/24 + \
|
||||
z**5/240 + O(z**6)
|
||||
|
||||
assert expint(n, x).series(x, oo, n=3) == \
|
||||
(n*(n + 1)/x**2 - n/x + 1 + O(x**(-3), (x, oo)))*exp(-x)/x
|
||||
|
||||
assert expint(z, y).series(z, 0, 2) == exp(-y)/y - z*meijerg(((), (1, 1)),
|
||||
((0, 0, 1), ()), y)/y + O(z**2)
|
||||
raises(ArgumentIndexError, lambda: expint(x, y).fdiff(3))
|
||||
|
||||
neg = Symbol('neg', negative=True)
|
||||
assert Ei(neg).rewrite(Si) == Shi(neg) + Chi(neg) - I*pi
|
||||
|
||||
|
||||
def test__eis():
|
||||
assert _eis(z).diff(z) == -_eis(z) + 1/z
|
||||
|
||||
assert _eis(1/z).series(z) == \
|
||||
z + z**2 + 2*z**3 + 6*z**4 + 24*z**5 + O(z**6)
|
||||
|
||||
assert Ei(z).rewrite('tractable') == exp(z)*_eis(z)
|
||||
assert li(z).rewrite('tractable') == z*_eis(log(z))
|
||||
|
||||
assert _eis(z).rewrite('intractable') == exp(-z)*Ei(z)
|
||||
|
||||
assert expand(li(z).rewrite('tractable').diff(z).rewrite('intractable')) \
|
||||
== li(z).diff(z)
|
||||
|
||||
assert expand(Ei(z).rewrite('tractable').diff(z).rewrite('intractable')) \
|
||||
== Ei(z).diff(z)
|
||||
|
||||
assert _eis(z).series(z, n=3) == EulerGamma + log(z) + z*(-log(z) - \
|
||||
EulerGamma + 1) + z**2*(log(z)/2 - Rational(3, 4) + EulerGamma/2)\
|
||||
+ O(z**3*log(z))
|
||||
raises(ArgumentIndexError, lambda: _eis(z).fdiff(2))
|
||||
|
||||
|
||||
def tn_arg(func):
|
||||
def test(arg, e1, e2):
|
||||
from sympy.core.random import uniform
|
||||
v = uniform(1, 5)
|
||||
v1 = func(arg*x).subs(x, v).n()
|
||||
v2 = func(e1*v + e2*1e-15).n()
|
||||
return abs(v1 - v2).n() < 1e-10
|
||||
return test(exp_polar(I*pi/2), I, 1) and \
|
||||
test(exp_polar(-I*pi/2), -I, 1) and \
|
||||
test(exp_polar(I*pi), -1, I) and \
|
||||
test(exp_polar(-I*pi), -1, -I)
|
||||
|
||||
|
||||
def test_li():
|
||||
z = Symbol("z")
|
||||
zr = Symbol("z", real=True)
|
||||
zp = Symbol("z", positive=True)
|
||||
zn = Symbol("z", negative=True)
|
||||
|
||||
assert li(0) is S.Zero
|
||||
assert li(1) is -oo
|
||||
assert li(oo) is oo
|
||||
|
||||
assert isinstance(li(z), li)
|
||||
assert unchanged(li, -zp)
|
||||
assert unchanged(li, zn)
|
||||
|
||||
assert diff(li(z), z) == 1/log(z)
|
||||
|
||||
assert conjugate(li(z)) == li(conjugate(z))
|
||||
assert conjugate(li(-zr)) == li(-zr)
|
||||
assert unchanged(conjugate, li(-zp))
|
||||
assert unchanged(conjugate, li(zn))
|
||||
|
||||
assert li(z).rewrite(Li) == Li(z) + li(2)
|
||||
assert li(z).rewrite(Ei) == Ei(log(z))
|
||||
assert li(z).rewrite(uppergamma) == (-log(1/log(z))/2 - log(-log(z)) +
|
||||
log(log(z))/2 - expint(1, -log(z)))
|
||||
assert li(z).rewrite(Si) == (-log(I*log(z)) - log(1/log(z))/2 +
|
||||
log(log(z))/2 + Ci(I*log(z)) + Shi(log(z)))
|
||||
assert li(z).rewrite(Ci) == (-log(I*log(z)) - log(1/log(z))/2 +
|
||||
log(log(z))/2 + Ci(I*log(z)) + Shi(log(z)))
|
||||
assert li(z).rewrite(Shi) == (-log(1/log(z))/2 + log(log(z))/2 +
|
||||
Chi(log(z)) - Shi(log(z)))
|
||||
assert li(z).rewrite(Chi) == (-log(1/log(z))/2 + log(log(z))/2 +
|
||||
Chi(log(z)) - Shi(log(z)))
|
||||
assert li(z).rewrite(hyper) ==(log(z)*hyper((1, 1), (2, 2), log(z)) -
|
||||
log(1/log(z))/2 + log(log(z))/2 + EulerGamma)
|
||||
assert li(z).rewrite(meijerg) == (-log(1/log(z))/2 - log(-log(z)) + log(log(z))/2 -
|
||||
meijerg(((), (1,)), ((0, 0), ()), -log(z)))
|
||||
|
||||
assert gruntz(1/li(z), z, oo) is S.Zero
|
||||
assert li(z).series(z) == log(z)**5/600 + log(z)**4/96 + log(z)**3/18 + log(z)**2/4 + \
|
||||
log(z) + log(log(z)) + EulerGamma
|
||||
raises(ArgumentIndexError, lambda: li(z).fdiff(2))
|
||||
|
||||
|
||||
def test_Li():
|
||||
assert Li(2) is S.Zero
|
||||
assert Li(oo) is oo
|
||||
|
||||
assert isinstance(Li(z), Li)
|
||||
|
||||
assert diff(Li(z), z) == 1/log(z)
|
||||
|
||||
assert gruntz(1/Li(z), z, oo) is S.Zero
|
||||
assert Li(z).rewrite(li) == li(z) - li(2)
|
||||
assert Li(z).series(z) == \
|
||||
log(z)**5/600 + log(z)**4/96 + log(z)**3/18 + log(z)**2/4 + log(z) + log(log(z)) - li(2) + EulerGamma
|
||||
raises(ArgumentIndexError, lambda: Li(z).fdiff(2))
|
||||
|
||||
|
||||
def test_si():
|
||||
assert Si(I*x) == I*Shi(x)
|
||||
assert Shi(I*x) == I*Si(x)
|
||||
assert Si(-I*x) == -I*Shi(x)
|
||||
assert Shi(-I*x) == -I*Si(x)
|
||||
assert Si(-x) == -Si(x)
|
||||
assert Shi(-x) == -Shi(x)
|
||||
assert Si(exp_polar(2*pi*I)*x) == Si(x)
|
||||
assert Si(exp_polar(-2*pi*I)*x) == Si(x)
|
||||
assert Shi(exp_polar(2*pi*I)*x) == Shi(x)
|
||||
assert Shi(exp_polar(-2*pi*I)*x) == Shi(x)
|
||||
|
||||
assert Si(oo) == pi/2
|
||||
assert Si(-oo) == -pi/2
|
||||
assert Shi(oo) is oo
|
||||
assert Shi(-oo) is -oo
|
||||
|
||||
assert mytd(Si(x), sin(x)/x, x)
|
||||
assert mytd(Shi(x), sinh(x)/x, x)
|
||||
|
||||
assert mytn(Si(x), Si(x).rewrite(Ei),
|
||||
-I*(-Ei(x*exp_polar(-I*pi/2))/2
|
||||
+ Ei(x*exp_polar(I*pi/2))/2 - I*pi) + pi/2, x)
|
||||
assert mytn(Si(x), Si(x).rewrite(expint),
|
||||
-I*(-expint(1, x*exp_polar(-I*pi/2))/2 +
|
||||
expint(1, x*exp_polar(I*pi/2))/2) + pi/2, x)
|
||||
assert mytn(Shi(x), Shi(x).rewrite(Ei),
|
||||
Ei(x)/2 - Ei(x*exp_polar(I*pi))/2 + I*pi/2, x)
|
||||
assert mytn(Shi(x), Shi(x).rewrite(expint),
|
||||
expint(1, x)/2 - expint(1, x*exp_polar(I*pi))/2 - I*pi/2, x)
|
||||
|
||||
assert tn_arg(Si)
|
||||
assert tn_arg(Shi)
|
||||
|
||||
assert Si(x)._eval_as_leading_term(x, None, 1) == x
|
||||
assert Si(2*x)._eval_as_leading_term(x, None, 1) == 2*x
|
||||
assert Si(sin(x))._eval_as_leading_term(x, None, 1) == x
|
||||
assert Si(x + 1)._eval_as_leading_term(x, None, 1) == Si(1)
|
||||
assert Si(1/x)._eval_as_leading_term(x, None, 1) == \
|
||||
Si(1/x)._eval_as_leading_term(x, None, -1) == Si(1/x)
|
||||
|
||||
assert Si(x).nseries(x, n=8) == \
|
||||
x - x**3/18 + x**5/600 - x**7/35280 + O(x**8)
|
||||
assert Shi(x).nseries(x, n=8) == \
|
||||
x + x**3/18 + x**5/600 + x**7/35280 + O(x**8)
|
||||
assert Si(sin(x)).nseries(x, n=5) == x - 2*x**3/9 + O(x**5)
|
||||
assert Si(x).nseries(x, 1, n=3) == \
|
||||
Si(1) + (x - 1)*sin(1) + (x - 1)**2*(-sin(1)/2 + cos(1)/2) + O((x - 1)**3, (x, 1))
|
||||
|
||||
assert Si(x).series(x, oo) == -sin(x)*(-6/x**4 + x**(-2) + O(x**(-6), (x, oo))) - \
|
||||
cos(x)*(24/x**5 - 2/x**3 + 1/x + O(x**(-6), (x, oo))) + pi/2
|
||||
|
||||
t = Symbol('t', Dummy=True)
|
||||
assert Si(x).rewrite(sinc).dummy_eq(Integral(sinc(t), (t, 0, x)))
|
||||
|
||||
assert limit(Shi(x), x, S.Infinity) == S.Infinity
|
||||
assert limit(Shi(x), x, S.NegativeInfinity) == S.NegativeInfinity
|
||||
|
||||
|
||||
def test_ci():
|
||||
m1 = exp_polar(I*pi)
|
||||
m1_ = exp_polar(-I*pi)
|
||||
pI = exp_polar(I*pi/2)
|
||||
mI = exp_polar(-I*pi/2)
|
||||
|
||||
assert Ci(m1*x) == Ci(x) + I*pi
|
||||
assert Ci(m1_*x) == Ci(x) - I*pi
|
||||
assert Ci(pI*x) == Chi(x) + I*pi/2
|
||||
assert Ci(mI*x) == Chi(x) - I*pi/2
|
||||
assert Chi(m1*x) == Chi(x) + I*pi
|
||||
assert Chi(m1_*x) == Chi(x) - I*pi
|
||||
assert Chi(pI*x) == Ci(x) + I*pi/2
|
||||
assert Chi(mI*x) == Ci(x) - I*pi/2
|
||||
assert Ci(exp_polar(2*I*pi)*x) == Ci(x) + 2*I*pi
|
||||
assert Chi(exp_polar(-2*I*pi)*x) == Chi(x) - 2*I*pi
|
||||
assert Chi(exp_polar(2*I*pi)*x) == Chi(x) + 2*I*pi
|
||||
assert Ci(exp_polar(-2*I*pi)*x) == Ci(x) - 2*I*pi
|
||||
|
||||
assert Ci(oo) is S.Zero
|
||||
assert Ci(-oo) == I*pi
|
||||
assert Chi(oo) is oo
|
||||
assert Chi(-oo) is oo
|
||||
|
||||
assert mytd(Ci(x), cos(x)/x, x)
|
||||
assert mytd(Chi(x), cosh(x)/x, x)
|
||||
|
||||
assert mytn(Ci(x), Ci(x).rewrite(Ei),
|
||||
Ei(x*exp_polar(-I*pi/2))/2 + Ei(x*exp_polar(I*pi/2))/2, x)
|
||||
assert mytn(Chi(x), Chi(x).rewrite(Ei),
|
||||
Ei(x)/2 + Ei(x*exp_polar(I*pi))/2 - I*pi/2, x)
|
||||
|
||||
assert tn_arg(Ci)
|
||||
assert tn_arg(Chi)
|
||||
|
||||
assert Ci(x).nseries(x, n=4) == \
|
||||
EulerGamma + log(x) - x**2/4 + O(x**4)
|
||||
assert Chi(x).nseries(x, n=4) == \
|
||||
EulerGamma + log(x) + x**2/4 + O(x**4)
|
||||
|
||||
assert Ci(x).series(x, oo) == -cos(x)*(-6/x**4 + x**(-2) + O(x**(-6), (x, oo))) + \
|
||||
sin(x)*(24/x**5 - 2/x**3 + 1/x + O(x**(-6), (x, oo)))
|
||||
|
||||
assert Ci(x).series(x, -oo) == -cos(x)*(-6/x**4 + x**(-2) + O(x**(-6), (x, -oo))) + \
|
||||
sin(x)*(24/x**5 - 2/x**3 + 1/x + O(x**(-6), (x, -oo))) + I*pi
|
||||
|
||||
assert limit(log(x) - Ci(2*x), x, 0) == -log(2) - EulerGamma
|
||||
assert Ci(x).rewrite(uppergamma) == -expint(1, x*exp_polar(-I*pi/2))/2 -\
|
||||
expint(1, x*exp_polar(I*pi/2))/2
|
||||
assert Ci(x).rewrite(expint) == -expint(1, x*exp_polar(-I*pi/2))/2 -\
|
||||
expint(1, x*exp_polar(I*pi/2))/2
|
||||
raises(ArgumentIndexError, lambda: Ci(x).fdiff(2))
|
||||
|
||||
|
||||
def test_fresnel():
|
||||
assert fresnels(0) is S.Zero
|
||||
assert fresnels(oo) is S.Half
|
||||
assert fresnels(-oo) == Rational(-1, 2)
|
||||
assert fresnels(I*oo) == -I*S.Half
|
||||
|
||||
assert unchanged(fresnels, z)
|
||||
assert fresnels(-z) == -fresnels(z)
|
||||
assert fresnels(I*z) == -I*fresnels(z)
|
||||
assert fresnels(-I*z) == I*fresnels(z)
|
||||
|
||||
assert conjugate(fresnels(z)) == fresnels(conjugate(z))
|
||||
|
||||
assert fresnels(z).diff(z) == sin(pi*z**2/2)
|
||||
|
||||
assert fresnels(z).rewrite(erf) == (S.One + I)/4 * (
|
||||
erf((S.One + I)/2*sqrt(pi)*z) - I*erf((S.One - I)/2*sqrt(pi)*z))
|
||||
|
||||
assert fresnels(z).rewrite(hyper) == \
|
||||
pi*z**3/6 * hyper([Rational(3, 4)], [Rational(3, 2), Rational(7, 4)], -pi**2*z**4/16)
|
||||
|
||||
assert fresnels(z).series(z, n=15) == \
|
||||
pi*z**3/6 - pi**3*z**7/336 + pi**5*z**11/42240 + O(z**15)
|
||||
|
||||
assert fresnels(w).is_extended_real is True
|
||||
assert fresnels(w).is_finite is True
|
||||
|
||||
assert fresnels(z).is_extended_real is None
|
||||
assert fresnels(z).is_finite is None
|
||||
|
||||
assert fresnels(z).as_real_imag() == (fresnels(re(z) - I*im(z))/2 +
|
||||
fresnels(re(z) + I*im(z))/2,
|
||||
-I*(-fresnels(re(z) - I*im(z)) + fresnels(re(z) + I*im(z)))/2)
|
||||
|
||||
assert fresnels(z).as_real_imag(deep=False) == (fresnels(re(z) - I*im(z))/2 +
|
||||
fresnels(re(z) + I*im(z))/2,
|
||||
-I*(-fresnels(re(z) - I*im(z)) + fresnels(re(z) + I*im(z)))/2)
|
||||
|
||||
assert fresnels(w).as_real_imag() == (fresnels(w), 0)
|
||||
assert fresnels(w).as_real_imag(deep=True) == (fresnels(w), 0)
|
||||
|
||||
assert fresnels(2 + 3*I).as_real_imag() == (
|
||||
fresnels(2 + 3*I)/2 + fresnels(2 - 3*I)/2,
|
||||
-I*(fresnels(2 + 3*I) - fresnels(2 - 3*I))/2
|
||||
)
|
||||
|
||||
assert expand_func(integrate(fresnels(z), z)) == \
|
||||
z*fresnels(z) + cos(pi*z**2/2)/pi
|
||||
|
||||
assert fresnels(z).rewrite(meijerg) == sqrt(2)*pi*z**Rational(9, 4) * \
|
||||
meijerg(((), (1,)), ((Rational(3, 4),),
|
||||
(Rational(1, 4), 0)), -pi**2*z**4/16)/(2*(-z)**Rational(3, 4)*(z**2)**Rational(3, 4))
|
||||
|
||||
assert fresnelc(0) is S.Zero
|
||||
assert fresnelc(oo) == S.Half
|
||||
assert fresnelc(-oo) == Rational(-1, 2)
|
||||
assert fresnelc(I*oo) == I*S.Half
|
||||
|
||||
assert unchanged(fresnelc, z)
|
||||
assert fresnelc(-z) == -fresnelc(z)
|
||||
assert fresnelc(I*z) == I*fresnelc(z)
|
||||
assert fresnelc(-I*z) == -I*fresnelc(z)
|
||||
|
||||
assert conjugate(fresnelc(z)) == fresnelc(conjugate(z))
|
||||
|
||||
assert fresnelc(z).diff(z) == cos(pi*z**2/2)
|
||||
|
||||
assert fresnelc(z).rewrite(erf) == (S.One - I)/4 * (
|
||||
erf((S.One + I)/2*sqrt(pi)*z) + I*erf((S.One - I)/2*sqrt(pi)*z))
|
||||
|
||||
assert fresnelc(z).rewrite(hyper) == \
|
||||
z * hyper([Rational(1, 4)], [S.Half, Rational(5, 4)], -pi**2*z**4/16)
|
||||
|
||||
assert fresnelc(w).is_extended_real is True
|
||||
|
||||
assert fresnelc(z).as_real_imag() == \
|
||||
(fresnelc(re(z) - I*im(z))/2 + fresnelc(re(z) + I*im(z))/2,
|
||||
-I*(-fresnelc(re(z) - I*im(z)) + fresnelc(re(z) + I*im(z)))/2)
|
||||
|
||||
assert fresnelc(z).as_real_imag(deep=False) == \
|
||||
(fresnelc(re(z) - I*im(z))/2 + fresnelc(re(z) + I*im(z))/2,
|
||||
-I*(-fresnelc(re(z) - I*im(z)) + fresnelc(re(z) + I*im(z)))/2)
|
||||
|
||||
assert fresnelc(2 + 3*I).as_real_imag() == (
|
||||
fresnelc(2 - 3*I)/2 + fresnelc(2 + 3*I)/2,
|
||||
-I*(fresnelc(2 + 3*I) - fresnelc(2 - 3*I))/2
|
||||
)
|
||||
|
||||
assert expand_func(integrate(fresnelc(z), z)) == \
|
||||
z*fresnelc(z) - sin(pi*z**2/2)/pi
|
||||
|
||||
assert fresnelc(z).rewrite(meijerg) == sqrt(2)*pi*z**Rational(3, 4) * \
|
||||
meijerg(((), (1,)), ((Rational(1, 4),),
|
||||
(Rational(3, 4), 0)), -pi**2*z**4/16)/(2*(-z)**Rational(1, 4)*(z**2)**Rational(1, 4))
|
||||
|
||||
from sympy.core.random import verify_numerically
|
||||
|
||||
verify_numerically(re(fresnels(z)), fresnels(z).as_real_imag()[0], z)
|
||||
verify_numerically(im(fresnels(z)), fresnels(z).as_real_imag()[1], z)
|
||||
verify_numerically(fresnels(z), fresnels(z).rewrite(hyper), z)
|
||||
verify_numerically(fresnels(z), fresnels(z).rewrite(meijerg), z)
|
||||
|
||||
verify_numerically(re(fresnelc(z)), fresnelc(z).as_real_imag()[0], z)
|
||||
verify_numerically(im(fresnelc(z)), fresnelc(z).as_real_imag()[1], z)
|
||||
verify_numerically(fresnelc(z), fresnelc(z).rewrite(hyper), z)
|
||||
verify_numerically(fresnelc(z), fresnelc(z).rewrite(meijerg), z)
|
||||
|
||||
raises(ArgumentIndexError, lambda: fresnels(z).fdiff(2))
|
||||
raises(ArgumentIndexError, lambda: fresnelc(z).fdiff(2))
|
||||
|
||||
assert fresnels(x).taylor_term(-1, x) is S.Zero
|
||||
assert fresnelc(x).taylor_term(-1, x) is S.Zero
|
||||
assert fresnelc(x).taylor_term(1, x) == -pi**2*x**5/40
|
||||
|
||||
|
||||
def test_fresnel_series():
|
||||
assert fresnelc(z).series(z, n=15) == \
|
||||
z - pi**2*z**5/40 + pi**4*z**9/3456 - pi**6*z**13/599040 + O(z**15)
|
||||
|
||||
# issues 6510, 10102
|
||||
fs = (S.Half - sin(pi*z**2/2)/(pi**2*z**3)
|
||||
+ (-1/(pi*z) + 3/(pi**3*z**5))*cos(pi*z**2/2))
|
||||
fc = (S.Half - cos(pi*z**2/2)/(pi**2*z**3)
|
||||
+ (1/(pi*z) - 3/(pi**3*z**5))*sin(pi*z**2/2))
|
||||
assert fresnels(z).series(z, oo) == fs + O(z**(-6), (z, oo))
|
||||
assert fresnelc(z).series(z, oo) == fc + O(z**(-6), (z, oo))
|
||||
assert (fresnels(z).series(z, -oo) + fs.subs(z, -z)).expand().is_Order
|
||||
assert (fresnelc(z).series(z, -oo) + fc.subs(z, -z)).expand().is_Order
|
||||
assert (fresnels(1/z).series(z) - fs.subs(z, 1/z)).expand().is_Order
|
||||
assert (fresnelc(1/z).series(z) - fc.subs(z, 1/z)).expand().is_Order
|
||||
assert ((2*fresnels(3*z)).series(z, oo) - 2*fs.subs(z, 3*z)).expand().is_Order
|
||||
assert ((3*fresnelc(2*z)).series(z, oo) - 3*fc.subs(z, 2*z)).expand().is_Order
|
||||
|
||||
|
||||
def test_integral_rewrites(): #issues 26134, 26144, 26306
|
||||
assert expint(n, x).rewrite(Integral).dummy_eq(Integral(t**-n * exp(-t*x), (t, 1, oo)))
|
||||
assert Si(x).rewrite(Integral).dummy_eq(Integral(sinc(t), (t, 0, x)))
|
||||
assert Ci(x).rewrite(Integral).dummy_eq(log(x) - Integral((1 - cos(t))/t, (t, 0, x)) + EulerGamma)
|
||||
assert fresnels(x).rewrite(Integral).dummy_eq(Integral(sin(pi*t**2/2), (t, 0, x)))
|
||||
assert fresnelc(x).rewrite(Integral).dummy_eq(Integral(cos(pi*t**2/2), (t, 0, x)))
|
||||
assert Ei(x).rewrite(Integral).dummy_eq(Integral(exp(t)/t, (t, -oo, x)))
|
||||
assert fresnels(x).diff(x) == fresnels(x).rewrite(Integral).diff(x)
|
||||
assert fresnelc(x).diff(x) == fresnelc(x).rewrite(Integral).diff(x)
|
||||
|
|
@ -0,0 +1,741 @@
|
|||
from sympy.core.function import expand_func, Subs
|
||||
from sympy.core import EulerGamma
|
||||
from sympy.core.numbers import (I, Rational, nan, oo, pi, zoo)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, Symbol)
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.combinatorial.numbers import harmonic
|
||||
from sympy.functions.elementary.complexes import (Abs, conjugate, im, re)
|
||||
from sympy.functions.elementary.exponential import (exp, exp_polar, log)
|
||||
from sympy.functions.elementary.hyperbolic import tanh
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin, atan)
|
||||
from sympy.functions.special.error_functions import (Ei, erf, erfc)
|
||||
from sympy.functions.special.gamma_functions import (digamma, gamma, loggamma, lowergamma, multigamma, polygamma, trigamma, uppergamma)
|
||||
from sympy.functions.special.zeta_functions import zeta
|
||||
from sympy.series.order import O
|
||||
|
||||
from sympy.core.expr import unchanged
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.random import (test_derivative_numerically as td,
|
||||
random_complex_number as randcplx,
|
||||
verify_numerically as tn)
|
||||
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
n = Symbol('n', integer=True)
|
||||
w = Symbol('w', real=True)
|
||||
|
||||
def test_gamma():
|
||||
assert gamma(nan) is nan
|
||||
assert gamma(oo) is oo
|
||||
|
||||
assert gamma(-100) is zoo
|
||||
assert gamma(0) is zoo
|
||||
assert gamma(-100.0) is zoo
|
||||
|
||||
assert gamma(1) == 1
|
||||
assert gamma(2) == 1
|
||||
assert gamma(3) == 2
|
||||
|
||||
assert gamma(102) == factorial(101)
|
||||
|
||||
assert gamma(S.Half) == sqrt(pi)
|
||||
|
||||
assert gamma(Rational(3, 2)) == sqrt(pi)*S.Half
|
||||
assert gamma(Rational(5, 2)) == sqrt(pi)*Rational(3, 4)
|
||||
assert gamma(Rational(7, 2)) == sqrt(pi)*Rational(15, 8)
|
||||
|
||||
assert gamma(Rational(-1, 2)) == -2*sqrt(pi)
|
||||
assert gamma(Rational(-3, 2)) == sqrt(pi)*Rational(4, 3)
|
||||
assert gamma(Rational(-5, 2)) == sqrt(pi)*Rational(-8, 15)
|
||||
|
||||
assert gamma(Rational(-15, 2)) == sqrt(pi)*Rational(256, 2027025)
|
||||
|
||||
assert gamma(Rational(
|
||||
-11, 8)).expand(func=True) == Rational(64, 33)*gamma(Rational(5, 8))
|
||||
assert gamma(Rational(
|
||||
-10, 3)).expand(func=True) == Rational(81, 280)*gamma(Rational(2, 3))
|
||||
assert gamma(Rational(
|
||||
14, 3)).expand(func=True) == Rational(880, 81)*gamma(Rational(2, 3))
|
||||
assert gamma(Rational(
|
||||
17, 7)).expand(func=True) == Rational(30, 49)*gamma(Rational(3, 7))
|
||||
assert gamma(Rational(
|
||||
19, 8)).expand(func=True) == Rational(33, 64)*gamma(Rational(3, 8))
|
||||
|
||||
assert gamma(x).diff(x) == gamma(x)*polygamma(0, x)
|
||||
|
||||
assert gamma(x - 1).expand(func=True) == gamma(x)/(x - 1)
|
||||
assert gamma(x + 2).expand(func=True, mul=False) == x*(x + 1)*gamma(x)
|
||||
|
||||
assert conjugate(gamma(x)) == gamma(conjugate(x))
|
||||
|
||||
assert expand_func(gamma(x + Rational(3, 2))) == \
|
||||
(x + S.Half)*gamma(x + S.Half)
|
||||
|
||||
assert expand_func(gamma(x - S.Half)) == \
|
||||
gamma(S.Half + x)/(x - S.Half)
|
||||
|
||||
# Test a bug:
|
||||
assert expand_func(gamma(x + Rational(3, 4))) == gamma(x + Rational(3, 4))
|
||||
|
||||
# XXX: Not sure about these tests. I can fix them by defining e.g.
|
||||
# exp_polar.is_integer but I'm not sure if that makes sense.
|
||||
assert gamma(3*exp_polar(I*pi)/4).is_nonnegative is False
|
||||
assert gamma(3*exp_polar(I*pi)/4).is_extended_nonpositive is True
|
||||
|
||||
y = Symbol('y', nonpositive=True, integer=True)
|
||||
assert gamma(y).is_real == False
|
||||
y = Symbol('y', positive=True, noninteger=True)
|
||||
assert gamma(y).is_real == True
|
||||
|
||||
assert gamma(-1.0, evaluate=False).is_real == False
|
||||
assert gamma(0, evaluate=False).is_real == False
|
||||
assert gamma(-2, evaluate=False).is_real == False
|
||||
|
||||
|
||||
def test_gamma_rewrite():
|
||||
assert gamma(n).rewrite(factorial) == factorial(n - 1)
|
||||
|
||||
|
||||
def test_gamma_series():
|
||||
assert gamma(x + 1).series(x, 0, 3) == \
|
||||
1 - EulerGamma*x + x**2*(EulerGamma**2/2 + pi**2/12) + O(x**3)
|
||||
assert gamma(x).series(x, -1, 3) == \
|
||||
-1/(x + 1) + EulerGamma - 1 + (x + 1)*(-1 - pi**2/12 - EulerGamma**2/2 + \
|
||||
EulerGamma) + (x + 1)**2*(-1 - pi**2/12 - EulerGamma**2/2 + EulerGamma**3/6 - \
|
||||
polygamma(2, 1)/6 + EulerGamma*pi**2/12 + EulerGamma) + O((x + 1)**3, (x, -1))
|
||||
|
||||
|
||||
def tn_branch(s, func):
|
||||
from sympy.core.random import uniform
|
||||
c = uniform(1, 5)
|
||||
expr = func(s, c*exp_polar(I*pi)) - func(s, c*exp_polar(-I*pi))
|
||||
eps = 1e-15
|
||||
expr2 = func(s + eps, -c + eps*I) - func(s + eps, -c - eps*I)
|
||||
return abs(expr.n() - expr2.n()).n() < 1e-10
|
||||
|
||||
|
||||
def test_lowergamma():
|
||||
from sympy.functions.special.error_functions import expint
|
||||
from sympy.functions.special.hyper import meijerg
|
||||
assert lowergamma(x, 0) == 0
|
||||
assert lowergamma(x, y).diff(y) == y**(x - 1)*exp(-y)
|
||||
assert td(lowergamma(randcplx(), y), y)
|
||||
assert td(lowergamma(x, randcplx()), x)
|
||||
assert lowergamma(x, y).diff(x) == \
|
||||
gamma(x)*digamma(x) - uppergamma(x, y)*log(y) \
|
||||
- meijerg([], [1, 1], [0, 0, x], [], y)
|
||||
|
||||
assert lowergamma(S.Half, x) == sqrt(pi)*erf(sqrt(x))
|
||||
assert not lowergamma(S.Half - 3, x).has(lowergamma)
|
||||
assert not lowergamma(S.Half + 3, x).has(lowergamma)
|
||||
assert lowergamma(S.Half, x, evaluate=False).has(lowergamma)
|
||||
assert tn(lowergamma(S.Half + 3, x, evaluate=False),
|
||||
lowergamma(S.Half + 3, x), x)
|
||||
assert tn(lowergamma(S.Half - 3, x, evaluate=False),
|
||||
lowergamma(S.Half - 3, x), x)
|
||||
|
||||
assert tn_branch(-3, lowergamma)
|
||||
assert tn_branch(-4, lowergamma)
|
||||
assert tn_branch(Rational(1, 3), lowergamma)
|
||||
assert tn_branch(pi, lowergamma)
|
||||
assert lowergamma(3, exp_polar(4*pi*I)*x) == lowergamma(3, x)
|
||||
assert lowergamma(y, exp_polar(5*pi*I)*x) == \
|
||||
exp(4*I*pi*y)*lowergamma(y, x*exp_polar(pi*I))
|
||||
assert lowergamma(-2, exp_polar(5*pi*I)*x) == \
|
||||
lowergamma(-2, x*exp_polar(I*pi)) + 2*pi*I
|
||||
|
||||
assert conjugate(lowergamma(x, y)) == lowergamma(conjugate(x), conjugate(y))
|
||||
assert conjugate(lowergamma(x, 0)) == 0
|
||||
assert unchanged(conjugate, lowergamma(x, -oo))
|
||||
|
||||
assert lowergamma(0, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(S(1)/3, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(1, x, evaluate=False)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(x, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(x + 1, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(1/x, x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(0, x + 1)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(S(1)/3, x + 1)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(1, x + 1, evaluate=False)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(x, x + 1)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(x + 1, x + 1)._eval_is_meromorphic(x, 0) == True
|
||||
assert lowergamma(1/x, x + 1)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(0, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(S(1)/3, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(1, 1/x, evaluate=False)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(x, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(x + 1, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
assert lowergamma(1/x, 1/x)._eval_is_meromorphic(x, 0) == False
|
||||
|
||||
assert lowergamma(x, 2).series(x, oo, 3) == \
|
||||
2**x*(1 + 2/(x + 1))*exp(-2)/x + O(exp(x*log(2))/x**3, (x, oo))
|
||||
|
||||
assert lowergamma(
|
||||
x, y).rewrite(expint) == -y**x*expint(-x + 1, y) + gamma(x)
|
||||
k = Symbol('k', integer=True)
|
||||
assert lowergamma(
|
||||
k, y).rewrite(expint) == -y**k*expint(-k + 1, y) + gamma(k)
|
||||
k = Symbol('k', integer=True, positive=False)
|
||||
assert lowergamma(k, y).rewrite(expint) == lowergamma(k, y)
|
||||
assert lowergamma(x, y).rewrite(uppergamma) == gamma(x) - uppergamma(x, y)
|
||||
|
||||
assert lowergamma(70, 6) == factorial(69) - 69035724522603011058660187038367026272747334489677105069435923032634389419656200387949342530805432320 * exp(-6)
|
||||
assert (lowergamma(S(77) / 2, 6) - lowergamma(S(77) / 2, 6, evaluate=False)).evalf() < 1e-16
|
||||
assert (lowergamma(-S(77) / 2, 6) - lowergamma(-S(77) / 2, 6, evaluate=False)).evalf() < 1e-16
|
||||
|
||||
|
||||
def test_uppergamma():
|
||||
from sympy.functions.special.error_functions import expint
|
||||
from sympy.functions.special.hyper import meijerg
|
||||
assert uppergamma(4, 0) == 6
|
||||
assert uppergamma(x, y).diff(y) == -y**(x - 1)*exp(-y)
|
||||
assert td(uppergamma(randcplx(), y), y)
|
||||
assert uppergamma(x, y).diff(x) == \
|
||||
uppergamma(x, y)*log(y) + meijerg([], [1, 1], [0, 0, x], [], y)
|
||||
assert td(uppergamma(x, randcplx()), x)
|
||||
|
||||
p = Symbol('p', positive=True)
|
||||
assert uppergamma(0, p) == -Ei(-p)
|
||||
assert uppergamma(p, 0) == gamma(p)
|
||||
assert uppergamma(S.Half, x) == sqrt(pi)*erfc(sqrt(x))
|
||||
assert not uppergamma(S.Half - 3, x).has(uppergamma)
|
||||
assert not uppergamma(S.Half + 3, x).has(uppergamma)
|
||||
assert uppergamma(S.Half, x, evaluate=False).has(uppergamma)
|
||||
assert tn(uppergamma(S.Half + 3, x, evaluate=False),
|
||||
uppergamma(S.Half + 3, x), x)
|
||||
assert tn(uppergamma(S.Half - 3, x, evaluate=False),
|
||||
uppergamma(S.Half - 3, x), x)
|
||||
|
||||
assert unchanged(uppergamma, x, -oo)
|
||||
assert unchanged(uppergamma, x, 0)
|
||||
|
||||
assert tn_branch(-3, uppergamma)
|
||||
assert tn_branch(-4, uppergamma)
|
||||
assert tn_branch(Rational(1, 3), uppergamma)
|
||||
assert tn_branch(pi, uppergamma)
|
||||
assert uppergamma(3, exp_polar(4*pi*I)*x) == uppergamma(3, x)
|
||||
assert uppergamma(y, exp_polar(5*pi*I)*x) == \
|
||||
exp(4*I*pi*y)*uppergamma(y, x*exp_polar(pi*I)) + \
|
||||
gamma(y)*(1 - exp(4*pi*I*y))
|
||||
assert uppergamma(-2, exp_polar(5*pi*I)*x) == \
|
||||
uppergamma(-2, x*exp_polar(I*pi)) - 2*pi*I
|
||||
|
||||
assert uppergamma(-2, x) == expint(3, x)/x**2
|
||||
|
||||
assert conjugate(uppergamma(x, y)) == uppergamma(conjugate(x), conjugate(y))
|
||||
assert unchanged(conjugate, uppergamma(x, -oo))
|
||||
|
||||
assert uppergamma(x, y).rewrite(expint) == y**x*expint(-x + 1, y)
|
||||
assert uppergamma(x, y).rewrite(lowergamma) == gamma(x) - lowergamma(x, y)
|
||||
|
||||
assert uppergamma(70, 6) == 69035724522603011058660187038367026272747334489677105069435923032634389419656200387949342530805432320*exp(-6)
|
||||
assert (uppergamma(S(77) / 2, 6) - uppergamma(S(77) / 2, 6, evaluate=False)).evalf() < 1e-16
|
||||
assert (uppergamma(-S(77) / 2, 6) - uppergamma(-S(77) / 2, 6, evaluate=False)).evalf() < 1e-16
|
||||
|
||||
|
||||
def test_polygamma():
|
||||
assert polygamma(n, nan) is nan
|
||||
|
||||
assert polygamma(0, oo) is oo
|
||||
assert polygamma(0, -oo) is oo
|
||||
assert polygamma(0, I*oo) is oo
|
||||
assert polygamma(0, -I*oo) is oo
|
||||
assert polygamma(1, oo) == 0
|
||||
assert polygamma(5, oo) == 0
|
||||
|
||||
assert polygamma(0, -9) is zoo
|
||||
|
||||
assert polygamma(0, -9) is zoo
|
||||
assert polygamma(0, -1) is zoo
|
||||
assert polygamma(Rational(3, 2), -1) is zoo
|
||||
|
||||
assert polygamma(0, 0) is zoo
|
||||
|
||||
assert polygamma(0, 1) == -EulerGamma
|
||||
assert polygamma(0, 7) == Rational(49, 20) - EulerGamma
|
||||
|
||||
assert polygamma(1, 1) == pi**2/6
|
||||
assert polygamma(1, 2) == pi**2/6 - 1
|
||||
assert polygamma(1, 3) == pi**2/6 - Rational(5, 4)
|
||||
assert polygamma(3, 1) == pi**4 / 15
|
||||
assert polygamma(3, 5) == 6*(Rational(-22369, 20736) + pi**4/90)
|
||||
assert polygamma(5, 1) == 8 * pi**6 / 63
|
||||
|
||||
assert polygamma(1, S.Half) == pi**2 / 2
|
||||
assert polygamma(2, S.Half) == -14*zeta(3)
|
||||
assert polygamma(11, S.Half) == 176896*pi**12
|
||||
|
||||
def t(m, n):
|
||||
x = S(m)/n
|
||||
r = polygamma(0, x)
|
||||
if r.has(polygamma):
|
||||
return False
|
||||
return abs(polygamma(0, x.n()).n() - r.n()).n() < 1e-10
|
||||
assert t(1, 2)
|
||||
assert t(3, 2)
|
||||
assert t(-1, 2)
|
||||
assert t(1, 4)
|
||||
assert t(-3, 4)
|
||||
assert t(1, 3)
|
||||
assert t(4, 3)
|
||||
assert t(3, 4)
|
||||
assert t(2, 3)
|
||||
assert t(123, 5)
|
||||
|
||||
assert polygamma(0, x).rewrite(zeta) == polygamma(0, x)
|
||||
assert polygamma(1, x).rewrite(zeta) == zeta(2, x)
|
||||
assert polygamma(2, x).rewrite(zeta) == -2*zeta(3, x)
|
||||
assert polygamma(I, 2).rewrite(zeta) == polygamma(I, 2)
|
||||
n1 = Symbol('n1')
|
||||
n2 = Symbol('n2', real=True)
|
||||
n3 = Symbol('n3', integer=True)
|
||||
n4 = Symbol('n4', positive=True)
|
||||
n5 = Symbol('n5', positive=True, integer=True)
|
||||
assert polygamma(n1, x).rewrite(zeta) == polygamma(n1, x)
|
||||
assert polygamma(n2, x).rewrite(zeta) == polygamma(n2, x)
|
||||
assert polygamma(n3, x).rewrite(zeta) == polygamma(n3, x)
|
||||
assert polygamma(n4, x).rewrite(zeta) == polygamma(n4, x)
|
||||
assert polygamma(n5, x).rewrite(zeta) == (-1)**(n5 + 1) * factorial(n5) * zeta(n5 + 1, x)
|
||||
|
||||
assert polygamma(3, 7*x).diff(x) == 7*polygamma(4, 7*x)
|
||||
|
||||
assert polygamma(0, x).rewrite(harmonic) == harmonic(x - 1) - EulerGamma
|
||||
assert polygamma(2, x).rewrite(harmonic) == 2*harmonic(x - 1, 3) - 2*zeta(3)
|
||||
ni = Symbol("n", integer=True)
|
||||
assert polygamma(ni, x).rewrite(harmonic) == (-1)**(ni + 1)*(-harmonic(x - 1, ni + 1)
|
||||
+ zeta(ni + 1))*factorial(ni)
|
||||
|
||||
# Polygamma of non-negative integer order is unbranched:
|
||||
k = Symbol('n', integer=True, nonnegative=True)
|
||||
assert polygamma(k, exp_polar(2*I*pi)*x) == polygamma(k, x)
|
||||
|
||||
# but negative integers are branched!
|
||||
k = Symbol('n', integer=True)
|
||||
assert polygamma(k, exp_polar(2*I*pi)*x).args == (k, exp_polar(2*I*pi)*x)
|
||||
|
||||
# Polygamma of order -1 is loggamma:
|
||||
assert polygamma(-1, x) == loggamma(x) - log(2*pi) / 2
|
||||
|
||||
# But smaller orders are iterated integrals and don't have a special name
|
||||
assert polygamma(-2, x).func is polygamma
|
||||
|
||||
# Test a bug
|
||||
assert polygamma(0, -x).expand(func=True) == polygamma(0, -x)
|
||||
|
||||
assert polygamma(2, 2.5).is_positive == False
|
||||
assert polygamma(2, -2.5).is_positive == False
|
||||
assert polygamma(3, 2.5).is_positive == True
|
||||
assert polygamma(3, -2.5).is_positive is True
|
||||
assert polygamma(-2, -2.5).is_positive is None
|
||||
assert polygamma(-3, -2.5).is_positive is None
|
||||
|
||||
assert polygamma(2, 2.5).is_negative == True
|
||||
assert polygamma(3, 2.5).is_negative == False
|
||||
assert polygamma(3, -2.5).is_negative == False
|
||||
assert polygamma(2, -2.5).is_negative is True
|
||||
assert polygamma(-2, -2.5).is_negative is None
|
||||
assert polygamma(-3, -2.5).is_negative is None
|
||||
|
||||
assert polygamma(I, 2).is_positive is None
|
||||
assert polygamma(I, 3).is_negative is None
|
||||
|
||||
# issue 17350
|
||||
assert (I*polygamma(I, pi)).as_real_imag() == \
|
||||
(-im(polygamma(I, pi)), re(polygamma(I, pi)))
|
||||
assert (tanh(polygamma(I, 1))).rewrite(exp) == \
|
||||
(exp(polygamma(I, 1)) - exp(-polygamma(I, 1)))/(exp(polygamma(I, 1)) + exp(-polygamma(I, 1)))
|
||||
assert (I / polygamma(I, 4)).rewrite(exp) == \
|
||||
I*exp(-I*atan(im(polygamma(I, 4))/re(polygamma(I, 4))))/Abs(polygamma(I, 4))
|
||||
|
||||
# issue 12569
|
||||
assert unchanged(im, polygamma(0, I))
|
||||
assert polygamma(Symbol('a', positive=True), Symbol('b', positive=True)).is_real is True
|
||||
assert polygamma(0, I).is_real is None
|
||||
|
||||
assert str(polygamma(pi, 3).evalf(n=10)) == "0.1169314564"
|
||||
assert str(polygamma(2.3, 1.0).evalf(n=10)) == "-3.003302909"
|
||||
assert str(polygamma(-1, 1).evalf(n=10)) == "-0.9189385332" # not zero
|
||||
assert str(polygamma(I, 1).evalf(n=10)) == "-3.109856569 + 1.89089016*I"
|
||||
assert str(polygamma(1, I).evalf(n=10)) == "-0.5369999034 - 0.7942335428*I"
|
||||
assert str(polygamma(I, I).evalf(n=10)) == "6.332362889 + 45.92828268*I"
|
||||
|
||||
|
||||
def test_polygamma_expand_func():
|
||||
assert polygamma(0, x).expand(func=True) == polygamma(0, x)
|
||||
assert polygamma(0, 2*x).expand(func=True) == \
|
||||
polygamma(0, x)/2 + polygamma(0, S.Half + x)/2 + log(2)
|
||||
assert polygamma(1, 2*x).expand(func=True) == \
|
||||
polygamma(1, x)/4 + polygamma(1, S.Half + x)/4
|
||||
assert polygamma(2, x).expand(func=True) == \
|
||||
polygamma(2, x)
|
||||
assert polygamma(0, -1 + x).expand(func=True) == \
|
||||
polygamma(0, x) - 1/(x - 1)
|
||||
assert polygamma(0, 1 + x).expand(func=True) == \
|
||||
1/x + polygamma(0, x )
|
||||
assert polygamma(0, 2 + x).expand(func=True) == \
|
||||
1/x + 1/(1 + x) + polygamma(0, x)
|
||||
assert polygamma(0, 3 + x).expand(func=True) == \
|
||||
polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x)
|
||||
assert polygamma(0, 4 + x).expand(func=True) == \
|
||||
polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) + 1/(3 + x)
|
||||
assert polygamma(1, 1 + x).expand(func=True) == \
|
||||
polygamma(1, x) - 1/x**2
|
||||
assert polygamma(1, 2 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2
|
||||
assert polygamma(1, 3 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - 1/(2 + x)**2
|
||||
assert polygamma(1, 4 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - \
|
||||
1/(2 + x)**2 - 1/(3 + x)**2
|
||||
assert polygamma(0, x + y).expand(func=True) == \
|
||||
polygamma(0, x + y)
|
||||
assert polygamma(1, x + y).expand(func=True) == \
|
||||
polygamma(1, x + y)
|
||||
assert polygamma(1, 3 + 4*x + y).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, y + 4*x) - 1/(y + 4*x)**2 - \
|
||||
1/(1 + y + 4*x)**2 - 1/(2 + y + 4*x)**2
|
||||
assert polygamma(3, 3 + 4*x + y).expand(func=True, multinomial=False) == \
|
||||
polygamma(3, y + 4*x) - 6/(y + 4*x)**4 - \
|
||||
6/(1 + y + 4*x)**4 - 6/(2 + y + 4*x)**4
|
||||
assert polygamma(3, 4*x + y + 1).expand(func=True, multinomial=False) == \
|
||||
polygamma(3, y + 4*x) - 6/(y + 4*x)**4
|
||||
e = polygamma(3, 4*x + y + Rational(3, 2))
|
||||
assert e.expand(func=True) == e
|
||||
e = polygamma(3, x + y + Rational(3, 4))
|
||||
assert e.expand(func=True, basic=False) == e
|
||||
|
||||
assert polygamma(-1, x, evaluate=False).expand(func=True) == \
|
||||
loggamma(x) - log(pi)/2 - log(2)/2
|
||||
p2 = polygamma(-2, x).expand(func=True) + x**2/2 - x/2 + S(1)/12
|
||||
assert isinstance(p2, Subs)
|
||||
assert p2.point == (-1,)
|
||||
|
||||
|
||||
def test_digamma():
|
||||
assert digamma(nan) == nan
|
||||
|
||||
assert digamma(oo) == oo
|
||||
assert digamma(-oo) == oo
|
||||
assert digamma(I*oo) == oo
|
||||
assert digamma(-I*oo) == oo
|
||||
|
||||
assert digamma(-9) == zoo
|
||||
|
||||
assert digamma(-9) == zoo
|
||||
assert digamma(-1) == zoo
|
||||
|
||||
assert digamma(0) == zoo
|
||||
|
||||
assert digamma(1) == -EulerGamma
|
||||
assert digamma(7) == Rational(49, 20) - EulerGamma
|
||||
|
||||
def t(m, n):
|
||||
x = S(m)/n
|
||||
r = digamma(x)
|
||||
if r.has(digamma):
|
||||
return False
|
||||
return abs(digamma(x.n()).n() - r.n()).n() < 1e-10
|
||||
assert t(1, 2)
|
||||
assert t(3, 2)
|
||||
assert t(-1, 2)
|
||||
assert t(1, 4)
|
||||
assert t(-3, 4)
|
||||
assert t(1, 3)
|
||||
assert t(4, 3)
|
||||
assert t(3, 4)
|
||||
assert t(2, 3)
|
||||
assert t(123, 5)
|
||||
|
||||
assert digamma(x).rewrite(zeta) == polygamma(0, x)
|
||||
|
||||
assert digamma(x).rewrite(harmonic) == harmonic(x - 1) - EulerGamma
|
||||
|
||||
assert digamma(I).is_real is None
|
||||
|
||||
assert digamma(x,evaluate=False).fdiff() == polygamma(1, x)
|
||||
|
||||
assert digamma(x,evaluate=False).is_real is None
|
||||
|
||||
assert digamma(x,evaluate=False).is_positive is None
|
||||
|
||||
assert digamma(x,evaluate=False).is_negative is None
|
||||
|
||||
assert digamma(x,evaluate=False).rewrite(polygamma) == polygamma(0, x)
|
||||
|
||||
|
||||
def test_digamma_expand_func():
|
||||
assert digamma(x).expand(func=True) == polygamma(0, x)
|
||||
assert digamma(2*x).expand(func=True) == \
|
||||
polygamma(0, x)/2 + polygamma(0, Rational(1, 2) + x)/2 + log(2)
|
||||
assert digamma(-1 + x).expand(func=True) == \
|
||||
polygamma(0, x) - 1/(x - 1)
|
||||
assert digamma(1 + x).expand(func=True) == \
|
||||
1/x + polygamma(0, x )
|
||||
assert digamma(2 + x).expand(func=True) == \
|
||||
1/x + 1/(1 + x) + polygamma(0, x)
|
||||
assert digamma(3 + x).expand(func=True) == \
|
||||
polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x)
|
||||
assert digamma(4 + x).expand(func=True) == \
|
||||
polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) + 1/(3 + x)
|
||||
assert digamma(x + y).expand(func=True) == \
|
||||
polygamma(0, x + y)
|
||||
|
||||
def test_trigamma():
|
||||
assert trigamma(nan) == nan
|
||||
|
||||
assert trigamma(oo) == 0
|
||||
|
||||
assert trigamma(1) == pi**2/6
|
||||
assert trigamma(2) == pi**2/6 - 1
|
||||
assert trigamma(3) == pi**2/6 - Rational(5, 4)
|
||||
|
||||
assert trigamma(x, evaluate=False).rewrite(zeta) == zeta(2, x)
|
||||
assert trigamma(x, evaluate=False).rewrite(harmonic) == \
|
||||
trigamma(x).rewrite(polygamma).rewrite(harmonic)
|
||||
|
||||
assert trigamma(x,evaluate=False).fdiff() == polygamma(2, x)
|
||||
|
||||
assert trigamma(x,evaluate=False).is_real is None
|
||||
|
||||
assert trigamma(x,evaluate=False).is_positive is None
|
||||
|
||||
assert trigamma(x,evaluate=False).is_negative is None
|
||||
|
||||
assert trigamma(x,evaluate=False).rewrite(polygamma) == polygamma(1, x)
|
||||
|
||||
def test_trigamma_expand_func():
|
||||
assert trigamma(2*x).expand(func=True) == \
|
||||
polygamma(1, x)/4 + polygamma(1, Rational(1, 2) + x)/4
|
||||
assert trigamma(1 + x).expand(func=True) == \
|
||||
polygamma(1, x) - 1/x**2
|
||||
assert trigamma(2 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2
|
||||
assert trigamma(3 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - 1/(2 + x)**2
|
||||
assert trigamma(4 + x).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - \
|
||||
1/(2 + x)**2 - 1/(3 + x)**2
|
||||
assert trigamma(x + y).expand(func=True) == \
|
||||
polygamma(1, x + y)
|
||||
assert trigamma(3 + 4*x + y).expand(func=True, multinomial=False) == \
|
||||
polygamma(1, y + 4*x) - 1/(y + 4*x)**2 - \
|
||||
1/(1 + y + 4*x)**2 - 1/(2 + y + 4*x)**2
|
||||
|
||||
def test_loggamma():
|
||||
raises(TypeError, lambda: loggamma(2, 3))
|
||||
raises(ArgumentIndexError, lambda: loggamma(x).fdiff(2))
|
||||
|
||||
assert loggamma(-1) is oo
|
||||
assert loggamma(-2) is oo
|
||||
assert loggamma(0) is oo
|
||||
assert loggamma(1) == 0
|
||||
assert loggamma(2) == 0
|
||||
assert loggamma(3) == log(2)
|
||||
assert loggamma(4) == log(6)
|
||||
|
||||
n = Symbol("n", integer=True, positive=True)
|
||||
assert loggamma(n) == log(gamma(n))
|
||||
assert loggamma(-n) is oo
|
||||
assert loggamma(n/2) == log(2**(-n + 1)*sqrt(pi)*gamma(n)/gamma(n/2 + S.Half))
|
||||
|
||||
assert loggamma(oo) is oo
|
||||
assert loggamma(-oo) is zoo
|
||||
assert loggamma(I*oo) is zoo
|
||||
assert loggamma(-I*oo) is zoo
|
||||
assert loggamma(zoo) is zoo
|
||||
assert loggamma(nan) is nan
|
||||
|
||||
L = loggamma(Rational(16, 3))
|
||||
E = -5*log(3) + loggamma(Rational(1, 3)) + log(4) + log(7) + log(10) + log(13)
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
L = loggamma(Rational(19, 4))
|
||||
E = -4*log(4) + loggamma(Rational(3, 4)) + log(3) + log(7) + log(11) + log(15)
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
L = loggamma(Rational(23, 7))
|
||||
E = -3*log(7) + log(2) + loggamma(Rational(2, 7)) + log(9) + log(16)
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
L = loggamma(Rational(19, 4) - 7)
|
||||
E = -log(9) - log(5) + loggamma(Rational(3, 4)) + 3*log(4) - 3*I*pi
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
L = loggamma(Rational(23, 7) - 6)
|
||||
E = -log(19) - log(12) - log(5) + loggamma(Rational(2, 7)) + 3*log(7) - 3*I*pi
|
||||
assert expand_func(L).doit() == E
|
||||
assert L.n() == E.n()
|
||||
|
||||
assert loggamma(x).diff(x) == polygamma(0, x)
|
||||
s1 = loggamma(1/(x + sin(x)) + cos(x)).nseries(x, n=4)
|
||||
s2 = (-log(2*x) - 1)/(2*x) - log(x/pi)/2 + (4 - log(2*x))*x/24 + O(x**2) + \
|
||||
log(x)*x**2/2
|
||||
assert (s1 - s2).expand(force=True).removeO() == 0
|
||||
s1 = loggamma(1/x).series(x)
|
||||
s2 = (1/x - S.Half)*log(1/x) - 1/x + log(2*pi)/2 + \
|
||||
x/12 - x**3/360 + x**5/1260 + O(x**7)
|
||||
assert ((s1 - s2).expand(force=True)).removeO() == 0
|
||||
|
||||
assert loggamma(x).rewrite('intractable') == log(gamma(x))
|
||||
|
||||
s1 = loggamma(x).series(x).cancel()
|
||||
assert s1 == -log(x) - EulerGamma*x + pi**2*x**2/12 + x**3*polygamma(2, 1)/6 + \
|
||||
pi**4*x**4/360 + x**5*polygamma(4, 1)/120 + O(x**6)
|
||||
assert s1 == loggamma(x).rewrite('intractable').series(x).cancel()
|
||||
|
||||
assert conjugate(loggamma(x)) == loggamma(conjugate(x))
|
||||
assert conjugate(loggamma(0)) is oo
|
||||
assert conjugate(loggamma(1)) == loggamma(conjugate(1))
|
||||
assert conjugate(loggamma(-oo)) == conjugate(zoo)
|
||||
|
||||
assert loggamma(Symbol('v', positive=True)).is_real is True
|
||||
assert loggamma(Symbol('v', zero=True)).is_real is False
|
||||
assert loggamma(Symbol('v', negative=True)).is_real is False
|
||||
assert loggamma(Symbol('v', nonpositive=True)).is_real is False
|
||||
assert loggamma(Symbol('v', nonnegative=True)).is_real is None
|
||||
assert loggamma(Symbol('v', imaginary=True)).is_real is None
|
||||
assert loggamma(Symbol('v', real=True)).is_real is None
|
||||
assert loggamma(Symbol('v')).is_real is None
|
||||
|
||||
assert loggamma(S.Half).is_real is True
|
||||
assert loggamma(0).is_real is False
|
||||
assert loggamma(Rational(-1, 2)).is_real is False
|
||||
assert loggamma(I).is_real is None
|
||||
assert loggamma(2 + 3*I).is_real is None
|
||||
|
||||
def tN(N, M):
|
||||
assert loggamma(1/x)._eval_nseries(x, n=N).getn() == M
|
||||
tN(0, 0)
|
||||
tN(1, 1)
|
||||
tN(2, 2)
|
||||
tN(3, 3)
|
||||
tN(4, 4)
|
||||
tN(5, 5)
|
||||
|
||||
|
||||
def test_polygamma_expansion():
|
||||
# A. & S., pa. 259 and 260
|
||||
assert polygamma(0, 1/x).nseries(x, n=3) == \
|
||||
-log(x) - x/2 - x**2/12 + O(x**3)
|
||||
assert polygamma(1, 1/x).series(x, n=5) == \
|
||||
x + x**2/2 + x**3/6 + O(x**5)
|
||||
assert polygamma(3, 1/x).nseries(x, n=11) == \
|
||||
2*x**3 + 3*x**4 + 2*x**5 - x**7 + 4*x**9/3 + O(x**11)
|
||||
|
||||
|
||||
def test_polygamma_leading_term():
|
||||
expr = -log(1/x) + polygamma(0, 1 + 1/x) + S.EulerGamma
|
||||
assert expr.as_leading_term(x, logx=-y) == S.EulerGamma
|
||||
|
||||
|
||||
def test_issue_8657():
|
||||
n = Symbol('n', negative=True, integer=True)
|
||||
m = Symbol('m', integer=True)
|
||||
o = Symbol('o', positive=True)
|
||||
p = Symbol('p', negative=True, integer=False)
|
||||
assert gamma(n).is_real is False
|
||||
assert gamma(m).is_real is None
|
||||
assert gamma(o).is_real is True
|
||||
assert gamma(p).is_real is True
|
||||
assert gamma(w).is_real is None
|
||||
|
||||
|
||||
def test_issue_8524():
|
||||
x = Symbol('x', positive=True)
|
||||
y = Symbol('y', negative=True)
|
||||
z = Symbol('z', positive=False)
|
||||
p = Symbol('p', negative=False)
|
||||
q = Symbol('q', integer=True)
|
||||
r = Symbol('r', integer=False)
|
||||
e = Symbol('e', even=True, negative=True)
|
||||
assert gamma(x).is_positive is True
|
||||
assert gamma(y).is_positive is None
|
||||
assert gamma(z).is_positive is None
|
||||
assert gamma(p).is_positive is None
|
||||
assert gamma(q).is_positive is None
|
||||
assert gamma(r).is_positive is None
|
||||
assert gamma(e + S.Half).is_positive is True
|
||||
assert gamma(e - S.Half).is_positive is False
|
||||
|
||||
def test_issue_14450():
|
||||
assert uppergamma(Rational(3, 8), x).evalf() == uppergamma(Rational(3, 8), x)
|
||||
assert lowergamma(x, Rational(3, 8)).evalf() == lowergamma(x, Rational(3, 8))
|
||||
# some values from Wolfram Alpha for comparison
|
||||
assert abs(uppergamma(Rational(3, 8), 2).evalf() - 0.07105675881) < 1e-9
|
||||
assert abs(lowergamma(Rational(3, 8), 2).evalf() - 2.2993794256) < 1e-9
|
||||
|
||||
def test_issue_14528():
|
||||
k = Symbol('k', integer=True, nonpositive=True)
|
||||
assert isinstance(gamma(k), gamma)
|
||||
|
||||
def test_multigamma():
|
||||
from sympy.concrete.products import Product
|
||||
p = Symbol('p')
|
||||
_k = Dummy('_k')
|
||||
|
||||
assert multigamma(x, p).dummy_eq(pi**(p*(p - 1)/4)*\
|
||||
Product(gamma(x + (1 - _k)/2), (_k, 1, p)))
|
||||
|
||||
assert conjugate(multigamma(x, p)).dummy_eq(pi**((conjugate(p) - 1)*\
|
||||
conjugate(p)/4)*Product(gamma(conjugate(x) + (1-conjugate(_k))/2), (_k, 1, p)))
|
||||
assert conjugate(multigamma(x, 1)) == gamma(conjugate(x))
|
||||
|
||||
p = Symbol('p', positive=True)
|
||||
assert conjugate(multigamma(x, p)).dummy_eq(pi**((p - 1)*p/4)*\
|
||||
Product(gamma(conjugate(x) + (1-conjugate(_k))/2), (_k, 1, p)))
|
||||
|
||||
assert multigamma(nan, 1) is nan
|
||||
assert multigamma(oo, 1).doit() is oo
|
||||
|
||||
assert multigamma(1, 1) == 1
|
||||
assert multigamma(2, 1) == 1
|
||||
assert multigamma(3, 1) == 2
|
||||
|
||||
assert multigamma(102, 1) == factorial(101)
|
||||
assert multigamma(S.Half, 1) == sqrt(pi)
|
||||
|
||||
assert multigamma(1, 2) == pi
|
||||
assert multigamma(2, 2) == pi/2
|
||||
|
||||
assert multigamma(1, 3) is zoo
|
||||
assert multigamma(2, 3) == pi**2/2
|
||||
assert multigamma(3, 3) == 3*pi**2/2
|
||||
|
||||
assert multigamma(x, 1).diff(x) == gamma(x)*polygamma(0, x)
|
||||
assert multigamma(x, 2).diff(x) == sqrt(pi)*gamma(x)*gamma(x - S.Half)*\
|
||||
polygamma(0, x) + sqrt(pi)*gamma(x)*gamma(x - S.Half)*polygamma(0, x - S.Half)
|
||||
|
||||
assert multigamma(x - 1, 1).expand(func=True) == gamma(x)/(x - 1)
|
||||
assert multigamma(x + 2, 1).expand(func=True, mul=False) == x*(x + 1)*\
|
||||
gamma(x)
|
||||
assert multigamma(x - 1, 2).expand(func=True) == sqrt(pi)*gamma(x)*\
|
||||
gamma(x + S.Half)/(x**3 - 3*x**2 + x*Rational(11, 4) - Rational(3, 4))
|
||||
assert multigamma(x - 1, 3).expand(func=True) == pi**Rational(3, 2)*gamma(x)**2*\
|
||||
gamma(x + S.Half)/(x**5 - 6*x**4 + 55*x**3/4 - 15*x**2 + x*Rational(31, 4) - Rational(3, 2))
|
||||
|
||||
assert multigamma(n, 1).rewrite(factorial) == factorial(n - 1)
|
||||
assert multigamma(n, 2).rewrite(factorial) == sqrt(pi)*\
|
||||
factorial(n - Rational(3, 2))*factorial(n - 1)
|
||||
assert multigamma(n, 3).rewrite(factorial) == pi**Rational(3, 2)*\
|
||||
factorial(n - 2)*factorial(n - Rational(3, 2))*factorial(n - 1)
|
||||
|
||||
assert multigamma(Rational(-1, 2), 3, evaluate=False).is_real == False
|
||||
assert multigamma(S.Half, 3, evaluate=False).is_real == False
|
||||
assert multigamma(0, 1, evaluate=False).is_real == False
|
||||
assert multigamma(1, 3, evaluate=False).is_real == False
|
||||
assert multigamma(-1.0, 3, evaluate=False).is_real == False
|
||||
assert multigamma(0.7, 3, evaluate=False).is_real == True
|
||||
assert multigamma(3, 3, evaluate=False).is_real == True
|
||||
|
||||
def test_gamma_as_leading_term():
|
||||
assert gamma(x).as_leading_term(x) == 1/x
|
||||
assert gamma(2 + x).as_leading_term(x) == S(1)
|
||||
assert gamma(cos(x)).as_leading_term(x) == S(1)
|
||||
assert gamma(sin(x)).as_leading_term(x) == 1/x
|
||||
|
|
@ -0,0 +1,403 @@
|
|||
from sympy.core.containers import Tuple
|
||||
from sympy.core.function import Derivative
|
||||
from sympy.core.numbers import (I, Rational, oo, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.exponential import (exp, log)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import cos
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.functions.special.hyper import (appellf1, hyper, meijerg)
|
||||
from sympy.series.order import O
|
||||
from sympy.abc import x, z, k
|
||||
from sympy.series.limits import limit
|
||||
from sympy.testing.pytest import raises, slow
|
||||
from sympy.core.random import (
|
||||
random_complex_number as randcplx,
|
||||
verify_numerically as tn,
|
||||
test_derivative_numerically as td)
|
||||
|
||||
|
||||
def test_TupleParametersBase():
|
||||
# test that our implementation of the chain rule works
|
||||
p = hyper((), (), z**2)
|
||||
assert p.diff(z) == p*2*z
|
||||
|
||||
|
||||
def test_hyper():
|
||||
raises(TypeError, lambda: hyper(1, 2, z))
|
||||
|
||||
assert hyper((2, 1), (1,), z) == hyper(Tuple(1, 2), Tuple(1), z)
|
||||
assert hyper((2, 1, 2), (1, 2, 1, 3), z) == hyper((2,), (1, 3), z)
|
||||
u = hyper((2, 1, 2), (1, 2, 1, 3), z, evaluate=False)
|
||||
assert u.ap == Tuple(1, 2, 2)
|
||||
assert u.bq == Tuple(1, 1, 2, 3)
|
||||
|
||||
h = hyper((1, 2), (3, 4, 5), z)
|
||||
assert h.ap == Tuple(1, 2)
|
||||
assert h.bq == Tuple(3, 4, 5)
|
||||
assert h.argument == z
|
||||
assert h.is_commutative is True
|
||||
h = hyper((2, 1), (4, 3, 5), z)
|
||||
assert h.ap == Tuple(1, 2)
|
||||
assert h.bq == Tuple(3, 4, 5)
|
||||
assert h.argument == z
|
||||
assert h.is_commutative is True
|
||||
|
||||
# just a few checks to make sure that all arguments go where they should
|
||||
assert tn(hyper(Tuple(), Tuple(), z), exp(z), z)
|
||||
assert tn(z*hyper((1, 1), Tuple(2), -z), log(1 + z), z)
|
||||
|
||||
# differentiation
|
||||
h = hyper(
|
||||
(randcplx(), randcplx(), randcplx()), (randcplx(), randcplx()), z)
|
||||
assert td(h, z)
|
||||
|
||||
a1, a2, b1, b2, b3 = symbols('a1:3, b1:4')
|
||||
assert hyper((a1, a2), (b1, b2, b3), z).diff(z) == \
|
||||
a1*a2/(b1*b2*b3) * hyper((a1 + 1, a2 + 1), (b1 + 1, b2 + 1, b3 + 1), z)
|
||||
|
||||
# differentiation wrt parameters is not supported
|
||||
assert hyper([z], [], z).diff(z) == Derivative(hyper([z], [], z), z)
|
||||
|
||||
# hyper is unbranched wrt parameters
|
||||
from sympy.functions.elementary.complexes import polar_lift
|
||||
assert hyper([polar_lift(z)], [polar_lift(k)], polar_lift(x)) == \
|
||||
hyper([z], [k], polar_lift(x))
|
||||
|
||||
# hyper does not automatically evaluate anyway, but the test is to make
|
||||
# sure that the evaluate keyword is accepted
|
||||
assert hyper((1, 2), (1,), z, evaluate=False).func is hyper
|
||||
|
||||
|
||||
def test_expand_func():
|
||||
# evaluation at 1 of Gauss' hypergeometric function:
|
||||
from sympy.abc import a, b, c
|
||||
from sympy.core.function import expand_func
|
||||
a1, b1, c1 = randcplx(), randcplx(), randcplx() + 5
|
||||
assert expand_func(hyper([a, b], [c], 1)) == \
|
||||
gamma(c)*gamma(-a - b + c)/(gamma(-a + c)*gamma(-b + c))
|
||||
assert abs(expand_func(hyper([a1, b1], [c1], 1)).n()
|
||||
- hyper([a1, b1], [c1], 1).n()) < 1e-10
|
||||
|
||||
# hyperexpand wrapper for hyper:
|
||||
assert expand_func(hyper([], [], z)) == exp(z)
|
||||
assert expand_func(hyper([1, 2, 3], [], z)) == hyper([1, 2, 3], [], z)
|
||||
assert expand_func(meijerg([[1, 1], []], [[1], [0]], z)) == log(z + 1)
|
||||
assert expand_func(meijerg([[1, 1], []], [[], []], z)) == \
|
||||
meijerg([[1, 1], []], [[], []], z)
|
||||
|
||||
|
||||
def replace_dummy(expr, sym):
|
||||
from sympy.core.symbol import Dummy
|
||||
dum = expr.atoms(Dummy)
|
||||
if not dum:
|
||||
return expr
|
||||
assert len(dum) == 1
|
||||
return expr.xreplace({dum.pop(): sym})
|
||||
|
||||
|
||||
def test_hyper_rewrite_sum():
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.symbol import Dummy
|
||||
from sympy.functions.combinatorial.factorials import (RisingFactorial, factorial)
|
||||
_k = Dummy("k")
|
||||
assert replace_dummy(hyper((1, 2), (1, 3), x).rewrite(Sum), _k) == \
|
||||
Sum(x**_k / factorial(_k) * RisingFactorial(2, _k) /
|
||||
RisingFactorial(3, _k), (_k, 0, oo))
|
||||
|
||||
assert hyper((1, 2, 3), (-1, 3), z).rewrite(Sum) == \
|
||||
hyper((1, 2, 3), (-1, 3), z)
|
||||
|
||||
|
||||
def test_radius_of_convergence():
|
||||
assert hyper((1, 2), [3], z).radius_of_convergence == 1
|
||||
assert hyper((1, 2), [3, 4], z).radius_of_convergence is oo
|
||||
assert hyper((1, 2, 3), [4], z).radius_of_convergence == 0
|
||||
assert hyper((0, 1, 2), [4], z).radius_of_convergence is oo
|
||||
assert hyper((-1, 1, 2), [-4], z).radius_of_convergence == 0
|
||||
assert hyper((-1, -2, 2), [-1], z).radius_of_convergence is oo
|
||||
assert hyper((-1, 2), [-1, -2], z).radius_of_convergence == 0
|
||||
assert hyper([-1, 1, 3], [-2, 2], z).radius_of_convergence == 1
|
||||
assert hyper([-1, 1], [-2, 2], z).radius_of_convergence is oo
|
||||
assert hyper([-1, 1, 3], [-2], z).radius_of_convergence == 0
|
||||
assert hyper((-1, 2, 3, 4), [], z).radius_of_convergence is oo
|
||||
|
||||
assert hyper([1, 1], [3], 1).convergence_statement == True
|
||||
assert hyper([1, 1], [2], 1).convergence_statement == False
|
||||
assert hyper([1, 1], [2], -1).convergence_statement == True
|
||||
assert hyper([1, 1], [1], -1).convergence_statement == False
|
||||
|
||||
|
||||
def test_meijer():
|
||||
raises(TypeError, lambda: meijerg(1, z))
|
||||
raises(TypeError, lambda: meijerg(((1,), (2,)), (3,), (4,), z))
|
||||
|
||||
assert meijerg(((1, 2), (3,)), ((4,), (5,)), z) == \
|
||||
meijerg(Tuple(1, 2), Tuple(3), Tuple(4), Tuple(5), z)
|
||||
|
||||
g = meijerg((1, 2), (3, 4, 5), (6, 7, 8, 9), (10, 11, 12, 13, 14), z)
|
||||
assert g.an == Tuple(1, 2)
|
||||
assert g.ap == Tuple(1, 2, 3, 4, 5)
|
||||
assert g.aother == Tuple(3, 4, 5)
|
||||
assert g.bm == Tuple(6, 7, 8, 9)
|
||||
assert g.bq == Tuple(6, 7, 8, 9, 10, 11, 12, 13, 14)
|
||||
assert g.bother == Tuple(10, 11, 12, 13, 14)
|
||||
assert g.argument == z
|
||||
assert g.nu == 75
|
||||
assert g.delta == -1
|
||||
assert g.is_commutative is True
|
||||
assert g.is_number is False
|
||||
#issue 13071
|
||||
assert meijerg([[],[]], [[S.Half],[0]], 1).is_number is True
|
||||
|
||||
assert meijerg([1, 2], [3], [4], [5], z).delta == S.Half
|
||||
|
||||
# just a few checks to make sure that all arguments go where they should
|
||||
assert tn(meijerg(Tuple(), Tuple(), Tuple(0), Tuple(), -z), exp(z), z)
|
||||
assert tn(sqrt(pi)*meijerg(Tuple(), Tuple(),
|
||||
Tuple(0), Tuple(S.Half), z**2/4), cos(z), z)
|
||||
assert tn(meijerg(Tuple(1, 1), Tuple(), Tuple(1), Tuple(0), z),
|
||||
log(1 + z), z)
|
||||
|
||||
# test exceptions
|
||||
raises(ValueError, lambda: meijerg(((3, 1), (2,)), ((oo,), (2, 0)), x))
|
||||
raises(ValueError, lambda: meijerg(((3, 1), (2,)), ((1,), (2, 0)), x))
|
||||
|
||||
# differentiation
|
||||
g = meijerg((randcplx(),), (randcplx() + 2*I,), Tuple(),
|
||||
(randcplx(), randcplx()), z)
|
||||
assert td(g, z)
|
||||
|
||||
g = meijerg(Tuple(), (randcplx(),), Tuple(),
|
||||
(randcplx(), randcplx()), z)
|
||||
assert td(g, z)
|
||||
|
||||
g = meijerg(Tuple(), Tuple(), Tuple(randcplx()),
|
||||
Tuple(randcplx(), randcplx()), z)
|
||||
assert td(g, z)
|
||||
|
||||
a1, a2, b1, b2, c1, c2, d1, d2 = symbols('a1:3, b1:3, c1:3, d1:3')
|
||||
assert meijerg((a1, a2), (b1, b2), (c1, c2), (d1, d2), z).diff(z) == \
|
||||
(meijerg((a1 - 1, a2), (b1, b2), (c1, c2), (d1, d2), z)
|
||||
+ (a1 - 1)*meijerg((a1, a2), (b1, b2), (c1, c2), (d1, d2), z))/z
|
||||
|
||||
assert meijerg([z, z], [], [], [], z).diff(z) == \
|
||||
Derivative(meijerg([z, z], [], [], [], z), z)
|
||||
|
||||
# meijerg is unbranched wrt parameters
|
||||
from sympy.functions.elementary.complexes import polar_lift as pl
|
||||
assert meijerg([pl(a1)], [pl(a2)], [pl(b1)], [pl(b2)], pl(z)) == \
|
||||
meijerg([a1], [a2], [b1], [b2], pl(z))
|
||||
|
||||
# integrand
|
||||
from sympy.abc import a, b, c, d, s
|
||||
assert meijerg([a], [b], [c], [d], z).integrand(s) == \
|
||||
z**s*gamma(c - s)*gamma(-a + s + 1)/(gamma(b - s)*gamma(-d + s + 1))
|
||||
|
||||
|
||||
def test_meijerg_derivative():
|
||||
assert meijerg([], [1, 1], [0, 0, x], [], z).diff(x) == \
|
||||
log(z)*meijerg([], [1, 1], [0, 0, x], [], z) \
|
||||
+ 2*meijerg([], [1, 1, 1], [0, 0, x, 0], [], z)
|
||||
|
||||
y = randcplx()
|
||||
a = 5 # mpmath chokes with non-real numbers, and Mod1 with floats
|
||||
assert td(meijerg([x], [], [], [], y), x)
|
||||
assert td(meijerg([x**2], [], [], [], y), x)
|
||||
assert td(meijerg([], [x], [], [], y), x)
|
||||
assert td(meijerg([], [], [x], [], y), x)
|
||||
assert td(meijerg([], [], [], [x], y), x)
|
||||
assert td(meijerg([x], [a], [a + 1], [], y), x)
|
||||
assert td(meijerg([x], [a + 1], [a], [], y), x)
|
||||
assert td(meijerg([x, a], [], [], [a + 1], y), x)
|
||||
assert td(meijerg([x, a + 1], [], [], [a], y), x)
|
||||
b = Rational(3, 2)
|
||||
assert td(meijerg([a + 2], [b], [b - 3, x], [a], y), x)
|
||||
|
||||
|
||||
def test_meijerg_period():
|
||||
assert meijerg([], [1], [0], [], x).get_period() == 2*pi
|
||||
assert meijerg([1], [], [], [0], x).get_period() == 2*pi
|
||||
assert meijerg([], [], [0], [], x).get_period() == 2*pi # exp(x)
|
||||
assert meijerg(
|
||||
[], [], [0], [S.Half], x).get_period() == 2*pi # cos(sqrt(x))
|
||||
assert meijerg(
|
||||
[], [], [S.Half], [0], x).get_period() == 4*pi # sin(sqrt(x))
|
||||
assert meijerg([1, 1], [], [1], [0], x).get_period() is oo # log(1 + x)
|
||||
|
||||
|
||||
def test_hyper_unpolarify():
|
||||
from sympy.functions.elementary.exponential import exp_polar
|
||||
a = exp_polar(2*pi*I)*x
|
||||
b = x
|
||||
assert hyper([], [], a).argument == b
|
||||
assert hyper([0], [], a).argument == a
|
||||
assert hyper([0], [0], a).argument == b
|
||||
assert hyper([0, 1], [0], a).argument == a
|
||||
assert hyper([0, 1], [0], exp_polar(2*pi*I)).argument == 1
|
||||
|
||||
|
||||
@slow
|
||||
def test_hyperrep():
|
||||
from sympy.functions.special.hyper import (HyperRep, HyperRep_atanh,
|
||||
HyperRep_power1, HyperRep_power2, HyperRep_log1, HyperRep_asin1,
|
||||
HyperRep_asin2, HyperRep_sqrts1, HyperRep_sqrts2, HyperRep_log2,
|
||||
HyperRep_cosasin, HyperRep_sinasin)
|
||||
# First test the base class works.
|
||||
from sympy.functions.elementary.exponential import exp_polar
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
a, b, c, d, z = symbols('a b c d z')
|
||||
|
||||
class myrep(HyperRep):
|
||||
@classmethod
|
||||
def _expr_small(cls, x):
|
||||
return a
|
||||
|
||||
@classmethod
|
||||
def _expr_small_minus(cls, x):
|
||||
return b
|
||||
|
||||
@classmethod
|
||||
def _expr_big(cls, x, n):
|
||||
return c*n
|
||||
|
||||
@classmethod
|
||||
def _expr_big_minus(cls, x, n):
|
||||
return d*n
|
||||
assert myrep(z).rewrite('nonrep') == Piecewise((0, abs(z) > 1), (a, True))
|
||||
assert myrep(exp_polar(I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((0, abs(z) > 1), (b, True))
|
||||
assert myrep(exp_polar(2*I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((c, abs(z) > 1), (a, True))
|
||||
assert myrep(exp_polar(3*I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((d, abs(z) > 1), (b, True))
|
||||
assert myrep(exp_polar(4*I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((2*c, abs(z) > 1), (a, True))
|
||||
assert myrep(exp_polar(5*I*pi)*z).rewrite('nonrep') == \
|
||||
Piecewise((2*d, abs(z) > 1), (b, True))
|
||||
assert myrep(z).rewrite('nonrepsmall') == a
|
||||
assert myrep(exp_polar(I*pi)*z).rewrite('nonrepsmall') == b
|
||||
|
||||
def t(func, hyp, z):
|
||||
""" Test that func is a valid representation of hyp. """
|
||||
# First test that func agrees with hyp for small z
|
||||
if not tn(func.rewrite('nonrepsmall'), hyp, z,
|
||||
a=Rational(-1, 2), b=Rational(-1, 2), c=S.Half, d=S.Half):
|
||||
return False
|
||||
# Next check that the two small representations agree.
|
||||
if not tn(
|
||||
func.rewrite('nonrepsmall').subs(
|
||||
z, exp_polar(I*pi)*z).replace(exp_polar, exp),
|
||||
func.subs(z, exp_polar(I*pi)*z).rewrite('nonrepsmall'),
|
||||
z, a=Rational(-1, 2), b=Rational(-1, 2), c=S.Half, d=S.Half):
|
||||
return False
|
||||
# Next check continuity along exp_polar(I*pi)*t
|
||||
expr = func.subs(z, exp_polar(I*pi)*z).rewrite('nonrep')
|
||||
if abs(expr.subs(z, 1 + 1e-15).n() - expr.subs(z, 1 - 1e-15).n()) > 1e-10:
|
||||
return False
|
||||
# Finally check continuity of the big reps.
|
||||
|
||||
def dosubs(func, a, b):
|
||||
rv = func.subs(z, exp_polar(a)*z).rewrite('nonrep')
|
||||
return rv.subs(z, exp_polar(b)*z).replace(exp_polar, exp)
|
||||
for n in [0, 1, 2, 3, 4, -1, -2, -3, -4]:
|
||||
expr1 = dosubs(func, 2*I*pi*n, I*pi/2)
|
||||
expr2 = dosubs(func, 2*I*pi*n + I*pi, -I*pi/2)
|
||||
if not tn(expr1, expr2, z):
|
||||
return False
|
||||
expr1 = dosubs(func, 2*I*pi*(n + 1), -I*pi/2)
|
||||
expr2 = dosubs(func, 2*I*pi*n + I*pi, I*pi/2)
|
||||
if not tn(expr1, expr2, z):
|
||||
return False
|
||||
return True
|
||||
|
||||
# Now test the various representatives.
|
||||
a = Rational(1, 3)
|
||||
assert t(HyperRep_atanh(z), hyper([S.Half, 1], [Rational(3, 2)], z), z)
|
||||
assert t(HyperRep_power1(a, z), hyper([-a], [], z), z)
|
||||
assert t(HyperRep_power2(a, z), hyper([a, a - S.Half], [2*a], z), z)
|
||||
assert t(HyperRep_log1(z), -z*hyper([1, 1], [2], z), z)
|
||||
assert t(HyperRep_asin1(z), hyper([S.Half, S.Half], [Rational(3, 2)], z), z)
|
||||
assert t(HyperRep_asin2(z), hyper([1, 1], [Rational(3, 2)], z), z)
|
||||
assert t(HyperRep_sqrts1(a, z), hyper([-a, S.Half - a], [S.Half], z), z)
|
||||
assert t(HyperRep_sqrts2(a, z),
|
||||
-2*z/(2*a + 1)*hyper([-a - S.Half, -a], [S.Half], z).diff(z), z)
|
||||
assert t(HyperRep_log2(z), -z/4*hyper([Rational(3, 2), 1, 1], [2, 2], z), z)
|
||||
assert t(HyperRep_cosasin(a, z), hyper([-a, a], [S.Half], z), z)
|
||||
assert t(HyperRep_sinasin(a, z), 2*a*z*hyper([1 - a, 1 + a], [Rational(3, 2)], z), z)
|
||||
|
||||
|
||||
@slow
|
||||
def test_meijerg_eval():
|
||||
from sympy.functions.elementary.exponential import exp_polar
|
||||
from sympy.functions.special.bessel import besseli
|
||||
from sympy.abc import l
|
||||
a = randcplx()
|
||||
arg = x*exp_polar(k*pi*I)
|
||||
expr1 = pi*meijerg([[], [(a + 1)/2]], [[a/2], [-a/2, (a + 1)/2]], arg**2/4)
|
||||
expr2 = besseli(a, arg)
|
||||
|
||||
# Test that the two expressions agree for all arguments.
|
||||
for x_ in [0.5, 1.5]:
|
||||
for k_ in [0.0, 0.1, 0.3, 0.5, 0.8, 1, 5.751, 15.3]:
|
||||
assert abs((expr1 - expr2).n(subs={x: x_, k: k_})) < 1e-10
|
||||
assert abs((expr1 - expr2).n(subs={x: x_, k: -k_})) < 1e-10
|
||||
|
||||
# Test continuity independently
|
||||
eps = 1e-13
|
||||
expr2 = expr1.subs(k, l)
|
||||
for x_ in [0.5, 1.5]:
|
||||
for k_ in [0.5, Rational(1, 3), 0.25, 0.75, Rational(2, 3), 1.0, 1.5]:
|
||||
assert abs((expr1 - expr2).n(
|
||||
subs={x: x_, k: k_ + eps, l: k_ - eps})) < 1e-10
|
||||
assert abs((expr1 - expr2).n(
|
||||
subs={x: x_, k: -k_ + eps, l: -k_ - eps})) < 1e-10
|
||||
|
||||
expr = (meijerg(((0.5,), ()), ((0.5, 0, 0.5), ()), exp_polar(-I*pi)/4)
|
||||
+ meijerg(((0.5,), ()), ((0.5, 0, 0.5), ()), exp_polar(I*pi)/4)) \
|
||||
/(2*sqrt(pi))
|
||||
assert (expr - pi/exp(1)).n(chop=True) == 0
|
||||
|
||||
|
||||
def test_limits():
|
||||
k, x = symbols('k, x')
|
||||
assert hyper((1,), (Rational(4, 3), Rational(5, 3)), k**2).series(k) == \
|
||||
1 + 9*k**2/20 + 81*k**4/1120 + O(k**6) # issue 6350
|
||||
|
||||
# https://github.com/sympy/sympy/issues/11465
|
||||
assert limit(1/hyper((1, ), (1, ), x), x, 0) == 1
|
||||
|
||||
|
||||
def test_appellf1():
|
||||
a, b1, b2, c, x, y = symbols('a b1 b2 c x y')
|
||||
assert appellf1(a, b2, b1, c, y, x) == appellf1(a, b1, b2, c, x, y)
|
||||
assert appellf1(a, b1, b1, c, y, x) == appellf1(a, b1, b1, c, x, y)
|
||||
assert appellf1(a, b1, b2, c, S.Zero, S.Zero) is S.One
|
||||
|
||||
f = appellf1(a, b1, b2, c, S.Zero, S.Zero, evaluate=False)
|
||||
assert f.func is appellf1
|
||||
assert f.doit() is S.One
|
||||
|
||||
|
||||
def test_derivative_appellf1():
|
||||
from sympy.core.function import diff
|
||||
a, b1, b2, c, x, y, z = symbols('a b1 b2 c x y z')
|
||||
assert diff(appellf1(a, b1, b2, c, x, y), x) == a*b1*appellf1(a + 1, b2, b1 + 1, c + 1, y, x)/c
|
||||
assert diff(appellf1(a, b1, b2, c, x, y), y) == a*b2*appellf1(a + 1, b1, b2 + 1, c + 1, x, y)/c
|
||||
assert diff(appellf1(a, b1, b2, c, x, y), z) == 0
|
||||
assert diff(appellf1(a, b1, b2, c, x, y), a) == Derivative(appellf1(a, b1, b2, c, x, y), a)
|
||||
|
||||
|
||||
def test_eval_nseries():
|
||||
a1, b1, a2, b2 = symbols('a1 b1 a2 b2')
|
||||
assert hyper((1,2), (1,2,3), x**2)._eval_nseries(x, 7, None) == \
|
||||
1 + x**2/3 + x**4/24 + x**6/360 + O(x**7)
|
||||
assert exp(x)._eval_nseries(x,7,None) == \
|
||||
hyper((a1, b1), (a1, b1), x)._eval_nseries(x, 7, None)
|
||||
assert hyper((a1, a2), (b1, b2), x)._eval_nseries(z, 7, None) ==\
|
||||
hyper((a1, a2), (b1, b2), x) + O(z**7)
|
||||
assert hyper((-S(1)/2, S(1)/2), (1,), 4*x/(x + 1)).nseries(x) == \
|
||||
1 - x + x**2/4 - 3*x**3/4 - 15*x**4/64 - 93*x**5/64 + O(x**6)
|
||||
assert (pi/2*hyper((-S(1)/2, S(1)/2), (1,), 4*x/(x + 1))).nseries(x) == \
|
||||
pi/2 - pi*x/2 + pi*x**2/8 - 3*pi*x**3/8 - 15*pi*x**4/128 - 93*pi*x**5/128 + O(x**6)
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
from sympy.core.function import diff
|
||||
from sympy.functions.elementary.complexes import conjugate
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||||
from sympy.functions.special.mathieu_functions import (mathieuc, mathieucprime, mathieus, mathieusprime)
|
||||
|
||||
from sympy.abc import a, q, z
|
||||
|
||||
|
||||
def test_mathieus():
|
||||
assert isinstance(mathieus(a, q, z), mathieus)
|
||||
assert mathieus(a, 0, z) == sin(sqrt(a)*z)
|
||||
assert conjugate(mathieus(a, q, z)) == mathieus(conjugate(a), conjugate(q), conjugate(z))
|
||||
assert diff(mathieus(a, q, z), z) == mathieusprime(a, q, z)
|
||||
|
||||
def test_mathieuc():
|
||||
assert isinstance(mathieuc(a, q, z), mathieuc)
|
||||
assert mathieuc(a, 0, z) == cos(sqrt(a)*z)
|
||||
assert diff(mathieuc(a, q, z), z) == mathieucprime(a, q, z)
|
||||
|
||||
def test_mathieusprime():
|
||||
assert isinstance(mathieusprime(a, q, z), mathieusprime)
|
||||
assert mathieusprime(a, 0, z) == sqrt(a)*cos(sqrt(a)*z)
|
||||
assert diff(mathieusprime(a, q, z), z) == (-a + 2*q*cos(2*z))*mathieus(a, q, z)
|
||||
|
||||
def test_mathieucprime():
|
||||
assert isinstance(mathieucprime(a, q, z), mathieucprime)
|
||||
assert mathieucprime(a, 0, z) == -sqrt(a)*sin(sqrt(a)*z)
|
||||
assert diff(mathieucprime(a, q, z), z) == (-a + 2*q*cos(2*z))*mathieuc(a, q, z)
|
||||
|
|
@ -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
|
||||
|
|
@ -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))
|
||||
|
|
@ -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)))
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.function import expand_func
|
||||
from sympy.core.numbers import (Float, I, Rational, nan, oo, pi, zoo)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.elementary.complexes import (Abs, polar_lift)
|
||||
from sympy.functions.elementary.exponential import (exp, exp_polar, log)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.special.zeta_functions import (dirichlet_eta, lerchphi, polylog, riemann_xi, stieltjes, zeta)
|
||||
from sympy.series.order import O
|
||||
from sympy.core.function import ArgumentIndexError
|
||||
from sympy.functions.combinatorial.numbers import bernoulli, factorial, genocchi, harmonic
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.random import (test_derivative_numerically as td,
|
||||
random_complex_number as randcplx, verify_numerically)
|
||||
|
||||
x = Symbol('x')
|
||||
a = Symbol('a')
|
||||
b = Symbol('b', negative=True)
|
||||
z = Symbol('z')
|
||||
s = Symbol('s')
|
||||
|
||||
|
||||
def test_zeta_eval():
|
||||
|
||||
assert zeta(nan) is nan
|
||||
assert zeta(x, nan) is nan
|
||||
|
||||
assert zeta(0) == Rational(-1, 2)
|
||||
assert zeta(0, x) == S.Half - x
|
||||
assert zeta(0, b) == S.Half - b
|
||||
|
||||
assert zeta(1) is zoo
|
||||
assert zeta(1, 2) is zoo
|
||||
assert zeta(1, -7) is zoo
|
||||
assert zeta(1, x) is zoo
|
||||
|
||||
assert zeta(2, 1) == pi**2/6
|
||||
assert zeta(3, 1) == zeta(3)
|
||||
|
||||
assert zeta(2) == pi**2/6
|
||||
assert zeta(4) == pi**4/90
|
||||
assert zeta(6) == pi**6/945
|
||||
|
||||
assert zeta(4, 3) == pi**4/90 - Rational(17, 16)
|
||||
assert zeta(7, 4) == zeta(7) - Rational(282251, 279936)
|
||||
assert zeta(S.Half, 2).func == zeta
|
||||
assert expand_func(zeta(S.Half, 2)) == zeta(S.Half) - 1
|
||||
assert zeta(x, 3).func == zeta
|
||||
assert expand_func(zeta(x, 3)) == zeta(x) - 1 - 1/2**x
|
||||
|
||||
assert zeta(2, 0) is nan
|
||||
assert zeta(3, -1) is nan
|
||||
assert zeta(4, -2) is nan
|
||||
|
||||
assert zeta(oo) == 1
|
||||
|
||||
assert zeta(-1) == Rational(-1, 12)
|
||||
assert zeta(-2) == 0
|
||||
assert zeta(-3) == Rational(1, 120)
|
||||
assert zeta(-4) == 0
|
||||
assert zeta(-5) == Rational(-1, 252)
|
||||
|
||||
assert zeta(-1, 3) == Rational(-37, 12)
|
||||
assert zeta(-1, 7) == Rational(-253, 12)
|
||||
assert zeta(-1, -4) == Rational(-121, 12)
|
||||
assert zeta(-1, -9) == Rational(-541, 12)
|
||||
|
||||
assert zeta(-4, 3) == -17
|
||||
assert zeta(-4, -8) == 8772
|
||||
|
||||
assert zeta(0, 1) == Rational(-1, 2)
|
||||
assert zeta(0, -1) == Rational(3, 2)
|
||||
|
||||
assert zeta(0, 2) == Rational(-3, 2)
|
||||
assert zeta(0, -2) == Rational(5, 2)
|
||||
|
||||
assert zeta(
|
||||
3).evalf(20).epsilon_eq(Float("1.2020569031595942854", 20), 1e-19)
|
||||
|
||||
|
||||
def test_zeta_series():
|
||||
assert zeta(x, a).series(a, z, 2) == \
|
||||
zeta(x, z) - x*(a-z)*zeta(x+1, z) + O((a-z)**2, (a, z))
|
||||
|
||||
|
||||
def test_dirichlet_eta_eval():
|
||||
assert dirichlet_eta(0) == S.Half
|
||||
assert dirichlet_eta(-1) == Rational(1, 4)
|
||||
assert dirichlet_eta(1) == log(2)
|
||||
assert dirichlet_eta(1, S.Half).simplify() == pi/2
|
||||
assert dirichlet_eta(1, 2) == 1 - log(2)
|
||||
assert dirichlet_eta(2) == pi**2/12
|
||||
assert dirichlet_eta(4) == pi**4*Rational(7, 720)
|
||||
assert str(dirichlet_eta(I).evalf(n=10)) == '0.5325931818 + 0.2293848577*I'
|
||||
assert str(dirichlet_eta(I, I).evalf(n=10)) == '3.462349253 + 0.220285771*I'
|
||||
|
||||
|
||||
def test_riemann_xi_eval():
|
||||
assert riemann_xi(2) == pi/6
|
||||
assert riemann_xi(0) == Rational(1, 2)
|
||||
assert riemann_xi(1) == Rational(1, 2)
|
||||
assert riemann_xi(3).rewrite(zeta) == 3*zeta(3)/(2*pi)
|
||||
assert riemann_xi(4) == pi**2/15
|
||||
|
||||
|
||||
def test_rewriting():
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
assert isinstance(dirichlet_eta(x).rewrite(zeta), Piecewise)
|
||||
assert isinstance(dirichlet_eta(x).rewrite(genocchi), Piecewise)
|
||||
assert zeta(x).rewrite(dirichlet_eta) == dirichlet_eta(x)/(1 - 2**(1 - x))
|
||||
assert zeta(x).rewrite(dirichlet_eta, a=2) == zeta(x)
|
||||
assert verify_numerically(dirichlet_eta(x), dirichlet_eta(x).rewrite(zeta), x)
|
||||
assert verify_numerically(dirichlet_eta(x), dirichlet_eta(x).rewrite(genocchi), x)
|
||||
assert verify_numerically(zeta(x), zeta(x).rewrite(dirichlet_eta), x)
|
||||
|
||||
assert zeta(x, a).rewrite(lerchphi) == lerchphi(1, x, a)
|
||||
assert polylog(s, z).rewrite(lerchphi) == lerchphi(z, s, 1)*z
|
||||
|
||||
assert lerchphi(1, x, a).rewrite(zeta) == zeta(x, a)
|
||||
assert z*lerchphi(z, s, 1).rewrite(polylog) == polylog(s, z)
|
||||
|
||||
|
||||
def test_derivatives():
|
||||
from sympy.core.function import Derivative
|
||||
assert zeta(x, a).diff(x) == Derivative(zeta(x, a), x)
|
||||
assert zeta(x, a).diff(a) == -x*zeta(x + 1, a)
|
||||
assert lerchphi(
|
||||
z, s, a).diff(z) == (lerchphi(z, s - 1, a) - a*lerchphi(z, s, a))/z
|
||||
assert lerchphi(z, s, a).diff(a) == -s*lerchphi(z, s + 1, a)
|
||||
assert polylog(s, z).diff(z) == polylog(s - 1, z)/z
|
||||
|
||||
b = randcplx()
|
||||
c = randcplx()
|
||||
assert td(zeta(b, x), x)
|
||||
assert td(polylog(b, z), z)
|
||||
assert td(lerchphi(c, b, x), x)
|
||||
assert td(lerchphi(x, b, c), x)
|
||||
raises(ArgumentIndexError, lambda: lerchphi(c, b, x).fdiff(2))
|
||||
raises(ArgumentIndexError, lambda: lerchphi(c, b, x).fdiff(4))
|
||||
raises(ArgumentIndexError, lambda: polylog(b, z).fdiff(1))
|
||||
raises(ArgumentIndexError, lambda: polylog(b, z).fdiff(3))
|
||||
|
||||
|
||||
def myexpand(func, target):
|
||||
expanded = expand_func(func)
|
||||
if target is not None:
|
||||
return expanded == target
|
||||
if expanded == func: # it didn't expand
|
||||
return False
|
||||
|
||||
# check to see that the expanded and original evaluate to the same value
|
||||
subs = {}
|
||||
for a in func.free_symbols:
|
||||
subs[a] = randcplx()
|
||||
return abs(func.subs(subs).n()
|
||||
- expanded.replace(exp_polar, exp).subs(subs).n()) < 1e-10
|
||||
|
||||
|
||||
def test_polylog_expansion():
|
||||
assert polylog(s, 0) == 0
|
||||
assert polylog(s, 1) == zeta(s)
|
||||
assert polylog(s, -1) == -dirichlet_eta(s)
|
||||
assert polylog(s, exp_polar(I*pi*Rational(4, 3))) == polylog(s, exp(I*pi*Rational(4, 3)))
|
||||
assert polylog(s, exp_polar(I*pi)/3) == polylog(s, exp(I*pi)/3)
|
||||
|
||||
assert myexpand(polylog(1, z), -log(1 - z))
|
||||
assert myexpand(polylog(0, z), z/(1 - z))
|
||||
assert myexpand(polylog(-1, z), z/(1 - z)**2)
|
||||
assert ((1-z)**3 * expand_func(polylog(-2, z))).simplify() == z*(1 + z)
|
||||
assert myexpand(polylog(-5, z), None)
|
||||
|
||||
|
||||
def test_polylog_series():
|
||||
assert polylog(1, z).series(z, n=5) == z + z**2/2 + z**3/3 + z**4/4 + O(z**5)
|
||||
assert polylog(1, sqrt(z)).series(z, n=3) == z/2 + z**2/4 + sqrt(z)\
|
||||
+ z**(S(3)/2)/3 + z**(S(5)/2)/5 + O(z**3)
|
||||
|
||||
# https://github.com/sympy/sympy/issues/9497
|
||||
assert polylog(S(3)/2, -z).series(z, 0, 5) == -z + sqrt(2)*z**2/4\
|
||||
- sqrt(3)*z**3/9 + z**4/8 + O(z**5)
|
||||
|
||||
|
||||
def test_issue_8404():
|
||||
i = Symbol('i', integer=True)
|
||||
assert Abs(Sum(1/(3*i + 1)**2, (i, 0, S.Infinity)).doit().n(4)
|
||||
- 1.122) < 0.001
|
||||
|
||||
|
||||
def test_polylog_values():
|
||||
assert polylog(2, 2) == pi**2/4 - I*pi*log(2)
|
||||
assert polylog(2, S.Half) == pi**2/12 - log(2)**2/2
|
||||
for z in [S.Half, 2, (sqrt(5)-1)/2, -(sqrt(5)-1)/2, -(sqrt(5)+1)/2, (3-sqrt(5))/2]:
|
||||
assert Abs(polylog(2, z).evalf() - polylog(2, z, evaluate=False).evalf()) < 1e-15
|
||||
z = Symbol("z")
|
||||
for s in [-1, 0]:
|
||||
for _ in range(10):
|
||||
assert verify_numerically(polylog(s, z), polylog(s, z, evaluate=False),
|
||||
z, a=-3, b=-2, c=S.Half, d=2)
|
||||
assert verify_numerically(polylog(s, z), polylog(s, z, evaluate=False),
|
||||
z, a=2, b=-2, c=5, d=2)
|
||||
|
||||
from sympy.integrals.integrals import Integral
|
||||
assert polylog(0, Integral(1, (x, 0, 1))) == -S.Half
|
||||
|
||||
|
||||
def test_lerchphi_expansion():
|
||||
assert myexpand(lerchphi(1, s, a), zeta(s, a))
|
||||
assert myexpand(lerchphi(z, s, 1), polylog(s, z)/z)
|
||||
|
||||
# direct summation
|
||||
assert myexpand(lerchphi(z, -1, a), a/(1 - z) + z/(1 - z)**2)
|
||||
assert myexpand(lerchphi(z, -3, a), None)
|
||||
# polylog reduction
|
||||
assert myexpand(lerchphi(z, s, S.Half),
|
||||
2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z)
|
||||
- polylog(s, polar_lift(-1)*sqrt(z))/sqrt(z)))
|
||||
assert myexpand(lerchphi(z, s, 2), -1/z + polylog(s, z)/z**2)
|
||||
assert myexpand(lerchphi(z, s, Rational(3, 2)), None)
|
||||
assert myexpand(lerchphi(z, s, Rational(7, 3)), None)
|
||||
assert myexpand(lerchphi(z, s, Rational(-1, 3)), None)
|
||||
assert myexpand(lerchphi(z, s, Rational(-5, 2)), None)
|
||||
|
||||
# hurwitz zeta reduction
|
||||
assert myexpand(lerchphi(-1, s, a),
|
||||
2**(-s)*zeta(s, a/2) - 2**(-s)*zeta(s, (a + 1)/2))
|
||||
assert myexpand(lerchphi(I, s, a), None)
|
||||
assert myexpand(lerchphi(-I, s, a), None)
|
||||
assert myexpand(lerchphi(exp(I*pi*Rational(2, 5)), s, a), None)
|
||||
|
||||
|
||||
def test_stieltjes():
|
||||
assert isinstance(stieltjes(x), stieltjes)
|
||||
assert isinstance(stieltjes(x, a), stieltjes)
|
||||
|
||||
# Zero'th constant EulerGamma
|
||||
assert stieltjes(0) == S.EulerGamma
|
||||
assert stieltjes(0, 1) == S.EulerGamma
|
||||
|
||||
# Not defined
|
||||
assert stieltjes(nan) is nan
|
||||
assert stieltjes(0, nan) is nan
|
||||
assert stieltjes(-1) is S.ComplexInfinity
|
||||
assert stieltjes(1.5) is S.ComplexInfinity
|
||||
assert stieltjes(z, 0) is S.ComplexInfinity
|
||||
assert stieltjes(z, -1) is S.ComplexInfinity
|
||||
|
||||
|
||||
def test_stieltjes_evalf():
|
||||
assert abs(stieltjes(0).evalf() - 0.577215664) < 1E-9
|
||||
assert abs(stieltjes(0, 0.5).evalf() - 1.963510026) < 1E-9
|
||||
assert abs(stieltjes(1, 2).evalf() + 0.072815845) < 1E-9
|
||||
|
||||
|
||||
def test_issue_10475():
|
||||
a = Symbol('a', extended_real=True)
|
||||
b = Symbol('b', extended_positive=True)
|
||||
s = Symbol('s', zero=False)
|
||||
|
||||
assert zeta(2 + I).is_finite
|
||||
assert zeta(1).is_finite is False
|
||||
assert zeta(x).is_finite is None
|
||||
assert zeta(x + I).is_finite is None
|
||||
assert zeta(a).is_finite is None
|
||||
assert zeta(b).is_finite is None
|
||||
assert zeta(-b).is_finite is True
|
||||
assert zeta(b**2 - 2*b + 1).is_finite is None
|
||||
assert zeta(a + I).is_finite is True
|
||||
assert zeta(b + 1).is_finite is True
|
||||
assert zeta(s + 1).is_finite is True
|
||||
|
||||
|
||||
def test_issue_14177():
|
||||
n = Symbol('n', nonnegative=True, integer=True)
|
||||
|
||||
assert zeta(-n).rewrite(bernoulli) == bernoulli(n+1) / (-n-1)
|
||||
assert zeta(-n, a).rewrite(bernoulli) == bernoulli(n+1, a) / (-n-1)
|
||||
z2n = -(2*I*pi)**(2*n)*bernoulli(2*n) / (2*factorial(2*n))
|
||||
assert zeta(2*n).rewrite(bernoulli) == z2n
|
||||
assert expand_func(zeta(s, n+1)) == zeta(s) - harmonic(n, s)
|
||||
assert expand_func(zeta(-b, -n)) is nan
|
||||
assert expand_func(zeta(-b, n)) == zeta(-b, n)
|
||||
|
||||
n = Symbol('n')
|
||||
|
||||
assert zeta(2*n) == zeta(2*n) # As sign of z (= 2*n) is not determined
|
||||
|
|
@ -0,0 +1,786 @@
|
|||
""" Riemann zeta and related function. """
|
||||
|
||||
from sympy.core.add import Add
|
||||
from sympy.core.cache import cacheit
|
||||
from sympy.core.function import ArgumentIndexError, expand_mul, DefinedFunction
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.core.numbers import pi, I, Integer
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Dummy
|
||||
from sympy.core.sympify import sympify
|
||||
from sympy.functions.combinatorial.numbers import bernoulli, factorial, genocchi, harmonic
|
||||
from sympy.functions.elementary.complexes import re, unpolarify, Abs, polar_lift
|
||||
from sympy.functions.elementary.exponential import log, exp_polar, exp
|
||||
from sympy.functions.elementary.integers import ceiling, floor
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.polys.polytools import Poly
|
||||
|
||||
###############################################################################
|
||||
###################### LERCH TRANSCENDENT #####################################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class lerchphi(DefinedFunction):
|
||||
r"""
|
||||
Lerch transcendent (Lerch phi function).
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For $\operatorname{Re}(a) > 0$, $|z| < 1$ and $s \in \mathbb{C}$, the
|
||||
Lerch transcendent is defined as
|
||||
|
||||
.. math :: \Phi(z, s, a) = \sum_{n=0}^\infty \frac{z^n}{(n + a)^s},
|
||||
|
||||
where the standard branch of the argument is used for $n + a$,
|
||||
and by analytic continuation for other values of the parameters.
|
||||
|
||||
A commonly used related function is the Lerch zeta function, defined by
|
||||
|
||||
.. math:: L(q, s, a) = \Phi(e^{2\pi i q}, s, a).
|
||||
|
||||
**Analytic Continuation and Branching Behavior**
|
||||
|
||||
It can be shown that
|
||||
|
||||
.. math:: \Phi(z, s, a) = z\Phi(z, s, a+1) + a^{-s}.
|
||||
|
||||
This provides the analytic continuation to $\operatorname{Re}(a) \le 0$.
|
||||
|
||||
Assume now $\operatorname{Re}(a) > 0$. The integral representation
|
||||
|
||||
.. math:: \Phi_0(z, s, a) = \int_0^\infty \frac{t^{s-1} e^{-at}}{1 - ze^{-t}}
|
||||
\frac{\mathrm{d}t}{\Gamma(s)}
|
||||
|
||||
provides an analytic continuation to $\mathbb{C} - [1, \infty)$.
|
||||
Finally, for $x \in (1, \infty)$ we find
|
||||
|
||||
.. math:: \lim_{\epsilon \to 0^+} \Phi_0(x + i\epsilon, s, a)
|
||||
-\lim_{\epsilon \to 0^+} \Phi_0(x - i\epsilon, s, a)
|
||||
= \frac{2\pi i \log^{s-1}{x}}{x^a \Gamma(s)},
|
||||
|
||||
using the standard branch for both $\log{x}$ and
|
||||
$\log{\log{x}}$ (a branch of $\log{\log{x}}$ is needed to
|
||||
evaluate $\log{x}^{s-1}$).
|
||||
This concludes the analytic continuation. The Lerch transcendent is thus
|
||||
branched at $z \in \{0, 1, \infty\}$ and
|
||||
$a \in \mathbb{Z}_{\le 0}$. For fixed $z, a$ outside these
|
||||
branch points, it is an entire function of $s$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The Lerch transcendent is a fairly general function, for this reason it does
|
||||
not automatically evaluate to simpler functions. Use ``expand_func()`` to
|
||||
achieve this.
|
||||
|
||||
If $z=1$, the Lerch transcendent reduces to the Hurwitz zeta function:
|
||||
|
||||
>>> from sympy import lerchphi, expand_func
|
||||
>>> from sympy.abc import z, s, a
|
||||
>>> expand_func(lerchphi(1, s, a))
|
||||
zeta(s, a)
|
||||
|
||||
More generally, if $z$ is a root of unity, the Lerch transcendent
|
||||
reduces to a sum of Hurwitz zeta functions:
|
||||
|
||||
>>> expand_func(lerchphi(-1, s, a))
|
||||
zeta(s, a/2)/2**s - zeta(s, a/2 + 1/2)/2**s
|
||||
|
||||
If $a=1$, the Lerch transcendent reduces to the polylogarithm:
|
||||
|
||||
>>> expand_func(lerchphi(z, s, 1))
|
||||
polylog(s, z)/z
|
||||
|
||||
More generally, if $a$ is rational, the Lerch transcendent reduces
|
||||
to a sum of polylogarithms:
|
||||
|
||||
>>> from sympy import S
|
||||
>>> expand_func(lerchphi(z, s, S(1)/2))
|
||||
2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) -
|
||||
polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z))
|
||||
>>> expand_func(lerchphi(z, s, S(3)/2))
|
||||
-2**s/z + 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) -
|
||||
polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z))/z
|
||||
|
||||
The derivatives with respect to $z$ and $a$ can be computed in
|
||||
closed form:
|
||||
|
||||
>>> lerchphi(z, s, a).diff(z)
|
||||
(-a*lerchphi(z, s, a) + lerchphi(z, s - 1, a))/z
|
||||
>>> lerchphi(z, s, a).diff(a)
|
||||
-s*lerchphi(z, s + 1, a)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
polylog, zeta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Bateman, H.; Erdelyi, A. (1953), Higher Transcendental Functions,
|
||||
Vol. I, New York: McGraw-Hill. Section 1.11.
|
||||
.. [2] https://dlmf.nist.gov/25.14
|
||||
.. [3] https://en.wikipedia.org/wiki/Lerch_transcendent
|
||||
|
||||
"""
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
z, s, a = self.args
|
||||
if z == 1:
|
||||
return zeta(s, a)
|
||||
if s.is_Integer and s <= 0:
|
||||
t = Dummy('t')
|
||||
p = Poly((t + a)**(-s), t)
|
||||
start = 1/(1 - t)
|
||||
res = S.Zero
|
||||
for c in reversed(p.all_coeffs()):
|
||||
res += c*start
|
||||
start = t*start.diff(t)
|
||||
return res.subs(t, z)
|
||||
|
||||
if a.is_Rational:
|
||||
# See section 18 of
|
||||
# Kelly B. Roach. Hypergeometric Function Representations.
|
||||
# In: Proceedings of the 1997 International Symposium on Symbolic and
|
||||
# Algebraic Computation, pages 205-211, New York, 1997. ACM.
|
||||
# TODO should something be polarified here?
|
||||
add = S.Zero
|
||||
mul = S.One
|
||||
# First reduce a to the interaval (0, 1]
|
||||
if a > 1:
|
||||
n = floor(a)
|
||||
if n == a:
|
||||
n -= 1
|
||||
a -= n
|
||||
mul = z**(-n)
|
||||
add = Add(*[-z**(k - n)/(a + k)**s for k in range(n)])
|
||||
elif a <= 0:
|
||||
n = floor(-a) + 1
|
||||
a += n
|
||||
mul = z**n
|
||||
add = Add(*[z**(n - 1 - k)/(a - k - 1)**s for k in range(n)])
|
||||
|
||||
m, n = S([a.p, a.q])
|
||||
zet = exp_polar(2*pi*I/n)
|
||||
root = z**(1/n)
|
||||
up_zet = unpolarify(zet)
|
||||
addargs = []
|
||||
for k in range(n):
|
||||
p = polylog(s, zet**k*root)
|
||||
if isinstance(p, polylog):
|
||||
p = p._eval_expand_func(**hints)
|
||||
addargs.append(p/(up_zet**k*root)**m)
|
||||
return add + mul*n**(s - 1)*Add(*addargs)
|
||||
|
||||
# TODO use minpoly instead of ad-hoc methods when issue 5888 is fixed
|
||||
if isinstance(z, exp) and (z.args[0]/(pi*I)).is_Rational or z in [-1, I, -I]:
|
||||
# TODO reference?
|
||||
if z == -1:
|
||||
p, q = S([1, 2])
|
||||
elif z == I:
|
||||
p, q = S([1, 4])
|
||||
elif z == -I:
|
||||
p, q = S([-1, 4])
|
||||
else:
|
||||
arg = z.args[0]/(2*pi*I)
|
||||
p, q = S([arg.p, arg.q])
|
||||
return Add(*[exp(2*pi*I*k*p/q)/q**s*zeta(s, (k + a)/q)
|
||||
for k in range(q)])
|
||||
|
||||
return lerchphi(z, s, a)
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
z, s, a = self.args
|
||||
if argindex == 3:
|
||||
return -s*lerchphi(z, s + 1, a)
|
||||
elif argindex == 1:
|
||||
return (lerchphi(z, s - 1, a) - a*lerchphi(z, s, a))/z
|
||||
else:
|
||||
raise ArgumentIndexError
|
||||
|
||||
def _eval_rewrite_helper(self, target):
|
||||
res = self._eval_expand_func()
|
||||
if res.has(target):
|
||||
return res
|
||||
else:
|
||||
return self
|
||||
|
||||
def _eval_rewrite_as_zeta(self, z, s, a, **kwargs):
|
||||
return self._eval_rewrite_helper(zeta)
|
||||
|
||||
def _eval_rewrite_as_polylog(self, z, s, a, **kwargs):
|
||||
return self._eval_rewrite_helper(polylog)
|
||||
|
||||
###############################################################################
|
||||
###################### POLYLOGARITHM ##########################################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class polylog(DefinedFunction):
|
||||
r"""
|
||||
Polylogarithm function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For $|z| < 1$ and $s \in \mathbb{C}$, the polylogarithm is
|
||||
defined by
|
||||
|
||||
.. math:: \operatorname{Li}_s(z) = \sum_{n=1}^\infty \frac{z^n}{n^s},
|
||||
|
||||
where the standard branch of the argument is used for $n$. It admits
|
||||
an analytic continuation which is branched at $z=1$ (notably not on the
|
||||
sheet of initial definition), $z=0$ and $z=\infty$.
|
||||
|
||||
The name polylogarithm comes from the fact that for $s=1$, the
|
||||
polylogarithm is related to the ordinary logarithm (see examples), and that
|
||||
|
||||
.. math:: \operatorname{Li}_{s+1}(z) =
|
||||
\int_0^z \frac{\operatorname{Li}_s(t)}{t} \mathrm{d}t.
|
||||
|
||||
The polylogarithm is a special case of the Lerch transcendent:
|
||||
|
||||
.. math:: \operatorname{Li}_{s}(z) = z \Phi(z, s, 1).
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For $z \in \{0, 1, -1\}$, the polylogarithm is automatically expressed
|
||||
using other functions:
|
||||
|
||||
>>> from sympy import polylog
|
||||
>>> from sympy.abc import s
|
||||
>>> polylog(s, 0)
|
||||
0
|
||||
>>> polylog(s, 1)
|
||||
zeta(s)
|
||||
>>> polylog(s, -1)
|
||||
-dirichlet_eta(s)
|
||||
|
||||
If $s$ is a negative integer, $0$ or $1$, the polylogarithm can be
|
||||
expressed using elementary functions. This can be done using
|
||||
``expand_func()``:
|
||||
|
||||
>>> from sympy import expand_func
|
||||
>>> from sympy.abc import z
|
||||
>>> expand_func(polylog(1, z))
|
||||
-log(1 - z)
|
||||
>>> expand_func(polylog(0, z))
|
||||
z/(1 - z)
|
||||
|
||||
The derivative with respect to $z$ can be computed in closed form:
|
||||
|
||||
>>> polylog(s, z).diff(z)
|
||||
polylog(s - 1, z)/z
|
||||
|
||||
The polylogarithm can be expressed in terms of the lerch transcendent:
|
||||
|
||||
>>> from sympy import lerchphi
|
||||
>>> polylog(s, z).rewrite(lerchphi)
|
||||
z*lerchphi(z, s, 1)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
zeta, lerchphi
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, s, z):
|
||||
if z.is_number:
|
||||
if z is S.One:
|
||||
return zeta(s)
|
||||
elif z is S.NegativeOne:
|
||||
return -dirichlet_eta(s)
|
||||
elif z is S.Zero:
|
||||
return S.Zero
|
||||
elif s == 2:
|
||||
dilogtable = _dilogtable()
|
||||
if z in dilogtable:
|
||||
return dilogtable[z]
|
||||
|
||||
if z.is_zero:
|
||||
return S.Zero
|
||||
|
||||
# Make an effort to determine if z is 1 to avoid replacing into
|
||||
# expression with singularity
|
||||
zone = z.equals(S.One)
|
||||
|
||||
if zone:
|
||||
return zeta(s)
|
||||
elif zone is False:
|
||||
# For s = 0 or -1 use explicit formulas to evaluate, but
|
||||
# automatically expanding polylog(1, z) to -log(1-z) seems
|
||||
# undesirable for summation methods based on hypergeometric
|
||||
# functions
|
||||
if s is S.Zero:
|
||||
return z/(1 - z)
|
||||
elif s is S.NegativeOne:
|
||||
return z/(1 - z)**2
|
||||
if s.is_zero:
|
||||
return z/(1 - z)
|
||||
|
||||
# polylog is branched, but not over the unit disk
|
||||
if z.has(exp_polar, polar_lift) and (zone or (Abs(z) <= S.One) == True):
|
||||
return cls(s, unpolarify(z))
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
s, z = self.args
|
||||
if argindex == 2:
|
||||
return polylog(s - 1, z)/z
|
||||
raise ArgumentIndexError
|
||||
|
||||
def _eval_rewrite_as_lerchphi(self, s, z, **kwargs):
|
||||
return z*lerchphi(z, s, 1)
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
s, z = self.args
|
||||
if s == 1:
|
||||
return -log(1 - z)
|
||||
if s.is_Integer and s <= 0:
|
||||
u = Dummy('u')
|
||||
start = u/(1 - u)
|
||||
for _ in range(-s):
|
||||
start = u*start.diff(u)
|
||||
return expand_mul(start).subs(u, z)
|
||||
return polylog(s, z)
|
||||
|
||||
def _eval_is_zero(self):
|
||||
z = self.args[1]
|
||||
if z.is_zero:
|
||||
return True
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
from sympy.series.order import Order
|
||||
nu, z = self.args
|
||||
|
||||
z0 = z.subs(x, 0)
|
||||
if z0 is S.NaN:
|
||||
z0 = z.limit(x, 0, dir='-' if re(cdir).is_negative else '+')
|
||||
|
||||
if z0.is_zero:
|
||||
# In case of powers less than 1, number of terms need to be computed
|
||||
# separately to avoid repeated callings of _eval_nseries with wrong n
|
||||
try:
|
||||
_, exp = z.leadterm(x)
|
||||
except (ValueError, NotImplementedError):
|
||||
return self
|
||||
|
||||
if exp.is_positive:
|
||||
newn = ceiling(n/exp)
|
||||
o = Order(x**n, x)
|
||||
r = z._eval_nseries(x, n, logx, cdir).removeO()
|
||||
if r is S.Zero:
|
||||
return o
|
||||
|
||||
term = r
|
||||
s = [term]
|
||||
for k in range(2, newn):
|
||||
term *= r
|
||||
s.append(term/k**nu)
|
||||
return Add(*s) + o
|
||||
|
||||
return super(polylog, self)._eval_nseries(x, n, logx, cdir)
|
||||
|
||||
###############################################################################
|
||||
###################### HURWITZ GENERALIZED ZETA FUNCTION ######################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class zeta(DefinedFunction):
|
||||
r"""
|
||||
Hurwitz zeta function (or Riemann zeta function).
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For $\operatorname{Re}(a) > 0$ and $\operatorname{Re}(s) > 1$, this
|
||||
function is defined as
|
||||
|
||||
.. math:: \zeta(s, a) = \sum_{n=0}^\infty \frac{1}{(n + a)^s},
|
||||
|
||||
where the standard choice of argument for $n + a$ is used. For fixed
|
||||
$a$ not a nonpositive integer the Hurwitz zeta function admits a
|
||||
meromorphic continuation to all of $\mathbb{C}$; it is an unbranched
|
||||
function with a simple pole at $s = 1$.
|
||||
|
||||
The Hurwitz zeta function is a special case of the Lerch transcendent:
|
||||
|
||||
.. math:: \zeta(s, a) = \Phi(1, s, a).
|
||||
|
||||
This formula defines an analytic continuation for all possible values of
|
||||
$s$ and $a$ (also $\operatorname{Re}(a) < 0$), see the documentation of
|
||||
:class:`lerchphi` for a description of the branching behavior.
|
||||
|
||||
If no value is passed for $a$ a default value of $a = 1$ is assumed,
|
||||
yielding the Riemann zeta function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For $a = 1$ the Hurwitz zeta function reduces to the famous Riemann
|
||||
zeta function:
|
||||
|
||||
.. math:: \zeta(s, 1) = \zeta(s) = \sum_{n=1}^\infty \frac{1}{n^s}.
|
||||
|
||||
>>> from sympy import zeta
|
||||
>>> from sympy.abc import s
|
||||
>>> zeta(s, 1)
|
||||
zeta(s)
|
||||
>>> zeta(s)
|
||||
zeta(s)
|
||||
|
||||
The Riemann zeta function can also be expressed using the Dirichlet eta
|
||||
function:
|
||||
|
||||
>>> from sympy import dirichlet_eta
|
||||
>>> zeta(s).rewrite(dirichlet_eta)
|
||||
dirichlet_eta(s)/(1 - 2**(1 - s))
|
||||
|
||||
The Riemann zeta function at nonnegative even and negative integer
|
||||
values is related to the Bernoulli numbers and polynomials:
|
||||
|
||||
>>> zeta(2)
|
||||
pi**2/6
|
||||
>>> zeta(4)
|
||||
pi**4/90
|
||||
>>> zeta(0)
|
||||
-1/2
|
||||
>>> zeta(-1)
|
||||
-1/12
|
||||
>>> zeta(-4)
|
||||
0
|
||||
|
||||
The specific formulae are:
|
||||
|
||||
.. math:: \zeta(2n) = -\frac{(2\pi i)^{2n} B_{2n}}{2(2n)!}
|
||||
.. math:: \zeta(-n,a) = -\frac{B_{n+1}(a)}{n+1}
|
||||
|
||||
No closed-form expressions are known at positive odd integers, but
|
||||
numerical evaluation is possible:
|
||||
|
||||
>>> zeta(3).n()
|
||||
1.20205690315959
|
||||
|
||||
The derivative of $\zeta(s, a)$ with respect to $a$ can be computed:
|
||||
|
||||
>>> from sympy.abc import a
|
||||
>>> zeta(s, a).diff(a)
|
||||
-s*zeta(s + 1, a)
|
||||
|
||||
However the derivative with respect to $s$ has no useful closed form
|
||||
expression:
|
||||
|
||||
>>> zeta(s, a).diff(s)
|
||||
Derivative(zeta(s, a), s)
|
||||
|
||||
The Hurwitz zeta function can be expressed in terms of the Lerch
|
||||
transcendent, :class:`~.lerchphi`:
|
||||
|
||||
>>> from sympy import lerchphi
|
||||
>>> zeta(s, a).rewrite(lerchphi)
|
||||
lerchphi(1, s, a)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
dirichlet_eta, lerchphi, polylog
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://dlmf.nist.gov/25.11
|
||||
.. [2] https://en.wikipedia.org/wiki/Hurwitz_zeta_function
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, s, a=None):
|
||||
if a is S.One:
|
||||
return cls(s)
|
||||
elif s is S.NaN or a is S.NaN:
|
||||
return S.NaN
|
||||
elif s is S.One:
|
||||
return S.ComplexInfinity
|
||||
elif s is S.Infinity:
|
||||
return S.One
|
||||
elif a is S.Infinity:
|
||||
return S.Zero
|
||||
|
||||
sint = s.is_Integer
|
||||
if a is None:
|
||||
a = S.One
|
||||
if sint and s.is_nonpositive:
|
||||
return bernoulli(1-s, a) / (s-1)
|
||||
elif a is S.One:
|
||||
if sint and s.is_even:
|
||||
return -(2*pi*I)**s * bernoulli(s) / (2*factorial(s))
|
||||
elif sint and a.is_Integer and a.is_positive:
|
||||
return cls(s) - harmonic(a-1, s)
|
||||
elif a.is_Integer and a.is_nonpositive and \
|
||||
(s.is_integer is False or s.is_nonpositive is False):
|
||||
return S.NaN
|
||||
|
||||
def _eval_rewrite_as_bernoulli(self, s, a=1, **kwargs):
|
||||
if a == 1 and s.is_integer and s.is_nonnegative and s.is_even:
|
||||
return -(2*pi*I)**s * bernoulli(s) / (2*factorial(s))
|
||||
return bernoulli(1-s, a) / (s-1)
|
||||
|
||||
def _eval_rewrite_as_dirichlet_eta(self, s, a=1, **kwargs):
|
||||
if a != 1:
|
||||
return self
|
||||
s = self.args[0]
|
||||
return dirichlet_eta(s)/(1 - 2**(1 - s))
|
||||
|
||||
def _eval_rewrite_as_lerchphi(self, s, a=1, **kwargs):
|
||||
return lerchphi(1, s, a)
|
||||
|
||||
def _eval_is_finite(self):
|
||||
return fuzzy_not((self.args[0] - 1).is_zero)
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
s = self.args[0]
|
||||
a = self.args[1] if len(self.args) > 1 else S.One
|
||||
if a.is_integer:
|
||||
if a.is_positive:
|
||||
return zeta(s) - harmonic(a-1, s)
|
||||
if a.is_nonpositive and (s.is_integer is False or
|
||||
s.is_nonpositive is False):
|
||||
return S.NaN
|
||||
return self
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if len(self.args) == 2:
|
||||
s, a = self.args
|
||||
else:
|
||||
s, a = self.args + (1,)
|
||||
if argindex == 2:
|
||||
return -s*zeta(s + 1, a)
|
||||
else:
|
||||
raise ArgumentIndexError
|
||||
|
||||
def _eval_as_leading_term(self, x, logx, cdir):
|
||||
if len(self.args) == 2:
|
||||
s, a = self.args
|
||||
else:
|
||||
s, a = self.args + (S.One,)
|
||||
|
||||
try:
|
||||
c, e = a.leadterm(x)
|
||||
except NotImplementedError:
|
||||
return self
|
||||
|
||||
if e.is_negative and not s.is_positive:
|
||||
raise NotImplementedError
|
||||
|
||||
return super(zeta, self)._eval_as_leading_term(x, logx=logx, cdir=cdir)
|
||||
|
||||
|
||||
class dirichlet_eta(DefinedFunction):
|
||||
r"""
|
||||
Dirichlet eta function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For $\operatorname{Re}(s) > 0$ and $0 < x \le 1$, this function is defined as
|
||||
|
||||
.. math:: \eta(s, a) = \sum_{n=0}^\infty \frac{(-1)^n}{(n+a)^s}.
|
||||
|
||||
It admits a unique analytic continuation to all of $\mathbb{C}$ for any
|
||||
fixed $a$ not a nonpositive integer. It is an entire, unbranched function.
|
||||
|
||||
It can be expressed using the Hurwitz zeta function as
|
||||
|
||||
.. math:: \eta(s, a) = \zeta(s,a) - 2^{1-s} \zeta\left(s, \frac{a+1}{2}\right)
|
||||
|
||||
and using the generalized Genocchi function as
|
||||
|
||||
.. math:: \eta(s, a) = \frac{G(1-s, a)}{2(s-1)}.
|
||||
|
||||
In both cases the limiting value of $\log2 - \psi(a) + \psi\left(\frac{a+1}{2}\right)$
|
||||
is used when $s = 1$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import dirichlet_eta, zeta
|
||||
>>> from sympy.abc import s
|
||||
>>> dirichlet_eta(s).rewrite(zeta)
|
||||
Piecewise((log(2), Eq(s, 1)), ((1 - 2**(1 - s))*zeta(s), True))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
zeta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Dirichlet_eta_function
|
||||
.. [2] Peter Luschny, "An introduction to the Bernoulli function",
|
||||
https://arxiv.org/abs/2009.06743
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, s, a=None):
|
||||
if a is S.One:
|
||||
return cls(s)
|
||||
if a is None:
|
||||
if s == 1:
|
||||
return log(2)
|
||||
z = zeta(s)
|
||||
if not z.has(zeta):
|
||||
return (1 - 2**(1-s)) * z
|
||||
return
|
||||
elif s == 1:
|
||||
from sympy.functions.special.gamma_functions import digamma
|
||||
return log(2) - digamma(a) + digamma((a+1)/2)
|
||||
z1 = zeta(s, a)
|
||||
z2 = zeta(s, (a+1)/2)
|
||||
if not z1.has(zeta) and not z2.has(zeta):
|
||||
return z1 - 2**(1-s) * z2
|
||||
|
||||
def _eval_rewrite_as_zeta(self, s, a=1, **kwargs):
|
||||
from sympy.functions.special.gamma_functions import digamma
|
||||
if a == 1:
|
||||
return Piecewise((log(2), Eq(s, 1)), ((1 - 2**(1-s)) * zeta(s), True))
|
||||
return Piecewise((log(2) - digamma(a) + digamma((a+1)/2), Eq(s, 1)),
|
||||
(zeta(s, a) - 2**(1-s) * zeta(s, (a+1)/2), True))
|
||||
|
||||
def _eval_rewrite_as_genocchi(self, s, a=S.One, **kwargs):
|
||||
from sympy.functions.special.gamma_functions import digamma
|
||||
return Piecewise((log(2) - digamma(a) + digamma((a+1)/2), Eq(s, 1)),
|
||||
(genocchi(1-s, a) / (2 * (s-1)), True))
|
||||
|
||||
def _eval_evalf(self, prec):
|
||||
if all(i.is_number for i in self.args):
|
||||
return self.rewrite(zeta)._eval_evalf(prec)
|
||||
|
||||
|
||||
class riemann_xi(DefinedFunction):
|
||||
r"""
|
||||
Riemann Xi function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The Riemann Xi function is closely related to the Riemann zeta function.
|
||||
The zeros of Riemann Xi function are precisely the non-trivial zeros
|
||||
of the zeta function.
|
||||
|
||||
>>> from sympy import riemann_xi, zeta
|
||||
>>> from sympy.abc import s
|
||||
>>> riemann_xi(s).rewrite(zeta)
|
||||
s*(s - 1)*gamma(s/2)*zeta(s)/(2*pi**(s/2))
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Riemann_Xi_function
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@classmethod
|
||||
def eval(cls, s):
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
z = zeta(s)
|
||||
if s in (S.Zero, S.One):
|
||||
return S.Half
|
||||
|
||||
if not isinstance(z, zeta):
|
||||
return s*(s - 1)*gamma(s/2)*z/(2*pi**(s/2))
|
||||
|
||||
def _eval_rewrite_as_zeta(self, s, **kwargs):
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
return s*(s - 1)*gamma(s/2)*zeta(s)/(2*pi**(s/2))
|
||||
|
||||
|
||||
class stieltjes(DefinedFunction):
|
||||
r"""
|
||||
Represents Stieltjes constants, $\gamma_{k}$ that occur in
|
||||
Laurent Series expansion of the Riemann zeta function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import stieltjes
|
||||
>>> from sympy.abc import n, m
|
||||
>>> stieltjes(n)
|
||||
stieltjes(n)
|
||||
|
||||
The zero'th stieltjes constant:
|
||||
|
||||
>>> stieltjes(0)
|
||||
EulerGamma
|
||||
>>> stieltjes(0, 1)
|
||||
EulerGamma
|
||||
|
||||
For generalized stieltjes constants:
|
||||
|
||||
>>> stieltjes(n, m)
|
||||
stieltjes(n, m)
|
||||
|
||||
Constants are only defined for integers >= 0:
|
||||
|
||||
>>> stieltjes(-1)
|
||||
zoo
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Stieltjes_constants
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, n, a=None):
|
||||
if a is not None:
|
||||
a = sympify(a)
|
||||
if a is S.NaN:
|
||||
return S.NaN
|
||||
if a.is_Integer and a.is_nonpositive:
|
||||
return S.ComplexInfinity
|
||||
|
||||
if n.is_Number:
|
||||
if n is S.NaN:
|
||||
return S.NaN
|
||||
elif n < 0:
|
||||
return S.ComplexInfinity
|
||||
elif not n.is_Integer:
|
||||
return S.ComplexInfinity
|
||||
elif n is S.Zero and a in [None, 1]:
|
||||
return S.EulerGamma
|
||||
|
||||
if n.is_extended_negative:
|
||||
return S.ComplexInfinity
|
||||
|
||||
if n.is_zero and a in [None, 1]:
|
||||
return S.EulerGamma
|
||||
|
||||
if n.is_integer == False:
|
||||
return S.ComplexInfinity
|
||||
|
||||
|
||||
@cacheit
|
||||
def _dilogtable():
|
||||
return {
|
||||
S.Half: pi**2/12 - log(2)**2/2,
|
||||
Integer(2) : pi**2/4 - I*pi*log(2),
|
||||
-(sqrt(5) - 1)/2 : -pi**2/15 + log((sqrt(5)-1)/2)**2/2,
|
||||
-(sqrt(5) + 1)/2 : -pi**2/10 - log((sqrt(5)+1)/2)**2,
|
||||
(3 - sqrt(5))/2 : pi**2/15 - log((sqrt(5)-1)/2)**2,
|
||||
(sqrt(5) - 1)/2 : pi**2/10 - log((sqrt(5)-1)/2)**2,
|
||||
I : I*S.Catalan - pi**2/48,
|
||||
-I : -I*S.Catalan - pi**2/48,
|
||||
1 - I : pi**2/16 - I*S.Catalan - pi*I/4*log(2),
|
||||
1 + I : pi**2/16 + I*S.Catalan + pi*I/4*log(2),
|
||||
(1 - I)/2 : -log(2)**2/8 + pi*I*log(2)/8 + 5*pi**2/96 - I*S.Catalan
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue