1 #ifndef STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__NORMAL_HPP
2 #define STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__NORMAL_HPP
4 #include <boost/random/normal_distribution.hpp>
5 #include <boost/random/variate_generator.hpp>
6 #include <boost/utility/enable_if.hpp>
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%)";
68 "Random variable",
"Location parameter",
85 for (
size_t i = 0; i <
length(sigma); i++) {
86 inv_sigma[i] = 1.0 /
value_of(sigma_vec[i]);
91 for (
size_t n = 0; n < N; n++) {
93 const double y_dbl =
value_of(y_vec[n]);
94 const double mu_dbl =
value_of(mu_vec[n]);
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;
102 static double NEGATIVE_HALF = - 0.5;
106 logp += NEG_LOG_SQRT_TWO_PI;
108 logp -= log_sigma[n];
110 logp += NEGATIVE_HALF * y_minus_mu_over_sigma_squared;
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;
122 return operands_and_partials.
to_var(logp);
125 template <
typename T_y,
typename T_loc,
typename T_scale>
128 normal_log(
const T_y& y,
const T_loc& mu,
const T_scale& sigma) {
129 return normal_log<false>(y,mu,sigma);
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%)";
176 "Random variable",
"Location parameter",
181 operands_and_partials(y, mu, sigma);
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);
198 cdf_ = 0.5 *
erfc(-scaled_diff);
202 cdf_ = 0.5 * (1.0 +
erf(scaled_diff));
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;
220 operands_and_partials.
d_x1[n] *= cdf;
223 operands_and_partials.
d_x2[n] *= cdf;
226 operands_and_partials.
d_x3[n] *= cdf;
228 return operands_and_partials.
to_var(cdf);
231 template <
typename T_y,
typename T_loc,
typename T_scale>
234 static const char*
function =
"stan::prob::normal_cdf_log(%1%)";
251 check_finite(
function, mu,
"Location parameter", &cdf_log);
256 "Random variable",
"Location parameter",
257 "Scale parameter", &cdf_log);
260 operands_and_partials(y, mu, sigma);
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]);
274 const double scaled_diff = (y_dbl - mu_dbl) / (sigma_dbl *
SQRT_2);
280 one_p_erf =
erfc(-scaled_diff);
284 one_p_erf = 1.0 +
erf(scaled_diff);
287 cdf_log += log_half +
log(one_p_erf);
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
300 return operands_and_partials.
to_var(cdf_log);
303 template <
typename T_y,
typename T_loc,
typename T_scale>
306 static const char*
function =
"stan::prob::normal_ccdf_log(%1%)";
315 double ccdf_log(0.0);
323 check_finite(
function, mu,
"Location parameter", &ccdf_log);
324 check_not_nan(
function, sigma,
"Scale parameter", &ccdf_log);
328 "Random variable",
"Location parameter",
329 "Scale parameter", &ccdf_log);
332 operands_and_partials(y, mu, sigma);
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]);
346 const double scaled_diff = (y_dbl - mu_dbl) / (sigma_dbl *
SQRT_2);
352 one_m_erf = 2.0 -
erfc(-scaled_diff);
356 one_m_erf = 1.0 -
erf(scaled_diff);
359 ccdf_log += log_half +
log(one_m_erf);
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
372 return operands_and_partials.
to_var(ccdf_log);
380 using boost::variate_generator;
381 using boost::normal_distribution;
386 static const char*
function =
"stan::prob::normal_rng(%1%)";
388 check_finite(
function, mu,
"Location parameter", (
double*)0);
389 check_not_nan(
function, mu,
"Location parameter", (
double*)0);
391 check_not_nan(
function, sigma,
"Scale parameter", (
double*)0);
393 variate_generator<RNG&, normal_distribution<> >
394 norm_rng(rng, normal_distribution<>(mu, sigma));
fvar< T > erf(const fvar< T > &x)
T_return_type to_var(double logp)
fvar< T > erfc(const fvar< T > &x)
DoubleVectorView allocates double values to be used as intermediate values.
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.
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
return_type< T_y, T_loc, T_scale >::type normal_ccdf_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Metaprogram to determine if a type has a base scalar type that can be assigned to type double...
double value_of(const T x)
Return the value of the specified scalar argument converted to a double value.
Template metaprogram to calculate whether a summand needs to be included in a proportional (log) prob...
const double SQRT_2
The value of the square root of 2, .
const double INV_SQRT_2
The value of 1 over the square root of 2, .
fvar< T > sqrt(const fvar< T > &x)
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)
size_t max_size(const T1 &x1, const T2 &x2)
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.
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)
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)
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.
fvar< T > log(const fvar< T > &x)
VectorView is a template metaprogram that takes its argument and allows it to be used like a vector...
fvar< T > exp(const fvar< T > &x)