Stan  2.5.0
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
double_exponential.hpp
Go to the documentation of this file.
1 #ifndef STAN__PROB__DISTRIBUTIONS__DOUBLE_EXPONENTIAL_HPP
2 #define STAN__PROB__DISTRIBUTIONS__DOUBLE_EXPONENTIAL_HPP
3 
4 #include <boost/random/uniform_01.hpp>
5 #include <boost/random/variate_generator.hpp>
6 
10 #include <stan/meta/traits.hpp>
11 #include <stan/prob/constants.hpp>
12 #include <stan/prob/traits.hpp>
14 
15 namespace stan {
16 
17  namespace prob {
18 
19  // DoubleExponential(y|mu,sigma) [sigma > 0]
20  // FIXME: add documentation
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  double_exponential_log(const T_y& y,
25  const T_loc& mu, const T_scale& sigma) {
26  static const char* function
27  = "stan::prob::double_exponential_log(%1%)";
28 
35  using std::log;
36  using std::fabs;
37  using stan::math::sign;
38 
39  // check if any vectors are zero length
40  if (!(stan::length(y)
41  && stan::length(mu)
42  && stan::length(sigma)))
43  return 0.0;
44 
45  // set up return value accumulator
46  double logp(0.0);
47  check_finite(function, y, "Random variable", &logp);
48  check_finite(function, mu, "Location parameter", &logp);
49  check_positive_finite(function, sigma, "Scale parameter", &logp);
50  check_consistent_sizes(function,y,mu,sigma,
51  "Random variable","Location parameter",
52  "Shape parameter",&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_y> y_vec(y);
60  VectorView<const T_loc> mu_vec(mu);
61  VectorView<const T_scale> sigma_vec(sigma);
62  size_t N = max_size(y, mu, sigma);
63  agrad::OperandsAndPartials<T_y,T_loc,T_scale> operands_and_partials(y, mu, sigma);
64 
66  inv_sigma(length(sigma));
68  inv_sigma_squared(length(sigma));
70  log_sigma(length(sigma));
71  for (size_t i = 0; i < length(sigma); i++) {
72  const double sigma_dbl = value_of(sigma_vec[i]);
74  inv_sigma[i] = 1.0 / sigma_dbl;
76  log_sigma[i] = log(value_of(sigma_vec[i]));
78  inv_sigma_squared[i] = inv_sigma[i] * inv_sigma[i];
79  }
80 
81 
82  for (size_t n = 0; n < N; n++) {
83  const double y_dbl = value_of(y_vec[n]);
84  const double mu_dbl = value_of(mu_vec[n]);
85 
86  // reusable subexpressions values
87  const double y_m_mu = y_dbl - mu_dbl;
88  const double fabs_y_m_mu = fabs(y_m_mu);
89 
90  // log probability
92  logp += NEG_LOG_TWO;
94  logp -= log_sigma[n];
96  logp -= fabs_y_m_mu * inv_sigma[n];
97 
98  // gradients
99  double sign_y_m_mu_times_inv_sigma(0);
101  sign_y_m_mu_times_inv_sigma = sign(y_m_mu) * inv_sigma[n];
103  operands_and_partials.d_x1[n] -= sign_y_m_mu_times_inv_sigma;
104  }
106  operands_and_partials.d_x2[n] += sign_y_m_mu_times_inv_sigma;
107  }
109  operands_and_partials.d_x3[n] += -inv_sigma[n] + fabs_y_m_mu * inv_sigma_squared[n];
110  }
111  return operands_and_partials.to_var(logp);
112  }
113 
114 
115  template <typename T_y, typename T_loc, typename T_scale>
117  double_exponential_log(const T_y& y, const T_loc& mu,
118  const T_scale& sigma) {
119  return double_exponential_log<false>(y,mu,sigma);
120  }
121 
136  template <typename T_y, typename T_loc, typename T_scale>
138  double_exponential_cdf(const T_y& y,
139  const T_loc& mu, const T_scale& sigma) {
140  static const char* function
141  = "stan::prob::double_exponential_cdf(%1%)";
142 
143  // Size checks
144  if ( !( stan::length(y) && stan::length(mu)
145  && stan::length(sigma) ) )
146  return 1.0;
147 
148  using stan::math::value_of;
152  using boost::math::tools::promote_args;
153 
154  double cdf(1.0);
155  check_not_nan(function, y, "Random variable", &cdf);
156  check_finite(function, mu, "Location parameter", &cdf);
157  check_positive_finite(function, sigma, "Scale parameter", &cdf);
158 
160  operands_and_partials(y, mu, sigma);
161 
162  VectorView<const T_y> y_vec(y);
163  VectorView<const T_loc> mu_vec(mu);
164  VectorView<const T_scale> sigma_vec(sigma);
165  size_t N = max_size(y, mu, sigma);
166 
167  //cdf
168  for (size_t n = 0; n < N; n++) {
169  const double y_dbl = value_of(y_vec[n]);
170  const double mu_dbl = value_of(mu_vec[n]);
171  const double sigma_dbl = value_of(sigma_vec[n]);
172  const double scaled_diff = (y_dbl - mu_dbl) / (sigma_dbl);
173  const double exp_scaled_diff = exp(scaled_diff);
174 
175  if(y_dbl < mu_dbl) {
176  cdf *= exp_scaled_diff * 0.5;
177  }
178  else
179  cdf *= 1.0 - 0.5 / exp_scaled_diff;
180  }
181 
182  //gradients
183  for (size_t n = 0; n < N; n++) {
184  const double y_dbl = value_of(y_vec[n]);
185  const double mu_dbl = value_of(mu_vec[n]);
186  const double sigma_dbl = value_of(sigma_vec[n]);
187  const double scaled_diff = (y_dbl - mu_dbl) / sigma_dbl;
188  const double exp_scaled_diff = exp(scaled_diff);
189  const double inv_sigma = 1.0 / sigma_dbl;
190 
191  if(y_dbl < mu_dbl) {
193  operands_and_partials.d_x1[n] += inv_sigma * cdf;
195  operands_and_partials.d_x2[n] -= inv_sigma * cdf;
197  operands_and_partials.d_x3[n] -= scaled_diff * inv_sigma * cdf;
198  }
199  else {
200  const double rep_deriv = cdf * inv_sigma / (2.0 * exp_scaled_diff
201  - 1.0);
203  operands_and_partials.d_x1[n] += rep_deriv;
205  operands_and_partials.d_x2[n] -= rep_deriv;
207  operands_and_partials.d_x3[n] -= rep_deriv * scaled_diff;
208  }
209  }
210  return operands_and_partials.to_var(cdf);
211  }
212 
213  template <typename T_y, typename T_loc, typename T_scale>
215  double_exponential_cdf_log(const T_y& y, const T_loc& mu,
216  const T_scale& sigma) {
217  static const char* function
218  = "stan::prob::double_exponential_cdf_log(%1%)";
219 
224  using stan::math::value_of;
225 
226  double cdf_log(0.0);
227 
228  // check if any vectors are zero length
229  if (!(stan::length(y)
230  && stan::length(mu)
231  && stan::length(sigma)))
232  return cdf_log;
233 
234  check_not_nan(function, y, "Random variable", &cdf_log);
235  check_finite(function, mu, "Location parameter", &cdf_log);
236  check_positive_finite(function, sigma, "Scale parameter", &cdf_log);
237  check_consistent_sizes(function, y, mu, sigma,
238  "Random variable", "Location parameter",
239  "Scale Parameter", &cdf_log);
240 
241  using std::log;
242  using std::exp;
243 
245  operands_and_partials(y, mu, sigma);
246 
247  VectorView<const T_y> y_vec(y);
248  VectorView<const T_loc> mu_vec(mu);
249  VectorView<const T_scale> sigma_vec(sigma);
250  const double log_half = std::log(0.5);
251  size_t N = max_size(y, mu, sigma);
252 
253  for (size_t n = 0; n < N; n++) {
254  const double y_dbl = value_of(y_vec[n]);
255  const double mu_dbl = value_of(mu_vec[n]);
256  const double sigma_dbl = value_of(sigma_vec[n]);
257  const double scaled_diff = (y_dbl - mu_dbl) / sigma_dbl;
258  const double inv_sigma = 1.0 / sigma_dbl;
259  if(y_dbl < mu_dbl) {
260  // log cdf
261  cdf_log += log_half + scaled_diff;
262 
263  // gradients
265  operands_and_partials.d_x1[n] += inv_sigma;
267  operands_and_partials.d_x2[n] -= inv_sigma;
269  operands_and_partials.d_x3[n] -= scaled_diff * inv_sigma;
270  }
271  else {
272  //log cdf
273  cdf_log += log(1.0 - 0.5 * exp(-scaled_diff));
274 
275  //gradients
276  const double rep_deriv = 1.0 / (2.0 * exp(scaled_diff) - 1.0);
278  operands_and_partials.d_x1[n] += rep_deriv * inv_sigma;
280  operands_and_partials.d_x2[n] -= rep_deriv * inv_sigma;
282  operands_and_partials.d_x3[n] -= rep_deriv * scaled_diff
283  * inv_sigma;
284  }
285  }
286  return operands_and_partials.to_var(cdf_log);
287  }
288 
289  template <typename T_y, typename T_loc, typename T_scale>
291  double_exponential_ccdf_log(const T_y& y, const T_loc& mu,
292  const T_scale& sigma) {
293  static const char* function
294  = "stan::prob::double_exponential_ccdf_log(%1%)";
295 
300  using stan::math::value_of;
301 
302  double ccdf_log(0.0);
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_finite(function, mu, "Location parameter", &ccdf_log);
312  check_positive_finite(function, sigma, "Scale parameter", &ccdf_log);
313  check_consistent_sizes(function, y, mu, sigma,
314  "Random variable", "Location parameter",
315  "Scale Parameter", &ccdf_log);
316 
317  using std::log;
318  using std::exp;
319 
321  operands_and_partials(y, mu, sigma);
322 
323  VectorView<const T_y> y_vec(y);
324  VectorView<const T_loc> mu_vec(mu);
325  VectorView<const T_scale> sigma_vec(sigma);
326  const double log_half = std::log(0.5);
327  size_t N = max_size(y, mu, sigma);
328 
329  for (size_t n = 0; n < N; n++) {
330  const double y_dbl = value_of(y_vec[n]);
331  const double mu_dbl = value_of(mu_vec[n]);
332  const double sigma_dbl = value_of(sigma_vec[n]);
333  const double scaled_diff = (y_dbl - mu_dbl) / sigma_dbl;
334  const double inv_sigma = 1.0 / sigma_dbl;
335  if(y_dbl < mu_dbl) {
336  //log ccdf
337  ccdf_log += log(1.0 - 0.5 * exp(scaled_diff));
338 
339  //gradients
340  const double rep_deriv = 1.0 / (2.0 * exp(-scaled_diff) - 1.0);
342  operands_and_partials.d_x1[n] -= rep_deriv * inv_sigma;
344  operands_and_partials.d_x2[n] += rep_deriv * inv_sigma;
346  operands_and_partials.d_x3[n] += rep_deriv * scaled_diff
347  * inv_sigma;
348  }
349  else {
350  // log ccdf
351  ccdf_log += log_half - scaled_diff;
352 
353  // gradients
355  operands_and_partials.d_x1[n] -= inv_sigma;
357  operands_and_partials.d_x2[n] += inv_sigma;
359  operands_and_partials.d_x3[n] += scaled_diff * inv_sigma;
360  }
361  }
362  return operands_and_partials.to_var(ccdf_log);
363  }
364 
365  template <class RNG>
366  inline double
367  double_exponential_rng(const double mu,
368  const double sigma,
369  RNG& rng) {
370  using boost::variate_generator;
371  using boost::random::uniform_01;
372  using std::log;
373  using std::abs;
374 
375  static const char* function
376  = "stan::prob::double_exponential_rng(%1%)";
377 
380 
381  check_finite(function, mu, "Location parameter", (double*)0);
382  check_positive_finite(function, sigma, "Scale parameter", (double*)0);
383 
384  variate_generator<RNG&, uniform_01<> >
385  rng_unit_01(rng, uniform_01<>());
386  double a = 0;
387  double laplaceRN = rng_unit_01();
388  if(0.5 - laplaceRN > 0)
389  a = 1.0;
390  else if(0.5 - laplaceRN < 0)
391  a = -1.0;
392  return mu - sigma * a * log(1 - 2 * abs(0.5 - laplaceRN));
393  }
394  }
395 }
396 #endif
fvar< T > fabs(const fvar< T > &x)
Definition: fabs.hpp:18
T_return_type to_var(double logp)
bool check_positive_finite(const char *function, const T_y &y, const char *name, T_result *result)
int sign(const T &z)
Definition: sign.hpp:9
size_t length(const T &)
Definition: traits.hpp:159
return_type< T_y, T_loc, T_scale >::type double_exponential_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
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
return_type< T_y, T_loc, T_scale >::type double_exponential_ccdf_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
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
VectorView< double *, is_vector< T2 >::value, is_constant_struct< T2 >::value > d_x2
fvar< T > abs(const fvar< T > &x)
Definition: abs.hpp:19
return_type< T_y, T_loc, T_scale >::type double_exponential_cdf(const T_y &y, const T_loc &mu, const T_scale &sigma)
Calculates the double exponential cumulative density function.
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 double_exponential_cdf_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
double double_exponential_rng(const double mu, const double sigma, RNG &rng)
bool check_not_nan(const char *function, const T_y &y, const char *name, T_result *result)
Checks if the variable y is nan.
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
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.