openGPMP
Open Source Mathematics Package
Public Member Functions | Private Attributes | List of all members
gpmp::linalg::Eigen Class Reference

Class for computing eigenvalues of a matrix. More...

#include <eigen.hpp>

Public Member Functions

 Eigen (const std::vector< std::vector< double >> &mat)
 Constructor for the Eigen class. More...
 
double power_iter (int max_iters=100, double tolerance=1e-10) const
 Perform the power iteration method to find the dominant eigenvalue. More...
 
std::vector< double > qr_algorithm (int max_iters=100, double tolerance=1e-10) const
 Calculate all eigenvalues of the matrix using the QR algorithm. More...
 
std::vector< double > sensitivity (double perturbation) const
 Calculates the sensitivity of the eigenvalues of a matrix to small perturbations. More...
 
double determinant () const
 
void schur_decomp (std::vector< std::vector< double >> &schurMatrix, double tolerance=1e-10) const
 Computes the Schur decomposition of a matrix. More...
 
std::vector< std::vector< double > > jordan_normal_form (double tolerance=1e-10) const
 Computes the Jordan normal form of a matrix. More...
 
double rayleigh_iter (int maxIterations, double tolerance) const
 Perform Rayleigh Quotient Iteration to approximate the dominant eigenvalue. More...
 

Private Attributes

std::vector< std::vector< double > > matrix
 
int size
 

Detailed Description

Class for computing eigenvalues of a matrix.

Definition at line 45 of file eigen.hpp.

Constructor & Destructor Documentation

◆ Eigen()

gpmp::linalg::Eigen::Eigen ( const std::vector< std::vector< double >> &  mat)

Constructor for the Eigen class.

Parameters
matThe square matrix for eigenvalue computation

Definition at line 39 of file eigen.cpp.

40  : matrix(mat), size(mat.size()) {
41  // Check if the matrix is square
42  /*if (size != mat[0].size()) {
43  throw std::invalid_argument(
44  "Error: Eigenvalue computation requires a square matrix.");
45  }*/
46 }
std::vector< std::vector< double > > matrix
Definition: eigen.hpp:48

Member Function Documentation

◆ determinant()

double gpmp::linalg::Eigen::determinant ( ) const

Definition at line 143 of file eigen.cpp.

143  {
144  // compute the determinant as the product of eigenvalues
145  std::vector<double> eigenvalues = qr_algorithm();
146  double determinant = std::accumulate(eigenvalues.begin(),
147  eigenvalues.end(),
148  1.0,
149  std::multiplies<double>());
150  return determinant;
151 }
std::vector< double > qr_algorithm(int max_iters=100, double tolerance=1e-10) const
Calculate all eigenvalues of the matrix using the QR algorithm.
Definition: eigen.cpp:93
double determinant() const
Definition: eigen.cpp:143

◆ jordan_normal_form()

std::vector< std::vector< double > > gpmp::linalg::Eigen::jordan_normal_form ( double  tolerance = 1e-10) const

Computes the Jordan normal form of a matrix.

This method computes the Jordan normal form of a matrix The Jordan normal form is a block diagonal matrix, where each block is either a diagonal matrix or a Jordan block A Jordan block is a square matrix with ones on the superdiagonal and the eigenvalue on the diagonal

Parameters
toleranceThe tolerance for determining if a subdiagonal element is zero
Returns
The Jordan normal form of the matrix

The returned matrix will have the same dimensions as the original matrix

Definition at line 212 of file eigen.cpp.

212  {
213  std::vector<std::vector<double>> jordanMatrix(
214  size,
215  std::vector<double>(size, 0.0));
216  std::vector<double> eigenvalues = qr_algorithm();
217 
218  for (int i = 0; i < size; ++i) {
219  jordanMatrix[i][i] = eigenvalues[i];
220 
221  // find the size of the Jordan block
222  int jordanBlockSize = 1;
223  while (i + jordanBlockSize < size &&
224  std::abs(matrix[i + jordanBlockSize][i]) < tolerance) {
225  ++jordanBlockSize;
226  }
227 
228  // fill the Jordan block
229  for (int j = 1; j < jordanBlockSize; ++j) {
230  jordanMatrix[i + j][i + j - 1] = 1.0;
231  }
232  }
233 
234  return jordanMatrix;
235 }

◆ power_iter()

double gpmp::linalg::Eigen::power_iter ( int  max_iters = 100,
double  tolerance = 1e-10 
) const

Perform the power iteration method to find the dominant eigenvalue.

Parameters
max_itersMaximum number of iterations for power iteration
toleranceTolerance for convergence
Returns
The dominant eigenvalue of the matrix

Definition at line 48 of file eigen.cpp.

48  {
49  // initial guess
50  std::vector<double> x(size, 1.0);
51  std::vector<double> y(size);
52 
53  for (int iter = 0; iter < max_iters; ++iter) {
54  // perform matrix-vector multiplication: y = A * x
55  for (int i = 0; i < size; ++i) {
56  y[i] = 0.0;
57  for (int j = 0; j < size; ++j) {
58  y[i] += matrix[i][j] * x[j];
59  }
60  }
61 
62  // find the maximum element in y
63  double max_element = 0.0;
64  for (int i = 0; i < size; ++i) {
65  max_element = std::max(max_element, std::abs(y[i]));
66  }
67 
68  // normalize y
69  for (int i = 0; i < size; ++i) {
70  y[i] /= max_element;
71  }
72 
73  // check for convergence
74  double error = 0.0;
75  for (int i = 0; i < size; ++i) {
76  error += std::abs(y[i] - x[i]);
77  }
78 
79  if (error < tolerance) {
80  // eigenvalue found
81  return max_element;
82  }
83 
84  x = y;
85  }
86 
87  std::cerr << "Warning: Power iteration did not converge within the"
88  "specified iterations\n";
89  // not converged
90  return 0.0;
91 }

Referenced by main().

◆ qr_algorithm()

std::vector< double > gpmp::linalg::Eigen::qr_algorithm ( int  max_iters = 100,
double  tolerance = 1e-10 
) const

Calculate all eigenvalues of the matrix using the QR algorithm.

Parameters
max_itersMaximum number of iterations for QR algorithm
toleranceTolerance for convergence
Returns
A vector containing all eigenvalues of the matrix

Definition at line 93 of file eigen.cpp.

94  {
95  // initialize a copy of the matrix to avoid modifying the original
96  std::vector<std::vector<double>> hessenberg_mtx = matrix;
97 
98  // QR Iteration
99  for (int iter = 0; iter < max_iters; ++iter) {
100  // QR decomposition of the Hessenberg matrix
101  for (int i = 0; i < size - 1; ++i) {
102  // perform Givens rotation to introduce zeros below the subdiagonal
103  double a = hessenberg_mtx[i][i];
104  double b = hessenberg_mtx[i + 1][i];
105  double r = std::hypot(a, b);
106  double c = a / r;
107  double s = b / r;
108 
109  // apply Givens rotation to the submatrix
110  for (int j = 0; j < size; ++j) {
111  double temp1 =
112  c * hessenberg_mtx[i][j] + s * hessenberg_mtx[i + 1][j];
113  double temp2 =
114  -s * hessenberg_mtx[i][j] + c * hessenberg_mtx[i + 1][j];
115  hessenberg_mtx[i][j] = temp1;
116  hessenberg_mtx[i + 1][j] = temp2;
117  }
118  }
119 
120  // check for convergence (off-diagonal elements close to zero)
121  double offDiagonalSum = 0.0;
122  for (int i = 2; i < size; ++i) {
123  offDiagonalSum += std::abs(hessenberg_mtx[i][i - 1]);
124  }
125 
126  if (offDiagonalSum < tolerance) {
127  // extract eigenvalues from the diagonal of the Hessenberg matrix
128  std::vector<double> eigenvalues;
129  for (int i = 0; i < size; ++i) {
130  eigenvalues.push_back(hessenberg_mtx[i][i]);
131  }
132 
133  return eigenvalues;
134  }
135  }
136 
137  std::cerr << "Warning: QR iteration did not converge within the "
138  "specified iterations\n";
139  // empty vector if not converged
140  return std::vector<double>();
141 }

Referenced by sensitivity().

◆ rayleigh_iter()

double gpmp::linalg::Eigen::rayleigh_iter ( int  maxIterations,
double  tolerance 
) const

Perform Rayleigh Quotient Iteration to approximate the dominant eigenvalue.

This method iteratively refines an estimate of the dominant eigenvalue of the matrix using the Rayleigh quotient iteration. The method returns the final estimate of the dominant eigenvalue

Parameters
maxIterationsMaximum number of iterations
toleranceConvergence tolerance
Returns
The dominant eigenvalue estimate
Note
The iteration may not converge for all matrices. A warning is issued if convergence is not achieved

Definition at line 237 of file eigen.cpp.

238  {
239  // initial guess
240  std::vector<double> x(size, 1.0);
241  double lambdaPrev = 0.0;
242 
243  for (int iter = 0; iter < maxIterations; ++iter) {
244  // Rayleigh quotient iteration
245  std::vector<double> Ax(size, 0.0);
246 
247  // perform matrix-vector multiplication: Ax = A * x
248  for (int i = 0; i < size; ++i) {
249  for (int j = 0; j < size; ++j) {
250  Ax[i] += matrix[i][j] * x[j];
251  }
252  }
253 
254  // compute the Rayleigh quotient
255  double lambda =
256  std::inner_product(x.begin(), x.end(), Ax.begin(), 0.0) /
257  std::inner_product(x.begin(), x.end(), x.begin(), 0.0);
258 
259  // check for convergence
260  if (std::abs(lambda - lambdaPrev) < tolerance) {
261  return lambda;
262  }
263 
264  // update the guess vector
265  double normAx = std::sqrt(
266  std::inner_product(Ax.begin(), Ax.end(), Ax.begin(), 0.0));
267  for (int i = 0; i < size; ++i) {
268  // normalize each element of x by dividing by its magnitude
269  x[i] = Ax[i] / normAx;
270  }
271 
272  lambdaPrev = lambda;
273  }
274 
275  std::cerr << "Warning: Rayleigh quotient iteration did not converge within "
276  "the specified iterations."
277  << std::endl;
278  // if not converged
279  return 0.0;
280 }

◆ schur_decomp()

void gpmp::linalg::Eigen::schur_decomp ( std::vector< std::vector< double >> &  schurMatrix,
double  tolerance = 1e-10 
) const

Computes the Schur decomposition of a matrix.

This method computes the Schur decomposition of a matrix The Schur decomposition is a block triangular decomposition of a matrix, where the diagonal blocks are square and the off-diagonal blocks are zero or upper triangular

Parameters
schurMatrixThe output matrix to store the Schur decomposition
toleranceThe tolerance for determining if a subdiagonal element is zero

The schurMatrix parameter must be pre-allocated with the same dimensions as the matrix object This method modifies the contents of the schurMatrix parameter

Definition at line 181 of file eigen.cpp.

183  {
184  // Hessenberg matrix is already calculated in QR iteration
185  schurMatrix = matrix;
186 
187  for (int i = size - 1; i > 0; --i) {
188  // check for small subdiagonal elements to introduce a zero
189  if (std::abs(schurMatrix[i][i - 1]) < tolerance) {
190  schurMatrix[i][i - 1] = 0.0;
191  } else {
192  // Apply Givens rotation to introduce a zero below the subdiagonal
193  double a = schurMatrix[i - 1][i - 1];
194  double b = schurMatrix[i][i - 1];
195  double r = std::hypot(a, b);
196  double c = a / r;
197  double s = b / r;
198 
199  for (int j = 0; j < size; ++j) {
200  double temp1 =
201  c * schurMatrix[i - 1][j] + s * schurMatrix[i][j];
202  double temp2 =
203  -s * schurMatrix[i - 1][j] + c * schurMatrix[i][j];
204  schurMatrix[i - 1][j] = temp1;
205  schurMatrix[i][j] = temp2;
206  }
207  }
208  }
209 }

◆ sensitivity()

std::vector< double > gpmp::linalg::Eigen::sensitivity ( double  perturbation) const

Calculates the sensitivity of the eigenvalues of a matrix to small perturbations.

This method calculates the sensitivity of each eigenvalue of a matrix to small perturbations The sensitivity is defined as the change in the eigenvalue divided by the amount of perturbation

Parameters
perturbationThe amount of perturbation to apply to the matrix
Returns
A vector containing the sensitivity of each eigenvalue

The size of the returned vector will be the same as the size of the matrix

Definition at line 154 of file eigen.cpp.

154  {
155  std::vector<double> originalEigenvalues = qr_algorithm();
156 
157  std::vector<double> perturbedEigenvalues;
158  for (int i = 0; i < size; ++i) {
159  // perturb the matrix
160  std::vector<std::vector<double>> perturbedMatrix = matrix;
161  perturbedMatrix[i][i] += perturbation;
162 
163  // calculate eigenvalues of perturbed matrix
164  std::vector<double> perturbedVals =
165  Eigen(perturbedMatrix).qr_algorithm();
166  perturbedEigenvalues.push_back(perturbedVals[i]);
167  }
168 
169  // calculate sensitivity: (perturbed eigenvalue - original eigenvalue) /
170  // perturbation
171  std::vector<double> sensitivity;
172  for (int i = 0; i < size; ++i) {
173  double sens =
174  (perturbedEigenvalues[i] - originalEigenvalues[i]) / perturbation;
175  sensitivity.push_back(sens);
176  }
177 
178  return sensitivity;
179 }
std::vector< double > sensitivity(double perturbation) const
Calculates the sensitivity of the eigenvalues of a matrix to small perturbations.
Definition: eigen.cpp:154
Eigen(const std::vector< std::vector< double >> &mat)
Constructor for the Eigen class.
Definition: eigen.cpp:39

References qr_algorithm().

Member Data Documentation

◆ matrix

std::vector<std::vector<double> > gpmp::linalg::Eigen::matrix
private

Definition at line 48 of file eigen.hpp.

◆ size

int gpmp::linalg::Eigen::size
private

Definition at line 50 of file eigen.hpp.


The documentation for this class was generated from the following files: