Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opencl weibull_lpdf, neg_binomial_2_log_lpmf and neg_binomial_2_lpmf #2231

Merged
merged 6 commits into from
Dec 5, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions stan/math/opencl/opencl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@
#include <stan/math/opencl/prim/mdivide_left_tri_low.hpp>
#include <stan/math/opencl/prim/mdivide_right_tri_low.hpp>
#include <stan/math/opencl/prim/neg_binomial_2_log_glm_lpmf.hpp>
#include <stan/math/opencl/prim/neg_binomial_2_log_lpmf.hpp>
#include <stan/math/opencl/prim/neg_binomial_2_lpmf.hpp>
#include <stan/math/opencl/prim/normal_id_glm_lpdf.hpp>
#include <stan/math/opencl/prim/normal_lpdf.hpp>
#include <stan/math/opencl/prim/ordered_logistic_glm_lpmf.hpp>
Expand All @@ -155,6 +157,7 @@
#include <stan/math/opencl/prim/sum.hpp>
#include <stan/math/opencl/prim/tcrossprod.hpp>
#include <stan/math/opencl/prim/uniform_lpdf.hpp>
#include <stan/math/opencl/prim/weibull_lpdf.hpp>

#include <stan/math/opencl/err.hpp>

Expand Down
122 changes: 122 additions & 0 deletions stan/math/opencl/prim/neg_binomial_2_log_lpmf.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#ifndef STAN_MATH_OPENCL_PRIM_NEG_BINOMIAL_2_LOG_LPMF_HPP
#define STAN_MATH_OPENCL_PRIM_NEG_BINOMIAL_2_LOG_LPMF_HPP
#ifdef STAN_OPENCL

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/elt_divide.hpp>
#include <stan/math/prim/fun/elt_multiply.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/prim/functor/operands_and_partials.hpp>

namespace stan {
namespace math {

/** \ingroup opencl
* The log of the log transformed negative binomial density for the specified
* scalars given the specified mean(s) and deviation(s). n, eta, or phi can each
* be either a scalar or a vector matrix_cl. Any vector inputs must be the same
* length.
*
* <p>The result log probability is defined to be the sum of the
* log probabilities for each observation/mean/deviation triple.
*
* @tparam T_n_cl type of scalar
* @tparam T_log_location_cl type of location parameter
* @tparam T_precision_cl type of precision parameter
* @param n (Sequence of) scalar(s).
* @param eta (Sequence of) location parameter(s)
* @param phi (Sequence of) precision parameters
* @return The log of the product of the densities.
* @throw std::domain_error if the scale is not positive.
*/
template <bool propto, typename T_n_cl, typename T_log_location_cl,
typename T_precision_cl,
require_all_prim_or_rev_kernel_expression_t<
T_n_cl, T_log_location_cl, T_precision_cl>* = nullptr,
require_any_not_stan_scalar_t<T_n_cl, T_log_location_cl,
T_precision_cl>* = nullptr>
inline return_type_t<T_n_cl, T_log_location_cl, T_precision_cl>
neg_binomial_2_log_lpmf(const T_n_cl& n, const T_log_location_cl& eta,
const T_precision_cl& phi) {
static const char* function = "neg_binomial_2_log_lpmf(OpenCL)";
using T_partials_return
= partials_return_t<T_n_cl, T_log_location_cl, T_precision_cl>;
using std::isfinite;
using std::isnan;

check_consistent_sizes(function, "Failures variable", n,
"Log location parameter", eta, "Precision parameter",
phi);
const size_t N = max_size(n, eta, phi);
if (N == 0) {
return 0.0;
}
if (!include_summand<propto, T_n_cl, T_log_location_cl,
T_precision_cl>::value) {
return 0.0;
}

const auto& eta_val = value_of(eta);
const auto& phi_val = value_of(phi);

auto check_n_nonnegative
= check_cl(function, "Failures variable", n, "nonnegative");
auto n_nonnegative = n >= 0;
auto check_eta_finite
= check_cl(function, "Log location parameter", eta_val, "finite");
auto eta_finite = isfinite(eta_val);
auto check_phi_positive_finite
= check_cl(function, "Precision parameter", phi_val, "positive finite");
auto phi_positive_finite = 0 < phi_val && isfinite(phi_val);

auto log_phi = log(phi_val);
auto exp_eta = exp(eta_val);
auto exp_eta_over_exp_eta_phi
= elt_divide(1.0, elt_divide(phi_val, exp_eta) + 1.0);
auto log1p_exp_eta_m_logphi = log1p_exp(eta_val - log_phi);
auto n_plus_phi = n + phi_val;

auto logp1 = -elt_multiply(phi_val, log1p_exp_eta_m_logphi)
- elt_multiply(n, log_phi + log1p_exp_eta_m_logphi);
auto logp2 = static_select<include_summand<propto, T_precision_cl>::value>(
logp1 + binomial_coefficient_log(n_plus_phi - 1, n), logp1);
auto logp_expr = colwise_sum(
static_select<include_summand<propto, T_log_location_cl>::value>(
logp2 + elt_multiply(n, eta_val), logp2));

auto eta_deriv = n - elt_multiply(n_plus_phi, exp_eta_over_exp_eta_phi);
auto phi_deriv = exp_eta_over_exp_eta_phi - elt_divide(n, exp_eta + phi_val)
- log1p_exp_eta_m_logphi - digamma(phi_val)
+ digamma(n_plus_phi);

matrix_cl<double> logp_cl;
matrix_cl<double> eta_deriv_cl;
matrix_cl<double> phi_deriv_cl;

results(check_n_nonnegative, check_eta_finite, check_phi_positive_finite,
logp_cl, eta_deriv_cl, phi_deriv_cl)
= expressions(n_nonnegative, eta_finite, phi_positive_finite, logp_expr,
calc_if<!is_constant<T_log_location_cl>::value>(eta_deriv),
calc_if<!is_constant<T_precision_cl>::value>(phi_deriv));

T_partials_return logp = sum(from_matrix_cl(logp_cl));

operands_and_partials<T_log_location_cl, T_precision_cl> ops_partials(eta,
phi);

if (!is_constant<T_log_location_cl>::value) {
ops_partials.edge1_.partials_ = std::move(eta_deriv_cl);
}
if (!is_constant<T_precision_cl>::value) {
ops_partials.edge2_.partials_ = std::move(phi_deriv_cl);
}
return ops_partials.build(logp);
}

} // namespace math
} // namespace stan
#endif
#endif
119 changes: 119 additions & 0 deletions stan/math/opencl/prim/neg_binomial_2_lpmf.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#ifndef STAN_MATH_OPENCL_PRIM_NEG_BINOMIAL_2_LPMF_HPP
#define STAN_MATH_OPENCL_PRIM_NEG_BINOMIAL_2_LPMF_HPP
#ifdef STAN_OPENCL

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/elt_divide.hpp>
#include <stan/math/prim/fun/elt_multiply.hpp>
#include <stan/math/prim/fun/exp.hpp>
#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/prim/functor/operands_and_partials.hpp>

namespace stan {
namespace math {

/** \ingroup opencl
* The log of the negative binomial density for the specified scalars given
* the specified mean(s) and deviation(s). n, mu, or phi can
* each be either a scalar or a vector matrix_cl. Any vector inputs
* must be the same length.
*
* <p>The result log probability is defined to be the sum of the
* log probabilities for each observation/mean/deviation triple.
*
* @tparam T_n_cl type of scalar
* @tparam T_location_cl type of location parameter
* @tparam T_precision_cl type of precision parameter
* @param n (Sequence of) scalar(s).
* @param mu (Sequence of) location parameter(s)
* @param phi (Sequence of) precision parameters
* @return The log of the product of the densities.
* @throw std::domain_error if the scale is not positive.
*/
template <bool propto, typename T_n_cl, typename T_location_cl,
typename T_precision_cl,
require_all_prim_or_rev_kernel_expression_t<
T_n_cl, T_location_cl, T_precision_cl>* = nullptr,
require_any_not_stan_scalar_t<T_n_cl, T_location_cl,
T_precision_cl>* = nullptr>
inline return_type_t<T_n_cl, T_location_cl, T_precision_cl> neg_binomial_2_lpmf(
const T_n_cl& n, const T_location_cl& mu, const T_precision_cl& phi) {
static const char* function = "neg_binomial_2_lpmf(OpenCL)";
using T_partials_return
= partials_return_t<T_n_cl, T_location_cl, T_precision_cl>;
using std::isfinite;
using std::isnan;

check_consistent_sizes(function, "Failures variable", n, "Location parameter",
mu, "Precision parameter", phi);
const size_t N = max_size(n, mu, phi);
if (N == 0) {
return 0.0;
}
if (!include_summand<propto, T_n_cl, T_location_cl, T_precision_cl>::value) {
return 0.0;
}

const auto& mu_val = value_of(mu);
const auto& phi_val = value_of(phi);

auto check_n_nonnegative
= check_cl(function, "Failures variable", n, "nonnegative");
auto n_nonnegative = n >= 0;
auto check_mu_positive_finite
= check_cl(function, "Log location parameter", mu_val, "positive finite");
auto mu_positive_finite = 0 < mu_val && isfinite(mu_val);
auto check_phi_positive_finite
= check_cl(function, "Precision parameter", phi_val, "positive finite");
auto phi_positive_finite = 0 < phi_val && isfinite(phi_val);

auto log_phi = log(phi_val);
auto mu_plus_phi = mu_val + phi_val;
auto log_mu_plus_phi = log(mu_plus_phi);
auto n_plus_phi = n + phi_val;

auto logp1 = -elt_multiply(phi_val, log1p(elt_divide(mu_val, phi_val)))
- elt_multiply(n, log_mu_plus_phi);
auto logp2 = static_select<include_summand<propto, T_precision_cl>::value>(
logp1 + binomial_coefficient_log(n_plus_phi - 1, n), logp1);
auto logp_expr = colwise_sum(
static_select<include_summand<propto, T_location_cl>::value>(
logp2 + multiply_log(n, mu_val), logp2));

auto mu_deriv = elt_divide(n, mu_val) - elt_divide(n + phi_val, mu_plus_phi);
auto log_term
= select(mu_val < phi_val, log1p(-elt_divide(mu_val, mu_plus_phi)),
log_phi - log_mu_plus_phi);
auto phi_deriv = elt_divide(mu_val - n, mu_plus_phi) + log_term
- digamma(phi_val) + digamma(n_plus_phi);

matrix_cl<double> logp_cl;
matrix_cl<double> mu_deriv_cl;
matrix_cl<double> phi_deriv_cl;

results(check_n_nonnegative, check_mu_positive_finite,
check_phi_positive_finite, logp_cl, mu_deriv_cl, phi_deriv_cl)
= expressions(n_nonnegative, mu_positive_finite, phi_positive_finite,
logp_expr,
calc_if<!is_constant<T_location_cl>::value>(mu_deriv),
calc_if<!is_constant<T_precision_cl>::value>(phi_deriv));

T_partials_return logp = sum(from_matrix_cl(logp_cl));

operands_and_partials<T_location_cl, T_precision_cl> ops_partials(mu, phi);

if (!is_constant<T_location_cl>::value) {
ops_partials.edge1_.partials_ = std::move(mu_deriv_cl);
}
if (!is_constant<T_precision_cl>::value) {
ops_partials.edge2_.partials_ = std::move(phi_deriv_cl);
}
return ops_partials.build(logp);
}

} // namespace math
} // namespace stan
#endif
#endif
129 changes: 129 additions & 0 deletions stan/math/opencl/prim/weibull_lpdf.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#ifndef STAN_MATH_OPENCL_PRIM_WEIBULL_LPDF_HPP
#define STAN_MATH_OPENCL_PRIM_WEIBULL_LPDF_HPP
#ifdef STAN_OPENCL

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/elt_divide.hpp>
#include <stan/math/prim/fun/elt_multiply.hpp>
#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/prim/functor/operands_and_partials.hpp>

namespace stan {
namespace math {

/** \ingroup opencl
* Returns the Weibull log probability density for the given
* location and scale. Given containers of matching sizes, returns the
* log sum of probability densities.
*
* @tparam T_y_cl type of real parameter
* @tparam T_shape_cl type of shape parameter
* @tparam T_scale_cl type of scale parameter
* @param y real parameter
* @param alpha shape parameter
* @param sigma scale parameter
* @return log probability density or log sum of probability densities
* @throw std::domain_error if y is negative, alpha or sigma are nonpositive
*/
template <
bool propto, typename T_y_cl, typename T_shape_cl, typename T_scale_cl,
require_all_prim_or_rev_kernel_expression_t<T_y_cl, T_shape_cl,
T_scale_cl>* = nullptr,
require_any_not_stan_scalar_t<T_y_cl, T_shape_cl, T_scale_cl>* = nullptr>
inline return_type_t<T_y_cl, T_shape_cl, T_scale_cl> weibull_lpdf(
const T_y_cl& y, const T_shape_cl& alpha, const T_scale_cl& sigma) {
static const char* function = "weibull_lpdf(OpenCL)";
using T_partials_return = partials_return_t<T_y_cl, T_shape_cl, T_scale_cl>;
using std::isfinite;
using std::isnan;

check_consistent_sizes(function, "Random variable", y, "Shape parameter",
alpha, "Scale parameter", sigma);
const size_t N = max_size(y, alpha, sigma);
if (N == 0) {
return 0.0;
}
if (!include_summand<propto, T_y_cl, T_shape_cl, T_scale_cl>::value) {
return 0.0;
}

const auto& y_val = value_of(y);
const auto& alpha_val = value_of(alpha);
const auto& sigma_val = value_of(sigma);

auto check_y_finite = check_cl(function, "Random variable", y_val, "finite");
auto y_finite = isfinite(y_val);
auto check_alpha_positive_finite
= check_cl(function, "Shape parameter", alpha_val, "positive finite");
auto alpha_positive_finite = isfinite(alpha_val) && 0 < alpha_val;
auto check_sigma_positive_finite
= check_cl(function, "Scale parameter", sigma_val, "positive finite");
auto sigma_positive_finite = isfinite(sigma_val) && 0 < sigma_val;

auto any_y_negative = colwise_max(constant(0, N, 1) + (y_val < 0));
auto log_y = log(y_val);
auto log_sigma = log(sigma_val);
auto inv_sigma = elt_divide(1., sigma_val);
auto y_div_sigma_pow_alpha = pow(elt_multiply(y_val, inv_sigma), alpha_val);

auto logp1 = -y_div_sigma_pow_alpha;
auto logp2 = static_select<include_summand<propto, T_shape_cl>::value>(
logp1 + log(alpha_val), logp1);
auto logp3
= static_select<include_summand<propto, T_y_cl, T_shape_cl>::value>(
logp2 + elt_multiply(alpha_val - 1.0, log_y), logp2);
auto logp_expr = colwise_sum(
static_select<include_summand<propto, T_shape_cl, T_scale_cl>::value>(
logp3 - elt_multiply(alpha_val, log_sigma), logp3));

auto one_m_y_div_sigma_pow_alpha = 1.0 - y_div_sigma_pow_alpha;
auto y_deriv = elt_divide(
elt_multiply(alpha_val, one_m_y_div_sigma_pow_alpha) - 1.0, y_val);
auto alpha_deriv
= elt_divide(1.0, alpha_val)
+ elt_multiply(one_m_y_div_sigma_pow_alpha, log_y - log_sigma);
auto sigma_deriv = elt_multiply(elt_multiply(alpha_val, inv_sigma),
-one_m_y_div_sigma_pow_alpha);

matrix_cl<int> any_y_negative_cl;
matrix_cl<double> logp_cl;
matrix_cl<double> alpha_deriv_cl;
matrix_cl<double> y_deriv_cl;
matrix_cl<double> sigma_deriv_cl;

results(check_y_finite, check_alpha_positive_finite,
check_sigma_positive_finite, any_y_negative_cl, logp_cl, y_deriv_cl,
alpha_deriv_cl, sigma_deriv_cl)
= expressions(y_finite, alpha_positive_finite, sigma_positive_finite,
any_y_negative, logp_expr,
calc_if<!is_constant<T_y_cl>::value>(y_deriv),
calc_if<!is_constant<T_shape_cl>::value>(alpha_deriv),
calc_if<!is_constant<T_scale_cl>::value>(sigma_deriv));

if (from_matrix_cl(any_y_negative_cl).any()) {
return LOG_ZERO;
}

T_partials_return logp = sum(from_matrix_cl(logp_cl));

operands_and_partials<T_y_cl, T_shape_cl, T_scale_cl> ops_partials(y, alpha,
sigma);

if (!is_constant<T_y_cl>::value) {
ops_partials.edge1_.partials_ = std::move(y_deriv_cl);
}
if (!is_constant<T_shape_cl>::value) {
ops_partials.edge2_.partials_ = std::move(alpha_deriv_cl);
}
if (!is_constant<T_scale_cl>::value) {
ops_partials.edge3_.partials_ = std::move(sigma_deriv_cl);
}
return ops_partials.build(logp);
}

} // namespace math
} // namespace stan
#endif
#endif
Loading