Stan  2.5.0
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
chi_square.hpp
Go to the documentation of this file.
1 #ifndef STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__CHI_SQUARE_HPP
2 #define STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__CHI_SQUARE_HPP
3 
4 #include <boost/random/chi_squared_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>
16 
17 namespace stan {
18 
19  namespace prob {
20 
40  template <bool propto,
41  typename T_y, typename T_dof>
42  typename return_type<T_y,T_dof>::type
43  chi_square_log(const T_y& y, const T_dof& nu) {
44  static const char* function = "stan::prob::chi_square_log(%1%)";
45 
46  // check if any vectors are zero length
47  if (!(stan::length(y)
48  && stan::length(nu)))
49  return 0.0;
50 
56 
57  double logp(0.0);
58  check_not_nan(function, y, "Random variable", &logp);
59  check_nonnegative(function, y, "Random variable", &logp);
60  check_positive_finite(function, nu, "Degrees of freedom parameter",
61  &logp);
62  check_consistent_sizes(function,
63  y,nu,
64  "Random variable","Degrees of freedom parameter",
65  &logp);
66 
67 
68  // set up template expressions wrapping scalars into vector views
69  VectorView<const T_y> y_vec(y);
70  VectorView<const T_dof> nu_vec(nu);
71  size_t N = max_size(y, nu);
72 
73  for (size_t n = 0; n < length(y); n++)
74  if (value_of(y_vec[n]) < 0)
75  return LOG_ZERO;
76 
77  // check if no variables are involved and prop-to
79  return 0.0;
80 
82  using boost::math::lgamma;
84 
86  is_vector<T_y>::value> log_y(length(y));
87  for (size_t i = 0; i < length(y); i++)
89  log_y[i] = log(value_of(y_vec[i]));
90 
92  is_vector<T_y>::value> inv_y(length(y));
93  for (size_t i = 0; i < length(y); i++)
95  inv_y[i] = 1.0 / value_of(y_vec[i]);
96 
98  is_vector<T_dof>::value> lgamma_half_nu(length(nu));
100  is_vector<T_dof>::value> digamma_half_nu_over_two(length(nu));
101 
102  for (size_t i = 0; i < length(nu); i++) {
103  double half_nu = 0.5 * value_of(nu_vec[i]);
105  lgamma_half_nu[i] = lgamma(half_nu);
107  digamma_half_nu_over_two[i] = digamma(half_nu) * 0.5;
108  }
109 
110 
111  agrad::OperandsAndPartials<T_y,T_dof> operands_and_partials(y, nu);
112 
113  for (size_t n = 0; n < N; n++) {
114  const double y_dbl = value_of(y_vec[n]);
115  const double half_y = 0.5 * y_dbl;
116  const double nu_dbl = value_of(nu_vec[n]);
117  const double half_nu = 0.5 * nu_dbl;
119  logp += nu_dbl * NEG_LOG_TWO_OVER_TWO - lgamma_half_nu[n];
121  logp += (half_nu-1.0) * log_y[n];
123  logp -= half_y;
124 
126  operands_and_partials.d_x1[n] += (half_nu-1.0)*inv_y[n] - 0.5;
127  }
129  operands_and_partials.d_x2[n]
130  += NEG_LOG_TWO_OVER_TWO - digamma_half_nu_over_two[n] + log_y[n]*0.5;
131  }
132  }
133  return operands_and_partials.to_var(logp);
134  }
135 
136  template <typename T_y, typename T_dof>
137  inline
139  chi_square_log(const T_y& y, const T_dof& nu) {
140  return chi_square_log<false>(y,nu);
141  }
142 
152  template <typename T_y, typename T_dof>
154  chi_square_cdf(const T_y& y, const T_dof& nu) {
155  static const char* function = "stan::prob::chi_square_cdf(%1%)";
156 
161  using stan::math::value_of;
162 
163  double cdf(1.0);
164 
165  // Size checks
166  if (!(stan::length(y) && stan::length(nu)))
167  return cdf;
168 
169  check_not_nan(function, y, "Random variable", &cdf);
170  check_nonnegative(function, y, "Random variable", &cdf);
171  check_positive_finite(function, nu, "Degrees of freedom parameter", &cdf);
172  check_consistent_sizes(function,
173  y,nu,
174  "Random variable","Degrees of freedom parameter",
175  &cdf);
176 
177  // Wrap arguments in vectors
178  VectorView<const T_y> y_vec(y);
179  VectorView<const T_dof> nu_vec(nu);
180  size_t N = max_size(y, nu);
181 
183  operands_and_partials(y, nu);
184 
185  // Explicit return for extreme values
186  // The gradients are technically ill-defined, but treated as zero
187  for (size_t i = 0; i < stan::length(y); i++) {
188  if (value_of(y_vec[i]) == 0)
189  return operands_and_partials.to_var(0.0);
190  }
191 
192  // Compute CDF and its gradients
193  using boost::math::gamma_p_derivative;
194  using boost::math::gamma_p;
195  using boost::math::digamma;
196  using boost::math::tgamma;
197 
198  // Cache a few expensive function calls if nu is a parameter
201  gamma_vec(stan::length(nu));
204  digamma_vec(stan::length(nu));
205 
207  for (size_t i = 0; i < stan::length(nu); i++) {
208  const double alpha_dbl = value_of(nu_vec[i]) * 0.5;
209  gamma_vec[i] = tgamma(alpha_dbl);
210  digamma_vec[i] = digamma(alpha_dbl);
211  }
212  }
213 
214  // Compute vectorized CDF and gradient
215  for (size_t n = 0; n < N; n++) {
216  // Explicit results for extreme values
217  // The gradients are technically ill-defined, but treated as zero
218  if (value_of(y_vec[n]) == std::numeric_limits<double>::infinity())
219  continue;
220 
221  // Pull out values
222  const double y_dbl = value_of(y_vec[n]);
223  const double alpha_dbl = value_of(nu_vec[n]) * 0.5;
224  const double beta_dbl = 0.5;
225 
226  // Compute
227  const double Pn = gamma_p(alpha_dbl, beta_dbl * y_dbl);
228 
229  cdf *= Pn;
230 
232  operands_and_partials.d_x1[n]
233  += beta_dbl * gamma_p_derivative(alpha_dbl, beta_dbl * y_dbl)
234  / Pn;
236  operands_and_partials.d_x2[n]
237  -= 0.5 * stan::math::gradRegIncGamma(alpha_dbl, beta_dbl
238  * y_dbl, gamma_vec[n],
239  digamma_vec[n]) / Pn;
240  }
241 
243  for (size_t n = 0; n < stan::length(y); ++n)
244  operands_and_partials.d_x1[n] *= cdf;
246  for (size_t n = 0; n < stan::length(nu); ++n)
247  operands_and_partials.d_x2[n] *= cdf;
248 
249  return operands_and_partials.to_var(cdf);
250  }
251 
252  template <typename T_y, typename T_dof>
254  chi_square_cdf_log(const T_y& y, const T_dof& nu) {
255  static const char* function = "stan::prob::chi_square_cdf_log(%1%)";
256 
261  using stan::math::value_of;
262 
263  double cdf_log(0.0);
264 
265  // Size checks
266  if (!(stan::length(y) && stan::length(nu)))
267  return cdf_log;
268 
269  check_not_nan(function, y, "Random variable", &cdf_log);
270  check_nonnegative(function, y, "Random variable", &cdf_log);
271  check_positive_finite(function, nu, "Degrees of freedom parameter",
272  &cdf_log);
273  check_consistent_sizes(function,
274  y,nu,
275  "Random variable","Degrees of freedom parameter",
276  &cdf_log);
277 
278  // Wrap arguments in vectors
279  VectorView<const T_y> y_vec(y);
280  VectorView<const T_dof> nu_vec(nu);
281  size_t N = max_size(y, nu);
282 
284  operands_and_partials(y, nu);
285 
286  // Explicit return for extreme values
287  // The gradients are technically ill-defined, but treated as zero
288  for (size_t i = 0; i < stan::length(y); i++) {
289  if (value_of(y_vec[i]) == 0)
290  return operands_and_partials.to_var(stan::math::negative_infinity());
291  }
292 
293  // Compute cdf_log and its gradients
294  using boost::math::gamma_p_derivative;
295  using boost::math::gamma_p;
296  using boost::math::digamma;
297  using boost::math::tgamma;
298 
299  // Cache a few expensive function calls if nu is a parameter
302  gamma_vec(stan::length(nu));
305  digamma_vec(stan::length(nu));
306 
308  for (size_t i = 0; i < stan::length(nu); i++) {
309  const double alpha_dbl = value_of(nu_vec[i]) * 0.5;
310  gamma_vec[i] = tgamma(alpha_dbl);
311  digamma_vec[i] = digamma(alpha_dbl);
312  }
313  }
314 
315  // Compute vectorized cdf_log and gradient
316  for (size_t n = 0; n < N; n++) {
317  // Explicit results for extreme values
318  // The gradients are technically ill-defined, but treated as zero
319  if (value_of(y_vec[n]) == std::numeric_limits<double>::infinity())
320  return operands_and_partials.to_var(0.0);
321 
322  // Pull out values
323  const double y_dbl = value_of(y_vec[n]);
324  const double alpha_dbl = value_of(nu_vec[n]) * 0.5;
325  const double beta_dbl = 0.5;
326 
327  // Compute
328  const double Pn = gamma_p(alpha_dbl, beta_dbl * y_dbl);
329 
330  cdf_log += log(Pn);
331 
333  operands_and_partials.d_x1[n]
334  += beta_dbl * gamma_p_derivative(alpha_dbl, beta_dbl * y_dbl)
335  / Pn;
337  operands_and_partials.d_x2[n]
338  -= 0.5 * stan::math::gradRegIncGamma(alpha_dbl, beta_dbl
339  * y_dbl, gamma_vec[n],
340  digamma_vec[n]) / Pn;
341  }
342 
343  return operands_and_partials.to_var(cdf_log);
344  }
345 
346  template <typename T_y, typename T_dof>
348  chi_square_ccdf_log(const T_y& y, const T_dof& nu) {
349  static const char* function = "stan::prob::chi_square_ccdf_log(%1%)";
350 
355  using stan::math::value_of;
356 
357  double ccdf_log(0.0);
358 
359  // Size checks
360  if (!(stan::length(y) && stan::length(nu)))
361  return ccdf_log;
362 
363  check_not_nan(function, y, "Random variable", &ccdf_log);
364  check_nonnegative(function, y, "Random variable", &ccdf_log);
365  check_positive_finite(function, nu, "Degrees of freedom parameter",
366  &ccdf_log);
367  check_consistent_sizes(function,
368  y,nu,
369  "Random variable","Degrees of freedom parameter",
370  &ccdf_log);
371 
372  // Wrap arguments in vectors
373  VectorView<const T_y> y_vec(y);
374  VectorView<const T_dof> nu_vec(nu);
375  size_t N = max_size(y, nu);
376 
378  operands_and_partials(y, nu);
379 
380  // Explicit return for extreme values
381  // The gradients are technically ill-defined, but treated as zero
382  for (size_t i = 0; i < stan::length(y); i++) {
383  if (value_of(y_vec[i]) == 0)
384  return operands_and_partials.to_var(0.0);
385  }
386 
387  // Compute ccdf_log and its gradients
388  using boost::math::gamma_p_derivative;
389  using boost::math::gamma_p;
390  using boost::math::digamma;
391  using boost::math::tgamma;
392 
393  // Cache a few expensive function calls if nu is a parameter
396  gamma_vec(stan::length(nu));
399  digamma_vec(stan::length(nu));
400 
402  for (size_t i = 0; i < stan::length(nu); i++) {
403  const double alpha_dbl = value_of(nu_vec[i]) * 0.5;
404  gamma_vec[i] = tgamma(alpha_dbl);
405  digamma_vec[i] = digamma(alpha_dbl);
406  }
407  }
408 
409  // Compute vectorized ccdf_log and gradient
410  for (size_t n = 0; n < N; n++) {
411  // Explicit results for extreme values
412  // The gradients are technically ill-defined, but treated as zero
413  if (value_of(y_vec[n]) == std::numeric_limits<double>::infinity())
414  return operands_and_partials.to_var(stan::math::negative_infinity());
415 
416  // Pull out values
417  const double y_dbl = value_of(y_vec[n]);
418  const double alpha_dbl = value_of(nu_vec[n]) * 0.5;
419  const double beta_dbl = 0.5;
420 
421  // Compute
422  const double Pn = 1.0 - gamma_p(alpha_dbl, beta_dbl * y_dbl);
423 
424  ccdf_log += log(Pn);
425 
427  operands_and_partials.d_x1[n]
428  -= beta_dbl * gamma_p_derivative(alpha_dbl, beta_dbl * y_dbl)
429  / Pn;
431  operands_and_partials.d_x2[n]
432  += 0.5 * stan::math::gradRegIncGamma(alpha_dbl, beta_dbl
433  * y_dbl, gamma_vec[n],
434  digamma_vec[n]) / Pn;
435  }
436 
437  return operands_and_partials.to_var(ccdf_log);
438  }
439 
440  template <class RNG>
441  inline double
442  chi_square_rng(const double nu,
443  RNG& rng) {
444  using boost::variate_generator;
445  using boost::random::chi_squared_distribution;
446 
447  static const char* function = "stan::prob::chi_square_rng(%1%)";
448 
450 
451  check_positive_finite(function, nu, "Degrees of freedom parameter",
452  (double*)0);
453 
454 
455  variate_generator<RNG&, chi_squared_distribution<> >
456  chi_square_rng(rng, chi_squared_distribution<>(nu));
457  return chi_square_rng();
458  }
459  }
460 }
461 
462 #endif
463 
fvar< T > tgamma(const fvar< T > &x)
Definition: tgamma.hpp:15
T_return_type to_var(double logp)
bool check_positive_finite(const char *function, const T_y &y, const char *name, T_result *result)
boost::math::tools::promote_args< T_a, T_b >::type multiply_log(const T_a a, const T_b b)
Calculated the value of the first argument times log of the second argument while behaving properly w...
size_t length(const T &)
Definition: traits.hpp:159
DoubleVectorView allocates double values to be used as intermediate values.
Definition: traits.hpp:358
T value_of(const fvar< T > &v)
Return the value of the specified variable.
Definition: value_of.hpp:16
return_type< T_y, T_dof >::type chi_square_log(const T_y &y, const T_dof &nu)
The log of a chi-squared density for y with the specified degrees of freedom parameter.
Definition: chi_square.hpp:43
fvar< T > lgamma(const fvar< T > &x)
Definition: lgamma.hpp:15
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
return_type< T_y, T_dof >::type chi_square_cdf_log(const T_y &y, const T_dof &nu)
Definition: chi_square.hpp:254
double gradRegIncGamma(double a, double z, double g, double dig, double precision=1e-6)
bool check_nonnegative(const char *function, const T_y &y, const char *name, T_result *result)
return_type< T_y, T_dof >::type chi_square_ccdf_log(const T_y &y, const T_dof &nu)
Definition: chi_square.hpp:348
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
fvar< T > gamma_p(const fvar< T > &x1, const fvar< T > &x2)
Definition: gamma_p.hpp:16
bool check_not_nan(const char *function, const T_y &y, const char *name, T_result *result)
Checks if the variable y is nan.
fvar< T > digamma(const fvar< T > &x)
Definition: digamma.hpp:16
VectorView< double *, is_vector< T1 >::value, is_constant_struct< T1 >::value > d_x1
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
return_type< T_y, T_dof >::type chi_square_cdf(const T_y &y, const T_dof &nu)
Calculates the chi square cumulative distribution function for the given variate and degrees of freed...
Definition: chi_square.hpp:154
double negative_infinity()
Return negative infinity.
Definition: constants.hpp:123
double chi_square_rng(const double nu, RNG &rng)
Definition: chi_square.hpp:442

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