1#ifndef STAN_MATH_PRIM_FUN_SYLVESTER_SOLVER_HPP
2#define STAN_MATH_PRIM_FUN_SYLVESTER_SOLVER_HPP
7#include <Eigen/Eigenvalues>
32template <
typename MatA,
typename MatB,
typename MatC,
33 require_all_matrix_t<MatA, MatB, MatC>* =
nullptr,
34 require_all_bt_arithmetic<MatA, MatB, MatC>* =
nullptr>
37 = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic>;
46 if (
unlikely(A.rows() == 0 || B.rows() == 0)) {
47 return complex_mat_t(A.rows(), B.rows());
50 const Eigen::Index m = B.rows();
53 Eigen::ComplexSchur<plain_type_t<MatA>> schur_A{
eval(std::forward<MatA>(A))};
54 auto&& U = schur_A.matrixU();
55 auto&& S = schur_A.matrixT();
57 Eigen::ComplexSchur<plain_type_t<MatB>> schur_B{
eval(std::forward<MatB>(B))};
58 auto&& V = schur_B.matrixU();
59 auto&& T = schur_B.matrixT();
62 auto&& C_ref =
to_ref(std::forward<MatC>(C));
63 auto Y = (U.adjoint() * C_ref * V).
eval();
65 for (Eigen::Index i = 0; i < m; ++i) {
66 Y.col(i).noalias() -= Y.leftCols(i) * T.col(i).head(i);
67 Sshift.diagonal() = S.diagonal().array() + T(i, i);
68 Sshift.template triangularView<Eigen::Upper>().solveInPlace(Y.col(i));
70 return complex_mat_t(U * Y * V.adjoint());
void check_square(const char *function, const char *name, const T_y &y)
Check if the specified matrix is square.
auto sylvester_solver(const MatA &A, const MatB &B, const MatC &C)
Solve the Sylvester equation A X + X B = C for X, forward mode.
T eval(T &&arg)
Inputs which have a plain_type equal to the own time are forwarded unmodified (for Eigen expressions ...
ref_type_t< T && > to_ref(T &&a)
This evaluates expensive Eigen expressions.
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.
typename plain_type< std::decay_t< T > >::type plain_type_t
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...