Stan  2.5.0
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
logistic.hpp
Go to the documentation of this file.
1 #ifndef STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__LOGISTIC_HPP
2 #define STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__LOGISTIC_HPP
3 
4 #include <boost/random/exponential_distribution.hpp>
5 #include <boost/random/variate_generator.hpp>
6 
12 #include <stan/math/constants.hpp>
15 #include <stan/meta/traits.hpp>
16 #include <stan/prob/constants.hpp>
17 #include <stan/prob/traits.hpp>
18 
19 namespace stan {
20  namespace prob {
21 
22  // Logistic(y|mu,sigma) [sigma > 0]
23  // FIXME: document
24  template <bool propto,
25  typename T_y, typename T_loc, typename T_scale>
26  typename return_type<T_y,T_loc,T_scale>::type
27  logistic_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
28  static const char* function = "stan::prob::logistic_log(%1%)";
29 
35 
36  // check if any vectors are zero length
37  if (!(stan::length(y)
38  && stan::length(mu)
39  && stan::length(sigma)))
40  return 0.0;
41 
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_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,
51  y,mu,sigma,
52  "Random variable","Location parameter",
53  "Scale parameter",
54  &logp);
55 
56  // check if no variables are involved and prop-to
58  return 0.0;
59 
60 
61  // set up template expressions wrapping scalars into vector views
63  operands_and_partials(y, mu, sigma);
64 
65  VectorView<const T_y> y_vec(y);
66  VectorView<const T_loc> mu_vec(mu);
67  VectorView<const T_scale> sigma_vec(sigma);
68  size_t N = max_size(y, mu, sigma);
69 
71  inv_sigma(length(sigma));
73  is_vector<T_scale>::value> log_sigma(length(sigma));
74  for (size_t i = 0; i < length(sigma); i++) {
75  inv_sigma[i] = 1.0 / value_of(sigma_vec[i]);
77  log_sigma[i] = log(value_of(sigma_vec[i]));
78  }
79 
82  exp_mu_div_sigma(max_size(mu,sigma));
85  exp_y_div_sigma(max_size(y,sigma));
87  for (size_t n = 0; n < max_size(mu,sigma); n++)
88  exp_mu_div_sigma[n] = exp(value_of(mu_vec[n])
89  / value_of(sigma_vec[n]));
90  for (size_t n = 0; n < max_size(y,sigma); n++)
91  exp_y_div_sigma[n] = exp(value_of(y_vec[n])
92  / value_of(sigma_vec[n]));
93  }
94 
95  using stan::math::log1p;
96  for (size_t n = 0; n < N; n++) {
97  const double y_dbl = value_of(y_vec[n]);
98  const double mu_dbl = value_of(mu_vec[n]);
99 
100  const double y_minus_mu = y_dbl - mu_dbl;
101  const double y_minus_mu_div_sigma = y_minus_mu * inv_sigma[n];
102  double exp_m_y_minus_mu_div_sigma(0);
104  exp_m_y_minus_mu_div_sigma = exp(-y_minus_mu_div_sigma);
105  double inv_1p_exp_y_minus_mu_div_sigma(0);
108  inv_1p_exp_y_minus_mu_div_sigma = 1 / (1 + exp(y_minus_mu_div_sigma));
109 
111  logp -= y_minus_mu_div_sigma;
113  logp -= log_sigma[n];
115  logp -= 2.0 * log1p(exp_m_y_minus_mu_div_sigma);
116 
118  operands_and_partials.d_x1[n]
119  += (2 * inv_1p_exp_y_minus_mu_div_sigma - 1) * inv_sigma[n];
121  operands_and_partials.d_x2[n] +=
122  (1 - 2 * exp_mu_div_sigma[n] / (exp_mu_div_sigma[n]
123  + exp_y_div_sigma[n]))
124  * inv_sigma[n];
126  operands_and_partials.d_x3[n] +=
127  ((1 - 2 * inv_1p_exp_y_minus_mu_div_sigma)
128  *y_minus_mu*inv_sigma[n] - 1) * inv_sigma[n];
129  }
130  return operands_and_partials.to_var(logp);
131  }
132 
133  template <typename T_y, typename T_loc, typename T_scale>
134  inline
136  logistic_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
137  return logistic_log<false>(y,mu,sigma);
138  }
139 
140  // Logistic(y|mu,sigma) [sigma > 0]
141  template <typename T_y, typename T_loc, typename T_scale>
143  logistic_cdf(const T_y& y, const T_loc& mu, const T_scale& sigma) {
144 
145  // Size checks
146  if ( !( stan::length(y) && stan::length(mu)
147  && stan::length(sigma) ) )
148  return 1.0;
149 
150  // Error checks
151  static const char* function = "stan::prob::logistic_cdf(%1%)";
152 
157  using stan::math::value_of;
158  using boost::math::tools::promote_args;
159 
160  double P(1.0);
161 
162  check_not_nan(function, y, "Random variable", &P);
163  check_finite(function, mu, "Location parameter", &P);
164  check_positive_finite(function, sigma, "Scale parameter", &P);
165  check_consistent_sizes(function, y, mu, sigma,
166  "Random variable", "Location parameter",
167  "Scale parameter", &P);
168 
169  // Wrap arguments in vectors
170  VectorView<const T_y> y_vec(y);
171  VectorView<const T_loc> mu_vec(mu);
172  VectorView<const T_scale> sigma_vec(sigma);
173  size_t N = max_size(y, mu, sigma);
174 
176  operands_and_partials(y, mu, sigma);
177 
178  // Explicit return for extreme values
179  // The gradients are technically ill-defined, but treated as zero
180 
181  for (size_t i = 0; i < stan::length(y); i++) {
182  if (value_of(y_vec[i]) == -std::numeric_limits<double>::infinity())
183  return operands_and_partials.to_var(0.0);
184  }
185 
186  // Compute vectorized CDF and its gradients
187  for (size_t n = 0; n < N; n++) {
188 
189  // Explicit results for extreme values
190  // The gradients are technically ill-defined, but treated as zero
191  if (value_of(y_vec[n]) == std::numeric_limits<double>::infinity()) {
192  continue;
193  }
194 
195  // Pull out values
196  const double y_dbl = value_of(y_vec[n]);
197  const double mu_dbl = value_of(mu_vec[n]);
198  const double sigma_dbl = value_of(sigma_vec[n]);
199  const double sigma_inv_vec = 1.0 / value_of(sigma_vec[n]);
200 
201  // Compute
202  const double Pn = 1.0 / ( 1.0 + exp( - (y_dbl - mu_dbl)
203  * sigma_inv_vec ) );
204 
205  P *= Pn;
206 
208  operands_and_partials.d_x1[n]
209  += exp(logistic_log(y_dbl, mu_dbl, sigma_dbl)) / Pn;
211  operands_and_partials.d_x2[n]
212  += - exp(logistic_log(y_dbl, mu_dbl, sigma_dbl)) / Pn;
214  operands_and_partials.d_x3[n] += - (y_dbl - mu_dbl) * sigma_inv_vec
215  * exp(logistic_log(y_dbl, mu_dbl, sigma_dbl)) / Pn;
216  }
217 
219  for(size_t n = 0; n < stan::length(y); ++n)
220  operands_and_partials.d_x1[n] *= P;
221  }
223  for(size_t n = 0; n < stan::length(mu); ++n)
224  operands_and_partials.d_x2[n] *= P;
225  }
227  for(size_t n = 0; n < stan::length(sigma); ++n)
228  operands_and_partials.d_x3[n] *= P;
229  }
230 
231  return operands_and_partials.to_var(P);
232 
233  }
234 
235  template <typename T_y, typename T_loc, typename T_scale>
237  logistic_cdf_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
238 
239  // Size checks
240  if ( !( stan::length(y) && stan::length(mu) && stan::length(sigma) ) )
241  return 0.0;
242 
243  // Error checks
244  static const char* function = "stan::prob::logistic_cdf_log(%1%)";
245 
250  using stan::math::value_of;
251  using boost::math::tools::promote_args;
252 
253  double P(0.0);
254 
255  check_not_nan(function, y, "Random variable", &P);
256  check_finite(function, mu, "Location parameter", &P);
257  check_positive_finite(function, sigma, "Scale parameter", &P);
258  check_consistent_sizes(function, y, mu, sigma,
259  "Random variable", "Location parameter",
260  "Scale parameter", &P);
261 
262  // Wrap arguments in vectors
263  VectorView<const T_y> y_vec(y);
264  VectorView<const T_loc> mu_vec(mu);
265  VectorView<const T_scale> sigma_vec(sigma);
266  size_t N = max_size(y, mu, sigma);
267 
269  operands_and_partials(y, mu, sigma);
270 
271  // Explicit return for extreme values
272  // The gradients are technically ill-defined, but treated as zero
273 
274  for (size_t i = 0; i < stan::length(y); i++) {
275  if (value_of(y_vec[i]) == -std::numeric_limits<double>::infinity())
276  return operands_and_partials.to_var(-std::numeric_limits<double>::infinity());
277  }
278 
279  // Compute vectorized cdf_log and its gradients
280  for (size_t n = 0; n < N; n++) {
281 
282  // Explicit results for extreme values
283  // The gradients are technically ill-defined, but treated as zero
284  if (value_of(y_vec[n]) == std::numeric_limits<double>::infinity()) {
285  continue;
286  }
287 
288  // Pull out values
289  const double y_dbl = value_of(y_vec[n]);
290  const double mu_dbl = value_of(mu_vec[n]);
291  const double sigma_dbl = value_of(sigma_vec[n]);
292  const double sigma_inv_vec = 1.0 / value_of(sigma_vec[n]);
293 
294  // Compute
295  const double Pn = 1.0 / ( 1.0 + exp( - (y_dbl - mu_dbl)
296  * sigma_inv_vec ) );
297  P += log(Pn);
298 
300  operands_and_partials.d_x1[n]
301  += exp(logistic_log(y_dbl, mu_dbl, sigma_dbl)) / Pn;
303  operands_and_partials.d_x2[n]
304  += - exp(logistic_log(y_dbl, mu_dbl, sigma_dbl)) / Pn;
306  operands_and_partials.d_x3[n] += - (y_dbl - mu_dbl) * sigma_inv_vec
307  * exp(logistic_log(y_dbl, mu_dbl, sigma_dbl)) / Pn;
308  }
309 
310  return operands_and_partials.to_var(P);
311  }
312 
313  template <typename T_y, typename T_loc, typename T_scale>
315  logistic_ccdf_log(const T_y& y, const T_loc& mu, const T_scale& sigma) {
316 
317  // Size checks
318  if ( !( stan::length(y) && stan::length(mu) && stan::length(sigma) ) )
319  return 0.0;
320 
321  // Error checks
322  static const char* function = "stan::prob::logistic_cdf_log(%1%)";
323 
328  using stan::math::value_of;
329  using boost::math::tools::promote_args;
330 
331  double P(0.0);
332 
333  check_not_nan(function, y, "Random variable", &P);
334  check_finite(function, mu, "Location parameter", &P);
335  check_positive_finite(function, sigma, "Scale parameter", &P);
336  check_consistent_sizes(function, y, mu, sigma,
337  "Random variable", "Location parameter",
338  "Scale parameter", &P);
339 
340  // Wrap arguments in vectors
341  VectorView<const T_y> y_vec(y);
342  VectorView<const T_loc> mu_vec(mu);
343  VectorView<const T_scale> sigma_vec(sigma);
344  size_t N = max_size(y, mu, sigma);
345 
347  operands_and_partials(y, mu, sigma);
348 
349  // Explicit return for extreme values
350  // The gradients are technically ill-defined, but treated as zero
351 
352  for (size_t i = 0; i < stan::length(y); i++) {
353  if (value_of(y_vec[i]) == -std::numeric_limits<double>::infinity())
354  return operands_and_partials.to_var(0.0);
355  }
356 
357  // Compute vectorized cdf_log and its gradients
358  for (size_t n = 0; n < N; n++) {
359 
360  // Explicit results for extreme values
361  // The gradients are technically ill-defined, but treated as zero
362  if (value_of(y_vec[n]) == std::numeric_limits<double>::infinity()) {
363  return operands_and_partials.to_var(stan::math::negative_infinity());
364  }
365 
366  // Pull out values
367  const double y_dbl = value_of(y_vec[n]);
368  const double mu_dbl = value_of(mu_vec[n]);
369  const double sigma_dbl = value_of(sigma_vec[n]);
370  const double sigma_inv_vec = 1.0 / value_of(sigma_vec[n]);
371 
372  // Compute
373  const double Pn = 1.0 - 1.0 / ( 1.0 + exp( - (y_dbl - mu_dbl)
374  * sigma_inv_vec ) );
375  P += log(Pn);
376 
378  operands_and_partials.d_x1[n]
379  -= exp(logistic_log(y_dbl, mu_dbl, sigma_dbl)) / Pn;
381  operands_and_partials.d_x2[n]
382  -= - exp(logistic_log(y_dbl, mu_dbl, sigma_dbl)) / Pn;
384  operands_and_partials.d_x3[n] -= - (y_dbl - mu_dbl) * sigma_inv_vec
385  * exp(logistic_log(y_dbl, mu_dbl, sigma_dbl)) / Pn;
386  }
387 
388  return operands_and_partials.to_var(P);
389  }
390 
391  template <class RNG>
392  inline double
393  logistic_rng(const double mu,
394  const double sigma,
395  RNG& rng) {
396  using boost::variate_generator;
397  using boost::random::exponential_distribution;
398 
399  static const char* function = "stan::prob::logistic_rng(%1%)";
400 
403 
404  check_finite(function, mu, "Location parameter", (double*)0);
405  check_positive_finite(function, sigma, "Scale parameter", (double*)0);
406 
407  variate_generator<RNG&, exponential_distribution<> >
408  exp_rng(rng, exponential_distribution<>(1));
409  return mu - sigma * std::log(exp_rng() / exp_rng());
410  }
411  }
412 }
413 #endif
return_type< T_y, T_loc, T_scale >::type logistic_cdf_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: logistic.hpp:237
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)
bool check_positive_finite(const char *function, const T_y &y, const char *name, T_result *result)
size_t length(const T &)
Definition: traits.hpp:159
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.
return_type< T_y, T_loc, T_scale >::type logistic_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: logistic.hpp:27
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 logistic_ccdf_log(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: logistic.hpp:315
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
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
double logistic_rng(const double mu, const double sigma, RNG &rng)
Definition: logistic.hpp:393
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
fvar< T > log1p(const fvar< T > &x)
Definition: log1p.hpp:16
double negative_infinity()
Return negative infinity.
Definition: constants.hpp:123
return_type< T_y, T_loc, T_scale >::type logistic_cdf(const T_y &y, const T_loc &mu, const T_scale &sigma)
Definition: logistic.hpp:143

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