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