Stan  2.5.0
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bernoulli.hpp
Go to the documentation of this file.
1 #ifndef STAN__PROB__DISTRIBUTIONS__UNIVARIATE__DISCRETE__BERNOULLI_HPP
2 #define STAN__PROB__DISTRIBUTIONS__UNIVARIATE__DISCRETE__BERNOULLI_HPP
3 
4 #include <boost/random/bernoulli_distribution.hpp>
5 #include <boost/random/variate_generator.hpp>
6 
13 #include <stan/meta/traits.hpp>
14 #include <stan/prob/traits.hpp>
15 #include <stan/prob/constants.hpp>
16 
17 namespace stan {
18 
19  namespace prob {
20 
21  // Bernoulli(n|theta) [0 <= n <= 1; 0 <= theta <= 1]
22  // FIXME: documentation
23  template <bool propto, typename T_n, typename T_prob>
24  typename return_type<T_prob>::type
25  bernoulli_log(const T_n& n,
26  const T_prob& theta) {
27  static const char* function = "stan::prob::bernoulli_log(%1%)";
28 
31  using stan::math::log1m;
35 
36  // check if any vectors are zero length
37  if (!(stan::length(n)
38  && stan::length(theta)))
39  return 0.0;
40 
41  // set up return value accumulator
42  double logp(0.0);
43 
44  // validate args (here done over var, which should be OK)
45  check_bounded(function, n, 0, 1, "n", &logp);
46  check_finite(function, theta, "Probability parameter", &logp);
47  check_bounded(function, theta, 0.0, 1.0,
48  "Probability parameter", &logp);
49  check_consistent_sizes(function,
50  n,theta,
51  "Random variable","Probability parameter",
52  &logp);
53 
54  // check if no variables are involved and prop-to
56  return 0.0;
57 
58  // set up template expressions wrapping scalars into vector views
59  VectorView<const T_n> n_vec(n);
60  VectorView<const T_prob> theta_vec(theta);
61  size_t N = max_size(n, theta);
62  agrad::OperandsAndPartials<T_prob> operands_and_partials(theta);
63 
64  if (length(theta) == 1) {
65  size_t sum = 0;
66  for (size_t n = 0; n < N; n++) {
67  sum += value_of(n_vec[n]);
68  }
69  const double theta_dbl = value_of(theta_vec[0]);
70  // avoid nans when sum == N or sum == 0
71  if (sum == N) {
72  logp += N * log(theta_dbl);
74  operands_and_partials.d_x1[0] += N / theta_dbl;
75  } else if (sum == 0) {
76  logp += N * log1m(theta_dbl);
78  operands_and_partials.d_x1[0] += N / (theta_dbl - 1);
79  } else {
80  const double log_theta = log(theta_dbl);
81  const double log1m_theta = log1m(theta_dbl);
82 
83  logp += sum * log_theta;
84  logp += (N - sum) * log1m_theta;
85 
86  // gradient
88  operands_and_partials.d_x1[0] += sum / theta_dbl;
89  operands_and_partials.d_x1[0] += (N - sum) / (theta_dbl - 1);
90  }
91  }
92  } else {
93  for (size_t n = 0; n < N; n++) {
94  // pull out values of arguments
95  const int n_int = value_of(n_vec[n]);
96  const double theta_dbl = value_of(theta_vec[n]);
97 
98  if (n_int == 1)
99  logp += log(theta_dbl);
100  else
101  logp += log1m(theta_dbl);
102 
103  // gradient
105  if (n_int == 1)
106  operands_and_partials.d_x1[n] += 1.0 / theta_dbl;
107  else
108  operands_and_partials.d_x1[n] += 1.0 / (theta_dbl - 1);
109  }
110  }
111  }
112  return operands_and_partials.to_var(logp);
113  }
114 
115  template <typename T_y, typename T_prob>
116  inline
118  bernoulli_log(const T_y& n,
119  const T_prob& theta) {
120  return bernoulli_log<false>(n,theta);
121  }
122 
123 
124  // Bernoulli(n|inv_logit(theta)) [0 <= n <= 1; -inf <= theta <= inf]
125  // FIXME: documentation
126  template <bool propto, typename T_n, typename T_prob>
128  bernoulli_logit_log(const T_n& n, const T_prob& theta) {
129  static const char* function = "stan::prob::bernoulli_logit_log(%1%)";
130 
134  using stan::math::value_of;
137  using stan::math::log1p;
138  using stan::math::inv_logit;
139 
140  // check if any vectors are zero length
141  if (!(stan::length(n)
142  && stan::length(theta)))
143  return 0.0;
144 
145  // set up return value accumulator
146  double logp(0.0);
147 
148  // validate args (here done over var, which should be OK)
149  check_bounded(function, n, 0, 1, "n", &logp);
150  check_not_nan(function, theta, "Logit transformed probability parameter",
151  &logp);
152  check_consistent_sizes(function,
153  n,theta,
154  "Random variable","Probability parameter",
155  &logp);
156 
157  // check if no variables are involved and prop-to
159  return 0.0;
160 
161  // set up template expressions wrapping scalars into vector views
162  VectorView<const T_n> n_vec(n);
163  VectorView<const T_prob> theta_vec(theta);
164  size_t N = max_size(n, theta);
165  agrad::OperandsAndPartials<T_prob> operands_and_partials(theta);
166 
167  for (size_t n = 0; n < N; n++) {
168  // pull out values of arguments
169  const int n_int = value_of(n_vec[n]);
170  const double theta_dbl = value_of(theta_vec[n]);
171 
172  // reusable subexpression values
173  const int sign = 2*n_int-1;
174  const double ntheta = sign * theta_dbl;
175  const double exp_m_ntheta = exp(-ntheta);
176 
177  // Handle extreme values gracefully using Taylor approximations.
178  const static double cutoff = 20.0;
179  if (ntheta > cutoff)
180  logp -= exp_m_ntheta;
181  else if (ntheta < -cutoff)
182  logp += ntheta;
183  else
184  logp -= log1p(exp_m_ntheta);
185 
186  // gradients
188  const static double cutoff = 20.0;
189  if (ntheta > cutoff)
190  operands_and_partials.d_x1[n] -= exp_m_ntheta;
191  else if (ntheta < -cutoff)
192  operands_and_partials.d_x1[n] += sign;
193  else
194  operands_and_partials.d_x1[n] += sign * exp_m_ntheta / (exp_m_ntheta + 1);
195  }
196  }
197  return operands_and_partials.to_var(logp);
198  }
199 
200  template <typename T_n,
201  typename T_prob>
202  inline
204  bernoulli_logit_log(const T_n& n,
205  const T_prob& theta) {
206  return bernoulli_logit_log<false>(n,theta);
207  }
208 
209  // Bernoulli CDF
210  template <typename T_n, typename T_prob>
212  bernoulli_cdf(const T_n& n, const T_prob& theta) {
213  static const char* function = "stan::prob::bernoulli_cdf(%1%)";
214 
219 
220  // Ensure non-zero argument lenghts
221  if (!(stan::length(n) && stan::length(theta)))
222  return 1.0;
223 
224  double P(1.0);
225 
226  // Validate arguments
227  check_finite(function, theta, "Probability parameter", &P);
228  check_bounded(function, theta, 0.0, 1.0,
229  "Probability parameter", &P);
230  check_consistent_sizes(function,
231  n, theta,
232  "Random variable","Probability parameter",
233  &P);
234 
235  // set up template expressions wrapping scalars into vector views
236  VectorView<const T_n> n_vec(n);
237  VectorView<const T_prob> theta_vec(theta);
238  size_t size = max_size(n, theta);
239 
240  // Compute vectorized CDF and gradient
241  using stan::math::value_of;
242  agrad::OperandsAndPartials<T_prob> operands_and_partials(theta);
243 
244  // Explicit return for extreme values
245  // The gradients are technically ill-defined, but treated as zero
246  for (size_t i = 0; i < stan::length(n); i++) {
247  if (value_of(n_vec[i]) < 0)
248  return operands_and_partials.to_var(0.0);
249  }
250 
251  for (size_t i = 0; i < size; i++) {
252 
253  // Explicit results for extreme values
254  // The gradients are technically ill-defined, but treated as zero
255  if (value_of(n_vec[i]) >= 1) continue;
256  else {
257  const double Pi = 1 - value_of(theta_vec[i]);
258 
259  P *= Pi;
260 
262  operands_and_partials.d_x1[i] += - 1 / Pi;
263  }
264  }
265 
267  for(size_t i = 0; i < stan::length(theta); ++i) operands_and_partials.d_x1[i] *= P;
268  }
269  return operands_and_partials.to_var(P);
270  }
271 
272  template <typename T_n, typename T_prob>
274  bernoulli_cdf_log(const T_n& n, const T_prob& theta) {
275  static const char* function = "stan::prob::bernoulli_cdf_log(%1%)";
276 
281 
282  // Ensure non-zero argument lenghts
283  if (!(stan::length(n) && stan::length(theta)))
284  return 0.0;
285 
286  double P(0.0);
287 
288  // Validate arguments
289  check_finite(function, theta, "Probability parameter", &P);
290  check_bounded(function, theta, 0.0, 1.0,
291  "Probability parameter", &P);
292  check_consistent_sizes(function,
293  n, theta,
294  "Random variable","Probability parameter",
295  &P);
296 
297  // set up template expressions wrapping scalars into vector views
298  VectorView<const T_n> n_vec(n);
299  VectorView<const T_prob> theta_vec(theta);
300  size_t size = max_size(n, theta);
301 
302  // Compute vectorized cdf_log and gradient
303  using stan::math::value_of;
304  agrad::OperandsAndPartials<T_prob> operands_and_partials(theta);
305 
306  // Explicit return for extreme values
307  // The gradients are technically ill-defined, but treated as zero
308  for (size_t i = 0; i < stan::length(n); i++) {
309  if (value_of(n_vec[i]) < 0)
310  return operands_and_partials.to_var(stan::math::negative_infinity());
311  }
312 
313  for (size_t i = 0; i < size; i++) {
314 
315  // Explicit results for extreme values
316  // The gradients are technically ill-defined, but treated as zero
317  if (value_of(n_vec[i]) >= 1) continue;
318  else {
319  const double Pi = 1 - value_of(theta_vec[i]);
320 
321  P += log(Pi);
322 
324  operands_and_partials.d_x1[i] -= 1 / Pi;
325  }
326  }
327 
328  return operands_and_partials.to_var(P);
329  }
330 
331  template <typename T_n, typename T_prob>
333  bernoulli_ccdf_log(const T_n& n, const T_prob& theta) {
334  static const char* function = "stan::prob::bernoulli_ccdf_log(%1%)";
335 
340 
341  // Ensure non-zero argument lenghts
342  if (!(stan::length(n) && stan::length(theta)))
343  return 0.0;
344 
345  double P(0.0);
346 
347  // Validate arguments
348  check_finite(function, theta, "Probability parameter", &P);
349  check_bounded(function, theta, 0.0, 1.0,
350  "Probability parameter", &P);
351  check_consistent_sizes(function,
352  n, theta,
353  "Random variable","Probability parameter",
354  &P);
355 
356  // set up template expressions wrapping scalars into vector views
357  VectorView<const T_n> n_vec(n);
358  VectorView<const T_prob> theta_vec(theta);
359  size_t size = max_size(n, theta);
360 
361  // Compute vectorized cdf_log and gradient
362  using stan::math::value_of;
363  agrad::OperandsAndPartials<T_prob> operands_and_partials(theta);
364 
365  // Explicit return for extreme values
366  // The gradients are technically ill-defined, but treated as zero
367  for (size_t i = 0; i < stan::length(n); i++) {
368  if (value_of(n_vec[i]) < 0)
369  return operands_and_partials.to_var(0.0);
370  }
371 
372  for (size_t i = 0; i < size; i++) {
373 
374  // Explicit results for extreme values
375  // The gradients are technically ill-defined, but treated as zero
376  if (value_of(n_vec[i]) >= 1)
377  return operands_and_partials.to_var(stan::math::negative_infinity());
378  else {
379  const double Pi = value_of(theta_vec[i]);
380 
381  P += log(Pi);
382 
384  operands_and_partials.d_x1[i] += 1 / Pi;
385  }
386  }
387 
388  return operands_and_partials.to_var(P);
389  }
390 
391 
392  template <class RNG>
393  inline int
394  bernoulli_rng(const double theta,
395  RNG& rng) {
396  using boost::variate_generator;
397  using boost::bernoulli_distribution;
398 
399  static const char* function = "stan::prob::bernoulli_rng(%1%)";
400 
403 
404  check_finite(function, theta, "Probability parameter", (double*)0);
405  check_bounded(function, theta, 0, 1,
406  "Probability parameter", (double*)0);
407 
408  variate_generator<RNG&, bernoulli_distribution<> >
409  bernoulli_rng(rng, bernoulli_distribution<>(theta));
410  return bernoulli_rng();
411  }
412  }
413 }
414 #endif
fvar< T > log1m(const fvar< T > &x)
Definition: log1m.hpp:16
bool check_bounded(const char *function, const T_y &y, const T_low &low, const T_high &high, const char *name, T_result *result)
boost::math::tools::promote_args< T >::type log1p(const T x)
Return the natural logarithm of one plus the specified value.
Definition: log1p.hpp:39
T_return_type to_var(double logp)
int sign(const T &z)
Definition: sign.hpp:9
size_t length(const T &)
Definition: traits.hpp:159
bool check_finite(const char *function, const T_y &y, const char *name, T_result *result)
Checks if the variable y is finite.
boost::math::tools::promote_args< T >::type inv_logit(const T a)
Returns the inverse logit function applied to the argument.
Definition: inv_logit.hpp:52
return_type< T_prob >::type bernoulli_ccdf_log(const T_n &n, const T_prob &theta)
Definition: bernoulli.hpp:333
int bernoulli_rng(const double theta, RNG &rng)
Definition: bernoulli.hpp:394
T value_of(const fvar< T > &v)
Return the value of the specified variable.
Definition: value_of.hpp:16
fvar< T > sum(const Eigen::Matrix< fvar< T >, R, C > &m)
Definition: sum.hpp:14
A variable implementation that stores operands and derivatives with respect to the variable...
boost::math::tools::promote_args< typename scalar_type< T1 >::type, typename scalar_type< T2 >::type, typename scalar_type< T3 >::type, typename scalar_type< T4 >::type, typename scalar_type< T5 >::type, typename scalar_type< T6 >::type >::type type
Definition: traits.hpp:406
Metaprogram to determine if a type has a base scalar type that can be assigned to type double...
Definition: traits.hpp:57
double value_of(const T x)
Return the value of the specified scalar argument converted to a double value.
Definition: value_of.hpp:24
Template metaprogram to calculate whether a summand needs to be included in a proportional (log) prob...
Definition: traits.hpp:35
bool check_consistent_sizes(const char *function, const T1 &x1, const T2 &x2, const char *name1, const char *name2, T_result *result)
size_t max_size(const T1 &x1, const T2 &x2)
Definition: traits.hpp:191
return_type< T_prob >::type bernoulli_log(const T_n &n, const T_prob &theta)
Definition: bernoulli.hpp:25
return_type< T_prob >::type bernoulli_cdf_log(const T_n &n, const T_prob &theta)
Definition: bernoulli.hpp:274
bool check_not_nan(const char *function, const T_y &y, const char *name, T_result *result)
Checks if the variable y is nan.
int size(const std::vector< T > &x)
Definition: size.hpp:11
return_type< T_prob >::type bernoulli_cdf(const T_n &n, const T_prob &theta)
Definition: bernoulli.hpp:212
VectorView< double *, is_vector< T1 >::value, is_constant_struct< T1 >::value > d_x1
fvar< T > log(const fvar< T > &x)
Definition: log.hpp:15
return_type< T_prob >::type bernoulli_logit_log(const T_n &n, const T_prob &theta)
Definition: bernoulli.hpp:128
VectorView is a template metaprogram that takes its argument and allows it to be used like a vector...
Definition: traits.hpp:275
fvar< T > exp(const fvar< T > &x)
Definition: exp.hpp:16
fvar< T > log1p(const fvar< T > &x)
Definition: log1p.hpp:16
boost::math::tools::promote_args< T >::type log1m(T x)
Return the natural logarithm of one minus the specified value.
Definition: log1m.hpp:40
double negative_infinity()
Return negative infinity.
Definition: constants.hpp:123

     [ Stan Home Page ] © 2011–2014, Stan Development Team.