1 #ifndef STAN_MATH_PRIM_FUN_GAMMA_P_HPP
2 #define STAN_MATH_PRIM_FUN_GAMMA_P_HPP
3 
4 #include <stan/math/prim/err.hpp>
5 #include <stan/math/prim/fun/boost_policy.hpp>
6 #include <stan/math/prim/fun/constants.hpp>
7 #include <stan/math/prim/fun/is_nan.hpp>
8 #include <stan/math/prim/functor/apply_scalar_binary.hpp>
9 #include <boost/math/special_functions/gamma.hpp>
10 
11 namespace stan {
12 namespace math {
13 
14 /**
15  * Return the value of the normalized, lower-incomplete gamma function
16  * applied to the specified argument.
17  *
18  * <p>This function is defined, including error conditions, as follows
19    \f[
20    \mbox{gamma\_p}(a, z) =
21    \begin{cases}
22      \textrm{error} & \mbox{if } a\leq 0 \textrm{ or } z < 0\\
23      P(a, z) & \mbox{if } a > 0, z \geq 0 \\[6pt]
24      \textrm{NaN} & \mbox{if } a = \textrm{NaN or } z = \textrm{NaN}
25    \end{cases}
26    \f]
27 
28    \f[
29    \frac{\partial\, \mbox{gamma\_p}(a, z)}{\partial a} =
30    \begin{cases}
31      \textrm{error} & \mbox{if } a\leq 0 \textrm{ or } z < 0\\
32      \frac{\partial\, P(a, z)}{\partial a} & \mbox{if } a > 0, z \geq 0 \\[6pt]
33      \textrm{NaN} & \mbox{if } a = \textrm{NaN or } z = \textrm{NaN}
34    \end{cases}
35    \f]
36 
37    \f[
38    \frac{\partial\, \mbox{gamma\_p}(a, z)}{\partial z} =
39    \begin{cases}
40      \textrm{error} & \mbox{if } a\leq 0 \textrm{ or } z < 0\\
41      \frac{\partial\, P(a, z)}{\partial z} & \mbox{if } a > 0, z \geq 0 \\[6pt]
42      \textrm{NaN} & \mbox{if } a = \textrm{NaN or } z = \textrm{NaN}
43    \end{cases}
44    \f]
45 
46    \f[
47    P(a, z)=\frac{1}{\Gamma(a)}\int_0^zt^{a-1}e^{-t}dt
48    \f]
49 
50    \f[
51    \frac{\partial \, P(a, z)}{\partial a} =
52  -\frac{\Psi(a)}{\Gamma^2(a)}\int_0^zt^{a-1}e^{-t}dt
53    + \frac{1}{\Gamma(a)}\int_0^z (a-1)t^{a-2}e^{-t}dt
54    \f]
55 
56    \f[
57    \frac{\partial \, P(a, z)}{\partial z} = \frac{z^{a-1}e^{-z}}{\Gamma(a)}
58    \f]
59    *
60    * @param z first argument
61    * @param a second argument
62    * @return value of the normalized, lower-incomplete gamma function
63    * applied to z and a
64    * @throws std::domain_error if either argument is not positive or
65    * if z is at a pole of the function
66  */
gamma_p(double z,double a)67 inline double gamma_p(double z, double a) {
68   if (is_nan(z)) {
69     return not_a_number();
70   }
71   if (is_nan(a)) {
72     return not_a_number();
73   }
74   check_positive("gamma_p", "first argument (z)", z);
75   check_nonnegative("gamma_p", "second argument (a)", a);
76   return boost::math::gamma_p(z, a, boost_policy_t<>());
77 }
78 
79 /**
80  * Enables the vectorised application of the gamma_p function,
81  * when the first and/or second arguments are containers.
82  *
83  * @tparam T1 type of first input
84  * @tparam T2 type of second input
85  * @param a First input
86  * @param b Second input
87  * @return gamma_p function applied to the two inputs.
88  */
89 template <typename T1, typename T2, require_any_container_t<T1, T2>* = nullptr>
gamma_p(const T1 & a,const T2 & b)90 inline auto gamma_p(const T1& a, const T2& b) {
91   return apply_scalar_binary(
92       a, b, [&](const auto& c, const auto& d) { return gamma_p(c, d); });
93 }
94 
95 }  // namespace math
96 }  // namespace stan
97 #endif
98