Traktor/myenv/Lib/site-packages/sympy/functions/special/beta_functions.py
2024-05-26 05:12:46 +02:00

390 lines
12 KiB
Python

from sympy.core import S
from sympy.core.function import Function, ArgumentIndexError
from sympy.core.symbol import Dummy
from sympy.functions.special.gamma_functions import gamma, digamma
from sympy.functions.combinatorial.numbers import catalan
from sympy.functions.elementary.complexes import conjugate
# See mpmath #569 and SymPy #20569
def betainc_mpmath_fix(a, b, x1, x2, reg=0):
from mpmath import betainc, mpf
if x1 == x2:
return mpf(0)
else:
return betainc(a, b, x1, x2, reg)
###############################################################################
############################ COMPLETE BETA FUNCTION ##########################
###############################################################################
class beta(Function):
r"""
The beta integral is called the Eulerian integral of the first kind by
Legendre:
.. math::
\mathrm{B}(x,y) \int^{1}_{0} t^{x-1} (1-t)^{y-1} \mathrm{d}t.
Explanation
===========
The Beta function or Euler's first integral is closely associated
with the gamma function. The Beta function is often used in probability
theory and mathematical statistics. It satisfies properties like:
.. math::
\mathrm{B}(a,1) = \frac{1}{a} \\
\mathrm{B}(a,b) = \mathrm{B}(b,a) \\
\mathrm{B}(a,b) = \frac{\Gamma(a) \Gamma(b)}{\Gamma(a+b)}
Therefore for integral values of $a$ and $b$:
.. math::
\mathrm{B} = \frac{(a-1)! (b-1)!}{(a+b-1)!}
A special case of the Beta function when `x = y` is the
Central Beta function. It satisfies properties like:
.. math::
\mathrm{B}(x) = 2^{1 - 2x}\mathrm{B}(x, \frac{1}{2})
\mathrm{B}(x) = 2^{1 - 2x} cos(\pi x) \mathrm{B}(\frac{1}{2} - x, x)
\mathrm{B}(x) = \int_{0}^{1} \frac{t^x}{(1 + t)^{2x}} dt
\mathrm{B}(x) = \frac{2}{x} \prod_{n = 1}^{\infty} \frac{n(n + 2x)}{(n + x)^2}
Examples
========
>>> from sympy import I, pi
>>> from sympy.abc import x, y
The Beta function obeys the mirror symmetry:
>>> from sympy import beta, conjugate
>>> conjugate(beta(x, y))
beta(conjugate(x), conjugate(y))
Differentiation with respect to both $x$ and $y$ is supported:
>>> from sympy import beta, diff
>>> diff(beta(x, y), x)
(polygamma(0, x) - polygamma(0, x + y))*beta(x, y)
>>> diff(beta(x, y), y)
(polygamma(0, y) - polygamma(0, x + y))*beta(x, y)
>>> diff(beta(x), x)
2*(polygamma(0, x) - polygamma(0, 2*x))*beta(x, x)
We can numerically evaluate the Beta function to
arbitrary precision for any complex numbers x and y:
>>> from sympy import beta
>>> beta(pi).evalf(40)
0.02671848900111377452242355235388489324562
>>> beta(1 + I).evalf(20)
-0.2112723729365330143 - 0.7655283165378005676*I
See Also
========
gamma: Gamma function.
uppergamma: Upper incomplete gamma function.
lowergamma: Lower incomplete gamma function.
polygamma: Polygamma function.
loggamma: Log Gamma function.
digamma: Digamma function.
trigamma: Trigamma function.
References
==========
.. [1] https://en.wikipedia.org/wiki/Beta_function
.. [2] https://mathworld.wolfram.com/BetaFunction.html
.. [3] https://dlmf.nist.gov/5.12
"""
unbranched = True
def fdiff(self, argindex):
x, y = self.args
if argindex == 1:
# Diff wrt x
return beta(x, y)*(digamma(x) - digamma(x + y))
elif argindex == 2:
# Diff wrt y
return beta(x, y)*(digamma(y) - digamma(x + y))
else:
raise ArgumentIndexError(self, argindex)
@classmethod
def eval(cls, x, y=None):
if y is None:
return beta(x, x)
if x.is_Number and y.is_Number:
return beta(x, y, evaluate=False).doit()
def doit(self, **hints):
x = xold = self.args[0]
# Deal with unevaluated single argument beta
single_argument = len(self.args) == 1
y = yold = self.args[0] if single_argument else self.args[1]
if hints.get('deep', True):
x = x.doit(**hints)
y = y.doit(**hints)
if y.is_zero or x.is_zero:
return S.ComplexInfinity
if y is S.One:
return 1/x
if x is S.One:
return 1/y
if y == x + 1:
return 1/(x*y*catalan(x))
s = x + y
if (s.is_integer and s.is_negative and x.is_integer is False and
y.is_integer is False):
return S.Zero
if x == xold and y == yold and not single_argument:
return self
return beta(x, y)
def _eval_expand_func(self, **hints):
x, y = self.args
return gamma(x)*gamma(y) / gamma(x + y)
def _eval_is_real(self):
return self.args[0].is_real and self.args[1].is_real
def _eval_conjugate(self):
return self.func(self.args[0].conjugate(), self.args[1].conjugate())
def _eval_rewrite_as_gamma(self, x, y, piecewise=True, **kwargs):
return self._eval_expand_func(**kwargs)
def _eval_rewrite_as_Integral(self, x, y, **kwargs):
from sympy.integrals.integrals import Integral
t = Dummy('t')
return Integral(t**(x - 1)*(1 - t)**(y - 1), (t, 0, 1))
###############################################################################
########################## INCOMPLETE BETA FUNCTION ###########################
###############################################################################
class betainc(Function):
r"""
The Generalized Incomplete Beta function is defined as
.. math::
\mathrm{B}_{(x_1, x_2)}(a, b) = \int_{x_1}^{x_2} t^{a - 1} (1 - t)^{b - 1} dt
The Incomplete Beta function is a special case
of the Generalized Incomplete Beta function :
.. math:: \mathrm{B}_z (a, b) = \mathrm{B}_{(0, z)}(a, b)
The Incomplete Beta function satisfies :
.. math:: \mathrm{B}_z (a, b) = (-1)^a \mathrm{B}_{\frac{z}{z - 1}} (a, 1 - a - b)
The Beta function is a special case of the Incomplete Beta function :
.. math:: \mathrm{B}(a, b) = \mathrm{B}_{1}(a, b)
Examples
========
>>> from sympy import betainc, symbols, conjugate
>>> a, b, x, x1, x2 = symbols('a b x x1 x2')
The Generalized Incomplete Beta function is given by:
>>> betainc(a, b, x1, x2)
betainc(a, b, x1, x2)
The Incomplete Beta function can be obtained as follows:
>>> betainc(a, b, 0, x)
betainc(a, b, 0, x)
The Incomplete Beta function obeys the mirror symmetry:
>>> conjugate(betainc(a, b, x1, x2))
betainc(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
We can numerically evaluate the Incomplete Beta function to
arbitrary precision for any complex numbers a, b, x1 and x2:
>>> from sympy import betainc, I
>>> betainc(2, 3, 4, 5).evalf(10)
56.08333333
>>> betainc(0.75, 1 - 4*I, 0, 2 + 3*I).evalf(25)
0.2241657956955709603655887 + 0.3619619242700451992411724*I
The Generalized Incomplete Beta function can be expressed
in terms of the Generalized Hypergeometric function.
>>> from sympy import hyper
>>> betainc(a, b, x1, x2).rewrite(hyper)
(-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/a
See Also
========
beta: Beta function
hyper: Generalized Hypergeometric function
References
==========
.. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
.. [2] https://dlmf.nist.gov/8.17
.. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
.. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
"""
nargs = 4
unbranched = True
def fdiff(self, argindex):
a, b, x1, x2 = self.args
if argindex == 3:
# Diff wrt x1
return -(1 - x1)**(b - 1)*x1**(a - 1)
elif argindex == 4:
# Diff wrt x2
return (1 - x2)**(b - 1)*x2**(a - 1)
else:
raise ArgumentIndexError(self, argindex)
def _eval_mpmath(self):
return betainc_mpmath_fix, self.args
def _eval_is_real(self):
if all(arg.is_real for arg in self.args):
return True
def _eval_conjugate(self):
return self.func(*map(conjugate, self.args))
def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
from sympy.integrals.integrals import Integral
t = Dummy('t')
return Integral(t**(a - 1)*(1 - t)**(b - 1), (t, x1, x2))
def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
from sympy.functions.special.hyper import hyper
return (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
###############################################################################
#################### REGULARIZED INCOMPLETE BETA FUNCTION #####################
###############################################################################
class betainc_regularized(Function):
r"""
The Generalized Regularized Incomplete Beta function is given by
.. math::
\mathrm{I}_{(x_1, x_2)}(a, b) = \frac{\mathrm{B}_{(x_1, x_2)}(a, b)}{\mathrm{B}(a, b)}
The Regularized Incomplete Beta function is a special case
of the Generalized Regularized Incomplete Beta function :
.. math:: \mathrm{I}_z (a, b) = \mathrm{I}_{(0, z)}(a, b)
The Regularized Incomplete Beta function is the cumulative distribution
function of the beta distribution.
Examples
========
>>> from sympy import betainc_regularized, symbols, conjugate
>>> a, b, x, x1, x2 = symbols('a b x x1 x2')
The Generalized Regularized Incomplete Beta
function is given by:
>>> betainc_regularized(a, b, x1, x2)
betainc_regularized(a, b, x1, x2)
The Regularized Incomplete Beta function
can be obtained as follows:
>>> betainc_regularized(a, b, 0, x)
betainc_regularized(a, b, 0, x)
The Regularized Incomplete Beta function
obeys the mirror symmetry:
>>> conjugate(betainc_regularized(a, b, x1, x2))
betainc_regularized(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
We can numerically evaluate the Regularized Incomplete Beta function
to arbitrary precision for any complex numbers a, b, x1 and x2:
>>> from sympy import betainc_regularized, pi, E
>>> betainc_regularized(1, 2, 0, 0.25).evalf(10)
0.4375000000
>>> betainc_regularized(pi, E, 0, 1).evalf(5)
1.00000
The Generalized Regularized Incomplete Beta function can be
expressed in terms of the Generalized Hypergeometric function.
>>> from sympy import hyper
>>> betainc_regularized(a, b, x1, x2).rewrite(hyper)
(-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/(a*beta(a, b))
See Also
========
beta: Beta function
hyper: Generalized Hypergeometric function
References
==========
.. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
.. [2] https://dlmf.nist.gov/8.17
.. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
.. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
"""
nargs = 4
unbranched = True
def __new__(cls, a, b, x1, x2):
return Function.__new__(cls, a, b, x1, x2)
def _eval_mpmath(self):
return betainc_mpmath_fix, (*self.args, S(1))
def fdiff(self, argindex):
a, b, x1, x2 = self.args
if argindex == 3:
# Diff wrt x1
return -(1 - x1)**(b - 1)*x1**(a - 1) / beta(a, b)
elif argindex == 4:
# Diff wrt x2
return (1 - x2)**(b - 1)*x2**(a - 1) / beta(a, b)
else:
raise ArgumentIndexError(self, argindex)
def _eval_is_real(self):
if all(arg.is_real for arg in self.args):
return True
def _eval_conjugate(self):
return self.func(*map(conjugate, self.args))
def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
from sympy.integrals.integrals import Integral
t = Dummy('t')
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)