1 #ifndef __STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__STUDENT_T_HPP__
2 #define __STAN__PROB__DISTRIBUTIONS__UNIVARIATE__CONTINUOUS__STUDENT_T_HPP__
4 #include <boost/random/student_t_distribution.hpp>
5 #include <boost/random/variate_generator.hpp>
45 template <
bool propto,
typename T_y,
typename T_dof,
46 typename T_loc,
typename T_scale,
48 typename return_type<T_y,T_dof,T_loc,T_scale>::type
52 static const char*
function =
"stan::prob::student_t_log(%1%)";
69 if (!
check_not_nan(
function, y,
"Random variable", &logp, Policy()))
71 if(!
check_finite(
function, nu,
"Degrees of freedom parameter",
91 "Degrees of freedom parameter",
92 "Location parameter",
"Scale parameter",
104 size_t N =
max_size(y, nu, mu, sigma);
107 using boost::math::digamma;
114 for (
size_t i = 0; i <
length(nu); i++)
116 half_nu[i] = 0.5 *
value_of(nu_vec[i]);
122 for (
size_t i = 0; i <
length(nu); i++) {
123 lgamma_half_nu[i] =
lgamma(half_nu[i]);
124 lgamma_half_nu_plus_half[i] =
lgamma(half_nu[i] + 0.5);
131 for (
size_t i = 0; i <
length(nu); i++) {
132 digamma_half_nu[i] = digamma(half_nu[i]);
133 digamma_half_nu_plus_half[i] = digamma(half_nu[i] + 0.5);
140 for (
size_t i = 0; i <
length(nu); i++)
145 for (
size_t i = 0; i <
length(sigma); i++)
154 square_y_minus_mu_over_sigma__over_nu(N);
163 for (
size_t i = 0; i < N; i++)
165 const double y_dbl =
value_of(y_vec[i]);
166 const double mu_dbl =
value_of(mu_vec[i]);
167 const double sigma_dbl =
value_of(sigma_vec[i]);
168 const double nu_dbl =
value_of(nu_vec[i]);
169 square_y_minus_mu_over_sigma__over_nu[i]
170 =
square((y_dbl - mu_dbl) / sigma_dbl) / nu_dbl;
171 log1p_exp[i] =
log1p(square_y_minus_mu_over_sigma__over_nu[i]);
175 operands_and_partials(y,nu,mu,sigma);
176 for (
size_t n = 0; n < N; n++) {
177 const double y_dbl =
value_of(y_vec[n]);
178 const double mu_dbl =
value_of(mu_vec[n]);
179 const double sigma_dbl =
value_of(sigma_vec[n]);
180 const double nu_dbl =
value_of(nu_vec[n]);
182 logp += NEG_LOG_SQRT_PI;
184 logp += lgamma_half_nu_plus_half[n] - lgamma_half_nu[n]
187 logp -= log_sigma[n];
189 logp -= (half_nu[n] + 0.5)
193 operands_and_partials.
d_x1[n]
195 * 1.0 / (1.0 + square_y_minus_mu_over_sigma__over_nu[n])
196 * (2.0 * (y_dbl - mu_dbl) /
square(sigma_dbl) / nu_dbl);
199 const double inv_nu = 1.0 / nu_dbl;
200 operands_and_partials.
d_x2[n]
201 += 0.5*digamma_half_nu_plus_half[n] - 0.5*digamma_half_nu[n]
205 * (1.0/(1.0 + square_y_minus_mu_over_sigma__over_nu[n])
206 * square_y_minus_mu_over_sigma__over_nu[n] * inv_nu);
209 operands_and_partials.
d_x3[n]
210 -= (half_nu[n] + 0.5)
211 / (1.0 + square_y_minus_mu_over_sigma__over_nu[n])
212 * (2.0 * (mu_dbl - y_dbl) / (sigma_dbl*sigma_dbl*nu_dbl));
215 const double inv_sigma = 1.0 / sigma_dbl;
216 operands_and_partials.
d_x4[n]
218 + (nu_dbl + 1.0) / (1.0 + square_y_minus_mu_over_sigma__over_nu[n])
219 * (square_y_minus_mu_over_sigma__over_nu[n] * inv_sigma);
222 return operands_and_partials.
to_var(logp);
225 template <
bool propto,
226 typename T_y,
typename T_dof,
typename T_loc,
typename T_scale>
230 const T_scale& sigma) {
234 template <
typename T_y,
typename T_dof,
typename T_loc,
typename T_scale,
239 const T_scale& sigma,
241 return student_t_log<false>(y,nu,mu,sigma,Policy());
244 template <
typename T_y,
typename T_dof,
typename T_loc,
typename T_scale>
248 const T_scale& sigma) {
252 template <
typename T_y,
typename T_dof,
typename T_loc,
typename T_scale,
256 const T_scale& sigma,
const Policy&) {
263 static const char*
function =
"stan::prob::student_t_cdf(%1%)";
274 if (!
check_not_nan(
function, y,
"Random variable", &P, Policy()))
277 if (!
check_finite(
function, nu,
"Degrees of freedom parameter", &P,
281 if (!
check_positive(
function, nu,
"Degrees of freedom parameter", &P,
285 if (!
check_finite(
function, mu,
"Location parameter", &P, Policy()))
288 if (!
check_finite(
function, sigma,
"Scale parameter", &P, Policy()))
291 if (!
check_positive(
function, sigma,
"Scale parameter", &P, Policy()))
299 size_t N =
max_size(y, nu, mu, sigma);
302 operands_and_partials(y, nu, mu, sigma);
306 + operands_and_partials.
nvaris,
312 if (
value_of(y_vec[i]) == -std::numeric_limits<double>::infinity())
313 return operands_and_partials.
to_var(0.0);
317 using boost::math::ibeta_derivative;
319 using boost::math::digamma;
320 using boost::math::beta;
323 double digammaHalf = 0;
326 digamma_vec(stan::length(nu));
328 digammaNu_vec(stan::length(nu));
330 digammaNuPlusHalf_vec(stan::length(nu));
332 betaNuHalf_vec(stan::length(nu));
336 digammaHalf = digamma(0.5);
340 const double nu_dbl =
value_of(nu_vec[i]);
342 digammaNu_vec[i] = digamma(0.5 * nu_dbl);
343 digammaNuPlusHalf_vec[i] = digamma(0.5 + 0.5 * nu_dbl);
344 betaNuHalf_vec[i] = beta(0.5, 0.5 * nu_dbl);
351 for (
size_t n = 0; n < N; n++) {
355 if (
value_of(y_vec[n]) == std::numeric_limits<double>::infinity()) {
359 const double sigma_inv = 1.0 /
value_of(sigma_vec[n]);
361 const double nu_dbl =
value_of(nu_vec[n]);
362 const double q = nu_dbl / (t * t);
363 const double r = 1.0 / (1.0 + q);
364 const double J = 2 * r * r * q / t;
365 double zJacobian = t > 0 ? - 0.5 : 0.5;
370 double z =
ibeta(0.5 * nu_dbl, 0.5, 1.0 - r);
372 const double Pn = t > 0 ? 1.0 - 0.5 * z : 0.5 * z;
374 const double d_ibeta = ibeta_derivative(0.5 * nu_dbl, 0.5, 1.0 - r);
379 operands_and_partials.
d_x1[n]
380 += - zJacobian * d_ibeta * J * sigma_inv / Pn;
388 digammaNu_vec[n], digammaHalf,
389 digammaNuPlusHalf_vec[n],
392 operands_and_partials.
d_x2[n]
393 += zJacobian * ( d_ibeta * (r / t) * (r / t) + 0.5 * g1 ) / Pn;
398 operands_and_partials.
d_x3[n]
399 += zJacobian * d_ibeta * J * sigma_inv / Pn;
402 operands_and_partials.
d_x4[n]
403 += zJacobian * d_ibeta * J * sigma_inv * t / Pn;
409 double z = 1 -
ibeta(0.5, 0.5 * nu_dbl, r);
412 const double Pn = t > 0 ? 1.0 - 0.5 * z : 0.5 * z;
414 double d_ibeta = ibeta_derivative(0.5, 0.5 * nu_dbl, r);
419 operands_and_partials.
d_x1[n]
420 += zJacobian * d_ibeta * J * sigma_inv / Pn;
428 digammaHalf, digammaNu_vec[n],
429 digammaNuPlusHalf_vec[n],
432 operands_and_partials.
d_x2[n]
433 += zJacobian * ( - d_ibeta * (r / t) * (r / t) + 0.5 * g2 ) / Pn;
438 operands_and_partials.
d_x3[n]
439 += - zJacobian * d_ibeta * J * sigma_inv / Pn;
442 operands_and_partials.
d_x4[n]
443 += - zJacobian * d_ibeta * J * sigma_inv * t / Pn;
450 operands_and_partials.
d_x1[n] *= P;
454 operands_and_partials.
d_x2[n] *= P;
458 operands_and_partials.
d_x3[n] *= P;
463 operands_and_partials.
d_x4[n] *= P;
466 return operands_and_partials.
to_var(P);
470 template <
typename T_y,
typename T_dof,
typename T_loc,
typename T_scale>
472 student_t_cdf(
const T_y& y,
const T_dof& nu,
const T_loc& mu,
const T_scale& sigma) {
483 using boost::variate_generator;
484 using boost::random::student_t_distribution;
485 variate_generator<RNG&, student_t_distribution<> >
486 rng_unit_student_t(rng, student_t_distribution<>(nu));
487 return mu + sigma * rng_unit_student_t();