beta_functions.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. from sympy.core import S
  2. from sympy.core.function import Function, ArgumentIndexError
  3. from sympy.core.symbol import Dummy
  4. from sympy.functions.special.gamma_functions import gamma, digamma
  5. from sympy.functions.combinatorial.numbers import catalan
  6. from sympy.functions.elementary.complexes import conjugate
  7. # See mpmath #569 and SymPy #20569
  8. def betainc_mpmath_fix(a, b, x1, x2, reg=0):
  9. from mpmath import betainc, mpf
  10. if x1 == x2:
  11. return mpf(0)
  12. else:
  13. return betainc(a, b, x1, x2, reg)
  14. ###############################################################################
  15. ############################ COMPLETE BETA FUNCTION ##########################
  16. ###############################################################################
  17. class beta(Function):
  18. r"""
  19. The beta integral is called the Eulerian integral of the first kind by
  20. Legendre:
  21. .. math::
  22. \mathrm{B}(x,y) \int^{1}_{0} t^{x-1} (1-t)^{y-1} \mathrm{d}t.
  23. Explanation
  24. ===========
  25. The Beta function or Euler's first integral is closely associated
  26. with the gamma function. The Beta function is often used in probability
  27. theory and mathematical statistics. It satisfies properties like:
  28. .. math::
  29. \mathrm{B}(a,1) = \frac{1}{a} \\
  30. \mathrm{B}(a,b) = \mathrm{B}(b,a) \\
  31. \mathrm{B}(a,b) = \frac{\Gamma(a) \Gamma(b)}{\Gamma(a+b)}
  32. Therefore for integral values of $a$ and $b$:
  33. .. math::
  34. \mathrm{B} = \frac{(a-1)! (b-1)!}{(a+b-1)!}
  35. A special case of the Beta function when `x = y` is the
  36. Central Beta function. It satisfies properties like:
  37. .. math::
  38. \mathrm{B}(x) = 2^{1 - 2x}\mathrm{B}(x, \frac{1}{2})
  39. \mathrm{B}(x) = 2^{1 - 2x} cos(\pi x) \mathrm{B}(\frac{1}{2} - x, x)
  40. \mathrm{B}(x) = \int_{0}^{1} \frac{t^x}{(1 + t)^{2x}} dt
  41. \mathrm{B}(x) = \frac{2}{x} \prod_{n = 1}^{\infty} \frac{n(n + 2x)}{(n + x)^2}
  42. Examples
  43. ========
  44. >>> from sympy import I, pi
  45. >>> from sympy.abc import x, y
  46. The Beta function obeys the mirror symmetry:
  47. >>> from sympy import beta, conjugate
  48. >>> conjugate(beta(x, y))
  49. beta(conjugate(x), conjugate(y))
  50. Differentiation with respect to both $x$ and $y$ is supported:
  51. >>> from sympy import beta, diff
  52. >>> diff(beta(x, y), x)
  53. (polygamma(0, x) - polygamma(0, x + y))*beta(x, y)
  54. >>> diff(beta(x, y), y)
  55. (polygamma(0, y) - polygamma(0, x + y))*beta(x, y)
  56. >>> diff(beta(x), x)
  57. 2*(polygamma(0, x) - polygamma(0, 2*x))*beta(x, x)
  58. We can numerically evaluate the Beta function to
  59. arbitrary precision for any complex numbers x and y:
  60. >>> from sympy import beta
  61. >>> beta(pi).evalf(40)
  62. 0.02671848900111377452242355235388489324562
  63. >>> beta(1 + I).evalf(20)
  64. -0.2112723729365330143 - 0.7655283165378005676*I
  65. See Also
  66. ========
  67. gamma: Gamma function.
  68. uppergamma: Upper incomplete gamma function.
  69. lowergamma: Lower incomplete gamma function.
  70. polygamma: Polygamma function.
  71. loggamma: Log Gamma function.
  72. digamma: Digamma function.
  73. trigamma: Trigamma function.
  74. References
  75. ==========
  76. .. [1] https://en.wikipedia.org/wiki/Beta_function
  77. .. [2] https://mathworld.wolfram.com/BetaFunction.html
  78. .. [3] https://dlmf.nist.gov/5.12
  79. """
  80. unbranched = True
  81. def fdiff(self, argindex):
  82. x, y = self.args
  83. if argindex == 1:
  84. # Diff wrt x
  85. return beta(x, y)*(digamma(x) - digamma(x + y))
  86. elif argindex == 2:
  87. # Diff wrt y
  88. return beta(x, y)*(digamma(y) - digamma(x + y))
  89. else:
  90. raise ArgumentIndexError(self, argindex)
  91. @classmethod
  92. def eval(cls, x, y=None):
  93. if y is None:
  94. return beta(x, x)
  95. if x.is_Number and y.is_Number:
  96. return beta(x, y, evaluate=False).doit()
  97. def doit(self, **hints):
  98. x = xold = self.args[0]
  99. # Deal with unevaluated single argument beta
  100. single_argument = len(self.args) == 1
  101. y = yold = self.args[0] if single_argument else self.args[1]
  102. if hints.get('deep', True):
  103. x = x.doit(**hints)
  104. y = y.doit(**hints)
  105. if y.is_zero or x.is_zero:
  106. return S.ComplexInfinity
  107. if y is S.One:
  108. return 1/x
  109. if x is S.One:
  110. return 1/y
  111. if y == x + 1:
  112. return 1/(x*y*catalan(x))
  113. s = x + y
  114. if (s.is_integer and s.is_negative and x.is_integer is False and
  115. y.is_integer is False):
  116. return S.Zero
  117. if x == xold and y == yold and not single_argument:
  118. return self
  119. return beta(x, y)
  120. def _eval_expand_func(self, **hints):
  121. x, y = self.args
  122. return gamma(x)*gamma(y) / gamma(x + y)
  123. def _eval_is_real(self):
  124. return self.args[0].is_real and self.args[1].is_real
  125. def _eval_conjugate(self):
  126. return self.func(self.args[0].conjugate(), self.args[1].conjugate())
  127. def _eval_rewrite_as_gamma(self, x, y, piecewise=True, **kwargs):
  128. return self._eval_expand_func(**kwargs)
  129. def _eval_rewrite_as_Integral(self, x, y, **kwargs):
  130. from sympy.integrals.integrals import Integral
  131. t = Dummy('t')
  132. return Integral(t**(x - 1)*(1 - t)**(y - 1), (t, 0, 1))
  133. ###############################################################################
  134. ########################## INCOMPLETE BETA FUNCTION ###########################
  135. ###############################################################################
  136. class betainc(Function):
  137. r"""
  138. The Generalized Incomplete Beta function is defined as
  139. .. math::
  140. \mathrm{B}_{(x_1, x_2)}(a, b) = \int_{x_1}^{x_2} t^{a - 1} (1 - t)^{b - 1} dt
  141. The Incomplete Beta function is a special case
  142. of the Generalized Incomplete Beta function :
  143. .. math:: \mathrm{B}_z (a, b) = \mathrm{B}_{(0, z)}(a, b)
  144. The Incomplete Beta function satisfies :
  145. .. math:: \mathrm{B}_z (a, b) = (-1)^a \mathrm{B}_{\frac{z}{z - 1}} (a, 1 - a - b)
  146. The Beta function is a special case of the Incomplete Beta function :
  147. .. math:: \mathrm{B}(a, b) = \mathrm{B}_{1}(a, b)
  148. Examples
  149. ========
  150. >>> from sympy import betainc, symbols, conjugate
  151. >>> a, b, x, x1, x2 = symbols('a b x x1 x2')
  152. The Generalized Incomplete Beta function is given by:
  153. >>> betainc(a, b, x1, x2)
  154. betainc(a, b, x1, x2)
  155. The Incomplete Beta function can be obtained as follows:
  156. >>> betainc(a, b, 0, x)
  157. betainc(a, b, 0, x)
  158. The Incomplete Beta function obeys the mirror symmetry:
  159. >>> conjugate(betainc(a, b, x1, x2))
  160. betainc(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
  161. We can numerically evaluate the Incomplete Beta function to
  162. arbitrary precision for any complex numbers a, b, x1 and x2:
  163. >>> from sympy import betainc, I
  164. >>> betainc(2, 3, 4, 5).evalf(10)
  165. 56.08333333
  166. >>> betainc(0.75, 1 - 4*I, 0, 2 + 3*I).evalf(25)
  167. 0.2241657956955709603655887 + 0.3619619242700451992411724*I
  168. The Generalized Incomplete Beta function can be expressed
  169. in terms of the Generalized Hypergeometric function.
  170. >>> from sympy import hyper
  171. >>> betainc(a, b, x1, x2).rewrite(hyper)
  172. (-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/a
  173. See Also
  174. ========
  175. beta: Beta function
  176. hyper: Generalized Hypergeometric function
  177. References
  178. ==========
  179. .. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
  180. .. [2] https://dlmf.nist.gov/8.17
  181. .. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
  182. .. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
  183. """
  184. nargs = 4
  185. unbranched = True
  186. def fdiff(self, argindex):
  187. a, b, x1, x2 = self.args
  188. if argindex == 3:
  189. # Diff wrt x1
  190. return -(1 - x1)**(b - 1)*x1**(a - 1)
  191. elif argindex == 4:
  192. # Diff wrt x2
  193. return (1 - x2)**(b - 1)*x2**(a - 1)
  194. else:
  195. raise ArgumentIndexError(self, argindex)
  196. def _eval_mpmath(self):
  197. return betainc_mpmath_fix, self.args
  198. def _eval_is_real(self):
  199. if all(arg.is_real for arg in self.args):
  200. return True
  201. def _eval_conjugate(self):
  202. return self.func(*map(conjugate, self.args))
  203. def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
  204. from sympy.integrals.integrals import Integral
  205. t = Dummy('t')
  206. return Integral(t**(a - 1)*(1 - t)**(b - 1), (t, x1, x2))
  207. def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
  208. from sympy.functions.special.hyper import hyper
  209. return (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
  210. ###############################################################################
  211. #################### REGULARIZED INCOMPLETE BETA FUNCTION #####################
  212. ###############################################################################
  213. class betainc_regularized(Function):
  214. r"""
  215. The Generalized Regularized Incomplete Beta function is given by
  216. .. math::
  217. \mathrm{I}_{(x_1, x_2)}(a, b) = \frac{\mathrm{B}_{(x_1, x_2)}(a, b)}{\mathrm{B}(a, b)}
  218. The Regularized Incomplete Beta function is a special case
  219. of the Generalized Regularized Incomplete Beta function :
  220. .. math:: \mathrm{I}_z (a, b) = \mathrm{I}_{(0, z)}(a, b)
  221. The Regularized Incomplete Beta function is the cumulative distribution
  222. function of the beta distribution.
  223. Examples
  224. ========
  225. >>> from sympy import betainc_regularized, symbols, conjugate
  226. >>> a, b, x, x1, x2 = symbols('a b x x1 x2')
  227. The Generalized Regularized Incomplete Beta
  228. function is given by:
  229. >>> betainc_regularized(a, b, x1, x2)
  230. betainc_regularized(a, b, x1, x2)
  231. The Regularized Incomplete Beta function
  232. can be obtained as follows:
  233. >>> betainc_regularized(a, b, 0, x)
  234. betainc_regularized(a, b, 0, x)
  235. The Regularized Incomplete Beta function
  236. obeys the mirror symmetry:
  237. >>> conjugate(betainc_regularized(a, b, x1, x2))
  238. betainc_regularized(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2))
  239. We can numerically evaluate the Regularized Incomplete Beta function
  240. to arbitrary precision for any complex numbers a, b, x1 and x2:
  241. >>> from sympy import betainc_regularized, pi, E
  242. >>> betainc_regularized(1, 2, 0, 0.25).evalf(10)
  243. 0.4375000000
  244. >>> betainc_regularized(pi, E, 0, 1).evalf(5)
  245. 1.00000
  246. The Generalized Regularized Incomplete Beta function can be
  247. expressed in terms of the Generalized Hypergeometric function.
  248. >>> from sympy import hyper
  249. >>> betainc_regularized(a, b, x1, x2).rewrite(hyper)
  250. (-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/(a*beta(a, b))
  251. See Also
  252. ========
  253. beta: Beta function
  254. hyper: Generalized Hypergeometric function
  255. References
  256. ==========
  257. .. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function
  258. .. [2] https://dlmf.nist.gov/8.17
  259. .. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/
  260. .. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/
  261. """
  262. nargs = 4
  263. unbranched = True
  264. def __new__(cls, a, b, x1, x2):
  265. return Function.__new__(cls, a, b, x1, x2)
  266. def _eval_mpmath(self):
  267. return betainc_mpmath_fix, (*self.args, S(1))
  268. def fdiff(self, argindex):
  269. a, b, x1, x2 = self.args
  270. if argindex == 3:
  271. # Diff wrt x1
  272. return -(1 - x1)**(b - 1)*x1**(a - 1) / beta(a, b)
  273. elif argindex == 4:
  274. # Diff wrt x2
  275. return (1 - x2)**(b - 1)*x2**(a - 1) / beta(a, b)
  276. else:
  277. raise ArgumentIndexError(self, argindex)
  278. def _eval_is_real(self):
  279. if all(arg.is_real for arg in self.args):
  280. return True
  281. def _eval_conjugate(self):
  282. return self.func(*map(conjugate, self.args))
  283. def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs):
  284. from sympy.integrals.integrals import Integral
  285. t = Dummy('t')
  286. integrand = t**(a - 1)*(1 - t)**(b - 1)
  287. expr = Integral(integrand, (t, x1, x2))
  288. return expr / Integral(integrand, (t, 0, 1))
  289. def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs):
  290. from sympy.functions.special.hyper import hyper
  291. expr = (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a
  292. return expr / beta(a, b)