ARPACK-Armadillo
TridiagEigen.h
1 // Copyright (C) 2015 Yixuan Qiu
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef TRIDIAG_EIGEN_H
8 #define TRIDIAG_EIGEN_H
9 
10 #include <armadillo>
11 #include <stdexcept>
12 #include "LapackWrapperExtra.h"
13 
24 template <typename Scalar = double>
26 {
27 private:
28  typedef arma::Mat<Scalar> Matrix;
29  typedef arma::Col<Scalar> Vector;
30 
31  int n;
32  Vector main_diag; // Main diagonal elements of the matrix
33  Vector sub_diag; // Sub-diagonal elements of the matrix
34  Matrix evecs; // To store eigenvectors
35 
36  bool computed;
37 
38 public:
44  n(0), computed(false)
45  {}
46 
56  TridiagEigen(const Matrix &mat) :
57  n(mat.n_rows), computed(false)
58  {
59  compute(mat);
60  }
61 
70  void compute(const Matrix &mat)
71  {
72  if(!mat.is_square())
73  throw std::invalid_argument("TridiagEigen: matrix must be square");
74 
75  n = mat.n_rows;
76  main_diag = mat.diag();
77  sub_diag = mat.diag(-1);
78  evecs.set_size(n, n);
79 
80  char compz = 'I';
81  int lwork = -1;
82  Scalar lwork_opt;
83 
84  int liwork = -1;
85  int liwork_opt, info;
86 
87  // Query of lwork and liwork
88  arma::lapack::stedc(&compz, &n, main_diag.memptr(), sub_diag.memptr(),
89  evecs.memptr(), &n, &lwork_opt, &lwork, &liwork_opt, &liwork, &info);
90 
91  if(info == 0)
92  {
93  lwork = (int) lwork_opt;
94  liwork = liwork_opt;
95  } else {
96  lwork = 1 + 4 * n + n * n;
97  liwork = 3 + 5 * n;
98  }
99 
100  Scalar *work = new Scalar[lwork];
101  int *iwork = new int[liwork];
102 
103  arma::lapack::stedc(&compz, &n, main_diag.memptr(), sub_diag.memptr(),
104  evecs.memptr(), &n, work, &lwork, iwork, &liwork, &info);
105 
106  delete [] work;
107  delete [] iwork;
108 
109  if(info < 0)
110  throw std::invalid_argument("Lapack stedc: illegal value");
111  if(info > 0)
112  throw std::logic_error("Lapack stedc: failed to compute all the eigenvalues");
113 
114  computed = true;
115  }
116 
123  Vector eigenvalues()
124  {
125  if(!computed)
126  throw std::logic_error("TridiagEigen: need to call compute() first");
127 
128  // After calling compute(), main_diag will contain the eigenvalues.
129  return main_diag;
130  }
131 
138  Matrix eigenvectors()
139  {
140  if(!computed)
141  throw std::logic_error("TridiagEigen: need to call compute() first");
142 
143  return evecs;
144  }
145 };
146 
147 
148 
149 #endif // TRIDIAG_EIGEN_H
void compute(const Matrix &mat)
Definition: TridiagEigen.h:70
Matrix eigenvectors()
Definition: TridiagEigen.h:138
Vector eigenvalues()
Definition: TridiagEigen.h:123
TridiagEigen(const Matrix &mat)
Definition: TridiagEigen.h:56