33
44#include < stan/math/prim/meta.hpp>
55#include < stan/math/prim/err.hpp>
6- #include < stan/math/prim/fun/inv_Phi.hpp>
76#include < stan/math/prim/fun/to_vector.hpp>
87#include < stan/math/prim/fun/rep_vector.hpp>
98#include < stan/math/prim/fun/vector_seq_view.hpp>
109#include < stan/math/prim/fun/size.hpp>
1110#include < stan/math/prim/fun/size_mvt.hpp>
1211#include < stan/math/prim/prob/multi_normal_cholesky_lpdf.hpp>
1312#include < stan/math/prim/prob/std_normal_lpdf.hpp>
13+ #include < stan/math/prim/prob/std_normal_log_qf.hpp>
1414
1515namespace stan {
1616namespace math {
1717namespace internal {
1818
1919template <typename Ty_elem, typename Ttuple, std::size_t ... I>
20- auto apply_cdfs_elem_impl (Ty_elem&& y_elem, Ttuple&& cdf_tuple, std::index_sequence<I...>){
21- auto && cdf_func = std::get<0 >(cdf_tuple);
22- return cdf_func (
20+ auto apply_lcdfs_elem_impl (
21+ Ty_elem&& y_elem, Ttuple&& lcdf_tuple, std::index_sequence<I...>) {
22+ auto && lcdf_func = std::get<0 >(lcdf_tuple);
23+ return lcdf_func (
2324 std::forward<Ty_elem>(y_elem),
24- std::get<I + 1 >(std::forward<Ttuple>(cdf_tuple ))...
25+ std::get<I + 1 >(std::forward<Ttuple>(lcdf_tuple ))...
2526 );
2627}
2728
2829
2930template <typename Ty, typename Ttuple, std::size_t ... I>
30- auto apply_cdfs_impl (Ty&& y, Ttuple&& cdf_tuple, std::index_sequence<I...>){
31- plain_type_t <Ty> res (y. size ());
32-
33- // Use initializer-list expansion to assign the result of each CDF
34- // to the respective element in the result vector, as we need a constant
35- // expression for indexing the tuple of CDF functors
36- static_cast < void >(std::initializer_list< int >{(
37- res[I] = apply_cdfs_elem_impl (
31+ std::vector< return_type_t <Ty, Ttuple>> apply_lcdfs_impl (
32+ Ty&& y, Ttuple&& lcdf_tuple, std::index_sequence<I...>) {
33+ // Use initializer-list expansion to return a vector with the result of
34+ // applying each LCDF functor to the respective input.
35+ // We cannot use apply_scalar_unary here as we need a constant
36+ // expression for indexing the tuple of LCDF functors
37+ return {
38+ apply_lcdfs_elem_impl (
3839 std::forward<decltype (y[I])>(y[I]),
39- std::get<I>(cdf_tuple),
40- std::make_index_sequence<
41- // Using size - 1 as the first element is the functor to apply
42- std::tuple_size<
43- std::remove_reference_t <
44- decltype (std::get<I>(cdf_tuple))>>{} - 1 >{}),
45- 0 )...});
46-
47- return res;
40+ std::get<I>(lcdf_tuple),
41+ std::make_index_sequence<
42+ // Using size - 1 as the first element is the functor to apply
43+ std::tuple_size<
44+ std::remove_reference_t <
45+ decltype (std::get<I>(lcdf_tuple))>>{} - 1 >{}
46+ )...
47+ };
4848}
4949
5050template <typename Ty, typename Ttuple>
51- auto apply_cdfs (Ty&& y, Ttuple&& cdf_tuple ){
52- return apply_cdfs_impl (
51+ auto apply_lcdfs (Ty&& y, Ttuple&& lcdf_tuple ){
52+ return apply_lcdfs_impl (
5353 std::forward<Ty>(y),
54- std::forward<Ttuple>(cdf_tuple ),
55- std::make_index_sequence<
56- std::tuple_size<std::remove_reference_t <Ttuple>>{}>{}
54+ std::forward<Ttuple>(lcdf_tuple ),
55+ std::make_index_sequence<
56+ std::tuple_size<std::remove_reference_t <Ttuple>>{}>{}
5757 );
5858}
5959}
6060
61- /*
62- vectors ~ gaussian_copula_cholesky(cdf_funs_tuple, chol)
63- (cdf_fun, ...)
64- */
6561
66- template <typename T_y, typename T_cdf_fun_tuple, typename T_chol,
67- typename T_return = return_type_t <T_y, T_cdf_fun_tuple, T_chol>>
62+ /* * \ingroup multivar_dists
63+ * The log of the Gaussian copula density for the given y and
64+ * a Cholesky factor L of the variance matrix.
65+ *
66+ * As the Gaussian copula requires inputs to be in the unit interval,
67+ * users are required to provide a tuple (of the same size as y) where each
68+ * element is a tuple containing a functor for calculating the LCDF and any
69+ * additional parameters required by the LCDF functor.
70+ *
71+ * This version of the function is vectorized on y and the tuple of LCDF
72+ * functor tuples.
73+ *
74+ * @param y A scalar vector
75+ * @param lcdf_fun_tuple A tuple of tuples, where each inner tuple follows the
76+ * structure {functor, param1, param2, ...}, where the functor has signature
77+ * (y[i], param1, param2, ...) and returns the log CDF for the given y[i].
78+ * @param chol The Cholesky decomposition of a variance matrix
79+ * of the multivariate normal distribution
80+ * @return The log of the gaussian copula density.
81+ * @throw std::domain_error if LL' is not square, not symmetric,
82+ * or not semi-positive definite.
83+ * @tparam T_y Type of scalar.
84+ * @tparam T_lcdf_fun_tuple Type of tuple of LCDF functor tuples.
85+ * @tparam T_chol Type of cholesky factor.
86+ */
87+ template <bool propto, typename T_y, typename T_lcdf_fun_tuple, typename T_chol,
88+ typename T_return = return_type_t <T_y, T_lcdf_fun_tuple, T_chol>>
6889T_return gaussian_copula_cholesky_lpdf(
69- const T_y& y, const T_cdf_fun_tuple& cdf_fun_tuple , const T_chol chol) {
90+ const T_y& y, const T_lcdf_fun_tuple& lcdf_fun_tuple , const T_chol chol) {
7091 static constexpr const char * function = " gaussian_copula_cholesky_lpdf" ;
7192
7293 using T_y_ref = ref_type_t <T_y>;
73- using T_chochol_ref = ref_type_t <T_chol>;
74- using T_cdf_ref = ref_type_t <T_cdf_fun_tuple >;
94+ using T_chol_ref = ref_type_t <T_chol>;
95+ using T_lcdf_ref = ref_type_t <T_lcdf_fun_tuple >;
7596
76- check_consistent_sizes_mvt (function, " y" , y, " cdf_fun_tuple " , cdf_fun_tuple );
97+ check_consistent_sizes_mvt (function, " y" , y, " lcdf_fun_tuple " , lcdf_fun_tuple );
7798 const size_t size_mvt_y = size_mvt (y);
78- const size_t size_mvt_cdf_tuple = size_mvt (cdf_fun_tuple );
99+ const size_t size_mvt_lcdf_tuple = size_mvt (lcdf_fun_tuple );
79100 if (size_mvt_y == 0 ) {
80101 return 0 ;
81102 }
82103 T_y_ref y_ref = y;
83- T_chochol_ref chol_ref = chol;
84- T_cdf_ref cdf_tuple_ref = cdf_fun_tuple ;
104+ T_chol_ref chol_ref = chol;
105+ T_lcdf_ref lcdf_tuple_ref = lcdf_fun_tuple ;
85106
86107 vector_seq_view<T_y_ref> y_vec (y_ref);
87- vector_seq_view<T_cdf_ref> cdf_tuple_vec (cdf_tuple_ref );
88- const size_t size_vec = max_size_mvt (y, cdf_fun_tuple );
108+ vector_seq_view<T_lcdf_ref> lcdf_tuple_vec (lcdf_tuple_ref );
109+ const size_t size_vec = max_size_mvt (y, lcdf_fun_tuple );
89110
90111 const int size_y = math::size (y_vec[0 ]);
91- const int size_cdf_tuple = math::size (cdf_tuple_vec [0 ]);
112+ const int size_lcdf_tuple = math::size (lcdf_tuple_vec [0 ]);
92113
93114 // check size consistency of all random variables y
94115 for (size_t i = 1 ; i < size_mvt_y; i++) {
@@ -101,18 +122,18 @@ T_return gaussian_copula_cholesky_lpdf(
101122 size_y);
102123 }
103124 // check size consistency of all CDF tuples
104- for (size_t i = 1 ; i < size_mvt_cdf_tuple ; i++) {
125+ for (size_t i = 1 ; i < size_mvt_lcdf_tuple ; i++) {
105126 check_size_match (function,
106127 " Size of one of the vectors of "
107128 " the CDF functor tuple" ,
108- math::size (cdf_tuple_vec [i]),
129+ math::size (lcdf_tuple_vec [i]),
109130 " Size of the first vector of the "
110131 " location variable" ,
111- size_cdf_tuple );
132+ size_lcdf_tuple );
112133 }
113134
114135 check_size_match (function, " Size of random variable" , size_y,
115- " size of CDF functor tuple" , size_cdf_tuple );
136+ " size of CDF functor tuple" , size_lcdf_tuple );
116137 check_size_match (function, " Size of random variable" , size_y,
117138 " rows of covariance parameter" , chol.rows ());
118139 check_size_match (function, " Size of random variable" , size_y,
@@ -127,14 +148,22 @@ T_return gaussian_copula_cholesky_lpdf(
127148 promote_scalar_t <T_return, std::vector<Eigen::VectorXd>> q (size_vec);
128149 T_return lp (0 );
129150 for (size_t i = 0 ; i < size_vec; i++) {
130- q[i] = to_vector (inv_Phi (internal::apply_cdfs (y_vec[i], cdf_tuple_vec[i])));
131- lp -= std_normal_lpdf (q[i]);
151+ const auto & u = internal::apply_lcdfs (y_vec[i], lcdf_tuple_vec[i]);
152+ check_bounded (function, " CDF-transformed inputs" , u, NEGATIVE_INFTY, 0 );
153+ q[i] = to_vector (std_normal_log_qf (u));
154+ lp -= std_normal_lpdf<propto>(q[i]);
132155 }
133156 const std::vector<Eigen::VectorXd> zero_vec (size_vec, rep_vector (0 , size_y));
134- lp += multi_normal_cholesky_lpdf (q, zero_vec, chol_ref);
157+ lp += multi_normal_cholesky_lpdf<propto> (q, zero_vec, chol_ref);
135158 return lp;
136159}
137160
161+ template <typename T_y, typename T_lcdf_fun_tuple, typename T_chol,
162+ typename T_return = return_type_t <T_y, T_lcdf_fun_tuple, T_chol>>
163+ T_return gaussian_copula_cholesky_lpdf(
164+ const T_y& y, const T_lcdf_fun_tuple& lcdf_fun_tuple, const T_chol chol) {
165+ return gaussian_copula_cholesky_lpdf<false >(y, lcdf_fun_tuple, chol);
166+ }
138167} // namespace math
139168} // namespace stan
140169#endif
0 commit comments