chore: 添加虚拟环境到仓库
- 添加 backend_service/venv 虚拟环境 - 包含所有Python依赖包 - 注意:虚拟环境约393MB,包含12655个文件
This commit is contained in:
@@ -0,0 +1 @@
|
||||
# Stub __init__.py for the sympy.functions.special package
|
||||
@@ -0,0 +1,8 @@
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.special.spherical_harmonics import Ynm
|
||||
|
||||
x, y = symbols('x,y')
|
||||
|
||||
|
||||
def timeit_Ynm_xy():
|
||||
Ynm(1, 1, x, y)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,389 @@
|
||||
from sympy.core import S
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.symbol import Dummy, uniquely_named_symbol
|
||||
from sympy.functions.special.gamma_functions import gamma, digamma
|
||||
from sympy.functions.combinatorial.numbers import catalan
|
||||
from sympy.functions.elementary.complexes import conjugate
|
||||
|
||||
# See mpmath #569 and SymPy #20569
|
||||
def betainc_mpmath_fix(a, b, x1, x2, reg=0):
|
||||
from mpmath import betainc, mpf
|
||||
if x1 == x2:
|
||||
return mpf(0)
|
||||
else:
|
||||
return betainc(a, b, x1, x2, reg)
|
||||
|
||||
###############################################################################
|
||||
############################ COMPLETE BETA FUNCTION ##########################
|
||||
###############################################################################
|
||||
|
||||
class beta(DefinedFunction):
|
||||
r"""
|
||||
The beta integral is called the Eulerian integral of the first kind by
|
||||
Legendre:
|
||||
|
||||
.. math::
|
||||
\mathrm{B}(x,y) \int^{1}_{0} t^{x-1} (1-t)^{y-1} \mathrm{d}t.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Beta function or Euler's first integral is closely associated
|
||||
with the gamma function. The Beta function is often used in probability
|
||||
theory and mathematical statistics. It satisfies properties like:
|
||||
|
||||
.. math::
|
||||
\mathrm{B}(a,1) = \frac{1}{a} \\
|
||||
\mathrm{B}(a,b) = \mathrm{B}(b,a) \\
|
||||
\mathrm{B}(a,b) = \frac{\Gamma(a) \Gamma(b)}{\Gamma(a+b)}
|
||||
|
||||
Therefore for integral values of $a$ and $b$:
|
||||
|
||||
.. math::
|
||||
\mathrm{B} = \frac{(a-1)! (b-1)!}{(a+b-1)!}
|
||||
|
||||
A special case of the Beta function when `x = y` is the
|
||||
Central Beta function. It satisfies properties like:
|
||||
|
||||
.. math::
|
||||
\mathrm{B}(x) = 2^{1 - 2x}\mathrm{B}(x, \frac{1}{2})
|
||||
\mathrm{B}(x) = 2^{1 - 2x} cos(\pi x) \mathrm{B}(\frac{1}{2} - x, x)
|
||||
\mathrm{B}(x) = \int_{0}^{1} \frac{t^x}{(1 + t)^{2x}} dt
|
||||
\mathrm{B}(x) = \frac{2}{x} \prod_{n = 1}^{\infty} \frac{n(n + 2x)}{(n + x)^2}
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import I, pi
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
The Beta function obeys the mirror symmetry:
|
||||
|
||||
>>> from sympy import beta, conjugate
|
||||
>>> conjugate(beta(x, y))
|
||||
beta(conjugate(x), conjugate(y))
|
||||
|
||||
Differentiation with respect to both $x$ and $y$ is supported:
|
||||
|
||||
>>> from sympy import beta, diff
|
||||
>>> diff(beta(x, y), x)
|
||||
(polygamma(0, x) - polygamma(0, x + y))*beta(x, y)
|
||||
|
||||
>>> diff(beta(x, y), y)
|
||||
(polygamma(0, y) - polygamma(0, x + y))*beta(x, y)
|
||||
|
||||
>>> diff(beta(x), x)
|
||||
2*(polygamma(0, x) - polygamma(0, 2*x))*beta(x, x)
|
||||
|
||||
We can numerically evaluate the Beta function to
|
||||
arbitrary precision for any complex numbers x and y:
|
||||
|
||||
>>> from sympy import beta
|
||||
>>> beta(pi).evalf(40)
|
||||
0.02671848900111377452242355235388489324562
|
||||
|
||||
>>> beta(1 + I).evalf(20)
|
||||
-0.2112723729365330143 - 0.7655283165378005676*I
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gamma: Gamma function.
|
||||
uppergamma: Upper incomplete gamma function.
|
||||
lowergamma: Lower incomplete gamma function.
|
||||
polygamma: Polygamma function.
|
||||
loggamma: Log Gamma function.
|
||||
digamma: Digamma function.
|
||||
trigamma: Trigamma function.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Beta_function
|
||||
.. [2] https://mathworld.wolfram.com/BetaFunction.html
|
||||
.. [3] https://dlmf.nist.gov/5.12
|
||||
|
||||
"""
|
||||
unbranched = True
|
||||
|
||||
def fdiff(self, argindex):
|
||||
x, y = self.args
|
||||
if argindex == 1:
|
||||
# Diff wrt x
|
||||
return beta(x, y)*(digamma(x) - digamma(x + y))
|
||||
elif argindex == 2:
|
||||
# Diff wrt y
|
||||
return beta(x, y)*(digamma(y) - digamma(x + y))
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, x, y=None):
|
||||
if y is None:
|
||||
return beta(x, x)
|
||||
if x.is_Number and y.is_Number:
|
||||
return beta(x, y, evaluate=False).doit()
|
||||
|
||||
def doit(self, **hints):
|
||||
x = xold = self.args[0]
|
||||
# Deal with unevaluated single argument beta
|
||||
single_argument = len(self.args) == 1
|
||||
y = yold = self.args[0] if single_argument else self.args[1]
|
||||
if hints.get('deep', True):
|
||||
x = x.doit(**hints)
|
||||
y = y.doit(**hints)
|
||||
if y.is_zero or x.is_zero:
|
||||
return S.ComplexInfinity
|
||||
if y is S.One:
|
||||
return 1/x
|
||||
if x is S.One:
|
||||
return 1/y
|
||||
if y == x + 1:
|
||||
return 1/(x*y*catalan(x))
|
||||
s = x + y
|
||||
if (s.is_integer and s.is_negative and x.is_integer is False and
|
||||
y.is_integer is False):
|
||||
return S.Zero
|
||||
if x == xold and y == yold and not single_argument:
|
||||
return self
|
||||
return beta(x, y)
|
||||
|
||||
def _eval_expand_func(self, **hints):
|
||||
x, y = self.args
|
||||
return gamma(x)*gamma(y) / gamma(x + y)
|
||||
|
||||
def _eval_is_real(self):
|
||||
return self.args[0].is_real and self.args[1].is_real
|
||||
|
||||
def _eval_conjugate(self):
|
||||
return self.func(self.args[0].conjugate(), self.args[1].conjugate())
|
||||
|
||||
def _eval_rewrite_as_gamma(self, x, y, piecewise=True, **kwargs):
|
||||
return self._eval_expand_func(**kwargs)
|
||||
|
||||
def _eval_rewrite_as_Integral(self, x, y, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', [x, y]).name)
|
||||
return Integral(t**(x - 1)*(1 - t)**(y - 1), (t, 0, 1))
|
||||
|
||||
###############################################################################
|
||||
########################## INCOMPLETE BETA FUNCTION ###########################
|
||||
###############################################################################
|
||||
|
||||
class betainc(DefinedFunction):
|
||||
r"""
|
||||
The Generalized Incomplete Beta function is defined as
|
||||
|
||||
.. math::
|
||||
\mathrm{B}_{(x_1, x_2)}(a, b) = \int_{x_1}^{x_2} t^{a - 1} (1 - t)^{b - 1} dt
|
||||
|
||||
The Incomplete Beta function is a special case
|
||||
of the Generalized Incomplete Beta function :
|
||||
|
||||
.. math:: \mathrm{B}_z (a, b) = \mathrm{B}_{(0, z)}(a, b)
|
||||
|
||||
The Incomplete Beta function satisfies :
|
||||
|
||||
.. math:: \mathrm{B}_z (a, b) = (-1)^a \mathrm{B}_{\frac{z}{z - 1}} (a, 1 - a - b)
|
||||
|
||||
The Beta function is a special case of the Incomplete Beta function :
|
||||
|
||||
.. math:: \mathrm{B}(a, b) = \mathrm{B}_{1}(a, b)
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import betainc, symbols, conjugate
|
||||
>>> a, b, x, x1, x2 = symbols('a b x x1 x2')
|
||||
|
||||
The Generalized Incomplete Beta function is given by:
|
||||
|
||||
>>> betainc(a, b, x1, x2)
|
||||
betainc(a, b, x1, x2)
|
||||
|
||||
The Incomplete Beta function can be obtained as follows:
|
||||
|
||||
>>> betainc(a, b, 0, x)
|
||||
betainc(a, b, 0, x)
|
||||
|
||||
The Incomplete Beta function obeys the mirror symmetry:
|
||||
|
||||
>>> conjugate(betainc(a, b, x1, x2))
|
||||
betainc(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
|
||||
|
||||
We can numerically evaluate the Incomplete Beta function to
|
||||
arbitrary precision for any complex numbers a, b, x1 and x2:
|
||||
|
||||
>>> from sympy import betainc, I
|
||||
>>> betainc(2, 3, 4, 5).evalf(10)
|
||||
56.08333333
|
||||
>>> betainc(0.75, 1 - 4*I, 0, 2 + 3*I).evalf(25)
|
||||
0.2241657956955709603655887 + 0.3619619242700451992411724*I
|
||||
|
||||
The Generalized Incomplete Beta function can be expressed
|
||||
in terms of the Generalized Hypergeometric function.
|
||||
|
||||
>>> from sympy import hyper
|
||||
>>> betainc(a, b, x1, x2).rewrite(hyper)
|
||||
(-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/a
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
beta: Beta function
|
||||
hyper: Generalized Hypergeometric function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
|
||||
.. [2] https://dlmf.nist.gov/8.17
|
||||
.. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
|
||||
.. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
|
||||
|
||||
"""
|
||||
nargs = 4
|
||||
unbranched = True
|
||||
|
||||
def fdiff(self, argindex):
|
||||
a, b, x1, x2 = self.args
|
||||
if argindex == 3:
|
||||
# Diff wrt x1
|
||||
return -(1 - x1)**(b - 1)*x1**(a - 1)
|
||||
elif argindex == 4:
|
||||
# Diff wrt x2
|
||||
return (1 - x2)**(b - 1)*x2**(a - 1)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_mpmath(self):
|
||||
return betainc_mpmath_fix, self.args
|
||||
|
||||
def _eval_is_real(self):
|
||||
if all(arg.is_real for arg in self.args):
|
||||
return True
|
||||
|
||||
def _eval_conjugate(self):
|
||||
return self.func(*map(conjugate, self.args))
|
||||
|
||||
def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', [a, b, x1, x2]).name)
|
||||
return Integral(t**(a - 1)*(1 - t)**(b - 1), (t, x1, x2))
|
||||
|
||||
def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.functions.special.hyper import hyper
|
||||
return (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
|
||||
|
||||
###############################################################################
|
||||
#################### REGULARIZED INCOMPLETE BETA FUNCTION #####################
|
||||
###############################################################################
|
||||
|
||||
class betainc_regularized(DefinedFunction):
|
||||
r"""
|
||||
The Generalized Regularized Incomplete Beta function is given by
|
||||
|
||||
.. math::
|
||||
\mathrm{I}_{(x_1, x_2)}(a, b) = \frac{\mathrm{B}_{(x_1, x_2)}(a, b)}{\mathrm{B}(a, b)}
|
||||
|
||||
The Regularized Incomplete Beta function is a special case
|
||||
of the Generalized Regularized Incomplete Beta function :
|
||||
|
||||
.. math:: \mathrm{I}_z (a, b) = \mathrm{I}_{(0, z)}(a, b)
|
||||
|
||||
The Regularized Incomplete Beta function is the cumulative distribution
|
||||
function of the beta distribution.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import betainc_regularized, symbols, conjugate
|
||||
>>> a, b, x, x1, x2 = symbols('a b x x1 x2')
|
||||
|
||||
The Generalized Regularized Incomplete Beta
|
||||
function is given by:
|
||||
|
||||
>>> betainc_regularized(a, b, x1, x2)
|
||||
betainc_regularized(a, b, x1, x2)
|
||||
|
||||
The Regularized Incomplete Beta function
|
||||
can be obtained as follows:
|
||||
|
||||
>>> betainc_regularized(a, b, 0, x)
|
||||
betainc_regularized(a, b, 0, x)
|
||||
|
||||
The Regularized Incomplete Beta function
|
||||
obeys the mirror symmetry:
|
||||
|
||||
>>> conjugate(betainc_regularized(a, b, x1, x2))
|
||||
betainc_regularized(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
|
||||
|
||||
We can numerically evaluate the Regularized Incomplete Beta function
|
||||
to arbitrary precision for any complex numbers a, b, x1 and x2:
|
||||
|
||||
>>> from sympy import betainc_regularized, pi, E
|
||||
>>> betainc_regularized(1, 2, 0, 0.25).evalf(10)
|
||||
0.4375000000
|
||||
>>> betainc_regularized(pi, E, 0, 1).evalf(5)
|
||||
1.00000
|
||||
|
||||
The Generalized Regularized Incomplete Beta function can be
|
||||
expressed in terms of the Generalized Hypergeometric function.
|
||||
|
||||
>>> from sympy import hyper
|
||||
>>> betainc_regularized(a, b, x1, x2).rewrite(hyper)
|
||||
(-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/(a*beta(a, b))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
beta: Beta function
|
||||
hyper: Generalized Hypergeometric function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
|
||||
.. [2] https://dlmf.nist.gov/8.17
|
||||
.. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
|
||||
.. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
|
||||
|
||||
"""
|
||||
nargs = 4
|
||||
unbranched = True
|
||||
|
||||
def __new__(cls, a, b, x1, x2):
|
||||
return super().__new__(cls, a, b, x1, x2)
|
||||
|
||||
def _eval_mpmath(self):
|
||||
return betainc_mpmath_fix, (*self.args, S(1))
|
||||
|
||||
def fdiff(self, argindex):
|
||||
a, b, x1, x2 = self.args
|
||||
if argindex == 3:
|
||||
# Diff wrt x1
|
||||
return -(1 - x1)**(b - 1)*x1**(a - 1) / beta(a, b)
|
||||
elif argindex == 4:
|
||||
# Diff wrt x2
|
||||
return (1 - x2)**(b - 1)*x2**(a - 1) / beta(a, b)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_is_real(self):
|
||||
if all(arg.is_real for arg in self.args):
|
||||
return True
|
||||
|
||||
def _eval_conjugate(self):
|
||||
return self.func(*map(conjugate, self.args))
|
||||
|
||||
def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', [a, b, x1, x2]).name)
|
||||
integrand = t**(a - 1)*(1 - t)**(b - 1)
|
||||
expr = Integral(integrand, (t, x1, x2))
|
||||
return expr / Integral(integrand, (t, 0, 1))
|
||||
|
||||
def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
|
||||
from sympy.functions.special.hyper import hyper
|
||||
expr = (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
|
||||
return expr / beta(a, b)
|
||||
@@ -0,0 +1,348 @@
|
||||
from sympy.core import S, sympify
|
||||
from sympy.core.symbol import (Dummy, symbols)
|
||||
from sympy.functions import Piecewise, piecewise_fold
|
||||
from sympy.logic.boolalg import And
|
||||
from sympy.sets.sets import Interval
|
||||
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
def _ivl(cond, x):
|
||||
"""return the interval corresponding to the condition
|
||||
|
||||
Conditions in spline's Piecewise give the range over
|
||||
which an expression is valid like (lo <= x) & (x <= hi).
|
||||
This function returns (lo, hi).
|
||||
"""
|
||||
if isinstance(cond, And) and len(cond.args) == 2:
|
||||
a, b = cond.args
|
||||
if a.lts == x:
|
||||
a, b = b, a
|
||||
return a.lts, b.gts
|
||||
raise TypeError('unexpected cond type: %s' % cond)
|
||||
|
||||
|
||||
def _add_splines(c, b1, d, b2, x):
|
||||
"""Construct c*b1 + d*b2."""
|
||||
|
||||
if S.Zero in (b1, c):
|
||||
rv = piecewise_fold(d * b2)
|
||||
elif S.Zero in (b2, d):
|
||||
rv = piecewise_fold(c * b1)
|
||||
else:
|
||||
new_args = []
|
||||
# Just combining the Piecewise without any fancy optimization
|
||||
p1 = piecewise_fold(c * b1)
|
||||
p2 = piecewise_fold(d * b2)
|
||||
|
||||
# Search all Piecewise arguments except (0, True)
|
||||
p2args = list(p2.args[:-1])
|
||||
|
||||
# This merging algorithm assumes the conditions in
|
||||
# p1 and p2 are sorted
|
||||
for arg in p1.args[:-1]:
|
||||
expr = arg.expr
|
||||
cond = arg.cond
|
||||
|
||||
lower = _ivl(cond, x)[0]
|
||||
|
||||
# Check p2 for matching conditions that can be merged
|
||||
for i, arg2 in enumerate(p2args):
|
||||
expr2 = arg2.expr
|
||||
cond2 = arg2.cond
|
||||
|
||||
lower_2, upper_2 = _ivl(cond2, x)
|
||||
if cond2 == cond:
|
||||
# Conditions match, join expressions
|
||||
expr += expr2
|
||||
# Remove matching element
|
||||
del p2args[i]
|
||||
# No need to check the rest
|
||||
break
|
||||
elif lower_2 < lower and upper_2 <= lower:
|
||||
# Check if arg2 condition smaller than arg1,
|
||||
# add to new_args by itself (no match expected
|
||||
# in p1)
|
||||
new_args.append(arg2)
|
||||
del p2args[i]
|
||||
break
|
||||
|
||||
# Checked all, add expr and cond
|
||||
new_args.append((expr, cond))
|
||||
|
||||
# Add remaining items from p2args
|
||||
new_args.extend(p2args)
|
||||
|
||||
# Add final (0, True)
|
||||
new_args.append((0, True))
|
||||
|
||||
rv = Piecewise(*new_args, evaluate=False)
|
||||
|
||||
return rv.expand()
|
||||
|
||||
|
||||
@lru_cache(maxsize=128)
|
||||
def bspline_basis(d, knots, n, x):
|
||||
"""
|
||||
The $n$-th B-spline at $x$ of degree $d$ with knots.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
B-Splines are piecewise polynomials of degree $d$. They are defined on a
|
||||
set of knots, which is a sequence of integers or floats.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The 0th degree splines have a value of 1 on a single interval:
|
||||
|
||||
>>> from sympy import bspline_basis
|
||||
>>> from sympy.abc import x
|
||||
>>> d = 0
|
||||
>>> knots = tuple(range(5))
|
||||
>>> bspline_basis(d, knots, 0, x)
|
||||
Piecewise((1, (x >= 0) & (x <= 1)), (0, True))
|
||||
|
||||
For a given ``(d, knots)`` there are ``len(knots)-d-1`` B-splines
|
||||
defined, that are indexed by ``n`` (starting at 0).
|
||||
|
||||
Here is an example of a cubic B-spline:
|
||||
|
||||
>>> bspline_basis(3, tuple(range(5)), 0, x)
|
||||
Piecewise((x**3/6, (x >= 0) & (x <= 1)),
|
||||
(-x**3/2 + 2*x**2 - 2*x + 2/3,
|
||||
(x >= 1) & (x <= 2)),
|
||||
(x**3/2 - 4*x**2 + 10*x - 22/3,
|
||||
(x >= 2) & (x <= 3)),
|
||||
(-x**3/6 + 2*x**2 - 8*x + 32/3,
|
||||
(x >= 3) & (x <= 4)),
|
||||
(0, True))
|
||||
|
||||
By repeating knot points, you can introduce discontinuities in the
|
||||
B-splines and their derivatives:
|
||||
|
||||
>>> d = 1
|
||||
>>> knots = (0, 0, 2, 3, 4)
|
||||
>>> bspline_basis(d, knots, 0, x)
|
||||
Piecewise((1 - x/2, (x >= 0) & (x <= 2)), (0, True))
|
||||
|
||||
It is quite time consuming to construct and evaluate B-splines. If
|
||||
you need to evaluate a B-spline many times, it is best to lambdify them
|
||||
first:
|
||||
|
||||
>>> from sympy import lambdify
|
||||
>>> d = 3
|
||||
>>> knots = tuple(range(10))
|
||||
>>> b0 = bspline_basis(d, knots, 0, x)
|
||||
>>> f = lambdify(x, b0)
|
||||
>>> y = f(0.5)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
d : integer
|
||||
degree of bspline
|
||||
|
||||
knots : list of integer values
|
||||
list of knots points of bspline
|
||||
|
||||
n : integer
|
||||
$n$-th B-spline
|
||||
|
||||
x : symbol
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
bspline_basis_set
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/B-spline
|
||||
|
||||
"""
|
||||
# make sure x has no assumptions so conditions don't evaluate
|
||||
xvar = x
|
||||
x = Dummy()
|
||||
|
||||
knots = tuple(sympify(k) for k in knots)
|
||||
d = int(d)
|
||||
n = int(n)
|
||||
n_knots = len(knots)
|
||||
n_intervals = n_knots - 1
|
||||
if n + d + 1 > n_intervals:
|
||||
raise ValueError("n + d + 1 must not exceed len(knots) - 1")
|
||||
if d == 0:
|
||||
result = Piecewise(
|
||||
(S.One, Interval(knots[n], knots[n + 1]).contains(x)), (0, True)
|
||||
)
|
||||
elif d > 0:
|
||||
denom = knots[n + d + 1] - knots[n + 1]
|
||||
if denom != S.Zero:
|
||||
B = (knots[n + d + 1] - x) / denom
|
||||
b2 = bspline_basis(d - 1, knots, n + 1, x)
|
||||
else:
|
||||
b2 = B = S.Zero
|
||||
|
||||
denom = knots[n + d] - knots[n]
|
||||
if denom != S.Zero:
|
||||
A = (x - knots[n]) / denom
|
||||
b1 = bspline_basis(d - 1, knots, n, x)
|
||||
else:
|
||||
b1 = A = S.Zero
|
||||
|
||||
result = _add_splines(A, b1, B, b2, x)
|
||||
else:
|
||||
raise ValueError("degree must be non-negative: %r" % n)
|
||||
|
||||
# return result with user-given x
|
||||
return result.xreplace({x: xvar})
|
||||
|
||||
|
||||
def bspline_basis_set(d, knots, x):
|
||||
"""
|
||||
Return the ``len(knots)-d-1`` B-splines at *x* of degree *d*
|
||||
with *knots*.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function returns a list of piecewise polynomials that are the
|
||||
``len(knots)-d-1`` B-splines of degree *d* for the given knots.
|
||||
This function calls ``bspline_basis(d, knots, n, x)`` for different
|
||||
values of *n*.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import bspline_basis_set
|
||||
>>> from sympy.abc import x
|
||||
>>> d = 2
|
||||
>>> knots = range(5)
|
||||
>>> splines = bspline_basis_set(d, knots, x)
|
||||
>>> splines
|
||||
[Piecewise((x**2/2, (x >= 0) & (x <= 1)),
|
||||
(-x**2 + 3*x - 3/2, (x >= 1) & (x <= 2)),
|
||||
(x**2/2 - 3*x + 9/2, (x >= 2) & (x <= 3)),
|
||||
(0, True)),
|
||||
Piecewise((x**2/2 - x + 1/2, (x >= 1) & (x <= 2)),
|
||||
(-x**2 + 5*x - 11/2, (x >= 2) & (x <= 3)),
|
||||
(x**2/2 - 4*x + 8, (x >= 3) & (x <= 4)),
|
||||
(0, True))]
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
d : integer
|
||||
degree of bspline
|
||||
|
||||
knots : list of integers
|
||||
list of knots points of bspline
|
||||
|
||||
x : symbol
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
bspline_basis
|
||||
|
||||
"""
|
||||
n_splines = len(knots) - d - 1
|
||||
return [bspline_basis(d, tuple(knots), i, x) for i in range(n_splines)]
|
||||
|
||||
|
||||
def interpolating_spline(d, x, X, Y):
|
||||
"""
|
||||
Return spline of degree *d*, passing through the given *X*
|
||||
and *Y* values.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function returns a piecewise function such that each part is
|
||||
a polynomial of degree not greater than *d*. The value of *d*
|
||||
must be 1 or greater and the values of *X* must be strictly
|
||||
increasing.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import interpolating_spline
|
||||
>>> from sympy.abc import x
|
||||
>>> interpolating_spline(1, x, [1, 2, 4, 7], [3, 6, 5, 7])
|
||||
Piecewise((3*x, (x >= 1) & (x <= 2)),
|
||||
(7 - x/2, (x >= 2) & (x <= 4)),
|
||||
(2*x/3 + 7/3, (x >= 4) & (x <= 7)))
|
||||
>>> interpolating_spline(3, x, [-2, 0, 1, 3, 4], [4, 2, 1, 1, 3])
|
||||
Piecewise((7*x**3/117 + 7*x**2/117 - 131*x/117 + 2, (x >= -2) & (x <= 1)),
|
||||
(10*x**3/117 - 2*x**2/117 - 122*x/117 + 77/39, (x >= 1) & (x <= 4)))
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
d : integer
|
||||
Degree of Bspline strictly greater than equal to one
|
||||
|
||||
x : symbol
|
||||
|
||||
X : list of strictly increasing real values
|
||||
list of X coordinates through which the spline passes
|
||||
|
||||
Y : list of real values
|
||||
list of corresponding Y coordinates through which the spline passes
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
bspline_basis_set, interpolating_poly
|
||||
|
||||
"""
|
||||
from sympy.solvers.solveset import linsolve
|
||||
from sympy.matrices.dense import Matrix
|
||||
|
||||
# Input sanitization
|
||||
d = sympify(d)
|
||||
if not (d.is_Integer and d.is_positive):
|
||||
raise ValueError("Spline degree must be a positive integer, not %s." % d)
|
||||
if len(X) != len(Y):
|
||||
raise ValueError("Number of X and Y coordinates must be the same.")
|
||||
if len(X) < d + 1:
|
||||
raise ValueError("Degree must be less than the number of control points.")
|
||||
if not all(a < b for a, b in zip(X, X[1:])):
|
||||
raise ValueError("The x-coordinates must be strictly increasing.")
|
||||
X = [sympify(i) for i in X]
|
||||
|
||||
# Evaluating knots value
|
||||
if d.is_odd:
|
||||
j = (d + 1) // 2
|
||||
interior_knots = X[j:-j]
|
||||
else:
|
||||
j = d // 2
|
||||
interior_knots = [
|
||||
(a + b)/2 for a, b in zip(X[j : -j - 1], X[j + 1 : -j])
|
||||
]
|
||||
|
||||
knots = [X[0]] * (d + 1) + list(interior_knots) + [X[-1]] * (d + 1)
|
||||
|
||||
basis = bspline_basis_set(d, knots, x)
|
||||
|
||||
A = [[b.subs(x, v) for b in basis] for v in X]
|
||||
|
||||
coeff = linsolve((Matrix(A), Matrix(Y)), symbols("c0:{}".format(len(X)), cls=Dummy))
|
||||
coeff = list(coeff)[0]
|
||||
intervals = {c for b in basis for (e, c) in b.args if c != True}
|
||||
|
||||
# Sorting the intervals
|
||||
# ival contains the end-points of each interval
|
||||
intervals = sorted(intervals, key=lambda c: _ivl(c, x))
|
||||
|
||||
basis_dicts = [{c: e for (e, c) in b.args} for b in basis]
|
||||
spline = []
|
||||
for i in intervals:
|
||||
piece = sum(
|
||||
[c * d.get(i, S.Zero) for (c, d) in zip(coeff, basis_dicts)], S.Zero
|
||||
)
|
||||
spline.append((piece, i))
|
||||
return Piecewise(*spline)
|
||||
@@ -0,0 +1,664 @@
|
||||
from sympy.core import S, diff
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.logic import fuzzy_not
|
||||
from sympy.core.relational import Eq, Ne
|
||||
from sympy.functions.elementary.complexes import im, sign
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.polys.polyerrors import PolynomialError
|
||||
from sympy.polys.polyroots import roots
|
||||
from sympy.utilities.misc import filldedent
|
||||
|
||||
|
||||
###############################################################################
|
||||
################################ DELTA FUNCTION ###############################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class DiracDelta(DefinedFunction):
|
||||
r"""
|
||||
The DiracDelta function and its derivatives.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
DiracDelta is not an ordinary function. It can be rigorously defined either
|
||||
as a distribution or as a measure.
|
||||
|
||||
DiracDelta only makes sense in definite integrals, and in particular,
|
||||
integrals of the form ``Integral(f(x)*DiracDelta(x - x0), (x, a, b))``,
|
||||
where it equals ``f(x0)`` if ``a <= x0 <= b`` and ``0`` otherwise. Formally,
|
||||
DiracDelta acts in some ways like a function that is ``0`` everywhere except
|
||||
at ``0``, but in many ways it also does not. It can often be useful to treat
|
||||
DiracDelta in formal ways, building up and manipulating expressions with
|
||||
delta functions (which may eventually be integrated), but care must be taken
|
||||
to not treat it as a real function. SymPy's ``oo`` is similar. It only
|
||||
truly makes sense formally in certain contexts (such as integration limits),
|
||||
but SymPy allows its use everywhere, and it tries to be consistent with
|
||||
operations on it (like ``1/oo``), but it is easy to get into trouble and get
|
||||
wrong results if ``oo`` is treated too much like a number. Similarly, if
|
||||
DiracDelta is treated too much like a function, it is easy to get wrong or
|
||||
nonsensical results.
|
||||
|
||||
DiracDelta function has the following properties:
|
||||
|
||||
1) $\frac{d}{d x} \theta(x) = \delta(x)$
|
||||
2) $\int_{-\infty}^\infty \delta(x - a)f(x)\, dx = f(a)$ and $\int_{a-
|
||||
\epsilon}^{a+\epsilon} \delta(x - a)f(x)\, dx = f(a)$
|
||||
3) $\delta(x) = 0$ for all $x \neq 0$
|
||||
4) $\delta(g(x)) = \sum_i \frac{\delta(x - x_i)}{\|g'(x_i)\|}$ where $x_i$
|
||||
are the roots of $g$
|
||||
5) $\delta(-x) = \delta(x)$
|
||||
|
||||
Derivatives of ``k``-th order of DiracDelta have the following properties:
|
||||
|
||||
6) $\delta(x, k) = 0$ for all $x \neq 0$
|
||||
7) $\delta(-x, k) = -\delta(x, k)$ for odd $k$
|
||||
8) $\delta(-x, k) = \delta(x, k)$ for even $k$
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, diff, pi
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> DiracDelta(x)
|
||||
DiracDelta(x)
|
||||
>>> DiracDelta(1)
|
||||
0
|
||||
>>> DiracDelta(-1)
|
||||
0
|
||||
>>> DiracDelta(pi)
|
||||
0
|
||||
>>> DiracDelta(x - 4).subs(x, 4)
|
||||
DiracDelta(0)
|
||||
>>> diff(DiracDelta(x))
|
||||
DiracDelta(x, 1)
|
||||
>>> diff(DiracDelta(x - 1), x, 2)
|
||||
DiracDelta(x - 1, 2)
|
||||
>>> diff(DiracDelta(x**2 - 1), x, 2)
|
||||
2*(2*x**2*DiracDelta(x**2 - 1, 2) + DiracDelta(x**2 - 1, 1))
|
||||
>>> DiracDelta(3*x).is_simple(x)
|
||||
True
|
||||
>>> DiracDelta(x**2).is_simple(x)
|
||||
False
|
||||
>>> DiracDelta((x**2 - 1)*y).expand(diracdelta=True, wrt=x)
|
||||
DiracDelta(x - 1)/(2*Abs(y)) + DiracDelta(x + 1)/(2*Abs(y))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
Heaviside
|
||||
sympy.simplify.simplify.simplify, is_simple
|
||||
sympy.functions.special.tensor_functions.KroneckerDelta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://mathworld.wolfram.com/DeltaFunction.html
|
||||
|
||||
"""
|
||||
|
||||
is_real = True
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
"""
|
||||
Returns the first derivative of a DiracDelta Function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the
|
||||
user-level function and ``fdiff()`` is an object method. ``fdiff()`` is
|
||||
a convenience method available in the ``Function`` class. It returns
|
||||
the derivative of the function without considering the chain rule.
|
||||
``diff(function, x)`` calls ``Function._eval_derivative`` which in turn
|
||||
calls ``fdiff()`` internally to compute the derivative of the function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, diff
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> DiracDelta(x).fdiff()
|
||||
DiracDelta(x, 1)
|
||||
|
||||
>>> DiracDelta(x, 1).fdiff()
|
||||
DiracDelta(x, 2)
|
||||
|
||||
>>> DiracDelta(x**2 - 1).fdiff()
|
||||
DiracDelta(x**2 - 1, 1)
|
||||
|
||||
>>> diff(DiracDelta(x, 1)).fdiff()
|
||||
DiracDelta(x, 3)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
argindex : integer
|
||||
degree of derivative
|
||||
|
||||
"""
|
||||
if argindex == 1:
|
||||
#I didn't know if there is a better way to handle default arguments
|
||||
k = 0
|
||||
if len(self.args) > 1:
|
||||
k = self.args[1]
|
||||
return self.func(self.args[0], k + 1)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg, k=S.Zero):
|
||||
"""
|
||||
Returns a simplified form or a value of DiracDelta depending on the
|
||||
argument passed by the DiracDelta object.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The ``eval()`` method is automatically called when the ``DiracDelta``
|
||||
class is about to be instantiated and it returns either some simplified
|
||||
instance or the unevaluated instance depending on the argument passed.
|
||||
In other words, ``eval()`` method is not needed to be called explicitly,
|
||||
it is being called and evaluated once the object is called.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, S
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> DiracDelta(x)
|
||||
DiracDelta(x)
|
||||
|
||||
>>> DiracDelta(-x, 1)
|
||||
-DiracDelta(x, 1)
|
||||
|
||||
>>> DiracDelta(1)
|
||||
0
|
||||
|
||||
>>> DiracDelta(5, 1)
|
||||
0
|
||||
|
||||
>>> DiracDelta(0)
|
||||
DiracDelta(0)
|
||||
|
||||
>>> DiracDelta(-1)
|
||||
0
|
||||
|
||||
>>> DiracDelta(S.NaN)
|
||||
nan
|
||||
|
||||
>>> DiracDelta(x - 100).subs(x, 5)
|
||||
0
|
||||
|
||||
>>> DiracDelta(x - 100).subs(x, 100)
|
||||
DiracDelta(0)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
k : integer
|
||||
order of derivative
|
||||
|
||||
arg : argument passed to DiracDelta
|
||||
|
||||
"""
|
||||
if not k.is_Integer or k.is_negative:
|
||||
raise ValueError("Error: the second argument of DiracDelta must be \
|
||||
a non-negative integer, %s given instead." % (k,))
|
||||
if arg is S.NaN:
|
||||
return S.NaN
|
||||
if arg.is_nonzero:
|
||||
return S.Zero
|
||||
if fuzzy_not(im(arg).is_zero):
|
||||
raise ValueError(filldedent('''
|
||||
Function defined only for Real Values.
|
||||
Complex part: %s found in %s .''' % (
|
||||
repr(im(arg)), repr(arg))))
|
||||
c, nc = arg.args_cnc()
|
||||
if c and c[0] is S.NegativeOne:
|
||||
# keep this fast and simple instead of using
|
||||
# could_extract_minus_sign
|
||||
if k.is_odd:
|
||||
return -cls(-arg, k)
|
||||
elif k.is_even:
|
||||
return cls(-arg, k) if k else cls(-arg)
|
||||
elif k.is_zero:
|
||||
return cls(arg, evaluate=False)
|
||||
|
||||
def _eval_expand_diracdelta(self, **hints):
|
||||
"""
|
||||
Compute a simplified representation of the function using
|
||||
property number 4. Pass ``wrt`` as a hint to expand the expression
|
||||
with respect to a particular variable.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
``wrt`` is:
|
||||
|
||||
- a variable with respect to which a DiracDelta expression will
|
||||
get expanded.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> DiracDelta(x*y).expand(diracdelta=True, wrt=x)
|
||||
DiracDelta(x)/Abs(y)
|
||||
>>> DiracDelta(x*y).expand(diracdelta=True, wrt=y)
|
||||
DiracDelta(y)/Abs(x)
|
||||
|
||||
>>> DiracDelta(x**2 + x - 2).expand(diracdelta=True, wrt=x)
|
||||
DiracDelta(x - 1)/3 + DiracDelta(x + 2)/3
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_simple, Diracdelta
|
||||
|
||||
"""
|
||||
wrt = hints.get('wrt', None)
|
||||
if wrt is None:
|
||||
free = self.free_symbols
|
||||
if len(free) == 1:
|
||||
wrt = free.pop()
|
||||
else:
|
||||
raise TypeError(filldedent('''
|
||||
When there is more than 1 free symbol or variable in the expression,
|
||||
the 'wrt' keyword is required as a hint to expand when using the
|
||||
DiracDelta hint.'''))
|
||||
|
||||
if not self.args[0].has(wrt) or (len(self.args) > 1 and self.args[1] != 0 ):
|
||||
return self
|
||||
try:
|
||||
argroots = roots(self.args[0], wrt)
|
||||
result = 0
|
||||
valid = True
|
||||
darg = abs(diff(self.args[0], wrt))
|
||||
for r, m in argroots.items():
|
||||
if r.is_real is not False and m == 1:
|
||||
result += self.func(wrt - r)/darg.subs(wrt, r)
|
||||
else:
|
||||
# don't handle non-real and if m != 1 then
|
||||
# a polynomial will have a zero in the derivative (darg)
|
||||
# at r
|
||||
valid = False
|
||||
break
|
||||
if valid:
|
||||
return result
|
||||
except PolynomialError:
|
||||
pass
|
||||
return self
|
||||
|
||||
def is_simple(self, x):
|
||||
"""
|
||||
Tells whether the argument(args[0]) of DiracDelta is a linear
|
||||
expression in *x*.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, cos
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> DiracDelta(x*y).is_simple(x)
|
||||
True
|
||||
>>> DiracDelta(x*y).is_simple(y)
|
||||
True
|
||||
|
||||
>>> DiracDelta(x**2 + x - 2).is_simple(x)
|
||||
False
|
||||
|
||||
>>> DiracDelta(cos(x)).is_simple(x)
|
||||
False
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
x : can be a symbol
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.simplify.simplify.simplify, DiracDelta
|
||||
|
||||
"""
|
||||
p = self.args[0].as_poly(x)
|
||||
if p:
|
||||
return p.degree() == 1
|
||||
return False
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
|
||||
"""
|
||||
Represents DiracDelta in a piecewise form.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, Piecewise, Symbol
|
||||
>>> x = Symbol('x')
|
||||
|
||||
>>> DiracDelta(x).rewrite(Piecewise)
|
||||
Piecewise((DiracDelta(0), Eq(x, 0)), (0, True))
|
||||
|
||||
>>> DiracDelta(x - 5).rewrite(Piecewise)
|
||||
Piecewise((DiracDelta(0), Eq(x, 5)), (0, True))
|
||||
|
||||
>>> DiracDelta(x**2 - 5).rewrite(Piecewise)
|
||||
Piecewise((DiracDelta(0), Eq(x**2, 5)), (0, True))
|
||||
|
||||
>>> DiracDelta(x - 5, 4).rewrite(Piecewise)
|
||||
DiracDelta(x - 5, 4)
|
||||
|
||||
"""
|
||||
if len(args) == 1:
|
||||
return Piecewise((DiracDelta(0), Eq(args[0], 0)), (0, True))
|
||||
|
||||
def _eval_rewrite_as_SingularityFunction(self, *args, **kwargs):
|
||||
"""
|
||||
Returns the DiracDelta expression written in the form of Singularity
|
||||
Functions.
|
||||
|
||||
"""
|
||||
from sympy.solvers import solve
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
if self == DiracDelta(0):
|
||||
return SingularityFunction(0, 0, -1)
|
||||
if self == DiracDelta(0, 1):
|
||||
return SingularityFunction(0, 0, -2)
|
||||
free = self.free_symbols
|
||||
if len(free) == 1:
|
||||
x = (free.pop())
|
||||
if len(args) == 1:
|
||||
return SingularityFunction(x, solve(args[0], x)[0], -1)
|
||||
return SingularityFunction(x, solve(args[0], x)[0], -args[1] - 1)
|
||||
else:
|
||||
# I don't know how to handle the case for DiracDelta expressions
|
||||
# having arguments with more than one variable.
|
||||
raise TypeError(filldedent('''
|
||||
rewrite(SingularityFunction) does not support
|
||||
arguments with more that one variable.'''))
|
||||
|
||||
|
||||
###############################################################################
|
||||
############################## HEAVISIDE FUNCTION #############################
|
||||
###############################################################################
|
||||
|
||||
|
||||
class Heaviside(DefinedFunction):
|
||||
r"""
|
||||
Heaviside step function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Heaviside step function has the following properties:
|
||||
|
||||
1) $\frac{d}{d x} \theta(x) = \delta(x)$
|
||||
2) $\theta(x) = \begin{cases} 0 & \text{for}\: x < 0 \\ \frac{1}{2} &
|
||||
\text{for}\: x = 0 \\1 & \text{for}\: x > 0 \end{cases}$
|
||||
3) $\frac{d}{d x} \max(x, 0) = \theta(x)$
|
||||
|
||||
Heaviside(x) is printed as $\theta(x)$ with the SymPy LaTeX printer.
|
||||
|
||||
The value at 0 is set differently in different fields. SymPy uses 1/2,
|
||||
which is a convention from electronics and signal processing, and is
|
||||
consistent with solving improper integrals by Fourier transform and
|
||||
convolution.
|
||||
|
||||
To specify a different value of Heaviside at ``x=0``, a second argument
|
||||
can be given. Using ``Heaviside(x, nan)`` gives an expression that will
|
||||
evaluate to nan for x=0.
|
||||
|
||||
.. versionchanged:: 1.9 ``Heaviside(0)`` now returns 1/2 (before: undefined)
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, nan
|
||||
>>> from sympy.abc import x
|
||||
>>> Heaviside(9)
|
||||
1
|
||||
>>> Heaviside(-9)
|
||||
0
|
||||
>>> Heaviside(0)
|
||||
1/2
|
||||
>>> Heaviside(0, nan)
|
||||
nan
|
||||
>>> (Heaviside(x) + 1).replace(Heaviside(x), Heaviside(x, 1))
|
||||
Heaviside(x, 1) + 1
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
DiracDelta
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://mathworld.wolfram.com/HeavisideStepFunction.html
|
||||
.. [2] https://dlmf.nist.gov/1.16#iv
|
||||
|
||||
"""
|
||||
|
||||
is_real = True
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
"""
|
||||
Returns the first derivative of a Heaviside Function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, diff
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> Heaviside(x).fdiff()
|
||||
DiracDelta(x)
|
||||
|
||||
>>> Heaviside(x**2 - 1).fdiff()
|
||||
DiracDelta(x**2 - 1)
|
||||
|
||||
>>> diff(Heaviside(x)).fdiff()
|
||||
DiracDelta(x, 1)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
argindex : integer
|
||||
order of derivative
|
||||
|
||||
"""
|
||||
if argindex == 1:
|
||||
return DiracDelta(self.args[0])
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def __new__(cls, arg, H0=S.Half, **options):
|
||||
if isinstance(H0, Heaviside) and len(H0.args) == 1:
|
||||
H0 = S.Half
|
||||
return super(cls, cls).__new__(cls, arg, H0, **options)
|
||||
|
||||
@property
|
||||
def pargs(self):
|
||||
"""Args without default S.Half"""
|
||||
args = self.args
|
||||
if args[1] is S.Half:
|
||||
args = args[:1]
|
||||
return args
|
||||
|
||||
@classmethod
|
||||
def eval(cls, arg, H0=S.Half):
|
||||
"""
|
||||
Returns a simplified form or a value of Heaviside depending on the
|
||||
argument passed by the Heaviside object.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The ``eval()`` method is automatically called when the ``Heaviside``
|
||||
class is about to be instantiated and it returns either some simplified
|
||||
instance or the unevaluated instance depending on the argument passed.
|
||||
In other words, ``eval()`` method is not needed to be called explicitly,
|
||||
it is being called and evaluated once the object is called.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, S
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> Heaviside(x)
|
||||
Heaviside(x)
|
||||
|
||||
>>> Heaviside(19)
|
||||
1
|
||||
|
||||
>>> Heaviside(0)
|
||||
1/2
|
||||
|
||||
>>> Heaviside(0, 1)
|
||||
1
|
||||
|
||||
>>> Heaviside(-5)
|
||||
0
|
||||
|
||||
>>> Heaviside(S.NaN)
|
||||
nan
|
||||
|
||||
>>> Heaviside(x - 100).subs(x, 5)
|
||||
0
|
||||
|
||||
>>> Heaviside(x - 100).subs(x, 105)
|
||||
1
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
arg : argument passed by Heaviside object
|
||||
|
||||
H0 : value of Heaviside(0)
|
||||
|
||||
"""
|
||||
if arg.is_extended_negative:
|
||||
return S.Zero
|
||||
elif arg.is_extended_positive:
|
||||
return S.One
|
||||
elif arg.is_zero:
|
||||
return H0
|
||||
elif arg is S.NaN:
|
||||
return S.NaN
|
||||
elif fuzzy_not(im(arg).is_zero):
|
||||
raise ValueError("Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)) )
|
||||
|
||||
def _eval_rewrite_as_Piecewise(self, arg, H0=None, **kwargs):
|
||||
"""
|
||||
Represents Heaviside in a Piecewise form.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, Piecewise, Symbol, nan
|
||||
>>> x = Symbol('x')
|
||||
|
||||
>>> Heaviside(x).rewrite(Piecewise)
|
||||
Piecewise((0, x < 0), (1/2, Eq(x, 0)), (1, True))
|
||||
|
||||
>>> Heaviside(x,nan).rewrite(Piecewise)
|
||||
Piecewise((0, x < 0), (nan, Eq(x, 0)), (1, True))
|
||||
|
||||
>>> Heaviside(x - 5).rewrite(Piecewise)
|
||||
Piecewise((0, x < 5), (1/2, Eq(x, 5)), (1, True))
|
||||
|
||||
>>> Heaviside(x**2 - 1).rewrite(Piecewise)
|
||||
Piecewise((0, x**2 < 1), (1/2, Eq(x**2, 1)), (1, True))
|
||||
|
||||
"""
|
||||
if H0 == 0:
|
||||
return Piecewise((0, arg <= 0), (1, True))
|
||||
if H0 == 1:
|
||||
return Piecewise((0, arg < 0), (1, True))
|
||||
return Piecewise((0, arg < 0), (H0, Eq(arg, 0)), (1, True))
|
||||
|
||||
def _eval_rewrite_as_sign(self, arg, H0=S.Half, **kwargs):
|
||||
"""
|
||||
Represents the Heaviside function in the form of sign function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The value of Heaviside(0) must be 1/2 for rewriting as sign to be
|
||||
strictly equivalent. For easier usage, we also allow this rewriting
|
||||
when Heaviside(0) is undefined.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Heaviside, Symbol, sign, nan
|
||||
>>> x = Symbol('x', real=True)
|
||||
>>> y = Symbol('y')
|
||||
|
||||
>>> Heaviside(x).rewrite(sign)
|
||||
sign(x)/2 + 1/2
|
||||
|
||||
>>> Heaviside(x, 0).rewrite(sign)
|
||||
Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (0, True))
|
||||
|
||||
>>> Heaviside(x, nan).rewrite(sign)
|
||||
Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (nan, True))
|
||||
|
||||
>>> Heaviside(x - 2).rewrite(sign)
|
||||
sign(x - 2)/2 + 1/2
|
||||
|
||||
>>> Heaviside(x**2 - 2*x + 1).rewrite(sign)
|
||||
sign(x**2 - 2*x + 1)/2 + 1/2
|
||||
|
||||
>>> Heaviside(y).rewrite(sign)
|
||||
Heaviside(y)
|
||||
|
||||
>>> Heaviside(y**2 - 2*y + 1).rewrite(sign)
|
||||
Heaviside(y**2 - 2*y + 1)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sign
|
||||
|
||||
"""
|
||||
if arg.is_extended_real:
|
||||
pw1 = Piecewise(
|
||||
((sign(arg) + 1)/2, Ne(arg, 0)),
|
||||
(Heaviside(0, H0=H0), True))
|
||||
pw2 = Piecewise(
|
||||
((sign(arg) + 1)/2, Eq(Heaviside(0, H0=H0), S.Half)),
|
||||
(pw1, True))
|
||||
return pw2
|
||||
|
||||
def _eval_rewrite_as_SingularityFunction(self, args, H0=S.Half, **kwargs):
|
||||
"""
|
||||
Returns the Heaviside expression written in the form of Singularity
|
||||
Functions.
|
||||
|
||||
"""
|
||||
from sympy.solvers import solve
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
if self == Heaviside(0):
|
||||
return SingularityFunction(0, 0, 0)
|
||||
free = self.free_symbols
|
||||
if len(free) == 1:
|
||||
x = (free.pop())
|
||||
return SingularityFunction(x, solve(args, x)[0], 0)
|
||||
# TODO
|
||||
# ((x - 5)**3*Heaviside(x - 5)).rewrite(SingularityFunction) should output
|
||||
# SingularityFunction(x, 5, 0) instead of (x - 5)**3*SingularityFunction(x, 5, 0)
|
||||
else:
|
||||
# I don't know how to handle the case for Heaviside expressions
|
||||
# having arguments with more than one variable.
|
||||
raise TypeError(filldedent('''
|
||||
rewrite(SingularityFunction) does not
|
||||
support arguments with more that one variable.'''))
|
||||
@@ -0,0 +1,445 @@
|
||||
""" Elliptic Integrals. """
|
||||
|
||||
from sympy.core import S, pi, I, Rational
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.core.symbol import Dummy,uniquely_named_symbol
|
||||
from sympy.functions.elementary.complexes import sign
|
||||
from sympy.functions.elementary.hyperbolic import atanh
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import sin, tan
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.functions.special.hyper import hyper, meijerg
|
||||
|
||||
class elliptic_k(DefinedFunction):
|
||||
r"""
|
||||
The complete elliptic integral of the first kind, defined by
|
||||
|
||||
.. math:: K(m) = F\left(\tfrac{\pi}{2}\middle| m\right)
|
||||
|
||||
where $F\left(z\middle| m\right)$ is the Legendre incomplete
|
||||
elliptic integral of the first kind.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The function $K(m)$ is a single-valued function on the complex
|
||||
plane with branch cut along the interval $(1, \infty)$.
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_k, I
|
||||
>>> from sympy.abc import m
|
||||
>>> elliptic_k(0)
|
||||
pi/2
|
||||
>>> elliptic_k(1.0 + I)
|
||||
1.50923695405127 + 0.625146415202697*I
|
||||
>>> elliptic_k(m).series(n=3)
|
||||
pi/2 + pi*m/8 + 9*pi*m**2/128 + O(m**3)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
elliptic_f
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticK
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, m):
|
||||
if m.is_zero:
|
||||
return pi*S.Half
|
||||
elif m is S.Half:
|
||||
return 8*pi**Rational(3, 2)/gamma(Rational(-1, 4))**2
|
||||
elif m is S.One:
|
||||
return S.ComplexInfinity
|
||||
elif m is S.NegativeOne:
|
||||
return gamma(Rational(1, 4))**2/(4*sqrt(2*pi))
|
||||
elif m in (S.Infinity, S.NegativeInfinity, I*S.Infinity,
|
||||
I*S.NegativeInfinity, S.ComplexInfinity):
|
||||
return S.Zero
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
m = self.args[0]
|
||||
return (elliptic_e(m) - (1 - m)*elliptic_k(m))/(2*m*(1 - m))
|
||||
|
||||
def _eval_conjugate(self):
|
||||
m = self.args[0]
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(m.conjugate())
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
from sympy.simplify import hyperexpand
|
||||
return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx))
|
||||
|
||||
def _eval_rewrite_as_hyper(self, m, **kwargs):
|
||||
return pi*S.Half*hyper((S.Half, S.Half), (S.One,), m)
|
||||
|
||||
def _eval_rewrite_as_meijerg(self, m, **kwargs):
|
||||
return meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -m)/2
|
||||
|
||||
def _eval_is_zero(self):
|
||||
m = self.args[0]
|
||||
if m.is_infinite:
|
||||
return True
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
m = self.args[0]
|
||||
return Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, pi/2))
|
||||
|
||||
|
||||
class elliptic_f(DefinedFunction):
|
||||
r"""
|
||||
The Legendre incomplete elliptic integral of the first
|
||||
kind, defined by
|
||||
|
||||
.. math:: F\left(z\middle| m\right) =
|
||||
\int_0^z \frac{dt}{\sqrt{1 - m \sin^2 t}}
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function reduces to a complete elliptic integral of
|
||||
the first kind, $K(m)$, when $z = \pi/2$.
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_f, I
|
||||
>>> from sympy.abc import z, m
|
||||
>>> elliptic_f(z, m).series(z)
|
||||
z + z**5*(3*m**2/40 - m/30) + m*z**3/6 + O(z**6)
|
||||
>>> elliptic_f(3.0 + I/2, 1.0 + I)
|
||||
2.909449841483 + 1.74720545502474*I
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
elliptic_k
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticF
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, z, m):
|
||||
if z.is_zero:
|
||||
return S.Zero
|
||||
if m.is_zero:
|
||||
return z
|
||||
k = 2*z/pi
|
||||
if k.is_integer:
|
||||
return k*elliptic_k(m)
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif z.could_extract_minus_sign():
|
||||
return -elliptic_f(-z, m)
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
z, m = self.args
|
||||
fm = sqrt(1 - m*sin(z)**2)
|
||||
if argindex == 1:
|
||||
return 1/fm
|
||||
elif argindex == 2:
|
||||
return (elliptic_e(z, m)/(2*m*(1 - m)) - elliptic_f(z, m)/(2*m) -
|
||||
sin(2*z)/(4*(1 - m)*fm))
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_conjugate(self):
|
||||
z, m = self.args
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(z.conjugate(), m.conjugate())
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
z, m = self.args[0], self.args[1]
|
||||
return Integral(1/(sqrt(1 - m*sin(t)**2)), (t, 0, z))
|
||||
|
||||
def _eval_is_zero(self):
|
||||
z, m = self.args
|
||||
if z.is_zero:
|
||||
return True
|
||||
if m.is_extended_real and m.is_infinite:
|
||||
return True
|
||||
|
||||
|
||||
class elliptic_e(DefinedFunction):
|
||||
r"""
|
||||
Called with two arguments $z$ and $m$, evaluates the
|
||||
incomplete elliptic integral of the second kind, defined by
|
||||
|
||||
.. math:: E\left(z\middle| m\right) = \int_0^z \sqrt{1 - m \sin^2 t} dt
|
||||
|
||||
Called with a single argument $m$, evaluates the Legendre complete
|
||||
elliptic integral of the second kind
|
||||
|
||||
.. math:: E(m) = E\left(\tfrac{\pi}{2}\middle| m\right)
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The function $E(m)$ is a single-valued function on the complex
|
||||
plane with branch cut along the interval $(1, \infty)$.
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_e, I
|
||||
>>> from sympy.abc import z, m
|
||||
>>> elliptic_e(z, m).series(z)
|
||||
z + z**5*(-m**2/40 + m/30) - m*z**3/6 + O(z**6)
|
||||
>>> elliptic_e(m).series(n=4)
|
||||
pi/2 - pi*m/8 - 3*pi*m**2/128 - 5*pi*m**3/512 + O(m**4)
|
||||
>>> elliptic_e(1 + I, 2 - I/2).n()
|
||||
1.55203744279187 + 0.290764986058437*I
|
||||
>>> elliptic_e(0)
|
||||
pi/2
|
||||
>>> elliptic_e(2.0 - I)
|
||||
0.991052601328069 + 0.81879421395609*I
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticE2
|
||||
.. [3] https://functions.wolfram.com/EllipticIntegrals/EllipticE
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, m, z=None):
|
||||
if z is not None:
|
||||
z, m = m, z
|
||||
k = 2*z/pi
|
||||
if m.is_zero:
|
||||
return z
|
||||
if z.is_zero:
|
||||
return S.Zero
|
||||
elif k.is_integer:
|
||||
return k*elliptic_e(m)
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.ComplexInfinity
|
||||
elif z.could_extract_minus_sign():
|
||||
return -elliptic_e(-z, m)
|
||||
else:
|
||||
if m.is_zero:
|
||||
return pi/2
|
||||
elif m is S.One:
|
||||
return S.One
|
||||
elif m is S.Infinity:
|
||||
return I*S.Infinity
|
||||
elif m is S.NegativeInfinity:
|
||||
return S.Infinity
|
||||
elif m is S.ComplexInfinity:
|
||||
return S.ComplexInfinity
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if len(self.args) == 2:
|
||||
z, m = self.args
|
||||
if argindex == 1:
|
||||
return sqrt(1 - m*sin(z)**2)
|
||||
elif argindex == 2:
|
||||
return (elliptic_e(z, m) - elliptic_f(z, m))/(2*m)
|
||||
else:
|
||||
m = self.args[0]
|
||||
if argindex == 1:
|
||||
return (elliptic_e(m) - elliptic_k(m))/(2*m)
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_conjugate(self):
|
||||
if len(self.args) == 2:
|
||||
z, m = self.args
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(z.conjugate(), m.conjugate())
|
||||
else:
|
||||
m = self.args[0]
|
||||
if (m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(m.conjugate())
|
||||
|
||||
def _eval_nseries(self, x, n, logx, cdir=0):
|
||||
from sympy.simplify import hyperexpand
|
||||
if len(self.args) == 1:
|
||||
return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx))
|
||||
return super()._eval_nseries(x, n=n, logx=logx)
|
||||
|
||||
def _eval_rewrite_as_hyper(self, *args, **kwargs):
|
||||
if len(args) == 1:
|
||||
m = args[0]
|
||||
return (pi/2)*hyper((Rational(-1, 2), S.Half), (S.One,), m)
|
||||
|
||||
def _eval_rewrite_as_meijerg(self, *args, **kwargs):
|
||||
if len(args) == 1:
|
||||
m = args[0]
|
||||
return -meijerg(((S.Half, Rational(3, 2)), []), \
|
||||
((S.Zero,), (S.Zero,)), -m)/4
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
z, m = (pi/2, self.args[0]) if len(self.args) == 1 else self.args
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
return Integral(sqrt(1 - m*sin(t)**2), (t, 0, z))
|
||||
|
||||
|
||||
class elliptic_pi(DefinedFunction):
|
||||
r"""
|
||||
Called with three arguments $n$, $z$ and $m$, evaluates the
|
||||
Legendre incomplete elliptic integral of the third kind, defined by
|
||||
|
||||
.. math:: \Pi\left(n; z\middle| m\right) = \int_0^z \frac{dt}
|
||||
{\left(1 - n \sin^2 t\right) \sqrt{1 - m \sin^2 t}}
|
||||
|
||||
Called with two arguments $n$ and $m$, evaluates the complete
|
||||
elliptic integral of the third kind:
|
||||
|
||||
.. math:: \Pi\left(n\middle| m\right) =
|
||||
\Pi\left(n; \tfrac{\pi}{2}\middle| m\right)
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Note that our notation defines the incomplete elliptic integral
|
||||
in terms of the parameter $m$ instead of the elliptic modulus
|
||||
(eccentricity) $k$.
|
||||
In this case, the parameter $m$ is defined as $m=k^2$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import elliptic_pi, I
|
||||
>>> from sympy.abc import z, n, m
|
||||
>>> elliptic_pi(n, z, m).series(z, n=4)
|
||||
z + z**3*(m/6 + n/3) + O(z**4)
|
||||
>>> elliptic_pi(0.5 + I, 1.0 - I, 1.2)
|
||||
2.50232379629182 - 0.760939574180767*I
|
||||
>>> elliptic_pi(0, 0)
|
||||
pi/2
|
||||
>>> elliptic_pi(1.0 - I/3, 2.0 + I)
|
||||
3.29136443417283 + 0.32555634906645*I
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Elliptic_integrals
|
||||
.. [2] https://functions.wolfram.com/EllipticIntegrals/EllipticPi3
|
||||
.. [3] https://functions.wolfram.com/EllipticIntegrals/EllipticPi
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, n, m, z=None):
|
||||
if z is not None:
|
||||
z, m = m, z
|
||||
if n.is_zero:
|
||||
return elliptic_f(z, m)
|
||||
elif n is S.One:
|
||||
return (elliptic_f(z, m) +
|
||||
(sqrt(1 - m*sin(z)**2)*tan(z) -
|
||||
elliptic_e(z, m))/(1 - m))
|
||||
k = 2*z/pi
|
||||
if k.is_integer:
|
||||
return k*elliptic_pi(n, m)
|
||||
elif m.is_zero:
|
||||
return atanh(sqrt(n - 1)*tan(z))/sqrt(n - 1)
|
||||
elif n == m:
|
||||
return (elliptic_f(z, n) - elliptic_pi(1, z, n) +
|
||||
tan(z)/sqrt(1 - n*sin(z)**2))
|
||||
elif n in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif z.could_extract_minus_sign():
|
||||
return -elliptic_pi(n, -z, m)
|
||||
if n.is_zero:
|
||||
return elliptic_f(z, m)
|
||||
if m.is_extended_real and m.is_infinite or \
|
||||
n.is_extended_real and n.is_infinite:
|
||||
return S.Zero
|
||||
else:
|
||||
if n.is_zero:
|
||||
return elliptic_k(m)
|
||||
elif n is S.One:
|
||||
return S.ComplexInfinity
|
||||
elif m.is_zero:
|
||||
return pi/(2*sqrt(1 - n))
|
||||
elif m == S.One:
|
||||
return S.NegativeInfinity/sign(n - 1)
|
||||
elif n == m:
|
||||
return elliptic_e(n)/(1 - n)
|
||||
elif n in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
elif m in (S.Infinity, S.NegativeInfinity):
|
||||
return S.Zero
|
||||
if n.is_zero:
|
||||
return elliptic_k(m)
|
||||
if m.is_extended_real and m.is_infinite or \
|
||||
n.is_extended_real and n.is_infinite:
|
||||
return S.Zero
|
||||
|
||||
def _eval_conjugate(self):
|
||||
if len(self.args) == 3:
|
||||
n, z, m = self.args
|
||||
if (n.is_real and (n - 1).is_positive) is False and \
|
||||
(m.is_real and (m - 1).is_positive) is False:
|
||||
return self.func(n.conjugate(), z.conjugate(), m.conjugate())
|
||||
else:
|
||||
n, m = self.args
|
||||
return self.func(n.conjugate(), m.conjugate())
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if len(self.args) == 3:
|
||||
n, z, m = self.args
|
||||
fm, fn = sqrt(1 - m*sin(z)**2), 1 - n*sin(z)**2
|
||||
if argindex == 1:
|
||||
return (elliptic_e(z, m) + (m - n)*elliptic_f(z, m)/n +
|
||||
(n**2 - m)*elliptic_pi(n, z, m)/n -
|
||||
n*fm*sin(2*z)/(2*fn))/(2*(m - n)*(n - 1))
|
||||
elif argindex == 2:
|
||||
return 1/(fm*fn)
|
||||
elif argindex == 3:
|
||||
return (elliptic_e(z, m)/(m - 1) +
|
||||
elliptic_pi(n, z, m) -
|
||||
m*sin(2*z)/(2*(m - 1)*fm))/(2*(n - m))
|
||||
else:
|
||||
n, m = self.args
|
||||
if argindex == 1:
|
||||
return (elliptic_e(m) + (m - n)*elliptic_k(m)/n +
|
||||
(n**2 - m)*elliptic_pi(n, m)/n)/(2*(m - n)*(n - 1))
|
||||
elif argindex == 2:
|
||||
return (elliptic_e(m)/(m - 1) + elliptic_pi(n, m))/(2*(n - m))
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
def _eval_rewrite_as_Integral(self, *args, **kwargs):
|
||||
from sympy.integrals.integrals import Integral
|
||||
if len(self.args) == 2:
|
||||
n, m, z = self.args[0], self.args[1], pi/2
|
||||
else:
|
||||
n, z, m = self.args
|
||||
t = Dummy(uniquely_named_symbol('t', args).name)
|
||||
return Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, z))
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,269 @@
|
||||
""" This module contains the Mathieu functions.
|
||||
"""
|
||||
|
||||
from sympy.core.function import DefinedFunction, ArgumentIndexError
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import sin, cos
|
||||
|
||||
|
||||
class MathieuBase(DefinedFunction):
|
||||
"""
|
||||
Abstract base class for Mathieu functions.
|
||||
|
||||
This class is meant to reduce code duplication.
|
||||
|
||||
"""
|
||||
|
||||
unbranched = True
|
||||
|
||||
def _eval_conjugate(self):
|
||||
a, q, z = self.args
|
||||
return self.func(a.conjugate(), q.conjugate(), z.conjugate())
|
||||
|
||||
|
||||
class mathieus(MathieuBase):
|
||||
r"""
|
||||
The Mathieu Sine function $S(a,q,z)$.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Cosine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieus
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieus(a, q, z)
|
||||
mathieus(a, q, z)
|
||||
|
||||
>>> mathieus(a, 0, z)
|
||||
sin(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieus(a, q, z), z)
|
||||
mathieusprime(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieuc: Mathieu cosine function.
|
||||
mathieusprime: Derivative of Mathieu sine function.
|
||||
mathieucprime: Derivative of Mathieu cosine function.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuS/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return mathieusprime(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return sin(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return -cls(a, q, -z)
|
||||
|
||||
|
||||
class mathieuc(MathieuBase):
|
||||
r"""
|
||||
The Mathieu Cosine function $C(a,q,z)$.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Sine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieuc
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieuc(a, q, z)
|
||||
mathieuc(a, q, z)
|
||||
|
||||
>>> mathieuc(a, 0, z)
|
||||
cos(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieuc(a, q, z), z)
|
||||
mathieucprime(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieus: Mathieu sine function
|
||||
mathieusprime: Derivative of Mathieu sine function
|
||||
mathieucprime: Derivative of Mathieu cosine function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuC/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return mathieucprime(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return cos(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return cls(a, q, -z)
|
||||
|
||||
|
||||
class mathieusprime(MathieuBase):
|
||||
r"""
|
||||
The derivative $S^{\prime}(a,q,z)$ of the Mathieu Sine function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Cosine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieusprime
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieusprime(a, q, z)
|
||||
mathieusprime(a, q, z)
|
||||
|
||||
>>> mathieusprime(a, 0, z)
|
||||
sqrt(a)*cos(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieusprime(a, q, z), z)
|
||||
(-a + 2*q*cos(2*z))*mathieus(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieus: Mathieu sine function
|
||||
mathieuc: Mathieu cosine function
|
||||
mathieucprime: Derivative of Mathieu cosine function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuSPrime/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return (2*q*cos(2*z) - a)*mathieus(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return sqrt(a)*cos(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return cls(a, q, -z)
|
||||
|
||||
|
||||
class mathieucprime(MathieuBase):
|
||||
r"""
|
||||
The derivative $C^{\prime}(a,q,z)$ of the Mathieu Cosine function.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This function is one solution of the Mathieu differential equation:
|
||||
|
||||
.. math ::
|
||||
y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0
|
||||
|
||||
The other solution is the Mathieu Sine function.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import diff, mathieucprime
|
||||
>>> from sympy.abc import a, q, z
|
||||
|
||||
>>> mathieucprime(a, q, z)
|
||||
mathieucprime(a, q, z)
|
||||
|
||||
>>> mathieucprime(a, 0, z)
|
||||
-sqrt(a)*sin(sqrt(a)*z)
|
||||
|
||||
>>> diff(mathieucprime(a, q, z), z)
|
||||
(-a + 2*q*cos(2*z))*mathieuc(a, q, z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
mathieus: Mathieu sine function
|
||||
mathieuc: Mathieu cosine function
|
||||
mathieusprime: Derivative of Mathieu sine function
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Mathieu_function
|
||||
.. [2] https://dlmf.nist.gov/28
|
||||
.. [3] https://mathworld.wolfram.com/MathieuFunction.html
|
||||
.. [4] https://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuCPrime/
|
||||
|
||||
"""
|
||||
|
||||
def fdiff(self, argindex=1):
|
||||
if argindex == 3:
|
||||
a, q, z = self.args
|
||||
return (2*q*cos(2*z) - a)*mathieuc(a, q, z)
|
||||
else:
|
||||
raise ArgumentIndexError(self, argindex)
|
||||
|
||||
@classmethod
|
||||
def eval(cls, a, q, z):
|
||||
if q.is_Number and q.is_zero:
|
||||
return -sqrt(a)*sin(sqrt(a)*z)
|
||||
# Try to pull out factors of -1
|
||||
if z.could_extract_minus_sign():
|
||||
return -cls(a, q, -z)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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))
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user