Automatic Differentiation
 
Loading...
Searching...
No Matches
cholesky_corr_constrain.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_REV_CONSTRAINT_CHOLESKY_CORR_CONSTRAIN_HPP
2#define STAN_MATH_REV_CONSTRAINT_CHOLESKY_CORR_CONSTRAIN_HPP
3
11#include <cmath>
12
13namespace stan {
14namespace math {
15
27template <typename T, require_var_vector_t<T>* = nullptr>
29 using std::sqrt;
30 int k_choose_2 = (K * (K - 1)) / 2;
31 check_size_match("cholesky_corr_constrain", "y.size()", y.size(),
32 "k_choose_2", k_choose_2);
33
34 if (K == 0) {
35 return Eigen::MatrixXd();
36 }
37
39 arena_t<Eigen::MatrixXd> x_val = Eigen::MatrixXd::Zero(K, K);
40
41 x_val.coeffRef(0, 0) = 1;
42 int k = 0;
43 for (int i = 1; i < K; ++i) {
44 x_val.coeffRef(i, 0) = z.val().coeff(k);
45 k++;
46 double sum_sqs = square(x_val.coeff(i, 0));
47 for (int j = 1; j < i; ++j) {
48 x_val.coeffRef(i, j) = z.val().coeff(k) * sqrt(1.0 - sum_sqs);
49 k++;
50 sum_sqs += square(x_val.coeff(i, j));
51 }
52 x_val.coeffRef(i, i) = sqrt(1.0 - sum_sqs);
53 }
54
56
57 reverse_pass_callback([z, K, x]() mutable {
58 size_t k = z.size();
59 for (int i = K - 1; i > 0; --i) {
60 double sum_sqs_val = 1.0 - square(x.val().coeffRef(i, i));
61 double sum_sqs_adj = -0.5 * x.adj().coeff(i, i) / x.val().coeff(i, i);
62 for (int j = i - 1; j > 0; --j) {
63 x.adj().coeffRef(i, j) += 2 * sum_sqs_adj * x.val().coeff(i, j);
64 sum_sqs_val -= square(x.val().coeff(i, j));
65 k--;
66 sum_sqs_adj += -0.5 * x.adj().coeffRef(i, j) * z.val().coeff(k)
67 / sqrt(1.0 - sum_sqs_val);
68 z.adj().coeffRef(k) += x.adj().coeffRef(i, j) * sqrt(1.0 - sum_sqs_val);
69 }
70 x.adj().coeffRef(i, 0) += 2 * sum_sqs_adj * x.val().coeff(i, 0);
71 k--;
72 z.adj().coeffRef(k) += x.adj().coeffRef(i, 0);
73 }
74 });
75
76 return x;
77}
78
91template <typename T, require_var_vector_t<T>* = nullptr>
93 scalar_type_t<T>& lp) {
94 using Eigen::Dynamic;
95 using Eigen::Matrix;
96 using std::sqrt;
97 int k_choose_2 = (K * (K - 1)) / 2;
98 check_size_match("cholesky_corr_constrain", "y.size()", y.size(),
99 "k_choose_2", k_choose_2);
100
101 if (K == 0) {
102 return Eigen::MatrixXd();
103 }
104
106 arena_t<Eigen::MatrixXd> x_val = Eigen::MatrixXd::Zero(K, K);
107
108 x_val.coeffRef(0, 0) = 1;
109 int k = 0;
110 double lp_val = 0.0;
111 for (int i = 1; i < K; ++i) {
112 x_val.coeffRef(i, 0) = z.val().coeff(k);
113 k++;
114 double sum_sqs = square(x_val.coeff(i, 0));
115 for (int j = 1; j < i; ++j) {
116 lp_val += 0.5 * log1m(sum_sqs);
117 x_val.coeffRef(i, j) = z.val().coeff(k) * sqrt(1.0 - sum_sqs);
118 k++;
119 sum_sqs += square(x_val.coeff(i, j));
120 }
121 x_val.coeffRef(i, i) = sqrt(1.0 - sum_sqs);
122 }
123
124 lp += lp_val;
126
127 reverse_pass_callback([z, K, x, lp]() mutable {
128 size_t k = z.size();
129 for (int i = K - 1; i > 0; --i) {
130 double sum_sqs_val = 1.0 - square(x.val().coeffRef(i, i));
131 double sum_sqs_adj = -0.5 * x.adj().coeff(i, i) / x.val().coeff(i, i);
132 for (int j = i - 1; j > 0; --j) {
133 x.adj().coeffRef(i, j) += 2 * sum_sqs_adj * x.val().coeff(i, j);
134 sum_sqs_val -= square(x.val().coeff(i, j));
135
136 k--;
137 sum_sqs_adj += -0.5 * x.adj().coeffRef(i, j) * z.val().coeff(k)
138 / sqrt(1.0 - sum_sqs_val);
139 z.adj().coeffRef(k) += x.adj().coeffRef(i, j) * sqrt(1.0 - sum_sqs_val);
140 sum_sqs_adj -= 0.5 * lp.adj() / (1 - sum_sqs_val);
141 }
142 x.adj().coeffRef(i, 0) += 2 * sum_sqs_adj * x.val().coeff(i, 0);
143 k--;
144 z.adj().coeffRef(k) += x.adj().coeffRef(i, 0);
145 }
146 });
147
148 return x;
149}
150
151} // namespace math
152} // namespace stan
153#endif
void reverse_pass_callback(F &&functor)
Puts a callback on the autodiff stack to be called in reverse pass.
fvar< T > sqrt(const fvar< T > &x)
Definition sqrt.hpp:17
Eigen::Matrix< value_type_t< EigVec >, Eigen::Dynamic, Eigen::Dynamic > cholesky_corr_constrain(const EigVec &y, int K)
plain_type_t< T > corr_constrain(const T &x)
Return the result of transforming the specified scalar or container of values to have a valid correla...
void check_size_match(const char *function, const char *name_i, T_size1 i, const char *name_j, T_size2 j)
Check if the provided sizes match.
fvar< T > log1m(const fvar< T > &x)
Definition log1m.hpp:12
fvar< T > square(const fvar< T > &x)
Definition square.hpp:12
typename scalar_type< T >::type scalar_type_t
typename internal::arena_type_impl< std::decay_t< T > >::type arena_t
Determines a type that can be used in place of T that does any dynamic allocations on the AD stack.
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...