Automatic Differentiation
 
Loading...
Searching...
No Matches
student_t_qf.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_REV_PROB_STUDENT_T_QF_HPP
2#define STAN_MATH_REV_PROB_STUDENT_T_QF_HPP
3
15
16namespace stan {
17namespace math {
18
19template <typename T_p, typename T_nu, typename T_mu, typename T_sigma,
20 require_all_stan_scalar_t<T_p, T_mu, T_sigma, T_nu>* = nullptr,
21 require_any_var_t<T_p, T_mu, T_sigma, T_nu>* = nullptr>
22inline var student_t_qf(const T_p& p, const T_nu& nu, const T_mu& mu,
23 const T_sigma& sigma) {
24 static constexpr const char* function = "student_t_qf";
25 const double p_val = value_of(p);
26 const double nu_val = value_of(nu);
27 const double mu_val = value_of(mu);
28 const double sigma_val = value_of(sigma);
29 check_nonnegative(function, "Degrees of freedom parameter", nu_val);
30 check_positive(function, "Scale parameter", sigma_val);
31 check_bounded(function, "Probability parameter", p_val, 0.0, 1.0);
32 if (unlikely(p == 0.0)) {
33 return var{NEGATIVE_INFTY};
34 } else if (unlikely(p == 1.0)) {
35 return var{INFTY};
36 } else if (unlikely(p == 0.5)) {
37 return var{mu_val};
38 } else {
39 const double p_val_flip = p_val < 0.5 ? p_val : 1.0 - p_val;
40 const double p_sign = p_val < 0.5 ? -1.0 : 1.0;
41 const double ibeta_arg = inv_inc_beta(0.5 * nu_val, 0.5, 2 * p_val_flip);
42 const double sqrt_inv_ibeta_m1 = sqrt(inv(ibeta_arg) - 1.0);
43 double ret_val
44 = mu_val
45 + p_sign * sigma_val * sqrt(nu_val) * sqrt(-1.0 + 1.0 / ibeta_arg);
46 return make_callback_var(ret_val, [p, mu, sigma, nu,
47 ibeta_arg](auto& vi) mutable {
48 const double p_val = value_of(p);
49 const double mu_val = value_of(mu);
50 const double sigma_val = value_of(sigma);
51 const double nu_val = value_of(nu);
52 const double p_val_flip = p_val < 0.5 ? p_val : 1.0 - p_val;
53 const double p_sign = p_val < 0.5 ? -1.0 : 1.0;
54 const double sqrt_inv_ibeta_m1 = sqrt(inv(ibeta_arg) - 1.0);
55 if constexpr (is_autodiff_v<T_p>) {
56 if (likely(p.val() > 0.0 && p.val() < 1.0)) {
57 p.adj()
58 += vi.adj()
59 * exp(-student_t_lpdf(vi.val(), nu_val, mu_val, sigma_val));
60 }
61 }
62 if constexpr (is_autodiff_v<T_nu>) {
63 const double half_nu = nu_val / 2.0;
64 const double nu_p1_div_2 = (1.0 + nu_val) / 2.0;
65 Eigen::VectorXd hyper_arg_a{{0.5, half_nu, half_nu}};
66 Eigen::VectorXd hyper_arg_b{{1.0 + half_nu, 1.0 + half_nu}};
67 const double hyper_arg
68 = hypergeometric_pFq(hyper_arg_a, hyper_arg_b, ibeta_arg);
69 const double hyper2f1 = hypergeometric_2F1(
70 1.0, nu_p1_div_2, (2.0 + nu_val) / 2.0, ibeta_arg);
71 const double digamma_a1 = digamma(half_nu);
72 const double digamma_a2 = digamma(nu_p1_div_2);
73
74 const double arg_1 = (4.0 * hyper_arg * sqrt(1.0 - ibeta_arg)) / nu_val;
75 const double arg_2 = -2.0 * hyper2f1 * (-1.0 + ibeta_arg)
76 * (log(ibeta_arg) - digamma_a1 + digamma_a2);
77
78 const double num1
79 = sigma_val * (-2.0 + (2.0 - arg_1 + arg_2) / ibeta_arg);
80 const double den1 = 4.0 * sqrt(nu_val) * sqrt_inv_ibeta_m1;
81 nu.adj() += vi.adj() * p_sign * num1 / den1;
82 }
83 if constexpr (is_autodiff_v<T_mu>) {
84 if (p_val > 0.0 && p_val < 1.0) {
85 mu.adj() += vi.adj();
86 }
87 }
88 if constexpr (is_autodiff_v<T_sigma>) {
89 if (p_val > 0.0 && p_val < 1.0) {
90 sigma.adj() += vi.adj() * p_sign * sqrt(nu_val) * sqrt_inv_ibeta_m1;
91 }
92 }
93 });
94 }
95}
96} // namespace math
97} // namespace stan
98
99#endif
#define likely(x)
#define unlikely(x)
return_type_t< T_y_cl, T_dof_cl, T_loc_cl, T_scale_cl > student_t_lpdf(const T_y_cl &y, const T_dof_cl &nu, const T_loc_cl &mu, const T_scale_cl &sigma)
The log of the Student-t density for the given y, nu, mean, and scale parameter.
void check_nonnegative(const char *function, const char *name, const T_y &y)
Check if y is non-negative.
void check_bounded(const char *function, const char *name, const T_y &y, const T_low &low, const T_high &high)
Check if the value is between the low and high values, inclusively.
var_value< plain_type_t< T > > make_callback_var(T &&value, F &&functor)
Creates a new var initialized with a callback_vari with a given value and reverse-pass callback funct...
T value_of(const fvar< T > &v)
Return the value of the specified variable.
Definition value_of.hpp:18
fvar< T > log(const fvar< T > &x)
Definition log.hpp:18
static constexpr double NEGATIVE_INFTY
Negative infinity.
Definition constants.hpp:51
fvar< T > sqrt(const fvar< T > &x)
Definition sqrt.hpp:18
auto student_t_qf(const T_p &p, const T_nu &nu, const T_mu &mu, const T_sigma &sigma)
fvar< partials_return_t< T1, T2, T3 > > inv_inc_beta(const T1 &a, const T2 &b, const T3 &p)
The inverse of the normalized incomplete beta function of a, b, with probability p.
FvarT hypergeometric_pFq(Ta &&a, Tb &&b, Tz &&z)
Returns the generalized hypergeometric (pFq) function applied to the input arguments.
void check_positive(const char *function, const char *name, const T_y &y)
Check if y is positive.
return_type_t< Ta1, Ta2, Tb, Tz > hypergeometric_2F1(const Ta1 &a1, const Ta2 &a2, const Tb &b, const Tz &z)
Returns the Gauss hypergeometric function applied to the input arguments: .
fvar< T > inv(const fvar< T > &x)
Definition inv.hpp:13
static constexpr double INFTY
Positive infinity.
Definition constants.hpp:46
fvar< T > digamma(const fvar< T > &x)
Return the derivative of the log gamma function at the specified argument.
Definition digamma.hpp:23
fvar< T > exp(const fvar< T > &x)
Definition exp.hpp:15
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...