Skip to content

Commit cc6ba8b

Browse files
authored
Merge pull request #3355 from stan-dev/fix/3353-laplace_bernouilli_logit
update signature for laplace bernoulli logit functions.
2 parents 8f326d1 + 5424173 commit cc6ba8b

4 files changed

Lines changed: 54 additions & 30 deletions

File tree

stan/math/mix/prob/laplace_latent_bernoulli_logit_rng.hpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ namespace math {
2020
* @tparam Mean type of the mean of the latent normal distribution
2121
* \laplace_common_template_args
2222
* @tparam RNG A valid boost rng type
23-
* @param[in] y Vector Vector of total number of trials with a positive outcome.
24-
* @param[in] n_samples Vector of number of trials.
23+
* @param[in] y binary observations.
24+
* @param[in] y_index group to which each observation belongs.
2525
* @param[in] mean the mean of the latent normal variable.
2626
* \laplace_common_args
2727
* @param[in] hessian_block_size Block size for the Hessian approximation with
@@ -33,15 +33,15 @@ namespace math {
3333
template <typename Mean, typename CovarFun, typename CovarArgs,
3434
typename OpsTuple, typename RNG>
3535
inline Eigen::VectorXd laplace_latent_tol_bernoulli_logit_rng(
36-
const std::vector<int>& y, const std::vector<int>& n_samples, Mean&& mean,
36+
const std::vector<int>& y, const std::vector<int>& y_index, Mean&& mean,
3737
int hessian_block_size, CovarFun&& covariance_function,
3838
CovarArgs&& covar_args, OpsTuple&& ops, RNG& rng, std::ostream* msgs) {
3939
auto options
4040
= internal::tuple_to_laplace_options(std::forward<OpsTuple>(ops));
4141
options.hessian_block_size = hessian_block_size;
4242
return laplace_base_rng(
4343
bernoulli_logit_likelihood{},
44-
std::forward_as_tuple(to_vector(y), n_samples, std::forward<Mean>(mean)),
44+
std::forward_as_tuple(to_vector(y), y_index, std::forward<Mean>(mean)),
4545
std::forward<CovarFun>(covariance_function),
4646
std::forward<CovarArgs>(covar_args), std::move(options), rng, msgs);
4747
}
@@ -58,8 +58,8 @@ inline Eigen::VectorXd laplace_latent_tol_bernoulli_logit_rng(
5858
* @tparam Mean type of the mean of the latent normal distribution
5959
* \laplace_common_template_args
6060
* @tparam RNG A valid boost rng type
61-
* @param[in] y Vector Vector of total number of trials with a positive outcome.
62-
* @param[in] n_samples Vector of number of trials.
61+
* @param[in] y binary observations
62+
* @param[in] y_index group to which each observation belongs.
6363
* @param[in] mean the mean of the latent normal variable.
6464
* \laplace_common_args
6565
* @param[in] hessian_block_size Block size for the Hessian approximation with
@@ -69,13 +69,13 @@ inline Eigen::VectorXd laplace_latent_tol_bernoulli_logit_rng(
6969
*/
7070
template <typename Mean, typename CovarFun, typename CovarArgs, typename RNG>
7171
inline Eigen::VectorXd laplace_latent_bernoulli_logit_rng(
72-
const std::vector<int>& y, const std::vector<int>& n_samples, Mean&& mean,
72+
const std::vector<int>& y, const std::vector<int>& y_index, Mean&& mean,
7373
int hessian_block_size, CovarFun&& covariance_function,
7474
CovarArgs&& covar_args, RNG& rng, std::ostream* msgs) {
7575
auto options = laplace_options_default{hessian_block_size};
7676
return laplace_base_rng(
7777
bernoulli_logit_likelihood{},
78-
std::forward_as_tuple(to_vector(y), n_samples, std::forward<Mean>(mean)),
78+
std::forward_as_tuple(to_vector(y), y_index, std::forward<Mean>(mean)),
7979
std::forward<CovarFun>(covariance_function),
8080
std::forward<CovarArgs>(covar_args), options, rng, msgs);
8181
}

stan/math/mix/prob/laplace_marginal_bernoulli_logit_lpmf.hpp

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,36 @@ namespace stan {
2525
namespace math {
2626

2727
struct bernoulli_logit_likelihood {
28+
/**
29+
* Returns the lpmf for a Bernoulli with a logit link across
30+
* multiple groups. No need to compute the log normalizing constant.
31+
* @tparam Theta A type inheriting from `Eigen::EigenBase` with dynamic
32+
* sized rows and 1 column.
33+
* @tparam YVec A vector type containing integers.
34+
* @tparam Mean type of the mean of the latent normal distribution
35+
* @param[in] theta log Poisson rate for each group.
36+
* @param[in] y binary observations
37+
* @param[in] y_index group to which each observation belongs
38+
* return lpmf for a Poisson with a log link.
39+
* @param[in] mean the mean of the latent normal variable
40+
* \msg_arg
41+
*/
2842
template <typename ThetaVec, typename YVec, typename Mean>
2943
inline auto operator()(const ThetaVec& theta, const YVec& y,
30-
const std::vector<int>& delta_int, Mean&& mean,
31-
std::ostream* pstream) const {
44+
const std::vector<int>& y_index, Mean&& mean,
45+
std::ostream* msgs) const {
46+
Eigen::VectorXd counts_per_group = Eigen::VectorXd::Zero(theta.size());
47+
Eigen::VectorXd n_per_group = Eigen::VectorXd::Zero(theta.size());
48+
49+
for (int i = 0; i < theta.size(); i++) {
50+
counts_per_group(y_index[i] - 1) += y[i];
51+
n_per_group(y_index[i] - 1) += 1;
52+
}
53+
3254
auto theta_offset = to_ref(add(theta, mean));
33-
return sum(elt_multiply(theta_offset, y)
34-
- elt_multiply(to_vector(delta_int), log1p_exp(theta_offset)));
55+
56+
return sum(elt_multiply(theta_offset, counts_per_group)
57+
- elt_multiply(to_vector(n_per_group), log1p_exp(theta_offset)));
3558
}
3659
};
3760

@@ -47,9 +70,8 @@ struct bernoulli_logit_likelihood {
4770
* with dynamic sized rows and 1 column.
4871
* @tparam Mean type of the mean of the latent normal distribution
4972
* \laplace_common_template_args
50-
* @param[in] y total counts per group. Second sufficient statistics.
51-
* @param[in] n_samples number of samples per group. First sufficient
52-
* statistics.
73+
* @param[in] y binary observations
74+
* @param[in] y_index group to which each observation belongs
5375
* @param[in] mean the mean of the latent normal variable.
5476
* \laplace_common_args
5577
* @param[in] hessian_block_size Block size for the Hessian approximation with
@@ -60,15 +82,15 @@ struct bernoulli_logit_likelihood {
6082
template <bool propto = false, typename Mean, typename CovarFun,
6183
typename CovarArgs, typename OpsTuple>
6284
inline auto laplace_marginal_tol_bernoulli_logit_lpmf(
63-
const std::vector<int>& y, const std::vector<int>& n_samples, Mean&& mean,
85+
const std::vector<int>& y, const std::vector<int>& y_index, Mean&& mean,
6486
int hessian_block_size, CovarFun&& covariance_function,
6587
CovarArgs&& covar_args, OpsTuple&& ops, std::ostream* msgs) {
6688
auto options
6789
= internal::tuple_to_laplace_options(std::forward<OpsTuple>(ops));
6890
options.hessian_block_size = hessian_block_size;
6991
return laplace_marginal_density(
7092
bernoulli_logit_likelihood{},
71-
std::forward_as_tuple(to_vector(y), n_samples, std::forward<Mean>(mean)),
93+
std::forward_as_tuple(to_vector(y), y_index, std::forward<Mean>(mean)),
7294
std::forward<CovarFun>(covariance_function),
7395
std::forward<CovarArgs>(covar_args), std::move(options), msgs);
7496
}
@@ -83,9 +105,8 @@ inline auto laplace_marginal_tol_bernoulli_logit_lpmf(
83105
* @tparam propto boolean ignored
84106
* @tparam Mean type of the mean of the latent normal distribution
85107
* \laplace_common_template_args
86-
* @param[in] y total counts per group. Second sufficient statistics.
87-
* @param[in] n_samples number of samples per group. First sufficient
88-
* statistics.
108+
* @param[in] y binary observations
109+
* @param[in] y_index group to which each observation belongs
89110
* @param[in] mean the mean of the latent normal variable.
90111
* \laplace_common_args
91112
* @param[in] hessian_block_size Block size for the Hessian approximation with
@@ -95,13 +116,13 @@ inline auto laplace_marginal_tol_bernoulli_logit_lpmf(
95116
template <bool propto = false, typename Mean, typename CovarFun,
96117
typename CovarArgs>
97118
inline auto laplace_marginal_bernoulli_logit_lpmf(
98-
const std::vector<int>& y, const std::vector<int>& n_samples, Mean&& mean,
119+
const std::vector<int>& y, const std::vector<int>& y_index, Mean&& mean,
99120
int hessian_block_size, CovarFun&& covariance_function,
100121
CovarArgs&& covar_args, std::ostream* msgs) {
101122
auto options = laplace_options_default{hessian_block_size};
102123
return laplace_marginal_density(
103124
bernoulli_logit_likelihood{},
104-
std::forward_as_tuple(to_vector(y), n_samples, std::forward<Mean>(mean)),
125+
std::forward_as_tuple(to_vector(y), y_index, std::forward<Mean>(mean)),
105126
std::forward<CovarFun>(covariance_function),
106127
std::forward<CovarArgs>(covar_args), options, msgs);
107128
}

test/unit/math/laplace/laplace_bernoulli_logit_rng_test.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ TEST(laplace_bernoulli_logit_rng, two_dim_diag) {
6666

6767
Eigen::VectorXd theta_0{{0, 0}};
6868
Eigen::VectorXd phi{{3, 2}};
69-
std::vector<int> n_samples = {1, 1};
70-
std::vector<int> sums = {1, 0};
69+
std::vector<int> y_index = {1, 2};
70+
// std::vector<int> n_samples = {1, 1};
71+
std::vector<int> y = {1, 0};
7172
Eigen::VectorXd ye{{1, 1}};
7273
Eigen::VectorXd mean{{0, 0}};
7374
std::vector<double> d0;
@@ -76,7 +77,7 @@ TEST(laplace_bernoulli_logit_rng, two_dim_diag) {
7677
boost::random::mt19937 rng;
7778
rng.seed(1954);
7879
Eigen::MatrixXd theta_pred = laplace_latent_bernoulli_logit_rng(
79-
sums, n_samples, mean, 1, diagonal_kernel_functor{},
80+
y, y_index, mean, 1, diagonal_kernel_functor{},
8081
std::forward_as_tuple(phi(0), phi(1)), rng, nullptr);
8182

8283
// Compute exact mean and covariance

test/unit/math/laplace/laplace_marginal_bernoulli_logit_lpmf_test.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,17 @@ TEST_P(laplace_marginal_bernoulli_logit_lpmf, phi_dim500) {
3636
for (int i = 0; i < dim_theta; i++) {
3737
x[i] = Eigen::VectorXd{{x1[i], x2[i]}};
3838
}
39-
std::vector<int> n_samples = stan::math::rep_array(1, dim_theta);
39+
std::vector<int> y_index;
40+
y_index.reserve(dim_theta);
41+
for (int i = 1; i <= dim_theta; i++) {
42+
y_index.push_back(i);
43+
}
4044
Eigen::VectorXd theta_0 = Eigen::VectorXd::Zero(dim_theta);
4145
Eigen::VectorXd mean = Eigen::VectorXd::Zero(dim_theta);
42-
std::vector<double> delta;
43-
std::vector<int> delta_int;
4446
Eigen::Matrix<double, Eigen::Dynamic, 1> phi_dbl{{1.6, 1}};
4547
using stan::math::test::sqr_exp_kernel_functor;
4648
double target = laplace_marginal_bernoulli_logit_lpmf(
47-
y, n_samples, 0, hessian_block_size, sqr_exp_kernel_functor{},
49+
y, y_index, 0, hessian_block_size, sqr_exp_kernel_functor{},
4850
std::forward_as_tuple(x, phi_dbl(0), phi_dbl(1)), nullptr);
4951
// Benchmark against gpstuff.
5052
constexpr double tol = 8e-4;
@@ -56,7 +58,7 @@ TEST_P(laplace_marginal_bernoulli_logit_lpmf, phi_dim500) {
5658
auto f = [&](auto&& alpha, auto&& rho) {
5759
try {
5860
return laplace_marginal_tol_bernoulli_logit_lpmf(
59-
y, n_samples, mean, hessian_block_size, sqr_exp_kernel_functor{},
61+
y, y_index, mean, hessian_block_size, sqr_exp_kernel_functor{},
6062
std::forward_as_tuple(x, alpha, rho),
6163
std::make_tuple(theta_0, tolerance, max_num_steps, solver_num,
6264
max_steps_line_search, true),

0 commit comments

Comments
 (0)