1 #ifndef STAN_MATH_PRIM_FUN_CHOLESKY_FACTOR_FREE_HPP
2 #define STAN_MATH_PRIM_FUN_CHOLESKY_FACTOR_FREE_HPP
3 
4 #include <stan/math/prim/err.hpp>
5 #include <stan/math/prim/fun/Eigen.hpp>
6 #include <stan/math/prim/fun/log.hpp>
7 #include <stan/math/prim/fun/to_ref.hpp>
8 #include <cmath>
9 #include <stdexcept>
10 
11 namespace stan {
12 namespace math {
13 
14 /**
15  * Return the unconstrained vector of parameters corresponding to
16  * the specified Cholesky factor.  A Cholesky factor must be lower
17  * triangular and have positive diagonal elements.
18  *
19  * @tparam T type of the Cholesky factor (must be derived from \c
20  * Eigen::MatrixBase)
21  * @param y Cholesky factor.
22  * @return Unconstrained parameters for Cholesky factor.
23  * @throw std::domain_error If the matrix is not a Cholesky factor.
24  */
25 template <typename T, require_eigen_t<T>* = nullptr>
cholesky_factor_free(const T & y)26 Eigen::Matrix<value_type_t<T>, Eigen::Dynamic, 1> cholesky_factor_free(
27     const T& y) {
28   using std::log;
29 
30   const auto& y_ref = to_ref(y);
31   check_cholesky_factor("cholesky_factor_free", "y", y_ref);
32   int M = y.rows();
33   int N = y.cols();
34   Eigen::Matrix<value_type_t<T>, Eigen::Dynamic, 1> x((N * (N + 1)) / 2
35                                                       + (M - N) * N);
36   int pos = 0;
37 
38   for (int m = 0; m < N; ++m) {
39     x.segment(pos, m) = y_ref.row(m).head(m);
40     pos += m;
41     x.coeffRef(pos++) = log(y_ref.coeff(m, m));
42   }
43 
44   for (int m = N; m < M; ++m) {
45     x.segment(pos, N) = y_ref.row(m);
46     pos += N;
47   }
48   return x;
49 }
50 
51 /**
52  * Overload of `cholesky_factor_free()` to untransform each matrix
53  * in a standard vector.
54  * @tparam T A standard vector with with a `value_type` which inherits from
55  *  `Eigen::MatrixBase`.
56  * @param x The standard vector to untransform.
57  */
58 template <typename T, require_std_vector_t<T>* = nullptr>
cholesky_factor_free(const T & x)59 auto cholesky_factor_free(const T& x) {
60   return apply_vector_unary<T>::apply(
61       x, [](auto&& v) { return cholesky_factor_free(v); });
62 }
63 
64 }  // namespace math
65 }  // namespace stan
66 
67 #endif
68