1 #ifndef STAN_MATH_PRIM_PROB_CAUCHY_LCCDF_HPP
2 #define STAN_MATH_PRIM_PROB_CAUCHY_LCCDF_HPP
3 
4 #include <stan/math/prim/meta.hpp>
5 #include <stan/math/prim/err.hpp>
6 #include <stan/math/prim/fun/constants.hpp>
7 #include <stan/math/prim/fun/log.hpp>
8 #include <stan/math/prim/fun/max_size.hpp>
9 #include <stan/math/prim/fun/scalar_seq_view.hpp>
10 #include <stan/math/prim/fun/size_zero.hpp>
11 #include <stan/math/prim/fun/value_of.hpp>
12 #include <stan/math/prim/functor/operands_and_partials.hpp>
13 #include <cmath>
14 
15 namespace stan {
16 namespace math {
17 
18 /** \ingroup prob_dists
19  * Returns the cauchy log complementary cumulative distribution function
20  * for the given location, and scale. If given containers of matching sizes
21  * returns the log sum of probabilities.
22  *
23  * @tparam T_y type of real parameter
24  * @tparam T_loc type of location parameter
25  * @tparam T_scale type of scale parameter
26  * @param y real parameter
27  * @param mu location parameter
28  * @param sigma scale parameter
29  * @return log probability or log sum of probabilities
30  * @throw std::domain_error if sigma is nonpositive or y, mu are nan
31  * @throw std::invalid_argument if container sizes mismatch
32  */
33 template <typename T_y, typename T_loc, typename T_scale,
34           require_all_not_nonscalar_prim_or_rev_kernel_expression_t<
35               T_y, T_loc, T_scale>* = nullptr>
cauchy_lccdf(const T_y & y,const T_loc & mu,const T_scale & sigma)36 return_type_t<T_y, T_loc, T_scale> cauchy_lccdf(const T_y& y, const T_loc& mu,
37                                                 const T_scale& sigma) {
38   using T_partials_return = partials_return_t<T_y, T_loc, T_scale>;
39   using std::atan;
40   using std::log;
41   using T_y_ref = ref_type_t<T_y>;
42   using T_mu_ref = ref_type_t<T_loc>;
43   using T_sigma_ref = ref_type_t<T_scale>;
44   static const char* function = "cauchy_lccdf";
45   check_consistent_sizes(function, "Random variable", y, "Location parameter",
46                          mu, "Scale Parameter", sigma);
47   T_y_ref y_ref = y;
48   T_mu_ref mu_ref = mu;
49   T_sigma_ref sigma_ref = sigma;
50   check_not_nan(function, "Random variable", y_ref);
51   check_finite(function, "Location parameter", mu_ref);
52   check_positive_finite(function, "Scale parameter", sigma_ref);
53 
54   if (size_zero(y, mu, sigma)) {
55     return 0;
56   }
57 
58   T_partials_return ccdf_log(0.0);
59   operands_and_partials<T_y_ref, T_mu_ref, T_sigma_ref> ops_partials(
60       y_ref, mu_ref, sigma_ref);
61 
62   scalar_seq_view<T_y_ref> y_vec(y_ref);
63   scalar_seq_view<T_mu_ref> mu_vec(mu_ref);
64   scalar_seq_view<T_sigma_ref> sigma_vec(sigma_ref);
65   size_t N = max_size(y, mu, sigma);
66 
67   for (size_t n = 0; n < N; n++) {
68     const T_partials_return y_dbl = y_vec.val(n);
69     const T_partials_return mu_dbl = mu_vec.val(n);
70     const T_partials_return sigma_inv_dbl = 1.0 / sigma_vec.val(n);
71     const T_partials_return sigma_dbl = sigma_vec.val(n);
72     const T_partials_return z = (y_dbl - mu_dbl) * sigma_inv_dbl;
73 
74     const T_partials_return Pn = 0.5 - atan(z) / pi();
75     ccdf_log += log(Pn);
76 
77     const T_partials_return rep_deriv
78         = 1.0 / (Pn * pi() * (z * z * sigma_dbl + sigma_dbl));
79     if (!is_constant_all<T_y>::value) {
80       ops_partials.edge1_.partials_[n] -= rep_deriv;
81     }
82     if (!is_constant_all<T_loc>::value) {
83       ops_partials.edge2_.partials_[n] += rep_deriv;
84     }
85     if (!is_constant_all<T_scale>::value) {
86       ops_partials.edge3_.partials_[n] += rep_deriv * z;
87     }
88   }
89   return ops_partials.build(ccdf_log);
90 }
91 
92 }  // namespace math
93 }  // namespace stan
94 #endif
95