UpperHessenbergEigen.h
Go to the documentation of this file.
1 // The code was adapted from Eigen/src/Eigenvaleus/EigenSolver.h
2 //
3 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
4 // Copyright (C) 2010,2012 Jitse Niesen <jitse@maths.leeds.ac.uk>
5 // Copyright (C) 2016-2019 Yixuan Qiu <yixuan.qiu@cos.name>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
10 
11 #ifndef UPPER_HESSENBERG_EIGEN_H
12 #define UPPER_HESSENBERG_EIGEN_H
13 
14 #include <Eigen/Core>
15 #include <Eigen/Eigenvalues>
16 #include <stdexcept>
17 
18 namespace Spectra {
19 
20 template <typename Scalar = double>
22 {
23 private:
27 
30 
31  typedef std::complex<Scalar> Complex;
34 
35  Index m_n; // Size of the matrix
36  Eigen::RealSchur<Matrix> m_realSchur; // Schur decomposition solver
37  Matrix m_matT; // Schur T matrix
38  Matrix m_eivec; // Storing eigenvectors
39  ComplexVector m_eivalues; // Eigenvalues
40 
41  bool m_computed;
42 
44  {
45  using std::abs;
46 
47  const Index size = m_eivec.cols();
49 
50  // inefficient! this is already computed in RealSchur
51  Scalar norm(0);
52  for (Index j = 0; j < size; ++j)
53  {
54  norm += m_matT.row(j).segment((std::max)(j - 1, Index(0)), size - (std::max)(j - 1, Index(0))).cwiseAbs().sum();
55  }
56 
57  // Backsubstitute to find vectors of upper triangular form
58  if (norm == Scalar(0))
59  return;
60 
61  for (Index n = size - 1; n >= 0; n--)
62  {
63  Scalar p = m_eivalues.coeff(n).real();
64  Scalar q = m_eivalues.coeff(n).imag();
65 
66  // Scalar vector
67  if (q == Scalar(0))
68  {
69  Scalar lastr(0), lastw(0);
70  Index l = n;
71 
72  m_matT.coeffRef(n, n) = Scalar(1);
73  for (Index i = n - 1; i >= 0; i--)
74  {
75  Scalar w = m_matT.coeff(i, i) - p;
76  Scalar r = m_matT.row(i).segment(l, n - l + 1).dot(m_matT.col(n).segment(l, n - l + 1));
77 
78  if (m_eivalues.coeff(i).imag() < Scalar(0))
79  {
80  lastw = w;
81  lastr = r;
82  }
83  else
84  {
85  l = i;
86  if (m_eivalues.coeff(i).imag() == Scalar(0))
87  {
88  if (w != Scalar(0))
89  m_matT.coeffRef(i, n) = -r / w;
90  else
91  m_matT.coeffRef(i, n) = -r / (eps * norm);
92  }
93  else // Solve real equations
94  {
95  Scalar x = m_matT.coeff(i, i + 1);
96  Scalar y = m_matT.coeff(i + 1, i);
97  Scalar denom = (m_eivalues.coeff(i).real() - p) * (m_eivalues.coeff(i).real() - p) + m_eivalues.coeff(i).imag() * m_eivalues.coeff(i).imag();
98  Scalar t = (x * lastr - lastw * r) / denom;
99  m_matT.coeffRef(i, n) = t;
100  if (abs(x) > abs(lastw))
101  m_matT.coeffRef(i + 1, n) = (-r - w * t) / x;
102  else
103  m_matT.coeffRef(i + 1, n) = (-lastr - y * t) / lastw;
104  }
105 
106  // Overflow control
107  Scalar t = abs(m_matT.coeff(i, n));
108  if ((eps * t) * t > Scalar(1))
109  m_matT.col(n).tail(size - i) /= t;
110  }
111  }
112  }
113  else if (q < Scalar(0) && n > 0)
114  { // Complex vector
115  Scalar lastra(0), lastsa(0), lastw(0);
116  Index l = n - 1;
117 
118  // Last vector component imaginary so matrix is triangular
119  if (abs(m_matT.coeff(n, n - 1)) > abs(m_matT.coeff(n - 1, n)))
120  {
121  m_matT.coeffRef(n - 1, n - 1) = q / m_matT.coeff(n, n - 1);
122  m_matT.coeffRef(n - 1, n) = -(m_matT.coeff(n, n) - p) / m_matT.coeff(n, n - 1);
123  }
124  else
125  {
126  Complex cc = Complex(Scalar(0), -m_matT.coeff(n - 1, n)) / Complex(m_matT.coeff(n - 1, n - 1) - p, q);
127  m_matT.coeffRef(n - 1, n - 1) = Eigen::numext::real(cc);
128  m_matT.coeffRef(n - 1, n) = Eigen::numext::imag(cc);
129  }
130  m_matT.coeffRef(n, n - 1) = Scalar(0);
131  m_matT.coeffRef(n, n) = Scalar(1);
132  for (Index i = n - 2; i >= 0; i--)
133  {
134  Scalar ra = m_matT.row(i).segment(l, n - l + 1).dot(m_matT.col(n - 1).segment(l, n - l + 1));
135  Scalar sa = m_matT.row(i).segment(l, n - l + 1).dot(m_matT.col(n).segment(l, n - l + 1));
136  Scalar w = m_matT.coeff(i, i) - p;
137 
138  if (m_eivalues.coeff(i).imag() < Scalar(0))
139  {
140  lastw = w;
141  lastra = ra;
142  lastsa = sa;
143  }
144  else
145  {
146  l = i;
147  if (m_eivalues.coeff(i).imag() == Scalar(0))
148  {
149  Complex cc = Complex(-ra, -sa) / Complex(w, q);
150  m_matT.coeffRef(i, n - 1) = Eigen::numext::real(cc);
152  }
153  else
154  {
155  // Solve complex equations
156  Scalar x = m_matT.coeff(i, i + 1);
157  Scalar y = m_matT.coeff(i + 1, i);
158  Scalar vr = (m_eivalues.coeff(i).real() - p) * (m_eivalues.coeff(i).real() - p) + m_eivalues.coeff(i).imag() * m_eivalues.coeff(i).imag() - q * q;
159  Scalar vi = (m_eivalues.coeff(i).real() - p) * Scalar(2) * q;
160  if ((vr == Scalar(0)) && (vi == Scalar(0)))
161  vr = eps * norm * (abs(w) + abs(q) + abs(x) + abs(y) + abs(lastw));
162 
163  Complex cc = Complex(x * lastra - lastw * ra + q * sa, x * lastsa - lastw * sa - q * ra) / Complex(vr, vi);
164  m_matT.coeffRef(i, n - 1) = Eigen::numext::real(cc);
166  if (abs(x) > (abs(lastw) + abs(q)))
167  {
168  m_matT.coeffRef(i + 1, n - 1) = (-ra - w * m_matT.coeff(i, n - 1) + q * m_matT.coeff(i, n)) / x;
169  m_matT.coeffRef(i + 1, n) = (-sa - w * m_matT.coeff(i, n) - q * m_matT.coeff(i, n - 1)) / x;
170  }
171  else
172  {
173  cc = Complex(-lastra - y * m_matT.coeff(i, n - 1), -lastsa - y * m_matT.coeff(i, n)) / Complex(lastw, q);
174  m_matT.coeffRef(i + 1, n - 1) = Eigen::numext::real(cc);
175  m_matT.coeffRef(i + 1, n) = Eigen::numext::imag(cc);
176  }
177  }
178 
179  // Overflow control
180  Scalar t = std::max(abs(m_matT.coeff(i, n - 1)), abs(m_matT.coeff(i, n)));
181  if ((eps * t) * t > Scalar(1))
182  m_matT.block(i, n - 1, size - i, 2) /= t;
183  }
184  }
185 
186  // We handled a pair of complex conjugate eigenvalues, so need to skip them both
187  n--;
188  }
189  }
190 
191  // Back transformation to get eigenvectors of original matrix
192  Vector m_tmp(size);
193  for (Index j = size - 1; j >= 0; j--)
194  {
195  m_tmp.noalias() = m_eivec.leftCols(j + 1) * m_matT.col(j).segment(0, j + 1);
196  m_eivec.col(j) = m_tmp;
197  }
198  }
199 
200 public:
202  m_n(0), m_computed(false)
203  {}
204 
206  m_n(mat.rows()), m_computed(false)
207  {
208  compute(mat);
209  }
210 
212  {
213  using std::abs;
214  using std::sqrt;
215 
216  if (mat.rows() != mat.cols())
217  throw std::invalid_argument("UpperHessenbergEigen: matrix must be square");
218 
219  m_n = mat.rows();
220  // Scale matrix prior to the Schur decomposition
221  const Scalar scale = mat.cwiseAbs().maxCoeff();
222 
223  // Reduce to real Schur form
224  Matrix Q = Matrix::Identity(m_n, m_n);
225  m_realSchur.computeFromHessenberg(mat / scale, Q, true);
226  if (m_realSchur.info() != Eigen::Success)
227  throw std::runtime_error("UpperHessenbergEigen: eigen decomposition failed");
228 
229  m_matT = m_realSchur.matrixT();
230  m_eivec = m_realSchur.matrixU();
231 
232  // Compute eigenvalues from matT
234  Index i = 0;
235  while (i < m_n)
236  {
237  // Real eigenvalue
238  if (i == m_n - 1 || m_matT.coeff(i + 1, i) == Scalar(0))
239  {
241  ++i;
242  }
243  else // Complex eigenvalues
244  {
245  Scalar p = Scalar(0.5) * (m_matT.coeff(i, i) - m_matT.coeff(i + 1, i + 1));
246  Scalar z;
247  // Compute z = sqrt(abs(p * p + m_matT.coeff(i+1, i) * m_matT.coeff(i, i+1)));
248  // without overflow
249  {
250  Scalar t0 = m_matT.coeff(i + 1, i);
251  Scalar t1 = m_matT.coeff(i, i + 1);
252  Scalar maxval = std::max(abs(p), std::max(abs(t0), abs(t1)));
253  t0 /= maxval;
254  t1 /= maxval;
255  Scalar p0 = p / maxval;
256  z = maxval * sqrt(abs(p0 * p0 + t0 * t1));
257  }
258  m_eivalues.coeffRef(i) = Complex(m_matT.coeff(i + 1, i + 1) + p, z);
259  m_eivalues.coeffRef(i + 1) = Complex(m_matT.coeff(i + 1, i + 1) + p, -z);
260  i += 2;
261  }
262  }
263 
264  // Compute eigenvectors
266 
267  // Scale eigenvalues back
268  m_eivalues *= scale;
269 
270  m_computed = true;
271  }
272 
273  const ComplexVector& eigenvalues() const
274  {
275  if (!m_computed)
276  throw std::logic_error("UpperHessenbergEigen: need to call compute() first");
277 
278  return m_eivalues;
279  }
280 
282  {
283  using std::abs;
284 
285  if (!m_computed)
286  throw std::logic_error("UpperHessenbergEigen: need to call compute() first");
287 
288  Index n = m_eivec.cols();
289  ComplexMatrix matV(n, n);
290  for (Index j = 0; j < n; ++j)
291  {
292  // imaginary part of real eigenvalue is already set to exact zero
293  if (Eigen::numext::imag(m_eivalues.coeff(j)) == Scalar(0) || j + 1 == n)
294  {
295  // we have a real eigen value
296  matV.col(j) = m_eivec.col(j).template cast<Complex>();
297  matV.col(j).normalize();
298  }
299  else
300  {
301  // we have a pair of complex eigen values
302  for (Index i = 0; i < n; ++i)
303  {
304  matV.coeffRef(i, j) = Complex(m_eivec.coeff(i, j), m_eivec.coeff(i, j + 1));
305  matV.coeffRef(i, j + 1) = Complex(m_eivec.coeff(i, j), -m_eivec.coeff(i, j + 1));
306  }
307  matV.col(j).normalize();
308  matV.col(j + 1).normalize();
309  ++j;
310  }
311  }
312 
313  return matV;
314  }
315 };
316 
317 } // namespace Spectra
318 
319 #endif // UPPER_HESSENBERG_EIGEN_H
w
RowVector3d w
Definition: Matrix_resize_int.cpp:3
Spectra::UpperHessenbergEigen::Matrix
Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > Matrix
Definition: UpperHessenbergEigen.h:25
Spectra::UpperHessenbergEigen::ComplexMatrix
Eigen::Matrix< Complex, Eigen::Dynamic, Eigen::Dynamic > ComplexMatrix
Definition: UpperHessenbergEigen.h:32
Spectra::UpperHessenbergEigen::doComputeEigenvectors
void doComputeEigenvectors()
Definition: UpperHessenbergEigen.h:43
x
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
Definition: gnuplot_common_settings.hh:12
Spectra::UpperHessenbergEigen::GenericMatrix
Eigen::Ref< Matrix > GenericMatrix
Definition: UpperHessenbergEigen.h:28
Eigen::Success
@ Success
Definition: Constants.h:442
Spectra::UpperHessenbergEigen::ComplexVector
Eigen::Matrix< Complex, Eigen::Dynamic, 1 > ComplexVector
Definition: UpperHessenbergEigen.h:33
real
float real
Definition: datatypes.h:10
Spectra::UpperHessenbergEigen::UpperHessenbergEigen
UpperHessenbergEigen()
Definition: UpperHessenbergEigen.h:201
mat
MatrixXf mat
Definition: Tutorial_AdvancedInitialization_CommaTemporary.cpp:1
Eigen::PlainObjectBase::resize
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index rows, Index cols)
Definition: PlainObjectBase.h:271
Spectra::UpperHessenbergEigen::eigenvalues
const ComplexVector & eigenvalues() const
Definition: UpperHessenbergEigen.h:273
Spectra::UpperHessenbergEigen::m_matT
Matrix m_matT
Definition: UpperHessenbergEigen.h:37
rows
int rows
Definition: Tutorial_commainit_02.cpp:1
size
Scalar Scalar int size
Definition: benchVecAdd.cpp:17
n
int n
Definition: BiCGSTAB_simple.cpp:1
epsilon
static double epsilon
Definition: testRot3.cpp:37
Spectra::UpperHessenbergEigen::eigenvectors
ComplexMatrix eigenvectors()
Definition: UpperHessenbergEigen.h:281
Eigen::RealSchur
Performs a real Schur decomposition of a square matrix.
Definition: RealSchur.h:54
Spectra::UpperHessenbergEigen::Vector
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > Vector
Definition: UpperHessenbergEigen.h:26
scale
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy y set format x g set format y g set format x2 g set format y2 g set format z g set angles radians set nogrid set key title set key left top Right noreverse box linetype linewidth samplen spacing width set nolabel set noarrow set nologscale set logscale x set set pointsize set encoding default set nopolar set noparametric set set set set surface set nocontour set clabel set mapping cartesian set nohidden3d set cntrparam order set cntrparam linear set cntrparam levels auto set cntrparam points set size set set xzeroaxis lt lw set x2zeroaxis lt lw set yzeroaxis lt lw set y2zeroaxis lt lw set tics in set ticslevel set tics scale
Definition: gnuplot_common_settings.hh:54
j
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2
Eigen::numext::q
EIGEN_DEVICE_FUNC const Scalar & q
Definition: SpecialFunctionsImpl.h:1984
l
static const Line3 l(Rot3(), 1, 1)
Spectra::UpperHessenbergEigen::Index
Eigen::Index Index
Definition: UpperHessenbergEigen.h:24
Spectra::UpperHessenbergEigen::m_computed
bool m_computed
Definition: UpperHessenbergEigen.h:41
Spectra::UpperHessenbergEigen
Definition: UpperHessenbergEigen.h:21
imag
const EIGEN_DEVICE_FUNC ImagReturnType imag() const
Definition: CommonCwiseUnaryOps.h:109
Eigen::Matrix::coeffRef
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar & coeffRef(Index rowId, Index colId)
Definition: PlainObjectBase.h:175
pybind_wrapper_test_script.z
z
Definition: pybind_wrapper_test_script.py:61
Spectra::UpperHessenbergEigen::ConstGenericMatrix
const typedef Eigen::Ref< const Matrix > ConstGenericMatrix
Definition: UpperHessenbergEigen.h:29
Spectra::UpperHessenbergEigen::UpperHessenbergEigen
UpperHessenbergEigen(ConstGenericMatrix &mat)
Definition: UpperHessenbergEigen.h:205
y
Scalar * y
Definition: level1_cplx_impl.h:124
Spectra::UpperHessenbergEigen::m_eivalues
ComplexVector m_eivalues
Definition: UpperHessenbergEigen.h:39
Spectra::UpperHessenbergEigen::m_n
Index m_n
Definition: UpperHessenbergEigen.h:35
Eigen::Quaternion
The quaternion class used to represent 3D orientations and rotations.
Definition: ForwardDeclarations.h:293
Eigen::Ref
A matrix or vector expression mapping an existing expression.
Definition: Ref.h:281
Eigen::PlainObjectBase::cols
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT
Definition: PlainObjectBase.h:145
p0
Vector3f p0
Definition: MatrixBase_all.cpp:2
p
float * p
Definition: Tutorial_Map_using.cpp:9
Spectra::UpperHessenbergEigen::m_eivec
Matrix m_eivec
Definition: UpperHessenbergEigen.h:38
Eigen::PlainObjectBase::coeff
EIGEN_DEVICE_FUNC const EIGEN_STRONG_INLINE Scalar & coeff(Index rowId, Index colId) const
Definition: PlainObjectBase.h:152
Spectra::UpperHessenbergEigen::compute
void compute(ConstGenericMatrix &mat)
Definition: UpperHessenbergEigen.h:211
Spectra
Definition: LOBPCGSolver.h:19
Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic >
abs
#define abs(x)
Definition: datatypes.h:17
align_3::t
Point2 t(10, 10)
max
#define max(a, b)
Definition: datatypes.h:20
ceres::sqrt
Jet< T, N > sqrt(const Jet< T, N > &f)
Definition: jet.h:418
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9
Spectra::UpperHessenbergEigen::m_realSchur
Eigen::RealSchur< Matrix > m_realSchur
Definition: UpperHessenbergEigen.h:36
Spectra::UpperHessenbergEigen::Complex
std::complex< Scalar > Complex
Definition: UpperHessenbergEigen.h:31
Scalar
SCALAR Scalar
Definition: bench_gemm.cpp:46
Eigen::Index
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:74


gtsam
Author(s):
autogenerated on Sun Dec 22 2024 04:18:22