3
3
4
4
#include < stan/math/prim/meta.hpp>
5
5
#include < stan/math/prim/err.hpp>
6
- #include < stan/math/prim/fun/inv_Phi.hpp>
7
6
#include < stan/math/prim/fun/to_vector.hpp>
8
7
#include < stan/math/prim/fun/rep_vector.hpp>
9
8
#include < stan/math/prim/fun/vector_seq_view.hpp>
10
9
#include < stan/math/prim/fun/size.hpp>
11
10
#include < stan/math/prim/fun/size_mvt.hpp>
12
11
#include < stan/math/prim/prob/multi_normal_cholesky_lpdf.hpp>
13
12
#include < stan/math/prim/prob/std_normal_lpdf.hpp>
13
+ #include < stan/math/prim/prob/std_normal_log_qf.hpp>
14
14
15
15
namespace stan {
16
16
namespace math {
17
17
namespace internal {
18
18
19
19
template <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 (
23
24
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 ))...
25
26
);
26
27
}
27
28
28
29
29
30
template <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 (
38
39
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
+ };
48
48
}
49
49
50
50
template <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 (
53
53
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>>{}>{}
57
57
);
58
58
}
59
59
}
60
60
61
- /*
62
- vectors ~ gaussian_copula_cholesky(cdf_funs_tuple, chol)
63
- (cdf_fun, ...)
64
- */
65
61
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>>
68
89
T_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) {
70
91
static constexpr const char * function = " gaussian_copula_cholesky_lpdf" ;
71
92
72
93
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 >;
75
96
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 );
77
98
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 );
79
100
if (size_mvt_y == 0 ) {
80
101
return 0 ;
81
102
}
82
103
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 ;
85
106
86
107
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 );
89
110
90
111
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 ]);
92
113
93
114
// check size consistency of all random variables y
94
115
for (size_t i = 1 ; i < size_mvt_y; i++) {
@@ -101,18 +122,18 @@ T_return gaussian_copula_cholesky_lpdf(
101
122
size_y);
102
123
}
103
124
// 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++) {
105
126
check_size_match (function,
106
127
" Size of one of the vectors of "
107
128
" the CDF functor tuple" ,
108
- math::size (cdf_tuple_vec [i]),
129
+ math::size (lcdf_tuple_vec [i]),
109
130
" Size of the first vector of the "
110
131
" location variable" ,
111
- size_cdf_tuple );
132
+ size_lcdf_tuple );
112
133
}
113
134
114
135
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 );
116
137
check_size_match (function, " Size of random variable" , size_y,
117
138
" rows of covariance parameter" , chol.rows ());
118
139
check_size_match (function, " Size of random variable" , size_y,
@@ -127,14 +148,22 @@ T_return gaussian_copula_cholesky_lpdf(
127
148
promote_scalar_t <T_return, std::vector<Eigen::VectorXd>> q (size_vec);
128
149
T_return lp (0 );
129
150
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]);
132
155
}
133
156
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);
135
158
return lp;
136
159
}
137
160
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
+ }
138
167
} // namespace math
139
168
} // namespace stan
140
169
#endif
0 commit comments