sylvester_discrete.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement
4  *
5  * Copyright (c) 2020,
6  * TU Dortmund - Institute of Control Theory and Systems Engineering.
7  * All rights reserved.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  *
22  * Authors: Christoph Rösmann
23  *********************************************************************/
24 
28 
29 #include <Eigen/Core>
30 #include <Eigen/Dense>
31 #include <Eigen/Eigenvalues>
32 #include <algorithm>
33 
34 namespace corbo {
35 
37  const Eigen::Ref<const Eigen::MatrixXd>& C, Eigen::MatrixXd& X)
38 {
39  assert(is_square(A));
40  assert(is_square(B));
41  assert(A.rows() == C.rows());
42  assert(B.rows() == C.cols());
43 
44  Eigen::ComplexSchur<Eigen::MatrixXd> A_schur(A, true);
45  Eigen::ComplexSchur<Eigen::MatrixXd> B_schur(B, true);
46 
47  if (A_schur.info() == Eigen::NoConvergence) return false;
48  if (B_schur.info() == Eigen::NoConvergence) return false;
49 
50  const Eigen::MatrixXcd& T_A = A_schur.matrixT();
51  const Eigen::MatrixXcd& U_A = A_schur.matrixU();
52  const Eigen::MatrixXcd& T_B = B_schur.matrixT();
53  const Eigen::MatrixXcd& U_B = B_schur.matrixU();
54 
55  const int n = C.rows();
56  const int m = C.cols();
57 
58  // transform rhs
59  Eigen::MatrixXcd F = U_A.adjoint() * C * U_B;
60 
61  Eigen::MatrixXcd Y(n, m);
62  Y.setZero();
63 
65 
66  Eigen::MatrixXcd lhs(n, m);
67  lhs.setIdentity();
68 
69  // solve T_A Y T_B - Y + F = 0
70  // construct transformed solution by forward substitution
71  const int mm = m - 1;
72  for (int k = 0; k < m; ++k)
73  {
74  Eigen::VectorXcd rhs = F.col(k) + T_A * Y * T_B.col(k);
75  // move non-zero diagonal elements to lhs and multiply by T
76  // (this is the non-zero part of T_A Y T_B which depends only on Y.col(k)).
77  const std::complex<double> factor = T_B(k, k);
78  lhs -= T_A * factor;
79  // compute SVD
80  // TODO(roesmann): here is place for improving efficiency
81  // and robustness by avoiding the SVD (see references).
82  lhs_svd.compute(lhs);
83  // solve linear system
84  Y.col(k) = lhs_svd.solve(rhs);
85  // revert rhs diagonal element for subsequent iteration
86  if (k < mm) lhs.setIdentity();
87  }
88 
89  // transform back
90  X = (U_A * Y * U_B.adjoint()).real();
91 
92  return true;
93 }
94 
96 {
97  if (!is_square(A) || !is_square(B)) return false;
98 
99  Eigen::VectorXcd eigvals_A = A.eigenvalues();
100  Eigen::VectorXcd eigvals_B = B.eigenvalues();
101 
102  for (int i = 0; i < eigvals_A.size(); ++i)
103  {
104  for (int j = 0; j < eigvals_B.size(); ++j)
105  {
106  std::complex<double> product = eigvals_A[i] * eigvals_B[j];
107  if (approx_equal(product.real(), 1) && approx_equal(product.imag(), 0)) // TODO(roesman) is 1+i0 correct, or unit circle in general?
108  return false;
109  }
110  }
111  return true;
112 }
113 
114 } // namespace corbo
float real
Definition: datatypes.h:10
bool approx_equal(double a, double b, double epsilon=1e-6)
Check if two doubles are appoximately equal.
bool is_square(const Eigen::MatrixBase< Derived > &matrix)
Determine if a given matrix is square.
ComputationInfo info() const
Reports whether previous computation was successful.
Definition: ComplexSchur.h:217
const Solve< JacobiSVD< _MatrixType, QRPreconditioner >, Rhs > solve(const MatrixBase< Rhs > &b) const
Definition: SVDBase.h:208
MatrixType A(a, *n, *n, *lda)
static bool solve(const Eigen::Ref< const Eigen::MatrixXd > &A, const Eigen::Ref< const Eigen::MatrixXd > &B, const Eigen::Ref< const Eigen::MatrixXd > &C, Eigen::MatrixXd &X)
Solve discrete-time Sylvester equation.
A matrix or vector expression mapping an existing expression.
Definition: Ref.h:192
static bool hasUniqueSolution(const Eigen::Ref< const Eigen::MatrixXd > &A, const Eigen::Ref< const Eigen::MatrixXd > &B)
Determine if the Sylvester equation exhibits a unique solution.
const ComplexMatrixType & matrixU() const
Returns the unitary matrix in the Schur decomposition.
Definition: ComplexSchur.h:138
Two-sided Jacobi SVD decomposition of a rectangular matrix.
JacobiSVD & compute(const MatrixType &matrix, unsigned int computationOptions)
Method performing the decomposition of given matrix using custom options.
Definition: JacobiSVD.h:663
MatrixType B(b, *n, *nrhs, *ldb)
Performs a complex Schur decomposition of a real or complex square matrix.
Definition: ComplexSchur.h:51
#define X
Definition: icosphere.cpp:20
PlainMatrixType mat * n
Definition: eigenvalues.cpp:41
const ComplexMatrixType & matrixT() const
Returns the triangular matrix in the Schur decomposition.
Definition: ComplexSchur.h:162


control_box_rst
Author(s): Christoph Rösmann
autogenerated on Mon Feb 28 2022 22:07:33