Skip to content

Commit 9ca0e0a

Browse files
committed
Initial mix, fwd failing
1 parent 0767c19 commit 9ca0e0a

File tree

2 files changed

+67
-39
lines changed

2 files changed

+67
-39
lines changed

stan/math/prim/prob/gaussian_copula_cholesky_lpdf.hpp

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,35 +26,17 @@ auto apply_lcdfs_elem_impl(
2626
);
2727
}
2828

29-
30-
template <typename Ty, typename Ttuple, std::size_t... I>
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(
39-
std::forward<decltype(y[I])>(y[I]),
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-
}
49-
5029
template <typename Ty, typename Ttuple>
51-
auto apply_lcdfs(Ty&& y, Ttuple&& lcdf_tuple){
52-
return apply_lcdfs_impl(
53-
std::forward<Ty>(y),
54-
std::forward<Ttuple>(lcdf_tuple),
55-
std::make_index_sequence<
56-
std::tuple_size<std::remove_reference_t<Ttuple>>{}>{}
57-
);
30+
auto apply_lcdfs(Ty&& y, Ttuple&& lcdf_tuple) {
31+
return index_apply<std::tuple_size<std::remove_reference_t<Ttuple>>{}>(
32+
[&y, &lcdf_tuple](auto... Is) {
33+
return std::make_tuple(
34+
apply_lcdfs_elem_impl(
35+
y[Is], std::get<Is>(lcdf_tuple), std::make_index_sequence<
36+
std::tuple_size<std::remove_reference_t<decltype(std::get<Is>(lcdf_tuple))>>{} - 1>{}
37+
)...
38+
);
39+
});
5840
}
5941
}
6042

@@ -84,9 +66,8 @@ auto apply_lcdfs(Ty&& y, Ttuple&& lcdf_tuple){
8466
* @tparam T_lcdf_fun_tuple Type of tuple of LCDF functor tuples.
8567
* @tparam T_chol Type of cholesky factor.
8668
*/
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>>
89-
T_return gaussian_copula_cholesky_lpdf(
69+
template <bool propto, typename T_y, typename T_lcdf_fun_tuple, typename T_chol>
70+
auto gaussian_copula_cholesky_lpdf(
9071
const T_y& y, const T_lcdf_fun_tuple& lcdf_fun_tuple, const T_chol chol) {
9172
static constexpr const char* function = "gaussian_copula_cholesky_lpdf";
9273

@@ -97,15 +78,17 @@ T_return gaussian_copula_cholesky_lpdf(
9778
check_consistent_sizes_mvt(function, "y", y, "lcdf_fun_tuple", lcdf_fun_tuple);
9879
const size_t size_mvt_y = size_mvt(y);
9980
const size_t size_mvt_lcdf_tuple = size_mvt(lcdf_fun_tuple);
100-
if (size_mvt_y == 0) {
101-
return 0;
102-
}
10381
T_y_ref y_ref = y;
10482
T_chol_ref chol_ref = chol;
10583
T_lcdf_ref lcdf_tuple_ref = lcdf_fun_tuple;
10684

10785
vector_seq_view<T_y_ref> y_vec(y_ref);
10886
vector_seq_view<T_lcdf_ref> lcdf_tuple_vec(lcdf_tuple_ref);
87+
using T_return = return_type_t<T_y, decltype(internal::apply_lcdfs(y_vec[0], lcdf_tuple_vec[0])), T_chol>;
88+
89+
if (size_mvt_y == 0) {
90+
return T_return(0);
91+
}
10992
const size_t size_vec = max_size_mvt(y, lcdf_fun_tuple);
11093

11194
const int size_y = math::size(y_vec[0]);
@@ -148,19 +131,29 @@ T_return gaussian_copula_cholesky_lpdf(
148131
promote_scalar_t<T_return, std::vector<Eigen::VectorXd>> q(size_vec);
149132
T_return lp(0);
150133
for (size_t i = 0; i < size_vec; i++) {
151-
const auto& u = internal::apply_lcdfs(y_vec[i], lcdf_tuple_vec[i]);
134+
const auto& y_i = y_vec[i];
135+
const auto& func_i = lcdf_tuple_vec[i];
136+
137+
const auto& res = internal::apply_lcdfs(y_i, func_i);
138+
const auto& u = index_apply<std::tuple_size<std::remove_reference_t<decltype(res)>>{}>(
139+
[&res, size_y](auto... Is) {
140+
Eigen::Matrix<T_return, Eigen::Dynamic, 1> u_inner(size_y);
141+
static_cast<void>(std::initializer_list<int>{
142+
(u_inner[Is] = std::get<Is>(res), 0)...
143+
});
144+
return u_inner;
145+
});
152146
check_bounded(function, "LCDF-transformed inputs", u, NEGATIVE_INFTY, 0);
153-
q[i] = to_vector(std_normal_log_qf(u));
147+
q[i] = std_normal_log_qf(u);
154148
lp -= std_normal_lpdf<propto>(q[i]);
155149
}
156150
const std::vector<Eigen::VectorXd> zero_vec(size_vec, rep_vector(0, size_y));
157151
lp += multi_normal_cholesky_lpdf<propto>(q, zero_vec, chol_ref);
158152
return lp;
159153
}
160154

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(
155+
template <typename T_y, typename T_lcdf_fun_tuple, typename T_chol>
156+
auto gaussian_copula_cholesky_lpdf(
164157
const T_y& y, const T_lcdf_fun_tuple& lcdf_fun_tuple, const T_chol chol) {
165158
return gaussian_copula_cholesky_lpdf<false>(y, lcdf_fun_tuple, chol);
166159
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include <test/unit/math/test_ad.hpp>
2+
3+
TEST_F(AgradRev, ProbDistributionsGaussCopulaCholesky) {
4+
// Bind functors for compatibility with AD framework
5+
auto f = [](const auto func1, const auto func2) {
6+
return [=](const auto& y, const auto& args, const auto& sigma) {
7+
auto lcdf_functors = std::make_tuple(
8+
std::make_tuple(func1, args[0]),
9+
std::make_tuple(func2, args[1])
10+
);
11+
auto sigma_sym = stan::math::multiply(0.5, sigma + sigma.transpose());
12+
auto L = stan::math::cholesky_decompose(sigma_sym);
13+
return stan::math::gaussian_copula_cholesky_lpdf(y, lcdf_functors, L);
14+
};
15+
};
16+
17+
// y[0] ~ gamma(2, 1)
18+
// y[1] ~ std_normal()
19+
Eigen::VectorXd y1(2);
20+
y1 << 1.0, 0.1;
21+
Eigen::VectorXd args(2);
22+
args << 0, 2.0;
23+
24+
auto func1 = [](const auto& y, const auto& mu) {
25+
return stan::math::normal_lcdf(y, mu, 1.0);
26+
};
27+
auto func2 = [](const auto& y) {
28+
return stan::math::std_normal_lcdf(y);
29+
};
30+
31+
Eigen::MatrixXd Sigma22(2, 2);
32+
Sigma22 << 2.0, 0.5, 0.5, 1.1;
33+
34+
stan::test::expect_ad(f(func2, func2), y1, args, Sigma22);
35+
}

0 commit comments

Comments
 (0)