|
| 1 | +#ifndef STAN_MATH_PRIM_PROB_STUDENT_T_QF_HPP |
| 2 | +#define STAN_MATH_PRIM_PROB_STUDENT_T_QF_HPP |
| 3 | + |
| 4 | +#include <stan/math/prim/meta.hpp> |
| 5 | +#include <stan/math/prim/err.hpp> |
| 6 | +#include <stan/math/prim/fun/sqrt.hpp> |
| 7 | +#include <stan/math/prim/fun/inv_inc_beta.hpp> |
| 8 | +#include <stan/math/prim/fun/max_size.hpp> |
| 9 | + |
| 10 | +namespace stan { |
| 11 | +namespace math { |
| 12 | + |
| 13 | +/** |
| 14 | + * The quantile function of the Student's t-distribution. |
| 15 | + * |
| 16 | + * @tparam T_p type of the probability parameter |
| 17 | + * @tparam T_nu type of the degrees of freedom parameter |
| 18 | + * @tparam T_mu type of the location parameter |
| 19 | + * @tparam T_sigma type of the scale parameter |
| 20 | + * @param p Probability in the range [0, 1]. |
| 21 | + * @param nu Degrees of freedom, must be non-negative. |
| 22 | + * @param mu Location parameter. |
| 23 | + * @param sigma Scale parameter, must be positive. |
| 24 | + * @return Quantile function value. |
| 25 | + * @throw std::domain_error if `nu` is negative or `sigma` is not positive, |
| 26 | + * or if `p` is not in [0, 1]. |
| 27 | + */ |
| 28 | +template <typename T_p, typename T_nu, typename T_mu, typename T_sigma, |
| 29 | + require_all_stan_scalar_t<T_p, T_nu, T_mu, T_sigma>* = nullptr, |
| 30 | + require_all_arithmetic_t<T_p, T_nu, T_mu, T_sigma>* = nullptr> |
| 31 | +inline double student_t_qf(const T_p& p, const T_nu& nu, const T_mu& mu, |
| 32 | + const T_sigma& sigma) { |
| 33 | + static constexpr const char* function = "student_t_qf"; |
| 34 | + check_nonnegative(function, "Degrees of freedom parameter", nu); |
| 35 | + check_positive(function, "Scale parameter", sigma); |
| 36 | + check_bounded(function, "Probability parameter", p, 0.0, 1.0); |
| 37 | + |
| 38 | + if (p == 0.0) { |
| 39 | + return NEGATIVE_INFTY; |
| 40 | + } else if (p == 1.0) { |
| 41 | + return INFTY; |
| 42 | + } else if (p == 0.5) { |
| 43 | + return mu; |
| 44 | + } |
| 45 | + |
| 46 | + const double p_val_flip = p < 0.5 ? p : 1.0 - p; |
| 47 | + const double p_sign = p < 0.5 ? -1.0 : 1.0; |
| 48 | + const auto ibeta_arg = inv_inc_beta(0.5 * nu, 0.5, 2 * p_val_flip); |
| 49 | + |
| 50 | + return mu + p_sign * sigma * sqrt(nu) * sqrt(-1.0 + 1.0 / ibeta_arg); |
| 51 | +} |
| 52 | + |
| 53 | +/** |
| 54 | + * A vectorized version of the Student's t quantile function that accepts |
| 55 | + * std::vectors, Eigen Matrix/Array objects, or expressions, and containers of |
| 56 | + * these. |
| 57 | + * |
| 58 | + * @tparam T_p type of the probability parameter |
| 59 | + * @tparam T_nu type of the degrees of freedom parameter |
| 60 | + * @tparam T_mu type of the location parameter |
| 61 | + * @tparam T_sigma type of the scale parameter |
| 62 | + * @tparam T_container type of the container to hold results |
| 63 | + * @param p Probability in the range [0, 1]. |
| 64 | + * @param nu Degrees of freedom, must be non-negative. |
| 65 | + * @param mu Location parameter. |
| 66 | + * @param sigma Scale parameter, must be positive. |
| 67 | + * @return Container with quantile function values for each input. |
| 68 | + */ |
| 69 | +template <typename T_p, typename T_nu, typename T_mu, typename T_sigma, |
| 70 | + require_any_vector_t<T_p, T_nu, T_mu, T_sigma>* = nullptr> |
| 71 | +inline auto student_t_qf(const T_p& p, const T_nu& nu, const T_mu& mu, |
| 72 | + const T_sigma& sigma) { |
| 73 | + using T_container = common_container_t<T_p, T_nu, T_mu, T_sigma>; |
| 74 | + static constexpr const char* function = "student_t_qf"; |
| 75 | + const size_t max_size_all = max_size(p, nu, mu, sigma); |
| 76 | + T_container result(max_size_all); |
| 77 | + |
| 78 | + ref_type_t<T_p> p_ref = p; |
| 79 | + ref_type_t<T_nu> nu_ref = nu; |
| 80 | + ref_type_t<T_mu> mu_ref = mu; |
| 81 | + ref_type_t<T_sigma> sigma_ref = sigma; |
| 82 | + |
| 83 | + scalar_seq_view<ref_type_t<T_p>> p_vec(p_ref); |
| 84 | + scalar_seq_view<ref_type_t<T_nu>> nu_vec(nu_ref); |
| 85 | + scalar_seq_view<ref_type_t<T_mu>> mu_vec(mu_ref); |
| 86 | + scalar_seq_view<ref_type_t<T_sigma>> sigma_vec(sigma_ref); |
| 87 | + |
| 88 | + for (size_t i = 0; i < max_size_all; ++i) { |
| 89 | + result[i] = student_t_qf(p_vec[i], nu_vec[i], mu_vec[i], sigma_vec[i]); |
| 90 | + } |
| 91 | + |
| 92 | + return result; |
| 93 | +} |
| 94 | + |
| 95 | +} // namespace math |
| 96 | +} // namespace stan |
| 97 | + |
| 98 | +#endif |
0 commit comments