22#define STAN_MATH_OPENCL_PRIM_NORMAL_LCCDF_HPP
33#ifdef STAN_OPENCL
44
5- #include < stan/math/prim/meta.hpp>
6- #include < stan/math/prim/err.hpp>
7- #include < stan/math/prim/fun/constants.hpp>
8- #include < stan/math/prim/fun/elt_divide.hpp>
9- #include < stan/math/prim/fun/elt_multiply.hpp>
10- #include < stan/math/opencl/kernel_generator.hpp>
11- #include < stan/math/prim/functor/partials_propagator.hpp>
5+ #include < stan/math/opencl/prim/normal_lcdf.hpp>
126
137namespace stan {
148namespace math {
9+ namespace internal {
10+ constexpr char normal_lccdf_opencl_func[] = " normal_lccdf(OpenCL)" ;
11+ } // namespace internal
1512
1613/* * \ingroup opencl
1714 * Returns the normal log complementary cumulative distribution function
@@ -33,77 +30,7 @@ template <
3330 require_any_not_stan_scalar_t <T_y_cl, T_loc_cl, T_scale_cl>* = nullptr >
3431inline return_type_t <T_y_cl, T_loc_cl, T_scale_cl> normal_lccdf (
3532 const T_y_cl& y, const T_loc_cl& mu, const T_scale_cl& sigma) {
36- static constexpr const char * function = " normal_lccdf(OpenCL)" ;
37- using T_partials_return = partials_return_t <T_y_cl, T_loc_cl, T_scale_cl>;
38- using std::isfinite;
39- using std::isnan;
40-
41- check_consistent_sizes (function, " Random variable" , y, " Location parameter" ,
42- mu, " Scale parameter" , sigma);
43- const size_t N = max_size (y, mu, sigma);
44- if (N == 0 ) {
45- return 0.0 ;
46- }
47-
48- const auto & y_col = as_column_vector_or_scalar (y);
49- const auto & mu_col = as_column_vector_or_scalar (mu);
50- const auto & sigma_col = as_column_vector_or_scalar (sigma);
51-
52- const auto & y_val = value_of (y_col);
53- const auto & mu_val = value_of (mu_col);
54- const auto & sigma_val = value_of (sigma_col);
55-
56- auto check_y_not_nan
57- = check_cl (function, " Random variable" , y_val, " not NaN" );
58- auto y_not_nan_expr = !isnan (y_val);
59- auto check_mu_finite
60- = check_cl (function, " Location parameter" , mu_val, " finite" );
61- auto mu_finite_expr = isfinite (mu_val);
62- auto check_sigma_positive
63- = check_cl (function, " Scale parameter" , sigma_val, " positive" );
64- auto sigma_positive_expr = 0 < sigma_val;
65-
66- auto scaled_diff = elt_divide (y_val - mu_val, sigma_val * SQRT_TWO );
67- matrix_cl<double > one_m_erf = select (
68- scaled_diff < -37.5 * INV_SQRT_TWO , 2.0 ,
69- select (scaled_diff < -5.0 * INV_SQRT_TWO , 2.0 - erfc (-scaled_diff),
70- select (scaled_diff > 8.25 * INV_SQRT_TWO , 0.0 ,
71- 1.0 - erf (scaled_diff))));
72- auto lccdf_expr = log (one_m_erf);
73- auto mu_deriv = select (scaled_diff > 8.25 * INV_SQRT_TWO , INFTY ,
74- SQRT_TWO_OVER_SQRT_PI
75- * elt_divide (exp (-square (scaled_diff)),
76- elt_multiply (one_m_erf, sigma_val)));
77- auto y_deriv = -mu_deriv;
78- auto sigma_deriv = elt_multiply (mu_deriv, scaled_diff) * SQRT_TWO ;
79-
80- matrix_cl<double > lccdf_cl;
81- matrix_cl<double > y_deriv_cl;
82- matrix_cl<double > mu_deriv_cl;
83- matrix_cl<double > sigma_deriv_cl;
84-
85- results (check_y_not_nan, check_mu_finite, check_sigma_positive)
86- = expressions (y_not_nan_expr, mu_finite_expr, sigma_positive_expr);
87- results (lccdf_cl, y_deriv_cl, mu_deriv_cl, sigma_deriv_cl)
88- = expressions (lccdf_expr, calc_if<is_autodiff_v<T_y_cl>>(y_deriv),
89- calc_if<is_autodiff_v<T_loc_cl>>(mu_deriv),
90- calc_if<is_autodiff_v<T_scale_cl>>(sigma_deriv));
91-
92- T_partials_return lccdf
93- = LOG_HALF * lccdf_cl.size () + sum (from_matrix_cl (lccdf_cl));
94-
95- auto ops_partials = make_partials_propagator (y_col, mu_col, sigma_col);
96-
97- if constexpr (is_autodiff_v<T_y_cl>) {
98- partials<0 >(ops_partials) = std::move (y_deriv_cl);
99- }
100- if constexpr (is_autodiff_v<T_loc_cl>) {
101- partials<1 >(ops_partials) = std::move (mu_deriv_cl);
102- }
103- if constexpr (is_autodiff_v<T_scale_cl>) {
104- partials<2 >(ops_partials) = std::move (sigma_deriv_cl);
105- }
106- return ops_partials.build (lccdf);
33+ return normal_lcdf<internal::normal_lccdf_opencl_func>(-y, -mu, sigma);
10734}
10835
10936} // namespace math
0 commit comments