|
3 | 3 |
|
4 | 4 | #include <stan/math/prim/meta.hpp> |
5 | 5 | #include <stan/math/prim/err.hpp> |
| 6 | +#include <stan/math/prim/fun/binomial_coefficient_log.hpp> |
6 | 7 | #include <stan/math/prim/fun/digamma.hpp> |
7 | | -#include <stan/math/prim/fun/lgamma.hpp> |
8 | 8 | #include <stan/math/prim/fun/log.hpp> |
9 | 9 | #include <stan/math/prim/fun/max_size.hpp> |
10 | 10 | #include <stan/math/prim/fun/multiply_log.hpp> |
11 | 11 | #include <stan/math/prim/fun/size.hpp> |
12 | 12 | #include <stan/math/prim/fun/size_zero.hpp> |
13 | 13 | #include <stan/math/prim/fun/value_of.hpp> |
14 | | -#include <stan/math/prim/prob/poisson_lpmf.hpp> |
15 | 14 | #include <cmath> |
16 | 15 |
|
17 | 16 | namespace stan { |
@@ -47,7 +46,7 @@ return_type_t<T_location, T_precision> neg_binomial_2_lpmf( |
47 | 46 | size_t size_phi = stan::math::size(phi); |
48 | 47 | size_t size_mu_phi = max_size(mu, phi); |
49 | 48 | size_t size_n_phi = max_size(n, phi); |
50 | | - size_t max_size_seq_view = max_size(n, mu, phi); |
| 49 | + size_t size_all = max_size(n, mu, phi); |
51 | 50 |
|
52 | 51 | VectorBuilder<true, T_partials_return, T_location> mu_val(size_mu); |
53 | 52 | for (size_t i = 0; i < size_mu; ++i) { |
@@ -76,39 +75,30 @@ return_type_t<T_location, T_precision> neg_binomial_2_lpmf( |
76 | 75 | n_plus_phi[i] = n_vec[i] + phi_val[i]; |
77 | 76 | } |
78 | 77 |
|
79 | | - for (size_t i = 0; i < max_size_seq_view; i++) { |
80 | | - // if phi is large we probably overflow, defer to Poisson: |
81 | | - if (phi_val[i] > 1e5) { |
82 | | - // TODO(martinmodrak) This is wrong (doesn't pass propto information), |
83 | | - // and inaccurate for n = 0, but shouldn't break most models. |
84 | | - // Also the 1e5 cutoff is too small. |
85 | | - // Will be addressed better in PR #1497 |
86 | | - logp += poisson_lpmf(n_vec[i], mu_val[i]); |
87 | | - } else { |
88 | | - if (include_summand<propto>::value) { |
89 | | - logp -= lgamma(n_vec[i] + 1.0); |
90 | | - } |
91 | | - if (include_summand<propto, T_precision>::value) { |
92 | | - logp += multiply_log(phi_val[i], phi_val[i]) - lgamma(phi_val[i]); |
93 | | - } |
94 | | - if (include_summand<propto, T_location>::value) { |
95 | | - logp += multiply_log(n_vec[i], mu_val[i]); |
96 | | - } |
97 | | - if (include_summand<propto, T_precision>::value) { |
98 | | - logp += lgamma(n_plus_phi[i]); |
99 | | - } |
100 | | - logp -= n_plus_phi[i] * log_mu_plus_phi[i]; |
| 78 | + for (size_t i = 0; i < size_all; i++) { |
| 79 | + if (include_summand<propto, T_precision>::value) { |
| 80 | + logp += binomial_coefficient_log(n_plus_phi[i] - 1, n_vec[i]); |
| 81 | + } |
| 82 | + if (include_summand<propto, T_location>::value) { |
| 83 | + logp += multiply_log(n_vec[i], mu_val[i]); |
101 | 84 | } |
| 85 | + logp += -phi_val[i] * (log1p(mu_val[i] / phi_val[i])) |
| 86 | + - n_vec[i] * log_mu_plus_phi[i]; |
102 | 87 |
|
103 | 88 | if (!is_constant_all<T_location>::value) { |
104 | 89 | ops_partials.edge1_.partials_[i] |
105 | | - += n_vec[i] / mu_val[i] - n_plus_phi[i] / mu_plus_phi[i]; |
| 90 | + += n_vec[i] / mu_val[i] - (n_vec[i] + phi_val[i]) / (mu_plus_phi[i]); |
106 | 91 | } |
107 | 92 | if (!is_constant_all<T_precision>::value) { |
108 | | - ops_partials.edge2_.partials_[i] += 1.0 - n_plus_phi[i] / mu_plus_phi[i] |
109 | | - + log_phi[i] - log_mu_plus_phi[i] |
110 | | - - digamma(phi_val[i]) |
111 | | - + digamma(n_plus_phi[i]); |
| 93 | + T_partials_return log_term; |
| 94 | + if (mu_val[i] < phi_val[i]) { |
| 95 | + log_term = log1p(-mu_val[i] / (mu_plus_phi[i])); |
| 96 | + } else { |
| 97 | + log_term = log_phi[i] - log_mu_plus_phi[i]; |
| 98 | + } |
| 99 | + ops_partials.edge2_.partials_[i] |
| 100 | + += (mu_val[i] - n_vec[i]) / (mu_plus_phi[i]) + log_term |
| 101 | + - (digamma(phi_val[i]) - digamma(n_plus_phi[i])); |
112 | 102 | } |
113 | 103 | } |
114 | 104 | return ops_partials.build(logp); |
|
0 commit comments