1 #ifndef STAN_MATH_PRIM_FUN_CHOL2INV_HPP
2 #define STAN_MATH_PRIM_FUN_CHOL2INV_HPP
3 
4 #include <stan/math/prim/err.hpp>
5 #include <stan/math/prim/fun/Eigen.hpp>
6 #include <stan/math/prim/fun/dot_self.hpp>
7 #include <stan/math/prim/fun/dot_product.hpp>
8 #include <stan/math/prim/fun/mdivide_left_tri_low.hpp>
9 #include <stan/math/prim/fun/inv_square.hpp>
10 
11 namespace stan {
12 namespace math {
13 
14 /**
15  * Returns the inverse of the matrix whose Cholesky factor is L
16  *
17  * @tparam T type of elements in the matrix
18  * @param L Matrix that is a Cholesky factor.
19  * @return The matrix inverse of L * L'
20  * @throw std::domain_error If the input matrix is not square or
21  *  lower triangular
22  */
23 template <typename T, require_eigen_t<T>* = nullptr>
chol2inv(const T & L)24 plain_type_t<T> chol2inv(const T& L) {
25   const Eigen::Ref<const plain_type_t<T>>& L_ref = L;
26   check_square("chol2inv", "L", L_ref);
27   check_lower_triangular("chol2inv", "L", L_ref);
28   int K = L.rows();
29   using T_result = plain_type_t<T>;
30   if (K == 0) {
31     return L_ref;
32   }
33   if (K == 1) {
34     T_result X(1, 1);
35     X.coeffRef(0) = inv_square(L_ref.coeff(0, 0));
36     return X;
37   }
38   T_result L_inv = mdivide_left_tri_low(L_ref, T_result::Identity(K, K));
39   T_result X(K, K);
40   for (int k = 0; k < K; ++k) {
41     X.coeffRef(k, k) = dot_self(L_inv.col(k).tail(K - k).eval());
42     for (int j = k + 1; j < K; ++j) {
43       int Kmj = K - j;
44       X.coeffRef(k, j) = X.coeffRef(j, k) = dot_product(
45           L_inv.col(k).tail(Kmj).eval(), L_inv.col(j).tail(Kmj).eval());
46     }
47   }
48   return X;
49 }
50 
51 }  // namespace math
52 }  // namespace stan
53 
54 #endif
55