|
| 1 | +#ifndef STAN_MATH_PRIM_PROB_GEOMETRIC_LPMF_HPP |
| 2 | +#define STAN_MATH_PRIM_PROB_GEOMETRIC_LPMF_HPP |
| 3 | + |
| 4 | +#include <stan/math/prim/meta.hpp> |
| 5 | +#include <stan/math/prim/err.hpp> |
| 6 | +#include <stan/math/prim/fun/constants.hpp> |
| 7 | +#include <stan/math/prim/fun/log.hpp> |
| 8 | +#include <stan/math/prim/fun/log1m.hpp> |
| 9 | +#include <stan/math/prim/fun/max_size.hpp> |
| 10 | +#include <stan/math/prim/fun/scalar_seq_view.hpp> |
| 11 | +#include <stan/math/prim/fun/size.hpp> |
| 12 | +#include <stan/math/prim/fun/size_zero.hpp> |
| 13 | +#include <stan/math/prim/fun/value_of.hpp> |
| 14 | +#include <stan/math/prim/functor/partials_propagator.hpp> |
| 15 | + |
| 16 | +namespace stan { |
| 17 | +namespace math { |
| 18 | + |
| 19 | +/** \ingroup prob_dists |
| 20 | + * Returns the log PMF of the geometric distribution. If containers |
| 21 | + * of matching sizes are supplied, returns the log sum of probabilities. |
| 22 | + * |
| 23 | + * The geometric distribution with success probability \f$\theta\f$ has PMF |
| 24 | + * \f[ |
| 25 | + * P(n \mid \theta) = \theta (1 - \theta)^{n} |
| 26 | + * \f] |
| 27 | + * where \f$n \in \{0, 1, 2, \ldots\}\f$ and |
| 28 | + * \f$\theta \in (0, 1]\f$. |
| 29 | + * |
| 30 | + * This is the number-of-failures parameterization, consistent with |
| 31 | + * the geometric distribution being a special case of the negative |
| 32 | + * binomial distribution with r = 1. |
| 33 | + * |
| 34 | + * @tparam T_n type of outcome variable |
| 35 | + * @tparam T_prob type of success probability parameter |
| 36 | + * |
| 37 | + * @param n outcome variable (number of failures before first success) |
| 38 | + * @param theta success probability parameter |
| 39 | + * @return log probability or log sum of probabilities |
| 40 | + * @throw std::domain_error if theta is not in [0, 1] |
| 41 | + * @throw std::domain_error if n is negative |
| 42 | + * @throw std::invalid_argument if container sizes mismatch |
| 43 | + */ |
| 44 | +template <bool propto, typename T_n, typename T_prob, |
| 45 | + require_all_not_nonscalar_prim_or_rev_kernel_expression_t< |
| 46 | + T_n, T_prob>* = nullptr> |
| 47 | +inline return_type_t<T_prob> geometric_lpmf(const T_n& n, |
| 48 | + const T_prob& theta) { |
| 49 | + using std::log; |
| 50 | + using T_partials_return = partials_return_t<T_n, T_prob>; |
| 51 | + using T_n_ref = ref_type_t<T_n>; |
| 52 | + using T_prob_ref = ref_type_t<T_prob>; |
| 53 | + static constexpr const char* function = "geometric_lpmf"; |
| 54 | + check_consistent_sizes(function, "Outcome variable", n, |
| 55 | + "Success probability parameter", theta); |
| 56 | + if (size_zero(n, theta)) { |
| 57 | + return 0.0; |
| 58 | + } |
| 59 | + |
| 60 | + T_n_ref n_ref = n; |
| 61 | + T_prob_ref theta_ref = theta; |
| 62 | + check_nonnegative(function, "Outcome variable", n_ref); |
| 63 | + check_bounded(function, "Success probability parameter", |
| 64 | + value_of(theta_ref), 0.0, 1.0); |
| 65 | + |
| 66 | + if constexpr (!include_summand<propto, T_prob>::value) { |
| 67 | + return 0.0; |
| 68 | + } |
| 69 | + |
| 70 | + auto ops_partials = make_partials_propagator(theta_ref); |
| 71 | + |
| 72 | + scalar_seq_view<T_n_ref> n_vec(n_ref); |
| 73 | + scalar_seq_view<T_prob_ref> theta_vec(theta_ref); |
| 74 | + const size_t max_size_seq_view = max_size(n_ref, theta_ref); |
| 75 | + T_partials_return logp(0.0); |
| 76 | + |
| 77 | + for (size_t i = 0; i < max_size_seq_view; i++) { |
| 78 | + const auto theta_val = theta_vec.val(i); |
| 79 | + const auto n_val = n_vec.val(i); |
| 80 | + |
| 81 | + // When theta == 1.0, P(n=0) = 1, P(n>0) = 0 |
| 82 | + if (theta_val == 1.0) { |
| 83 | + if (n_val > 0) { |
| 84 | + return negative_infinity(); |
| 85 | + } |
| 86 | + // logp += 0 for n=0, theta=1 |
| 87 | + continue; |
| 88 | + } |
| 89 | + |
| 90 | + logp += log(theta_val) + n_val * log1m(theta_val); |
| 91 | + |
| 92 | + if constexpr (is_autodiff_v<T_prob>) { |
| 93 | + partials<0>(ops_partials)[i] |
| 94 | + += 1.0 / theta_val - n_val / (1.0 - theta_val); |
| 95 | + } |
| 96 | + } |
| 97 | + return ops_partials.build(logp); |
| 98 | +} |
| 99 | + |
| 100 | +template <typename T_n, typename T_prob> |
| 101 | +inline return_type_t<T_prob> geometric_lpmf(const T_n& n, |
| 102 | + const T_prob& theta) { |
| 103 | + return geometric_lpmf<false>(n, theta); |
| 104 | +} |
| 105 | + |
| 106 | +} // namespace math |
| 107 | +} // namespace stan |
| 108 | +#endif |
0 commit comments