UpperHessenbergQR.h
Go to the documentation of this file.
1 // Copyright (C) 2016-2025 Yixuan Qiu <yixuan.qiu@cos.name>
2 //
3 // This Source Code Form is subject to the terms of the Mozilla
4 // Public License v. 2.0. If a copy of the MPL was not distributed
5 // with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 
7 #ifndef SPECTRA_UPPER_HESSENBERG_QR_H
8 #define SPECTRA_UPPER_HESSENBERG_QR_H
9 
10 #include <Eigen/Core>
11 #include <cmath> // std::abs, std::sqrt, std::pow
12 #include <algorithm> // std::fill
13 #include <stdexcept> // std::logic_error
14 
15 #include "../Util/TypeTraits.h"
16 
17 namespace Spectra {
18 
24 
29 
35 
44 template <typename Scalar = double>
46 {
47 private:
53 
56 
58 
59 protected:
61  // Gi = [ cos[i] sin[i]]
62  // [-sin[i] cos[i]]
63  // Q = G1 * G2 * ... * G_{n-1}
67  bool m_computed;
68 
69  // Given a >= b > 0, compute r = sqrt(a^2 + b^2), c = a / r, and s = b / r with high precision
70  static void stable_scaling(const Scalar& a, const Scalar& b, Scalar& r, Scalar& c, Scalar& s)
71  {
72  using std::sqrt;
73  using std::pow;
74 
75  // Let t = b / a, then 0 < t <= 1
76  // c = 1 / sqrt(1 + t^2)
77  // s = t * c
78  // r = a * sqrt(1 + t^2)
79  const Scalar t = b / a;
80  // We choose a cutoff such that cutoff^4 < eps
81  // If t > cutoff, use the standard way; otherwise use Taylor series expansion
82  // to avoid an explicit sqrt() call that may lose precision
83  const Scalar eps = TypeTraits<Scalar>::epsilon();
84  // std::pow() is not constexpr, so we do not declare cutoff to be constexpr
85  // But most compilers should be able to compute cutoff at compile time
86  const Scalar cutoff = Scalar(0.1) * pow(eps, Scalar(0.25));
87  if (t >= cutoff)
88  {
89  const Scalar denom = sqrt(Scalar(1) + t * t);
90  c = Scalar(1) / denom;
91  s = t * c;
92  r = a * denom;
93  }
94  else
95  {
96  // 1 / sqrt(1 + t^2) ~= 1 - (1/2) * t^2 + (3/8) * t^4
97  // 1 / sqrt(1 + l^2) ~= 1 / l - (1/2) / l^3 + (3/8) / l^5
98  // == t - (1/2) * t^3 + (3/8) * t^5, where l = 1 / t
99  // sqrt(1 + t^2) ~= 1 + (1/2) * t^2 - (1/8) * t^4 + (1/16) * t^6
100  //
101  // c = 1 / sqrt(1 + t^2) ~= 1 - t^2 * (1/2 - (3/8) * t^2)
102  // s = 1 / sqrt(1 + l^2) ~= t * (1 - t^2 * (1/2 - (3/8) * t^2))
103  // r = a * sqrt(1 + t^2) ~= a + (1/2) * b * t - (1/8) * b * t^3 + (1/16) * b * t^5
104  // == a + (b/2) * t * (1 - t^2 * (1/4 - 1/8 * t^2))
105  const Scalar c1 = Scalar(1);
106  const Scalar c2 = Scalar(0.5);
107  const Scalar c4 = Scalar(0.25);
108  const Scalar c8 = Scalar(0.125);
109  const Scalar c38 = Scalar(0.375);
110  const Scalar t2 = t * t;
111  const Scalar tc = t2 * (c2 - c38 * t2);
112  c = c1 - tc;
113  s = t - t * tc;
114  r = a + c2 * b * t * (c1 - t2 * (c4 - c8 * t2));
115 
116  /* const Scalar t_2 = Scalar(0.5) * t;
117  const Scalar t2_2 = t_2 * t;
118  const Scalar t3_2 = t2_2 * t;
119  const Scalar t4_38 = Scalar(1.5) * t2_2 * t2_2;
120  const Scalar t5_16 = Scalar(0.25) * t3_2 * t2_2;
121  c = Scalar(1) - t2_2 + t4_38;
122  s = t - t3_2 + Scalar(6) * t5_16;
123  r = a + b * (t_2 - Scalar(0.25) * t3_2 + t5_16); */
124  }
125  }
126 
127  // Given x and y, compute 1) r = sqrt(x^2 + y^2), 2) c = x / r, 3) s = -y / r
128  // If both x and y are zero, set c = 1 and s = 0
129  // We must implement it in a numerically stable way
130  // The implementation below is shown to be more accurate than directly computing
131  // r = std::hypot(x, y); c = x / r; s = -y / r;
132  static void compute_rotation(const Scalar& x, const Scalar& y, Scalar& r, Scalar& c, Scalar& s)
133  {
134  using std::abs;
135 
136  // Only need xsign when x != 0
137  const Scalar xsign = (x > Scalar(0)) ? Scalar(1) : Scalar(-1);
138  const Scalar xabs = abs(x);
139  if (y == Scalar(0))
140  {
141  c = (x == Scalar(0)) ? Scalar(1) : xsign;
142  s = Scalar(0);
143  r = xabs;
144  return;
145  }
146 
147  // Now we know y != 0
148  const Scalar ysign = (y > Scalar(0)) ? Scalar(1) : Scalar(-1);
149  const Scalar yabs = abs(y);
150  if (x == Scalar(0))
151  {
152  c = Scalar(0);
153  s = -ysign;
154  r = yabs;
155  return;
156  }
157 
158  // Now we know x != 0, y != 0
159  if (xabs > yabs)
160  {
161  stable_scaling(xabs, yabs, r, c, s);
162  c = xsign * c;
163  s = -ysign * s;
164  }
165  else
166  {
167  stable_scaling(yabs, xabs, r, s, c);
168  c = xsign * c;
169  s = -ysign * s;
170  }
171  }
172 
173 public:
179  m_n(size),
180  m_shift(0),
181  m_rot_cos(m_n - 1),
182  m_rot_sin(m_n - 1),
183  m_computed(false)
184  {}
185 
199  m_n(mat.rows()),
200  m_shift(shift),
201  m_rot_cos(m_n - 1),
202  m_rot_sin(m_n - 1),
203  m_computed(false)
204  {
205  compute(mat, shift);
206  }
207 
211  virtual ~UpperHessenbergQR() {}
212 
223  virtual void compute(ConstGenericMatrix& mat, const Scalar& shift = Scalar(0))
224  {
225  m_n = mat.rows();
226  if (m_n != mat.cols())
227  throw std::invalid_argument("UpperHessenbergQR: matrix must be square");
228 
229  m_shift = shift;
230  m_mat_R.resize(m_n, m_n);
231  m_rot_cos.resize(m_n - 1);
232  m_rot_sin.resize(m_n - 1);
233 
234  // Make a copy of mat - s * I
235  m_mat_R.noalias() = mat;
236  m_mat_R.diagonal().array() -= m_shift;
237 
238  Scalar xi, xj, r, c, s;
239  Scalar *Rii, *ptr;
240  const Index n1 = m_n - 1;
241  for (Index i = 0; i < n1; i++)
242  {
243  Rii = &m_mat_R.coeffRef(i, i);
244 
245  // Make sure R is upper Hessenberg
246  // Zero the elements below R[i + 1, i]
247  std::fill(Rii + 2, Rii + m_n - i, Scalar(0));
248 
249  xi = Rii[0]; // R[i, i]
250  xj = Rii[1]; // R[i + 1, i]
251  compute_rotation(xi, xj, r, c, s);
252  m_rot_cos.coeffRef(i) = c;
253  m_rot_sin.coeffRef(i) = s;
254 
255  // For a complete QR decomposition,
256  // we first obtain the rotation matrix
257  // G = [ cos sin]
258  // [-sin cos]
259  // and then do R[i:(i + 1), i:(n - 1)] = G' * R[i:(i + 1), i:(n - 1)]
260 
261  // Gt << c, -s, s, c;
262  // m_mat_R.block(i, i, 2, m_n - i) = Gt * m_mat_R.block(i, i, 2, m_n - i);
263  Rii[0] = r; // R[i, i] => r
264  Rii[1] = 0; // R[i + 1, i] => 0
265  ptr = Rii + m_n; // R[i, k], k = i+1, i+2, ..., n-1
266  for (Index j = i + 1; j < m_n; j++, ptr += m_n)
267  {
268  const Scalar tmp = ptr[0];
269  ptr[0] = c * tmp - s * ptr[1];
270  ptr[1] = s * tmp + c * ptr[1];
271  }
272 
273  // If we do not need to calculate the R matrix, then
274  // only the cos and sin sequences are required.
275  // In such case we only update R[i + 1, (i + 1):(n - 1)]
276  // m_mat_R.block(i + 1, i + 1, 1, m_n - i - 1) *= c;
277  // m_mat_R.block(i + 1, i + 1, 1, m_n - i - 1) += s * m_mat_R.block(i, i + 1, 1, m_n - i - 1);
278  }
279 
280  m_computed = true;
281  }
282 
290  virtual Matrix matrix_R() const
291  {
292  if (!m_computed)
293  throw std::logic_error("UpperHessenbergQR: need to call compute() first");
294 
295  return m_mat_R;
296  }
297 
305  virtual void matrix_QtHQ(Matrix& dest) const
306  {
307  if (!m_computed)
308  throw std::logic_error("UpperHessenbergQR: need to call compute() first");
309 
310  // Make a copy of the R matrix
311  dest.resize(m_n, m_n);
312  dest.noalias() = m_mat_R;
313 
314  // Compute the RQ matrix
315  const Index n1 = m_n - 1;
316  for (Index i = 0; i < n1; i++)
317  {
318  const Scalar c = m_rot_cos.coeff(i);
319  const Scalar s = m_rot_sin.coeff(i);
320  // RQ[, i:(i + 1)] = RQ[, i:(i + 1)] * Gi
321  // Gi = [ cos[i] sin[i]]
322  // [-sin[i] cos[i]]
323  Scalar *Yi, *Yi1;
324  Yi = &dest.coeffRef(0, i);
325  Yi1 = Yi + m_n; // RQ[0, i + 1]
326  const Index i2 = i + 2;
327  for (Index j = 0; j < i2; j++)
328  {
329  const Scalar tmp = Yi[j];
330  Yi[j] = c * tmp - s * Yi1[j];
331  Yi1[j] = s * tmp + c * Yi1[j];
332  }
333 
334  /* Vector dest = RQ.block(0, i, i + 2, 1);
335  dest.block(0, i, i + 2, 1) = c * Yi - s * dest.block(0, i + 1, i + 2, 1);
336  dest.block(0, i + 1, i + 2, 1) = s * Yi + c * dest.block(0, i + 1, i + 2, 1); */
337  }
338 
339  // Add the shift to the diagonal
340  dest.diagonal().array() += m_shift;
341  }
342 
351  // Y -> QY = G1 * G2 * ... * Y
352  void apply_QY(Vector& Y) const
353  {
354  if (!m_computed)
355  throw std::logic_error("UpperHessenbergQR: need to call compute() first");
356 
357  for (Index i = m_n - 2; i >= 0; i--)
358  {
359  const Scalar c = m_rot_cos.coeff(i);
360  const Scalar s = m_rot_sin.coeff(i);
361  // Y[i:(i + 1)] = Gi * Y[i:(i + 1)]
362  // Gi = [ cos[i] sin[i]]
363  // [-sin[i] cos[i]]
364  const Scalar tmp = Y[i];
365  Y[i] = c * tmp + s * Y[i + 1];
366  Y[i + 1] = -s * tmp + c * Y[i + 1];
367  }
368  }
369 
378  // Y -> Q'Y = G_{n-1}' * ... * G2' * G1' * Y
379  void apply_QtY(Vector& Y) const
380  {
381  if (!m_computed)
382  throw std::logic_error("UpperHessenbergQR: need to call compute() first");
383 
384  const Index n1 = m_n - 1;
385  for (Index i = 0; i < n1; i++)
386  {
387  const Scalar c = m_rot_cos.coeff(i);
388  const Scalar s = m_rot_sin.coeff(i);
389  // Y[i:(i + 1)] = Gi' * Y[i:(i + 1)]
390  // Gi = [ cos[i] sin[i]]
391  // [-sin[i] cos[i]]
392  const Scalar tmp = Y[i];
393  Y[i] = c * tmp - s * Y[i + 1];
394  Y[i + 1] = s * tmp + c * Y[i + 1];
395  }
396  }
397 
407  // Y -> QY = G1 * G2 * ... * Y
409  {
410  if (!m_computed)
411  throw std::logic_error("UpperHessenbergQR: need to call compute() first");
412 
413  RowVector Yi(Y.cols()), Yi1(Y.cols());
414  for (Index i = m_n - 2; i >= 0; i--)
415  {
416  const Scalar c = m_rot_cos.coeff(i);
417  const Scalar s = m_rot_sin.coeff(i);
418  // Y[i:(i + 1), ] = Gi * Y[i:(i + 1), ]
419  // Gi = [ cos[i] sin[i]]
420  // [-sin[i] cos[i]]
421  Yi.noalias() = Y.row(i);
422  Yi1.noalias() = Y.row(i + 1);
423  Y.row(i) = c * Yi + s * Yi1;
424  Y.row(i + 1) = -s * Yi + c * Yi1;
425  }
426  }
427 
437  // Y -> Q'Y = G_{n-1}' * ... * G2' * G1' * Y
439  {
440  if (!m_computed)
441  throw std::logic_error("UpperHessenbergQR: need to call compute() first");
442 
443  RowVector Yi(Y.cols()), Yi1(Y.cols());
444  const Index n1 = m_n - 1;
445  for (Index i = 0; i < n1; i++)
446  {
447  const Scalar c = m_rot_cos.coeff(i);
448  const Scalar s = m_rot_sin.coeff(i);
449  // Y[i:(i + 1), ] = Gi' * Y[i:(i + 1), ]
450  // Gi = [ cos[i] sin[i]]
451  // [-sin[i] cos[i]]
452  Yi.noalias() = Y.row(i);
453  Yi1.noalias() = Y.row(i + 1);
454  Y.row(i) = c * Yi - s * Yi1;
455  Y.row(i + 1) = s * Yi + c * Yi1;
456  }
457  }
458 
468  // Y -> YQ = Y * G1 * G2 * ...
470  {
471  if (!m_computed)
472  throw std::logic_error("UpperHessenbergQR: need to call compute() first");
473 
474  /*Vector Yi(Y.rows());
475  for(Index i = 0; i < m_n - 1; i++)
476  {
477  const Scalar c = m_rot_cos.coeff(i);
478  const Scalar s = m_rot_sin.coeff(i);
479  // Y[, i:(i + 1)] = Y[, i:(i + 1)] * Gi
480  // Gi = [ cos[i] sin[i]]
481  // [-sin[i] cos[i]]
482  Yi.noalias() = Y.col(i);
483  Y.col(i) = c * Yi - s * Y.col(i + 1);
484  Y.col(i + 1) = s * Yi + c * Y.col(i + 1);
485  }*/
486  Scalar *Y_col_i, *Y_col_i1;
487  const Index n1 = m_n - 1;
488  const Index nrow = Y.rows();
489  for (Index i = 0; i < n1; i++)
490  {
491  const Scalar c = m_rot_cos.coeff(i);
492  const Scalar s = m_rot_sin.coeff(i);
493 
494  Y_col_i = &Y.coeffRef(0, i);
495  Y_col_i1 = &Y.coeffRef(0, i + 1);
496  for (Index j = 0; j < nrow; j++)
497  {
498  Scalar tmp = Y_col_i[j];
499  Y_col_i[j] = c * tmp - s * Y_col_i1[j];
500  Y_col_i1[j] = s * tmp + c * Y_col_i1[j];
501  }
502  }
503  }
504 
514  // Y -> YQ' = Y * G_{n-1}' * ... * G2' * G1'
516  {
517  if (!m_computed)
518  throw std::logic_error("UpperHessenbergQR: need to call compute() first");
519 
520  Vector Yi(Y.rows());
521  for (Index i = m_n - 2; i >= 0; i--)
522  {
523  const Scalar c = m_rot_cos.coeff(i);
524  const Scalar s = m_rot_sin.coeff(i);
525  // Y[, i:(i + 1)] = Y[, i:(i + 1)] * Gi'
526  // Gi = [ cos[i] sin[i]]
527  // [-sin[i] cos[i]]
528  Yi.noalias() = Y.col(i);
529  Y.col(i) = c * Yi + s * Y.col(i + 1);
530  Y.col(i + 1) = -s * Yi + c * Y.col(i + 1);
531  }
532  }
533 };
534 
544 template <typename Scalar = double>
545 class TridiagQR : public UpperHessenbergQR<Scalar>
546 {
547 private:
553 
559 
560  Vector m_T_diag; // diagonal elements of T
561  Vector m_T_subd; // 1st subdiagonal of T
562  Vector m_R_diag; // diagonal elements of R, where T = QR
563  Vector m_R_supd; // 1st superdiagonal of R
564  Vector m_R_supd2; // 2nd superdiagonal of R
565 
566 public:
573  {}
574 
588  {
589  this->compute(mat, shift);
590  }
591 
601  void compute(ConstGenericMatrix& mat, const Scalar& shift = Scalar(0)) override
602  {
603  using std::abs;
604 
605  m_n = mat.rows();
606  if (m_n != mat.cols())
607  throw std::invalid_argument("TridiagQR: matrix must be square");
608 
609  m_shift = shift;
610  m_rot_cos.resize(m_n - 1);
611  m_rot_sin.resize(m_n - 1);
612 
613  // Save the diagonal and subdiagonal elements of T
615  m_T_subd.resize(m_n - 1);
616  m_T_diag.noalias() = mat.diagonal();
617  m_T_subd.noalias() = mat.diagonal(-1);
618 
619  // Deflation of small sub-diagonal elements
620  const Scalar eps = TypeTraits<Scalar>::epsilon();
621  for (Index i = 0; i < m_n - 1; i++)
622  {
623  if (abs(m_T_subd[i]) <= eps * (abs(m_T_diag[i]) + abs(m_T_diag[i + 1])))
624  m_T_subd[i] = Scalar(0);
625  }
626 
627  // Apply shift and copy T to R
629  m_R_supd.resize(m_n - 1);
630  m_R_supd2.resize(m_n - 2);
631  m_R_diag.array() = m_T_diag.array() - m_shift;
632  m_R_supd.noalias() = m_T_subd;
633 
634  // A number of pointers to avoid repeated address calculation
635  Scalar *c = m_rot_cos.data(), // pointer to the cosine vector
636  *s = m_rot_sin.data(), // pointer to the sine vector
637  r;
638  const Index n1 = m_n - 1, n2 = m_n - 2;
639  for (Index i = 0; i < n1; i++)
640  {
641  // Rdiag[i] == R[i, i]
642  // Tsubd[i] == R[i + 1, i]
643  // r = sqrt(R[i, i]^2 + R[i + 1, i]^2)
644  // c = R[i, i] / r, s = -R[i + 1, i] / r
645  this->compute_rotation(m_R_diag.coeff(i), m_T_subd.coeff(i), r, *c, *s);
646 
647  // For a complete QR decomposition,
648  // we first obtain the rotation matrix
649  // G = [ cos sin]
650  // [-sin cos]
651  // and then do R[i:(i + 1), i:(i + 2)] = G' * R[i:(i + 1), i:(i + 2)]
652 
653  // Update R[i, i] and R[i + 1, i]
654  // The updated value of R[i, i] is known to be r
655  // The updated value of R[i + 1, i] is known to be 0
656  m_R_diag.coeffRef(i) = r;
657  // Update R[i, i + 1] and R[i + 1, i + 1]
658  // Rsupd[i] == R[i, i + 1]
659  // Rdiag[i + 1] == R[i + 1, i + 1]
660  const Scalar Tii1 = m_R_supd.coeff(i);
661  const Scalar Ti1i1 = m_R_diag.coeff(i + 1);
662  m_R_supd.coeffRef(i) = (*c) * Tii1 - (*s) * Ti1i1;
663  m_R_diag.coeffRef(i + 1) = (*s) * Tii1 + (*c) * Ti1i1;
664  // Update R[i, i + 2] and R[i + 1, i + 2]
665  // Rsupd2[i] == R[i, i + 2]
666  // Rsupd[i + 1] == R[i + 1, i + 2]
667  if (i < n2)
668  {
669  m_R_supd2.coeffRef(i) = -(*s) * m_R_supd.coeff(i + 1);
670  m_R_supd.coeffRef(i + 1) *= (*c);
671  }
672 
673  c++;
674  s++;
675 
676  // If we do not need to calculate the R matrix, then
677  // only the cos and sin sequences are required.
678  // In such case we only update R[i + 1, (i + 1):(i + 2)]
679  // R[i + 1, i + 1] = c * R[i + 1, i + 1] + s * R[i, i + 1];
680  // R[i + 1, i + 2] *= c;
681  }
682 
683  m_computed = true;
684  }
685 
693  Matrix matrix_R() const override
694  {
695  if (!m_computed)
696  throw std::logic_error("TridiagQR: need to call compute() first");
697 
698  Matrix R = Matrix::Zero(m_n, m_n);
699  R.diagonal().noalias() = m_R_diag;
700  R.diagonal(1).noalias() = m_R_supd;
701  R.diagonal(2).noalias() = m_R_supd2;
702 
703  return R;
704  }
705 
713  void matrix_QtHQ(Matrix& dest) const override
714  {
715  using std::abs;
716 
717  if (!m_computed)
718  throw std::logic_error("TridiagQR: need to call compute() first");
719 
720  // In exact arithmetics, Q'TQ = RQ + sI, so we can just apply Q to R and add the shift.
721  // However, some numerical examples show that this algorithm decreases the precision,
722  // so we directly apply Q' and Q to T.
723 
724  // Copy the saved diagonal and subdiagonal elements of T to `dest`
725  dest.resize(m_n, m_n);
726  dest.setZero();
727  dest.diagonal().noalias() = m_T_diag;
728  dest.diagonal(-1).noalias() = m_T_subd;
729 
730  // Ti = [x y 0], Gi = [ cos[i] sin[i] 0], Gi' * Ti * Gi = [x' y' o']
731  // [y z w] [-sin[i] cos[i] 0] [y' z' w']
732  // [0 w u] [ 0 0 1] [o' w' u']
733  //
734  // x' = c2*x - 2*c*s*y + s2*z
735  // y' = c*s*(x-z) + (c2-s2)*y
736  // z' = s2*x + 2*c*s*y + c2*z
737  // o' = -s*w, w' = c*w, u' = u
738  //
739  // In iteration (i+1), (y', o') will be further updated to (y'', o''),
740  // where o'' = 0, y'' = cos[i+1]*y' - sin[i+1]*o'
741  const Index n1 = m_n - 1, n2 = m_n - 2;
742  for (Index i = 0; i < n1; i++)
743  {
744  const Scalar c = m_rot_cos.coeff(i);
745  const Scalar s = m_rot_sin.coeff(i);
746  const Scalar cs = c * s, c2 = c * c, s2 = s * s;
747  const Scalar x = dest.coeff(i, i),
748  y = dest.coeff(i + 1, i),
749  z = dest.coeff(i + 1, i + 1);
750  const Scalar c2x = c2 * x, s2x = s2 * x, c2z = c2 * z, s2z = s2 * z;
751  const Scalar csy2 = Scalar(2) * c * s * y;
752 
753  // Update the diagonal and the lower subdiagonal of dest
754  dest.coeffRef(i, i) = c2x - csy2 + s2z; // x'
755  dest.coeffRef(i + 1, i) = cs * (x - z) + (c2 - s2) * y; // y'
756  dest.coeffRef(i + 1, i + 1) = s2x + csy2 + c2z; // z'
757 
758  if (i < n2)
759  {
760  const Scalar ci1 = m_rot_cos.coeff(i + 1);
761  const Scalar si1 = m_rot_sin.coeff(i + 1);
762  const Scalar o = -s * m_T_subd.coeff(i + 1); // o'
763  dest.coeffRef(i + 2, i + 1) *= c; // w'
764  dest.coeffRef(i + 1, i) = ci1 * dest.coeff(i + 1, i) - si1 * o; // y''
765  }
766  }
767 
768  // Deflation of small sub-diagonal elements
769  const Scalar eps = TypeTraits<Scalar>::epsilon();
770  for (Index i = 0; i < n1; i++)
771  {
772  const Scalar diag = abs(dest.coeff(i, i)) + abs(dest.coeff(i + 1, i + 1));
773  if (abs(dest.coeff(i + 1, i)) <= eps * diag)
774  dest.coeffRef(i + 1, i) = Scalar(0);
775  }
776 
777  // Copy the lower subdiagonal to upper subdiagonal
778  dest.diagonal(1).noalias() = dest.diagonal(-1);
779  }
780 
787  void matrix_QtHQ(ComplexMatrix& dest) const
788  {
789  // Simply compute the real-typed result and copy to the complex one
790  Matrix dest_real;
791  this->matrix_QtHQ(dest_real);
792  dest.resize(m_n, m_n);
793  dest.noalias() = dest_real.template cast<std::complex<Scalar>>();
794  }
795 };
796 
800 
801 } // namespace Spectra
802 
803 #endif // SPECTRA_UPPER_HESSENBERG_QR_H
Spectra::TridiagQR::m_T_diag
Vector m_T_diag
Definition: UpperHessenbergQR.h:560
Spectra::UpperHessenbergQR::apply_QY
void apply_QY(GenericMatrix Y) const
Definition: UpperHessenbergQR.h:408
Spectra::UpperHessenbergQR::m_mat_R
Matrix m_mat_R
Definition: UpperHessenbergQR.h:57
Spectra::TridiagQR::matrix_QtHQ
void matrix_QtHQ(ComplexMatrix &dest) const
Definition: UpperHessenbergQR.h:787
benchmark.n1
n1
Definition: benchmark.py:79
s
RealScalar s
Definition: level1_cplx_impl.h:126
Spectra::UpperHessenbergQR::m_n
Index m_n
Definition: UpperHessenbergQR.h:60
screwPose2::xi
Vector xi
Definition: testPose2.cpp:148
Spectra::TridiagQR::m_R_supd2
Vector m_R_supd2
Definition: UpperHessenbergQR.h:564
c
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
b
Scalar * b
Definition: benchVecAdd.cpp:17
gtsam::Y
GaussianFactorGraphValuePair Y
Definition: HybridGaussianProductFactor.cpp:29
gtsam::diag
Matrix diag(const std::vector< Matrix > &Hs)
Definition: Matrix.cpp:196
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::TridiagQR::m_T_subd
Vector m_T_subd
Definition: UpperHessenbergQR.h:561
Spectra::UpperHessenbergQR::m_rot_sin
Array m_rot_sin
Definition: UpperHessenbergQR.h:66
Spectra::TridiagQR::m_R_supd
Vector m_R_supd
Definition: UpperHessenbergQR.h:563
Spectra::UpperHessenbergQR::~UpperHessenbergQR
virtual ~UpperHessenbergQR()
Definition: UpperHessenbergQR.h:211
Spectra::UpperHessenbergQR::m_shift
Scalar m_shift
Definition: UpperHessenbergQR.h:64
Eigen::Array< double, Eigen::Dynamic, 1 >
Spectra::UpperHessenbergQR::apply_QtY
void apply_QtY(GenericMatrix Y) const
Definition: UpperHessenbergQR.h:438
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
rows
int rows
Definition: Tutorial_commainit_02.cpp:1
size
Scalar Scalar int size
Definition: benchVecAdd.cpp:17
c1
static double c1
Definition: airy.c:54
epsilon
static double epsilon
Definition: testRot3.cpp:37
Spectra::UpperHessenbergQR::compute
virtual void compute(ConstGenericMatrix &mat, const Scalar &shift=Scalar(0))
Definition: UpperHessenbergQR.h:223
benchmark.n2
n2
Definition: benchmark.py:85
j
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2
Spectra::UpperHessenbergQR< double >::Index
Eigen::Index Index
Definition: UpperHessenbergQR.h:48
Eigen::Dynamic
const int Dynamic
Definition: Constants.h:22
Spectra::UpperHessenbergQR::apply_YQ
void apply_YQ(GenericMatrix Y) const
Definition: UpperHessenbergQR.h:469
Spectra::UpperHessenbergQR::compute_rotation
static void compute_rotation(const Scalar &x, const Scalar &y, Scalar &r, Scalar &c, Scalar &s)
Definition: UpperHessenbergQR.h:132
Spectra::TridiagQR::TridiagQR
TridiagQR(Index size)
Definition: UpperHessenbergQR.h:571
Spectra::UpperHessenbergQR::apply_YQt
void apply_YQt(GenericMatrix Y) const
Definition: UpperHessenbergQR.h:515
Eigen::Matrix::coeffRef
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar & coeffRef(Index rowId, Index colId)
Definition: PlainObjectBase.h:175
Eigen::Array::coeff
EIGEN_DEVICE_FUNC const EIGEN_STRONG_INLINE Scalar & coeff(Index rowId, Index colId) const
Definition: PlainObjectBase.h:152
pybind_wrapper_test_script.z
z
Definition: pybind_wrapper_test_script.py:61
Spectra::UpperHessenbergQR::apply_QtY
void apply_QtY(Vector &Y) const
Definition: UpperHessenbergQR.h:379
ceres::pow
Jet< T, N > pow(const Jet< T, N > &f, double g)
Definition: jet.h:570
Spectra::TridiagQR::Index
Eigen::Index Index
Definition: UpperHessenbergQR.h:548
y
Scalar * y
Definition: level1_cplx_impl.h:124
Spectra::UpperHessenbergQR::UpperHessenbergQR
UpperHessenbergQR(Index size)
Definition: UpperHessenbergQR.h:178
Eigen::Array::coeffRef
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar & coeffRef(Index rowId, Index colId)
Definition: PlainObjectBase.h:175
a
ArrayXXi a
Definition: Array_initializer_list_23_cxx11.cpp:1
Eigen::Ref
A matrix or vector expression mapping an existing expression.
Definition: Ref.h:281
Spectra::UpperHessenbergQR::m_computed
bool m_computed
Definition: UpperHessenbergQR.h:67
Spectra::TridiagQR::m_R_diag
Vector m_R_diag
Definition: UpperHessenbergQR.h:562
Spectra::UpperHessenbergQR
Definition: UpperHessenbergQR.h:45
Spectra::TridiagQR::TridiagQR
TridiagQR(ConstGenericMatrix &mat, const Scalar &shift=Scalar(0))
Definition: UpperHessenbergQR.h:586
Spectra::UpperHessenbergQR::matrix_R
virtual Matrix matrix_R() const
Definition: UpperHessenbergQR.h:290
Eigen::PlainObjectBase::coeff
EIGEN_DEVICE_FUNC const EIGEN_STRONG_INLINE Scalar & coeff(Index rowId, Index colId) const
Definition: PlainObjectBase.h:152
Spectra
Definition: LOBPCGSolver.h:19
c2
static double c2
Definition: airy.c:55
Spectra::UpperHessenbergQR::m_rot_cos
Array m_rot_cos
Definition: UpperHessenbergQR.h:65
Spectra::TridiagQR::compute
void compute(ConstGenericMatrix &mat, const Scalar &shift=Scalar(0)) override
Definition: UpperHessenbergQR.h:601
Eigen::PlainObjectBase::data
EIGEN_DEVICE_FUNC const EIGEN_STRONG_INLINE Scalar * data() const
Definition: PlainObjectBase.h:247
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic >
abs
#define abs(x)
Definition: datatypes.h:17
Eigen::PlainObjectBase::setZero
EIGEN_DEVICE_FUNC Derived & setZero(Index size)
Definition: CwiseNullaryOp.h:562
Spectra::UpperHessenbergQR::matrix_QtHQ
virtual void matrix_QtHQ(Matrix &dest) const
Definition: UpperHessenbergQR.h:305
Spectra::TridiagQR
Definition: UpperHessenbergQR.h:545
align_3::t
Point2 t(10, 10)
Spectra::UpperHessenbergQR::apply_QY
void apply_QY(Vector &Y) const
Definition: UpperHessenbergQR.h:352
Spectra::UpperHessenbergQR::UpperHessenbergQR
UpperHessenbergQR(ConstGenericMatrix &mat, const Scalar &shift=Scalar(0))
Definition: UpperHessenbergQR.h:198
Spectra::UpperHessenbergQR::stable_scaling
static void stable_scaling(const Scalar &a, const Scalar &b, Scalar &r, Scalar &c, Scalar &s)
Definition: UpperHessenbergQR.h:70
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
R
Rot2 R(Rot2::fromAngle(0.1))
Scalar
SCALAR Scalar
Definition: bench_gemm.cpp:46
Spectra::TridiagQR::matrix_R
Matrix matrix_R() const override
Definition: UpperHessenbergQR.h:693
Spectra::TridiagQR::matrix_QtHQ
void matrix_QtHQ(Matrix &dest) const override
Definition: UpperHessenbergQR.h:713
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 Feb 16 2025 04:08:29