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