|
| 1 | +#ifndef STAN_MATH_OPENCL_PRIM_GAMMA_LPDF_HPP |
| 2 | +#define STAN_MATH_OPENCL_PRIM_GAMMA_LPDF_HPP |
| 3 | +#ifdef STAN_OPENCL |
| 4 | + |
| 5 | +#include <stan/math/opencl/kernel_generator.hpp> |
| 6 | +#include <stan/math/opencl/prim/size.hpp> |
| 7 | +#include <stan/math/prim/meta.hpp> |
| 8 | +#include <stan/math/prim/err.hpp> |
| 9 | +#include <stan/math/prim/fun/constants.hpp> |
| 10 | +#include <stan/math/prim/fun/digamma.hpp> |
| 11 | +#include <stan/math/prim/fun/lgamma.hpp> |
| 12 | +#include <stan/math/prim/fun/max_size.hpp> |
| 13 | +#include <stan/math/prim/functor/operands_and_partials.hpp> |
| 14 | + |
| 15 | +namespace stan { |
| 16 | +namespace math { |
| 17 | + |
| 18 | +/** \ingroup opencl |
| 19 | + * The log of a gamma density for y with the specified |
| 20 | + * shape and inverse scale parameters. |
| 21 | + * Shape and inverse scale parameters must be greater than 0. |
| 22 | + * y must be greater than or equal to 0. |
| 23 | + * |
| 24 | + \f{eqnarray*}{ |
| 25 | + y &\sim& \mbox{\sf{Gamma}}(\alpha, \beta) \\ |
| 26 | + \log (p (y \, |\, \alpha, \beta) ) &=& \log \left( |
| 27 | + \frac{\beta^\alpha}{\Gamma(\alpha)} y^{\alpha - 1} \exp^{- \beta y} \right) \\ |
| 28 | + &=& \alpha \log(\beta) - \log(\Gamma(\alpha)) + (\alpha - 1) \log(y) - \beta |
| 29 | + y\\ & & \mathrm{where} \; y > 0 \f} |
| 30 | + * |
| 31 | + * @tparam T_y_cl type of scalar |
| 32 | + * @tparam T_shape_cl type of shape |
| 33 | + * @tparam T_inv_scale_cl type of inverse scale |
| 34 | + * @param y A scalar variable. |
| 35 | + * @param alpha Shape parameter. |
| 36 | + * @param beta Inverse scale parameter. |
| 37 | + * @throw std::domain_error if alpha is not greater than 0. |
| 38 | + * @throw std::domain_error if beta is not greater than 0. |
| 39 | + * @throw std::domain_error if y is not greater than or equal to 0. |
| 40 | + */ |
| 41 | +template <bool propto, typename T_y_cl, typename T_shape_cl, |
| 42 | + typename T_inv_scale_cl, |
| 43 | + require_all_prim_or_rev_kernel_expression_t< |
| 44 | + T_y_cl, T_shape_cl, T_inv_scale_cl>* = nullptr, |
| 45 | + require_any_not_stan_scalar_t<T_y_cl, T_shape_cl, |
| 46 | + T_inv_scale_cl>* = nullptr> |
| 47 | +return_type_t<T_y_cl, T_shape_cl, T_inv_scale_cl> gamma_lpdf( |
| 48 | + const T_y_cl& y, const T_shape_cl& alpha, const T_inv_scale_cl& beta) { |
| 49 | + using std::isfinite; |
| 50 | + using std::isnan; |
| 51 | + static const char* function = "gamma_lpdf(OpenCL)"; |
| 52 | + using T_partials_return |
| 53 | + = partials_return_t<T_y_cl, T_shape_cl, T_inv_scale_cl>; |
| 54 | + |
| 55 | + check_consistent_sizes(function, "Random variable", y, "Shape parameter", |
| 56 | + alpha, "Inverse scale parameter", beta); |
| 57 | + const size_t N = max_size(y, alpha, beta); |
| 58 | + if (N == 0) { |
| 59 | + return 0.0; |
| 60 | + } |
| 61 | + if (!include_summand<propto, T_y_cl, T_shape_cl, T_inv_scale_cl>::value) { |
| 62 | + return 0.0; |
| 63 | + } |
| 64 | + |
| 65 | + const auto& y_val = value_of(y); |
| 66 | + const auto& alpha_val = value_of(alpha); |
| 67 | + const auto& beta_val = value_of(beta); |
| 68 | + |
| 69 | + auto check_y_not_nan |
| 70 | + = check_cl(function, "Random variable", y_val, "not NaN"); |
| 71 | + auto y_not_nan_expr = !isnan(y_val); |
| 72 | + auto check_alpha_pos_finite |
| 73 | + = check_cl(function, "Shape parameter", alpha_val, "positive finite"); |
| 74 | + auto alpha_pos_finite_expr = alpha_val > 0 && isfinite(alpha_val); |
| 75 | + auto check_beta_pos_finite = check_cl(function, "Inverse scale parameter", |
| 76 | + beta_val, "positive finite"); |
| 77 | + auto beta_pos_finite_expr = beta_val > 0 && isfinite(beta_val); |
| 78 | + |
| 79 | + auto any_y_negative_expr = colwise_max(constant(0, N, 1) + (y_val < 0)); |
| 80 | + auto log_y_expr = log(y_val); |
| 81 | + auto log_beta_expr = log(beta_val); |
| 82 | + auto logp1_expr = static_select<include_summand<propto, T_shape_cl>::value>( |
| 83 | + -lgamma(alpha_val), constant(0.0, N, 1)); |
| 84 | + auto logp2_expr = static_select< |
| 85 | + include_summand<propto, T_shape_cl, T_inv_scale_cl>::value>( |
| 86 | + logp1_expr + elt_multiply(alpha_val, log_beta_expr), logp1_expr); |
| 87 | + auto logp3_expr |
| 88 | + = static_select<include_summand<propto, T_y_cl, T_shape_cl>::value>( |
| 89 | + logp2_expr + elt_multiply(alpha_val - 1.0, log_y_expr), logp2_expr); |
| 90 | + auto logp_expr = colwise_sum( |
| 91 | + static_select<include_summand<propto, T_y_cl, T_inv_scale_cl>::value>( |
| 92 | + logp3_expr - elt_multiply(beta_val, y_val), logp3_expr)); |
| 93 | + |
| 94 | + auto y_deriv_expr = elt_divide(alpha_val - 1, y_val) - beta_val; |
| 95 | + auto alpha_deriv_expr = log_beta_expr + log_y_expr - digamma(alpha_val); |
| 96 | + auto beta_deriv_expr = elt_divide(alpha_val, beta_val) - y_val; |
| 97 | + |
| 98 | + matrix_cl<int> any_y_negative_cl; |
| 99 | + matrix_cl<double> logp_cl; |
| 100 | + matrix_cl<double> y_deriv_cl; |
| 101 | + matrix_cl<double> alpha_deriv_cl; |
| 102 | + matrix_cl<double> beta_deriv_cl; |
| 103 | + |
| 104 | + results(check_y_not_nan, check_alpha_pos_finite, check_beta_pos_finite, |
| 105 | + any_y_negative_cl, logp_cl, y_deriv_cl, alpha_deriv_cl, beta_deriv_cl) |
| 106 | + = expressions( |
| 107 | + y_not_nan_expr, alpha_pos_finite_expr, beta_pos_finite_expr, |
| 108 | + any_y_negative_expr, logp_expr, |
| 109 | + calc_if<!is_constant<T_y_cl>::value>(y_deriv_expr), |
| 110 | + calc_if<!is_constant<T_shape_cl>::value>(alpha_deriv_expr), |
| 111 | + calc_if<!is_constant<T_inv_scale_cl>::value>(beta_deriv_expr)); |
| 112 | + |
| 113 | + if (from_matrix_cl(any_y_negative_cl).any()) { |
| 114 | + return LOG_ZERO; |
| 115 | + } |
| 116 | + |
| 117 | + T_partials_return logp = sum(from_matrix_cl(logp_cl)); |
| 118 | + |
| 119 | + operands_and_partials<T_y_cl, T_shape_cl, T_inv_scale_cl> ops_partials( |
| 120 | + y, alpha, beta); |
| 121 | + if (!is_constant<T_y_cl>::value) { |
| 122 | + ops_partials.edge1_.partials_ = std::move(y_deriv_cl); |
| 123 | + } |
| 124 | + if (!is_constant<T_shape_cl>::value) { |
| 125 | + ops_partials.edge2_.partials_ = std::move(alpha_deriv_cl); |
| 126 | + } |
| 127 | + if (!is_constant<T_inv_scale_cl>::value) { |
| 128 | + ops_partials.edge3_.partials_ = std::move(beta_deriv_cl); |
| 129 | + } |
| 130 | + |
| 131 | + return ops_partials.build(logp); |
| 132 | +} |
| 133 | + |
| 134 | +} // namespace math |
| 135 | +} // namespace stan |
| 136 | +#endif |
| 137 | +#endif |
0 commit comments