Tomographer  v2.0
Tomographer C++ Framework Documentation
solveclyap.h
Go to the documentation of this file.
1 /* This file is part of the Tomographer project, which is distributed under the
2  * terms of the MIT license.
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2015 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 
27 #ifndef TOMOGRAPHER_MATHTOOLS_SOLVECLYAP_H
28 #define TOMOGRAPHER_MATHTOOLS_SOLVECLYAP_H
29 
37 #include <string>
38 
39 #include <Eigen/Core>
40 #include <Eigen/Eigenvalues>
41 
42 #include <tomographer2/tools/cxxutil.h> // tomographer_assert()
43 
44 
45 extern "C" void ztrsyl_(char *TRANA, char *TRANB, int *ISGN, int *M, int *N,
46  double *A, int *lda, double *B, int *ldb,
47  double *C, int *ldc, double *scale, int *info);
48 
49 namespace Tomographer {
50 namespace MathTools {
51 namespace SolveCLyap {
52 
57 class SolveError : public std::exception {
58  std::string p_msg;
59 public:
60  SolveError(const std::string& msg)
61  : p_msg(msg)
62  {
63  }
64  virtual ~SolveError() throw() { }
65  virtual const char * what() const throw() {
66  return p_msg.c_str();
67  }
68 };
69 
70 namespace tomo_internal {
71 
72  static const std::string ztrsyl_argnames[] = {
73  "TRANA", "TRANB", "ISGN", "M", "N", "A", "lda", "B", "ldb", "C", "ldc", "scale", "info"
74  };
75 
76 
77  template<bool debug_perform_check>
78  struct solve_check_helper {
79  template<typename XT, typename AT, typename CT, typename LoggerType>
80  static inline void check(const XT&, const AT&, const CT&, LoggerType&)
81  {
82  // no-op.
83  }
84  };
85  // specialize for if we want debug checks
86  template<>
87  struct solve_check_helper<true> {
88  template<typename XT, typename AT, typename CT, typename LoggerType>
89  static inline void check(const XT& X, const AT& A, const CT& C, LoggerType & logger)
90  {
91  //logger.debug("LyapCSolve::solve/check", "checking solution ...");
92 
93  double n1 = (A.adjoint() * X + X * A - C).norm();
94  double n2 = A.norm() + C.norm();
95  double ok = n1 / n2;
96  logger.debug("LyapCSolve::solve/check",
97  "(A.adjoint() * X + X * A - C).norm()/(A.norm()+C.norm()) == %g/%g == %g ; norm(C)=%g",
98  n1, n2, ok, (double)C.norm());
99  if (ok > 0.1) {
100  logger.warning("LyapCSolve::solve/check", "Bad solution quality! rel norm error = %g", (double)ok);
101  }
102  }
103  };
104 
105 } // namespace tomo_internal
106 
107 
127 template<bool debug_perform_check = false, typename LoggerType>
130  LoggerType & logger, const double tol = 1e-8)
131 {
132  // do an eigenvalue decomposition of A
133 
134  const int d = A.rows(); // dimension of problem
135 
136  tomographer_assert(X.rows() == X.cols() && X.rows() == d);
137  tomographer_assert(A.rows() == A.cols() && A.rows() == d);
138  tomographer_assert(C.rows() == C.cols() && C.rows() == d);
139 
140  typedef Eigen::MatrixXcd MatType;
141 
143 
144  if (eigA.info() == Eigen::NoConvergence) {
145  throw SolveError("Can't diagonalize matrix A: No Convergence");
146  }
147 
150 
151  int M = 0;
152  for (int k = 0; k < d; ++k) {
153  if (eigvalsA(k) > tol) {
154  ++M;
155  }
156  }
157 
158  // cout << "there are M="<< M << " nonzero eigenvalues\n";
159 
160  MatType D = MatType::Zero(M, M);
161  MatType W = MatType::Zero(d, M);
162 
163  D.setZero();
164 
165  int counter = 0;
166  for (int k = 0; k < d; ++k) {
167  if (eigvalsA(k) < tol) {
168  continue;
169  }
170  // include this eigenvector
171  W.col(counter) = eigU.col(k);
172  D(counter, counter) = eigvalsA(k);
173  ++counter;
174  }
175 
176  // cout << "W = \n" << W << "\nD = \n"<< D << "\n";
177 
178  // we have that A = W * D * W^{-1} , where D is full rank (Yes!)
179 
180  // Original equation: A^H*X + X*A == C (with A^H==A)
181  // replace eig of A: (W*D*W^{-1})*X + X*(W*D*W^{-1}) == C
182  // apply W^{-1} . W : D*(W^{-1}*X*W) + (W^{-1}*X*W)*D == W^{-1}*C*W
183  //
184  // we can now solve the Sylvester equation with ZTRSYL, for W^{-1}*X*W =: Z
185 
186  MatType Z(M, M);
187 
188  Z = W.adjoint() * C * W;
189 
190  int plusone = +1;
191 
192  int info = 0;
193  double scale = 0.0;
194 
195  int lda = D.outerStride();
196  int ldb = lda;//D.outerStride();
197  int ldc = Z.outerStride();
198 
199  ztrsyl_((char*)"C", (char*)"N", &plusone, &M, &M, (double*)D.data(), &lda, (double*)D.data(), &ldb,
200  (double*)Z.data(), &ldc, &scale, &info);
201 
202  if (info >= 0) {
203  if (info == 1) {
204  logger.warning("SolveCLyap::solve()", "Warning: A and B have common or very close eigenvalues; "
205  "perturbed values were used to solve the equation");
206  }
207  // success
208  X.noalias() = W * Z * W.adjoint() / scale;
209 
210  // maybe do some debug consistency check
211  tomo_internal::solve_check_helper<debug_perform_check>::check(X, A, C, logger);
212  return;
213  }
214 
215  // error with argument # (-info)
216  throw SolveError("Argument " + tomo_internal::ztrsyl_argnames[(-info)-1] + " to ztrsyl_ was invalid.");
217 }
218 
219 } // namespace SolveCLyap
220 } // namespace MathTools
221 } // namespace Tomographer
222 
223 #endif
ComputationInfo info() const
Base namespace for the Tomographer project.
Definition: densellh.h:44
const RealVectorType & eigenvalues() const
STL class.
void solve(Eigen::Ref< Eigen::MatrixXcd > X, const Eigen::Ref< const Eigen::MatrixXcd > &A, const Eigen::Ref< const Eigen::MatrixXcd > &C, LoggerType &logger, const double tol=1e-8)
Solve complex Lyapunov equation of the form A&#39;*X + X*A == C
Definition: solveclyap.h:128
Some C++ utilities, with a tad of C++11 tricks.
STL class.
Matrix< std::complex< double >, Dynamic, Dynamic > MatrixXcd
internal::plain_col_type< MatrixType, RealScalar >::type RealVectorType
const MatrixType & eigenvectors() const
T c_str(T...args)
NoConvergence
Error while attempting to solve complex Lyapunov/Sylvester equation.
Definition: solveclyap.h:57