Stan  2.5.0
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
normal.hpp
Go to the documentation of this file.
1 #ifndef STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__NORMAL_HPP
2 #define STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__NORMAL_HPP
3 
4 #include <boost/random/normal_distribution.hpp>
5 #include <boost/random/variate_generator.hpp>
6 #include <boost/utility/enable_if.hpp>
7 
9 #include <stan/math.hpp>
11 #include <stan/meta/traits.hpp>
12 #include <stan/prob/constants.hpp>
13 #include <stan/prob/traits.hpp>
14 
15 namespace stan {
16 
17  namespace prob {
18 
37  template <bool propto,
38  typename T_y, typename T_loc, typename T_scale>
39  typename boost::enable_if_c<is_var_or_arithmetic<T_y,T_loc,T_scale>::value,
40  typename return_type<T_y,T_loc,T_scale>::type>::type
41  normal_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
42  static const char* function = "stan::prob::normal_log(%1%)";
43 
44  using std::log;
52 
53  // check if any vectors are zero length
54  if (!(stan::length(y)
55  && stan::length(mu)
56  && stan::length(sigma)))
57  return 0.0;
58 
59  // set up return value accumulator
60  double logp(0.0);
61 
62  // validate args (here done over var, which should be OK)
63  check_not_nan(function, y, "Random variable", &logp);
64  check_finite(function, mu, "Location parameter", &logp);
65  check_positive(function, sigma, "Scale parameter", &logp);
66  check_consistent_sizes(function,
67  y,mu,sigma,
68  "Random variable","Location parameter",
69  "Scale parameter",
70  &logp);
71  // check if no variables are involved and prop-to
73  return 0.0;
74 
75  // set up template expressions wrapping scalars into vector views
76  agrad::OperandsAndPartials<T_y, T_loc, T_scale> operands_and_partials(y, mu, sigma);
77 
78  VectorView<const T_y> y_vec(y);
79  VectorView<const T_loc> mu_vec(mu);
80  VectorView<const T_scale> sigma_vec(sigma);
81  size_t N = max_size(y, mu, sigma);
82 
85  for (size_t i = 0; i < length(sigma); i++) {
86  inv_sigma[i] = 1.0 / value_of(sigma_vec[i]);
88  log_sigma[i] = log(value_of(sigma_vec[i]));
89  }
90 
91  for (size_t n = 0; n < N; n++) {
92  // pull out values of arguments
93  const double y_dbl = value_of(y_vec[n]);
94  const double mu_dbl = value_of(mu_vec[n]);
95 
96  // reusable subexpression values
97  const double y_minus_mu_over_sigma
98  = (y_dbl - mu_dbl) * inv_sigma[n];
99  const double y_minus_mu_over_sigma_squared
100  = y_minus_mu_over_sigma * y_minus_mu_over_sigma;
101 
102  static double NEGATIVE_HALF = - 0.5;
103 
104  // log probability
106  logp += NEG_LOG_SQRT_TWO_PI;
108  logp -= log_sigma[n];
110  logp += NEGATIVE_HALF * y_minus_mu_over_sigma_squared;
111 
112  // gradients
113  double scaled_diff = inv_sigma[n] * y_minus_mu_over_sigma;
115  operands_and_partials.d_x1[n] -= scaled_diff;
117  operands_and_partials.d_x2[n] += scaled_diff;
119  operands_and_partials.d_x3[n]
120  += -inv_sigma[n] + inv_sigma[n] * y_minus_mu_over_sigma_squared;
121  }
122  return operands_and_partials.to_var(logp);
123  }
124 
125  template <typename T_y, typename T_loc, typename T_scale>
126  inline
128  normal_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
129  return normal_log<false>(y,mu,sigma);
130  }
131 
150  template <typename T_y, typename T_loc, typename T_scale>
152  normal_cdf(const T_y& y, const T_loc& mu, const T_scale& sigma) {
153  static const char* function = "stan::prob::normal_cdf(%1%)";
154 
158  using stan::math::value_of;
161 
162  double cdf(1.0);
163 
164  // check if any vectors are zero length
165  if (!(stan::length(y)
166  && stan::length(mu)
167  && stan::length(sigma)))
168  return cdf;
169 
170  check_not_nan(function, y, "Random variable", &cdf);
171  check_finite(function, mu, "Location parameter", &cdf);
172  check_not_nan(function, sigma, "Scale parameter", &cdf);
173  check_positive(function, sigma, "Scale parameter", &cdf);
174  check_consistent_sizes(function,
175  y,mu,sigma,
176  "Random variable","Location parameter",
177  "Scale parameter",
178  &cdf);
179 
181  operands_and_partials(y, mu, sigma);
182 
183  VectorView<const T_y> y_vec(y);
184  VectorView<const T_loc> mu_vec(mu);
185  VectorView<const T_scale> sigma_vec(sigma);
186  size_t N = max_size(y, mu, sigma);
187  const double SQRT_TWO_OVER_PI = std::sqrt(2.0 / stan::math::pi());
188 
189  for (size_t n = 0; n < N; n++) {
190  const double y_dbl = value_of(y_vec[n]);
191  const double mu_dbl = value_of(mu_vec[n]);
192  const double sigma_dbl = value_of(sigma_vec[n]);
193  const double scaled_diff = (y_dbl - mu_dbl) / (sigma_dbl * SQRT_2);
194  double cdf_;
195  if (scaled_diff < -37.5 * INV_SQRT_2)
196  cdf_ = 0.0;
197  else if (scaled_diff < -5.0 * INV_SQRT_2)
198  cdf_ = 0.5 * erfc(-scaled_diff);
199  else if (scaled_diff > 8.25 * INV_SQRT_2)
200  cdf_ = 1;
201  else
202  cdf_ = 0.5 * (1.0 + erf(scaled_diff));
203 
204  // cdf
205  cdf *= cdf_;
206 
207  // gradients
208  const double rep_deriv = SQRT_TWO_OVER_PI * 0.5
209  * exp(-scaled_diff * scaled_diff) / cdf_ / sigma_dbl;
211  operands_and_partials.d_x1[n] += rep_deriv;
213  operands_and_partials.d_x2[n] -= rep_deriv;
215  operands_and_partials.d_x3[n] -= rep_deriv * scaled_diff * SQRT_2;
216  }
217 
219  for (size_t n = 0; n < stan::length(y); ++n)
220  operands_and_partials.d_x1[n] *= cdf;
222  for (size_t n = 0; n < stan::length(mu); ++n)
223  operands_and_partials.d_x2[n] *= cdf;
225  for (size_t n = 0; n < stan::length(sigma); ++n)
226  operands_and_partials.d_x3[n] *= cdf;
227 
228  return operands_and_partials.to_var(cdf);
229  }
230 
231  template <typename T_y, typename T_loc, typename T_scale>
233  normal_cdf_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
234  static const char* function = "stan::prob::normal_cdf_log(%1%)";
235 
240  using stan::math::value_of;
242 
243  double cdf_log(0.0);
244  // check if any vectors are zero length
245  if (!(stan::length(y)
246  && stan::length(mu)
247  && stan::length(sigma)))
248  return cdf_log;
249 
250  check_not_nan(function, y, "Random variable", &cdf_log);
251  check_finite(function, mu, "Location parameter", &cdf_log);
252  check_not_nan(function, sigma, "Scale parameter", &cdf_log);
253  check_positive(function, sigma, "Scale parameter", &cdf_log);
254  check_consistent_sizes(function,
255  y,mu,sigma,
256  "Random variable","Location parameter",
257  "Scale parameter", &cdf_log);
258 
260  operands_and_partials(y, mu, sigma);
261 
262  VectorView<const T_y> y_vec(y);
263  VectorView<const T_loc> mu_vec(mu);
264  VectorView<const T_scale> sigma_vec(sigma);
265  size_t N = max_size(y, mu, sigma);
266  double log_half = std::log(0.5);
267 
268  const double SQRT_TWO_OVER_PI = std::sqrt(2.0 / stan::math::pi());
269  for (size_t n = 0; n < N; n++) {
270  const double y_dbl = value_of(y_vec[n]);
271  const double mu_dbl = value_of(mu_vec[n]);
272  const double sigma_dbl = value_of(sigma_vec[n]);
273 
274  const double scaled_diff = (y_dbl - mu_dbl) / (sigma_dbl * SQRT_2);
275 
276  double one_p_erf;
277  if (scaled_diff < -37.5 * INV_SQRT_2)
278  one_p_erf = 0.0;
279  else if (scaled_diff < -5.0 * INV_SQRT_2)
280  one_p_erf = erfc(-scaled_diff);
281  else if (scaled_diff > 8.25 * INV_SQRT_2)
282  one_p_erf = 2.0;
283  else
284  one_p_erf = 1.0 + erf(scaled_diff);
285 
286  // log cdf
287  cdf_log += log_half + log(one_p_erf);
288 
289  // gradients
290  const double rep_deriv = SQRT_TWO_OVER_PI
291  * exp(-scaled_diff * scaled_diff) / one_p_erf;
293  operands_and_partials.d_x1[n] += rep_deriv / sigma_dbl;
295  operands_and_partials.d_x2[n] -= rep_deriv / sigma_dbl;
297  operands_and_partials.d_x3[n] -= rep_deriv * scaled_diff
298  * stan::math::SQRT_2 / sigma_dbl;
299  }
300  return operands_and_partials.to_var(cdf_log);
301  }
302 
303  template <typename T_y, typename T_loc, typename T_scale>
305  normal_ccdf_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
306  static const char* function = "stan::prob::normal_ccdf_log(%1%)";
307 
312  using stan::math::value_of;
314 
315  double ccdf_log(0.0);
316  // check if any vectors are zero length
317  if (!(stan::length(y)
318  && stan::length(mu)
319  && stan::length(sigma)))
320  return ccdf_log;
321 
322  check_not_nan(function, y, "Random variable", &ccdf_log);
323  check_finite(function, mu, "Location parameter", &ccdf_log);
324  check_not_nan(function, sigma, "Scale parameter", &ccdf_log);
325  check_positive(function, sigma, "Scale parameter", &ccdf_log);
326  check_consistent_sizes(function,
327  y,mu,sigma,
328  "Random variable","Location parameter",
329  "Scale parameter", &ccdf_log);
330 
332  operands_and_partials(y, mu, sigma);
333 
334  VectorView<const T_y> y_vec(y);
335  VectorView<const T_loc> mu_vec(mu);
336  VectorView<const T_scale> sigma_vec(sigma);
337  size_t N = max_size(y, mu, sigma);
338  double log_half = std::log(0.5);
339 
340  const double SQRT_TWO_OVER_PI = std::sqrt(2.0 / stan::math::pi());
341  for (size_t n = 0; n < N; n++) {
342  const double y_dbl = value_of(y_vec[n]);
343  const double mu_dbl = value_of(mu_vec[n]);
344  const double sigma_dbl = value_of(sigma_vec[n]);
345 
346  const double scaled_diff = (y_dbl - mu_dbl) / (sigma_dbl * SQRT_2);
347 
348  double one_m_erf;
349  if (scaled_diff < -37.5 * INV_SQRT_2)
350  one_m_erf = 2.0;
351  else if (scaled_diff < -5.0 * INV_SQRT_2)
352  one_m_erf = 2.0 - erfc(-scaled_diff);
353  else if (scaled_diff > 8.25 * INV_SQRT_2)
354  one_m_erf = 0.0;
355  else
356  one_m_erf = 1.0 - erf(scaled_diff);
357 
358  // log ccdf
359  ccdf_log += log_half + log(one_m_erf);
360 
361  // gradients
362  const double rep_deriv = SQRT_TWO_OVER_PI
363  * exp(-scaled_diff * scaled_diff) / one_m_erf;
365  operands_and_partials.d_x1[n] -= rep_deriv / sigma_dbl;
367  operands_and_partials.d_x2[n] += rep_deriv / sigma_dbl;
369  operands_and_partials.d_x3[n] += rep_deriv * scaled_diff
370  * stan::math::SQRT_2 / sigma_dbl;
371  }
372  return operands_and_partials.to_var(ccdf_log);
373  }
374 
375  template <class RNG>
376  inline double
377  normal_rng(const double mu,
378  const double sigma,
379  RNG& rng) {
380  using boost::variate_generator;
381  using boost::normal_distribution;
385 
386  static const char* function = "stan::prob::normal_rng(%1%)";
387 
388  check_finite(function, mu, "Location parameter", (double*)0);
389  check_not_nan(function, mu, "Location parameter", (double*)0);
390  check_positive(function, sigma, "Scale parameter", (double*)0);
391  check_not_nan(function, sigma, "Scale parameter", (double*)0);
392 
393  variate_generator<RNG&, normal_distribution<> >
394  norm_rng(rng, normal_distribution<>(mu, sigma));
395  return norm_rng();
396  }
397  }
398 }
399 #endif
fvar< T > erf(const fvar< T > &x)
Definition: erf.hpp:17
T_return_type to_var(double logp)
size_t length(const T &)
Definition: traits.hpp:159
fvar< T > erfc(const fvar< T > &x)
Definition: erfc.hpp:17
DoubleVectorView allocates double values to be used as intermediate values.
Definition: traits.hpp:358
bool check_finite(const char *function, const T_y &y, const char *name, T_result *result)
Checks if the variable y is finite.
T value_of(const fvar< T > &v)
Return the value of the specified variable.
Definition: value_of.hpp:16
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
return_type< T_y, T_loc, T_scale >::type normal_ccdf_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: normal.hpp:305
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
const double SQRT_2
The value of the square root of 2, .
Definition: constants.hpp:20
const double INV_SQRT_2
The value of 1 over the square root of 2, .
Definition: constants.hpp:26
fvar< T > sqrt(const fvar< T > &x)
Definition: sqrt.hpp:15
VectorView< double *, is_vector< T2 >::value, is_constant_struct< T2 >::value > d_x2
bool check_consistent_sizes(const char *function, const T1 &x1, const T2 &x2, const char *name1, const char *name2, T_result *result)
double normal_rng(const double mu, const double sigma, RNG &rng)
Definition: normal.hpp:377
size_t max_size(const T1 &x1, const T2 &x2)
Definition: traits.hpp:191
bool check_positive(const char *function, const T_y &y, const char *name, T_result *result)
return_type< T_y, T_loc, T_scale >::type normal_cdf(const T_y &y, const T_loc &mu, const T_scale &sigma)
Calculates the normal cumulative distribution function for the given variate, location, and scale.
Definition: normal.hpp:152
boost::enable_if_c< contains_fvar< T_y, T_loc, T_scale >::value, typename return_type< T_y, T_loc, T_scale >::type >::type normal_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: normal.hpp:22
bool check_not_nan(const char *function, const T_y &y, const char *name, T_result *result)
Checks if the variable y is nan.
return_type< T_y, T_loc, T_scale >::type normal_cdf_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: normal.hpp:233
VectorView< double *, is_vector< T1 >::value, is_constant_struct< T1 >::value > d_x1
VectorView< double *, is_vector< T3 >::value, is_constant_struct< T3 >::value > d_x3
double pi()
Return the value of pi.
Definition: constants.hpp:77
fvar< T > log(const fvar< T > &x)
Definition: log.hpp:15
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

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