lyapunov_continuous.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 
26 
29 
30 #include <Eigen/Core>
31 #include <Eigen/Dense>
32 #include <Eigen/Eigenvalues>
33 #include <algorithm>
34 
35 namespace corbo {
36 
38 {
39  assert(is_square(A));
40  assert(have_equal_size(A, Q));
41 
42  Eigen::ComplexSchur<Eigen::MatrixXd> A_schur(A, true);
43 
44  if (A_schur.info() == Eigen::NoConvergence) return false;
45 
46  Eigen::MatrixXcd T = A_schur.matrixT(); // create copy since we need to modify the diagonal later
47  const Eigen::MatrixXcd& U = A_schur.matrixU();
48 
49  // transform rhs
50  Eigen::MatrixXcd F = U.adjoint() * Q * U;
51 
52  const int n = A.rows();
53  Eigen::MatrixXcd Y(n, n);
54  Y.setZero();
55 
57  Eigen::MatrixXcd T_adjoint = T.adjoint();
58 
59  // solve T Y + Y T^* + F = 0
60  // construct transformed solution by backwards substitution
61  for (int k = n - 1; k >= 0; --k)
62  {
63  Eigen::VectorXcd rhs = F.col(k) + Y * T_adjoint.col(k);
64  // move non-zero diagonal element to lhs
65  const std::complex<double> offset = T_adjoint(k, k);
66  T.diagonal().array() += offset;
67  // compute SVD
68  // TODO(roesmann): here is place for improving efficiency
69  // and robustness by avoiding the SVD (see references).
70  T_svd.compute(T);
71  // solve linear system
72  Y.col(k) = T_svd.solve(-rhs);
73  // revert rhs diagonal element for subsequent iteration
74  if (k > 0) T.diagonal().array() -= offset;
75  }
76 
77  // transform back
78  X = (U * Y * U.adjoint()).real();
79 
80  return true;
81 }
82 
84 {
85  if (!is_square(A)) return false;
86 
87  Eigen::VectorXcd eigvals_A = A.eigenvalues();
88 
89  for (int i = 0; i < eigvals_A.size(); ++i)
90  {
91  for (int j = i; j < eigvals_A.size(); ++j)
92  {
93  if (approx_equal(eigvals_A[i].real(), -eigvals_A[j].real()) && approx_equal(eigvals_A[i].imag(), -eigvals_A[j].imag())) return false;
94  }
95  }
96  return true;
97 }
98 
99 } // namespace corbo
static bool hasUniqueSolution(const Eigen::Ref< const Eigen::MatrixXd > &A)
Determine if the Lyapunov equation exhibits a unique solution.
bool have_equal_size(const Eigen::MatrixBase< DerivedA > &matrix1, const Eigen::MatrixBase< DerivedB > &matrix2)
Determine if two matrices exhibit equal sizes/dimensions.
float real
Definition: datatypes.h:10
static bool solve(const Eigen::Ref< const Eigen::MatrixXd > &A, const Eigen::Ref< const Eigen::MatrixXd > &Q, Eigen::MatrixXd &X)
Solve continuous-time Lyapunov equation.
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)
A matrix or vector expression mapping an existing expression.
Definition: Ref.h:192
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
EIGEN_DEVICE_FUNC const ImagReturnType imag() const
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:00