Stan  2.5.0
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
lognormal.hpp
Go to the documentation of this file.
1 #ifndef STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__LOGNORMAL_HPP
2 #define STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__LOGNORMAL_HPP
3 
4 #include <boost/random/lognormal_distribution.hpp>
5 #include <boost/random/variate_generator.hpp>
6 
12 #include <stan/meta/traits.hpp>
13 #include <stan/prob/constants.hpp>
14 #include <stan/prob/traits.hpp>
15 
16 namespace stan {
17  namespace prob {
18 
19  // LogNormal(y|mu,sigma) [y >= 0; sigma > 0]
20  // FIXME: document
21  template <bool propto,
22  typename T_y, typename T_loc, typename T_scale>
23  typename return_type<T_y,T_loc,T_scale>::type
24  lognormal_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
25  static const char* function = "stan::prob::lognormal_log(%1%)";
26 
35 
36 
37  // check if any vectors are zero length
38  if (!(stan::length(y)
39  && stan::length(mu)
40  && stan::length(sigma)))
41  return 0.0;
42 
43  // set up return value accumulator
44  double logp(0.0);
45 
46  // validate args (here done over var, which should be OK)
47  check_not_nan(function, y, "Random variable", &logp);
48  check_nonnegative(function, y, "Random variable", &logp);
49  check_finite(function, mu, "Location parameter", &logp);
50  check_positive_finite(function, sigma, "Scale parameter", &logp);
51  check_consistent_sizes(function,
52  y,mu,sigma,
53  "Random variable","Location parameter",
54  "Scale parameter",
55  &logp);
56 
57  VectorView<const T_y> y_vec(y);
58  VectorView<const T_loc> mu_vec(mu);
59  VectorView<const T_scale> sigma_vec(sigma);
60  size_t N = max_size(y, mu, sigma);
61 
62  for (size_t n = 0; n < length(y); n++)
63  if (value_of(y_vec[n]) <= 0)
64  return LOG_ZERO;
65 
67  operands_and_partials(y, mu, sigma);
68 
69  using stan::math::square;
70  using std::log;
71  using stan::prob::NEG_LOG_SQRT_TWO_PI;
72 
73 
75  is_vector<T_scale>::value> log_sigma(length(sigma));
77  for (size_t n = 0; n < length(sigma); n++)
78  log_sigma[n] = log(value_of(sigma_vec[n]));
80  is_vector<T_scale>::value> inv_sigma(length(sigma));
82  is_vector<T_scale>::value> inv_sigma_sq(length(sigma));
84  for (size_t n = 0; n < length(sigma); n++)
85  inv_sigma[n] = 1 / value_of(sigma_vec[n]);
87  for (size_t n = 0; n < length(sigma); n++)
88  inv_sigma_sq[n] = inv_sigma[n] * inv_sigma[n];
89 
91  is_vector<T_y>::value> log_y(length(y));
93  for (size_t n = 0; n < length(y); n++)
94  log_y[n] = log(value_of(y_vec[n]));
96  is_vector<T_y>::value> inv_y(length(y));
98  for (size_t n = 0; n < length(y); n++)
99  inv_y[n] = 1 / value_of(y_vec[n]);
100 
102  logp += N * NEG_LOG_SQRT_TWO_PI;
103 
104  for (size_t n = 0; n < N; n++) {
105  const double mu_dbl = value_of(mu_vec[n]);
106 
107  double logy_m_mu(0);
110  logy_m_mu = log_y[n] - mu_dbl;
111 
112  double logy_m_mu_sq = logy_m_mu * logy_m_mu;
113  double logy_m_mu_div_sigma(0);
117  logy_m_mu_div_sigma = logy_m_mu * inv_sigma_sq[n];
118 
119 
120  // log probability
122  logp -= log_sigma[n];
124  logp -= log_y[n];
126  logp -= 0.5 * logy_m_mu_sq * inv_sigma_sq[n];
127 
128  // gradients
130  operands_and_partials.d_x1[n] -= (1 + logy_m_mu_div_sigma) * inv_y[n];
132  operands_and_partials.d_x2[n] += logy_m_mu_div_sigma;
134  operands_and_partials.d_x3[n]
135  += (logy_m_mu_div_sigma * logy_m_mu - 1) * inv_sigma[n];
136  }
137  return operands_and_partials.to_var(logp);
138  }
139 
140  template <typename T_y, typename T_loc, typename T_scale>
141  inline
143  lognormal_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
144  return lognormal_log<false>(y,mu,sigma);
145  }
146 
147 
148  template <typename T_y, typename T_loc, typename T_scale>
150  lognormal_cdf(const T_y& y, const T_loc& mu, const T_scale& sigma) {
151  static const char* function = "stan::prob::lognormal_cdf(%1%)";
152 
153  double cdf = 1.0;
154 
159  using boost::math::tools::promote_args;
160  using stan::math::value_of;
161 
162  // check if any vectors are zero length
163  if (!(stan::length(y)
164  && stan::length(mu)
165  && stan::length(sigma)))
166  return cdf;
167 
168  check_not_nan(function, y, "Random variable", &cdf);
169  check_nonnegative(function, y, "Random variable", &cdf);
170  check_finite(function, mu, "Location parameter", &cdf);
171  check_positive_finite(function, sigma, "Scale parameter", &cdf);
172 
174  operands_and_partials(y, mu, sigma);
175 
176  VectorView<const T_y> y_vec(y);
177  VectorView<const T_loc> mu_vec(mu);
178  VectorView<const T_scale> sigma_vec(sigma);
179  size_t N = max_size(y, mu, sigma);
180 
181  const double sqrt_pi = std::sqrt(stan::math::pi());
182 
183  for (size_t i = 0; i < stan::length(y); i++) {
184  if (value_of(y_vec[i]) == 0.0)
185  return operands_and_partials.to_var(0.0);
186  }
187 
188  for (size_t n = 0; n < N; n++) {
189  const double y_dbl = value_of(y_vec[n]);
190  const double mu_dbl = value_of(mu_vec[n]);
191  const double sigma_dbl = value_of(sigma_vec[n]);
192  const double scaled_diff = (log(y_dbl) - mu_dbl) / (sigma_dbl * SQRT_2);
193  const double rep_deriv = SQRT_2 * 0.5 / sqrt_pi
194  * exp(-scaled_diff * scaled_diff) / sigma_dbl;
195 
196  //cdf
197  const double cdf_ = 0.5 * erfc(-scaled_diff);
198  cdf *= cdf_;
199 
200  //gradients
202  operands_and_partials.d_x1[n] += rep_deriv / cdf_ / y_dbl ;
204  operands_and_partials.d_x2[n] -= rep_deriv / cdf_ ;
206  operands_and_partials.d_x3[n] -= rep_deriv * scaled_diff * SQRT_2
207  / cdf_;
208  }
209 
211  for (size_t n = 0; n < stan::length(y); ++n)
212  operands_and_partials.d_x1[n] *= cdf;
214  for (size_t n = 0; n < stan::length(mu); ++n)
215  operands_and_partials.d_x2[n] *= cdf;
217  for (size_t n = 0; n < stan::length(sigma); ++n)
218  operands_and_partials.d_x3[n] *= cdf;
219 
220  return operands_and_partials.to_var(cdf);
221  }
222 
223  template <typename T_y, typename T_loc, typename T_scale>
225  lognormal_cdf_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
226  static const char* function = "stan::prob::lognormal_cdf_log(%1%)";
227 
228  double cdf_log = 0.0;
229 
234  using boost::math::tools::promote_args;
235  using stan::math::value_of;
236 
237  // check if any vectors are zero length
238  if (!(stan::length(y)
239  && stan::length(mu)
240  && stan::length(sigma)))
241  return cdf_log;
242 
243  check_not_nan(function, y, "Random variable", &cdf_log);
244  check_nonnegative(function, y, "Random variable", &cdf_log);
245  check_finite(function, mu, "Location parameter", &cdf_log);
246  check_positive_finite(function, sigma, "Scale parameter", &cdf_log);
247 
249  operands_and_partials(y, mu, sigma);
250 
251  VectorView<const T_y> y_vec(y);
252  VectorView<const T_loc> mu_vec(mu);
253  VectorView<const T_scale> sigma_vec(sigma);
254  size_t N = max_size(y, mu, sigma);
255 
256  const double sqrt_pi = std::sqrt(stan::math::pi());
257 
258  for (size_t i = 0; i < stan::length(y); i++) {
259  if (value_of(y_vec[i]) == 0.0)
260  return operands_and_partials.to_var(stan::math::negative_infinity());
261  }
262 
263  const double log_half = std::log(0.5);
264 
265  for (size_t n = 0; n < N; n++) {
266  const double y_dbl = value_of(y_vec[n]);
267  const double mu_dbl = value_of(mu_vec[n]);
268  const double sigma_dbl = value_of(sigma_vec[n]);
269  const double scaled_diff = (log(y_dbl) - mu_dbl) / (sigma_dbl * SQRT_2);
270  const double rep_deriv = SQRT_2 / sqrt_pi
271  * exp(-scaled_diff * scaled_diff) / sigma_dbl;
272 
273  //cdf_log
274  const double erfc_calc = erfc(-scaled_diff);
275  cdf_log += log_half + log(erfc_calc);
276 
277  //gradients
279  operands_and_partials.d_x1[n] += rep_deriv / erfc_calc / y_dbl ;
281  operands_and_partials.d_x2[n] -= rep_deriv / erfc_calc;
283  operands_and_partials.d_x3[n] -= rep_deriv * scaled_diff * SQRT_2
284  / erfc_calc;
285  }
286 
287  return operands_and_partials.to_var(cdf_log);
288  }
289 
290  template <typename T_y, typename T_loc, typename T_scale>
292  lognormal_ccdf_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
293  static const char* function = "stan::prob::lognormal_ccdf_log(%1%)";
294 
295  double ccdf_log = 0.0;
296 
301  using boost::math::tools::promote_args;
302  using stan::math::value_of;
303 
304  // check if any vectors are zero length
305  if (!(stan::length(y)
306  && stan::length(mu)
307  && stan::length(sigma)))
308  return ccdf_log;
309 
310  check_not_nan(function, y, "Random variable", &ccdf_log);
311  check_nonnegative(function, y, "Random variable", &ccdf_log);
312  check_finite(function, mu, "Location parameter", &ccdf_log);
313  check_positive_finite(function, sigma, "Scale parameter", &ccdf_log);
314 
316  operands_and_partials(y, mu, sigma);
317 
318  VectorView<const T_y> y_vec(y);
319  VectorView<const T_loc> mu_vec(mu);
320  VectorView<const T_scale> sigma_vec(sigma);
321  size_t N = max_size(y, mu, sigma);
322 
323  const double sqrt_pi = std::sqrt(stan::math::pi());
324 
325  for (size_t i = 0; i < stan::length(y); i++) {
326  if (value_of(y_vec[i]) == 0.0)
327  return operands_and_partials.to_var(0.0);
328  }
329 
330  const double log_half = std::log(0.5);
331 
332  for (size_t n = 0; n < N; n++) {
333  const double y_dbl = value_of(y_vec[n]);
334  const double mu_dbl = value_of(mu_vec[n]);
335  const double sigma_dbl = value_of(sigma_vec[n]);
336  const double scaled_diff = (log(y_dbl) - mu_dbl) / (sigma_dbl * SQRT_2);
337  const double rep_deriv = SQRT_2 / sqrt_pi
338  * exp(-scaled_diff * scaled_diff) / sigma_dbl;
339 
340  //ccdf_log
341  const double erfc_calc = erfc(scaled_diff);
342  ccdf_log += log_half + log(erfc_calc);
343 
344  //gradients
346  operands_and_partials.d_x1[n] -= rep_deriv / erfc_calc / y_dbl ;
348  operands_and_partials.d_x2[n] += rep_deriv / erfc_calc;
350  operands_and_partials.d_x3[n] += rep_deriv * scaled_diff * SQRT_2
351  / erfc_calc;
352  }
353 
354  return operands_and_partials.to_var(ccdf_log);
355  }
356 
357 
358  template <class RNG>
359  inline double
360  lognormal_rng(const double mu,
361  const double sigma,
362  RNG& rng) {
363  using boost::variate_generator;
364  using boost::random::lognormal_distribution;
365 
366  static const char* function = "stan::prob::lognormal_rng(%1%)";
367 
370 
371  check_finite(function, mu, "Location parameter", (double*)0);
372  check_positive_finite(function, sigma, "Scale parameter", (double*)0);
373 
374  variate_generator<RNG&, lognormal_distribution<> >
375  lognorm_rng(rng, lognormal_distribution<>(mu, sigma));
376  return lognorm_rng();
377  }
378  }
379 }
380 #endif
T square(const T x)
Return the square of the specified argument.
Definition: square.hpp:22
return_type< T_y, T_loc, T_scale >::type lognormal_cdf(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: lognormal.hpp:150
T_return_type to_var(double logp)
bool check_positive_finite(const char *function, const T_y &y, const char *name, T_result *result)
return_type< T_y, T_loc, T_scale >::type lognormal_ccdf_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: lognormal.hpp:292
return_type< T_y, T_loc, T_scale >::type lognormal_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: lognormal.hpp:24
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
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
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_nonnegative(const char *function, const T_y &y, const char *name, T_result *result)
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_y, T_loc, T_scale >::type lognormal_cdf_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: lognormal.hpp:225
bool check_not_nan(const char *function, const T_y &y, const char *name, T_result *result)
Checks if the variable y is nan.
double lognormal_rng(const double mu, const double sigma, RNG &rng)
Definition: lognormal.hpp:360
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
double negative_infinity()
Return negative infinity.
Definition: constants.hpp:123

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