Skip to content

Commit 061ac50

Browse files
authored
Merge pull request #3126 from lingium/feature/issue-3121-beta-neg-binomial-rng
Feature/issue 3121 beta neg binomial rng
2 parents 8cfec9b + a225dd6 commit 061ac50

3 files changed

Lines changed: 122 additions & 0 deletions

File tree

stan/math/prim/prob.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <stan/math/prim/prob/beta_neg_binomial_lccdf.hpp>
3030
#include <stan/math/prim/prob/beta_neg_binomial_lcdf.hpp>
3131
#include <stan/math/prim/prob/beta_neg_binomial_lpmf.hpp>
32+
#include <stan/math/prim/prob/beta_neg_binomial_rng.hpp>
3233
#include <stan/math/prim/prob/beta_proportion_ccdf_log.hpp>
3334
#include <stan/math/prim/prob/beta_proportion_cdf_log.hpp>
3435
#include <stan/math/prim/prob/beta_proportion_lccdf.hpp>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#ifndef STAN_MATH_PRIM_PROB_BETA_NEG_BINOMIAL_RNG_HPP
2+
#define STAN_MATH_PRIM_PROB_BETA_NEG_BINOMIAL_RNG_HPP
3+
4+
#include <stan/math/prim/meta.hpp>
5+
#include <stan/math/prim/prob/neg_binomial_rng.hpp>
6+
#include <stan/math/prim/prob/beta_rng.hpp>
7+
8+
namespace stan {
9+
namespace math {
10+
11+
/** \ingroup prob_dists
12+
* Return a beta-negative binomial random variate with the given number of
13+
* successes, prior success, and prior failure parameters, using the given
14+
* random number generator.
15+
*
16+
* r, alpha, and beta can each be a scalar or a one-dimensional container. Any
17+
* non-scalar inputs must be the same size.
18+
*
19+
* @tparam T_r type of number of successes parameter
20+
* @tparam T_alpha type of prior success parameter
21+
* @tparam T_beta type of prior failure parameter
22+
* @tparam RNG type of random number generator
23+
*
24+
* @param r (Sequence of) number of successes parameter(s)
25+
* @param alpha (Sequence of) prior success parameter(s)
26+
* @param beta (Sequence of) prior failure parameter(s)
27+
* @param rng random number generator
28+
* @return (Sequence of) beta-negative binomial random variate(s)
29+
* @throw std::domain_error if r, alpha, or beta are nonpositive
30+
* @throw std::invalid_argument if non-scalar arguments are of different sizes
31+
*/
32+
template <typename T_r, typename T_alpha, typename T_beta, typename RNG>
33+
inline auto beta_neg_binomial_rng(const T_r &r, const T_alpha &alpha,
34+
const T_beta &beta, RNG &rng) {
35+
using T_r_ref = ref_type_t<T_r>;
36+
using T_alpha_ref = ref_type_t<T_alpha>;
37+
using T_beta_ref = ref_type_t<T_beta>;
38+
static constexpr const char *function = "beta_neg_binomial_rng";
39+
check_consistent_sizes(function, "Number of successes parameter", r,
40+
"Prior success parameter", alpha,
41+
"Prior failure parameter", beta);
42+
43+
T_r_ref r_ref = r;
44+
T_alpha_ref alpha_ref = alpha;
45+
T_beta_ref beta_ref = beta;
46+
check_positive_finite(function, "Number of successes parameter", r_ref);
47+
check_positive_finite(function, "Prior success parameter", alpha_ref);
48+
check_positive_finite(function, "Prior failure parameter", beta_ref);
49+
50+
using T_p = decltype(beta_rng(alpha_ref, beta_ref, rng));
51+
T_p p = beta_rng(alpha_ref, beta_ref, rng);
52+
53+
scalar_seq_view<T_p> p_vec(p);
54+
size_t size_p = stan::math::size(p);
55+
VectorBuilder<true, double, T_p> odds_ratio_p(size_p);
56+
for (size_t n = 0; n < size_p; ++n) {
57+
odds_ratio_p[n]
58+
= stan::math::exp(stan::math::log(p_vec.val(n)) - log1m(p_vec.val(n)));
59+
}
60+
61+
return neg_binomial_rng(r_ref, odds_ratio_p.data(), rng);
62+
}
63+
64+
} // namespace math
65+
} // namespace stan
66+
#endif
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <stan/math/prim.hpp>
2+
#include <test/unit/math/prim/prob/vector_rng_test_helper.hpp>
3+
#include <test/unit/math/prim/prob/VectorIntRNGTestRig.hpp>
4+
#include <boost/random/mersenne_twister.hpp>
5+
#include <boost/math/distributions.hpp>
6+
#include <gtest/gtest.h>
7+
#include <limits>
8+
#include <vector>
9+
10+
class BetaNegBinomialTestRig : public VectorIntRNGTestRig {
11+
public:
12+
BetaNegBinomialTestRig()
13+
: VectorIntRNGTestRig(10000, 10, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
14+
{1.1, 3.1, 8.1}, {1, 3, 8}, {-3.0, -2.0, 0.0},
15+
{-3, -2, 0}, {3.1, 4.1, 5.1}, {3, 4, 5},
16+
{-2.1, -0.5, 0.0}, {-3, -1, 0}, {1.1, 3.1, 8.1},
17+
{1, 3, 8}, {-3.0, -2.0, 0.0}, {-3, -2, 0}) {}
18+
19+
template <typename T1, typename T2, typename T3, typename T_rng>
20+
auto generate_samples(const T1& N, const T2& alpha, const T3& beta,
21+
T_rng& rng) const {
22+
return stan::math::beta_neg_binomial_rng(N, alpha, beta, rng);
23+
}
24+
25+
template <typename T1>
26+
double pmf(int y, T1 r, double alpha, double beta) const {
27+
return std::exp(stan::math::beta_neg_binomial_lpmf(y, r, alpha, beta));
28+
}
29+
};
30+
31+
TEST(ProbDistributionsBetaNegBinomial, errorCheck) {
32+
check_dist_throws_int_first_argument(BetaNegBinomialTestRig());
33+
}
34+
35+
TEST(ProbDistributionsBetaNegBinomial, distributionCheck) {
36+
check_counts_int_real_real(BetaNegBinomialTestRig());
37+
}
38+
39+
TEST(ProbDistributionBetaNegBinomial, error_check) {
40+
boost::random::mt19937 rng;
41+
EXPECT_NO_THROW(stan::math::beta_neg_binomial_rng(4, 0.6, 2.0, rng));
42+
43+
EXPECT_THROW(stan::math::beta_neg_binomial_rng(-4, 0.6, 2, rng),
44+
std::domain_error);
45+
EXPECT_THROW(stan::math::beta_neg_binomial_rng(4, -0.6, 2, rng),
46+
std::domain_error);
47+
EXPECT_THROW(stan::math::beta_neg_binomial_rng(4, 0.6, -2, rng),
48+
std::domain_error);
49+
EXPECT_THROW(stan::math::beta_neg_binomial_rng(
50+
4, stan::math::positive_infinity(), 2, rng),
51+
std::domain_error);
52+
EXPECT_THROW(stan::math::beta_neg_binomial_rng(
53+
4, 0.6, stan::math::positive_infinity(), rng),
54+
std::domain_error);
55+
}

0 commit comments

Comments
 (0)