Automatic Differentiation
 
Loading...
Searching...
No Matches
sylvester_solver.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_FUN_SYLVESTER_SOLVER_HPP
2#define STAN_MATH_PRIM_FUN_SYLVESTER_SOLVER_HPP
3
7#include <Eigen/Eigenvalues>
8#include <complex>
9#include <type_traits>
10
11namespace stan {
12namespace math {
13
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>
35inline auto sylvester_solver(MatA&& A, MatB&& B, MatC&& C) {
36 using complex_mat_t
37 = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic>;
38
39 check_square("sylvester_solver", "A", A);
40 check_square("sylvester_solver", "B", B);
41 check_size_match("sylvester_solver", "rows of A", A.rows(), "rows of C",
42 C.rows());
43 check_size_match("sylvester_solver", "rows of B", B.rows(), "cols of C",
44 C.cols());
45
46 if (unlikely(A.rows() == 0 || B.rows() == 0)) {
47 return complex_mat_t(A.rows(), B.rows());
48 }
49
50 const Eigen::Index m = B.rows();
51
52 // ComplexSchur needs a plain matrix (same pattern as complex_schur_decompose)
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();
56
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();
60
61 // Y holds D = U^H C V initially, overwritten column by column
62 auto&& C_ref = to_ref(std::forward<MatC>(C));
63 auto Y = (U.adjoint() * C_ref * V).eval();
64 plain_type_t<decltype(S)> Sshift = S;
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));
69 }
70 return complex_mat_t(U * Y * V.adjoint());
71}
72
73} // namespace math
74} // namespace stan
75#endif
#define unlikely(x)
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 ...
Definition eval.hpp:20
ref_type_t< T && > to_ref(T &&a)
This evaluates expensive Eigen expressions.
Definition to_ref.hpp:18
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 ...