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