1 #ifndef STAN_MATH_PRIM_FUN_FACTOR_U_HPP
2 #define STAN_MATH_PRIM_FUN_FACTOR_U_HPP
3
4 #include <stan/math/prim/fun/Eigen.hpp>
5 #include <stan/math/prim/fun/atanh.hpp>
6 #include <stan/math/prim/fun/sqrt.hpp>
7 #include <cstddef>
8 #include <stdexcept>
9 #include <vector>
10
11 namespace stan {
12 namespace math {
13
14 /**
15 * This function is intended to make starting values, given a unit
16 * upper-triangular matrix U such that U'DU is a correlation matrix
17 *
18 * @tparam T type of elements in the matrix
19 * @param U Sigma matrix
20 * @param CPCs fill this unbounded
21 */
22 template <typename T_U, typename T_CPCs, require_eigen_t<T_U>* = nullptr,
23 require_eigen_vector_t<T_CPCs>* = nullptr,
24 require_vt_same<T_U, T_CPCs>* = nullptr>
factor_U(const T_U & U,T_CPCs && CPCs)25 void factor_U(const T_U& U, T_CPCs&& CPCs) {
26 size_t K = U.rows();
27 size_t position = 0;
28 size_t pull = K - 1;
29
30 const Eigen::Ref<const plain_type_t<T_U>>& U_ref = U;
31
32 if (K == 2) {
33 CPCs(0) = atanh(U_ref(0, 1));
34 return;
35 }
36
37 Eigen::Array<value_type_t<T_U>, 1, Eigen::Dynamic> temp
38 = U_ref.row(0).tail(pull);
39
40 CPCs.head(pull) = temp;
41
42 Eigen::Array<value_type_t<T_U>, Eigen::Dynamic, 1> acc(K);
43 acc(0) = -0.0;
44 acc.tail(pull) = 1.0 - temp.square();
45 for (size_t i = 1; i < (K - 1); i++) {
46 position += pull;
47 pull--;
48 temp = U_ref.row(i).tail(pull);
49 temp /= sqrt(acc.tail(pull) / acc(i));
50 CPCs.segment(position, pull) = temp;
51 acc.tail(pull) *= 1.0 - temp.square();
52 }
53 CPCs = 0.5 * ((1.0 + CPCs) / (1.0 - CPCs)).log(); // now unbounded
54 }
55
56 } // namespace math
57 } // namespace stan
58
59 #endif
60