Power Iteration Method
Routine Name : Power Iteration
Author : Kyle Hovey
Language : C++
Description/Purpose :
This method finds the eigenvalue with largest absolute magnitude assuming a strict ordering.
Input :
A square matrix.
Output :
A tuple containing the largest eigenvalue and its corresponding eigenvector.
Usage/Example :
#include "../../matrix/src/matrix/matrix.h"
#include <iostream>
#include <vector>
using Mtx = Matrix :: Matrix < double > ;
int main () {
auto A = Mtx :: hilbert ( 5 );
const auto [ bigEigen , x ] = A . largestEigenpair ();
std :: cout << "A \n " ;
std :: cout << A << std :: endl ;
std :: cout << "Largest Eigenvalue \n " ;
std :: cout << bigEigen << std :: endl ;
std :: cout << std :: endl ;
std :: cout << "x vector \n " ;
std :: cout << x << std :: endl ;
std :: cout << "A * x \n " ;
std :: cout << A * x << std :: endl ;
std :: cout << "Largest Eigenvalue * x \n " ;
std :: cout << bigEigen * x << std :: endl ;
return EXIT_SUCCESS ;
}
Output:
A
1 0.5 0.333333 0.25 0.2
0.5 0.333333 0.25 0.2 0.166667
0.333333 0.25 0.2 0.166667 0.142857
0.25 0.2 0.166667 0.142857 0.125
0.2 0.166667 0.142857 0.125 0.111111
Largest Eigenvalue
1.56705
x vector
1.20327
0.698577
0.503929
0.397152
0.328803
A * x
1.88558
1.09471
0.789683
0.622357
0.515251
Largest Eigenvalue * x
1.88558
1.09471
0.789683
0.622357
0.515251
Now that we have this method implemented, we can see that the eigenvalue on a matrix generated for a second order finite difference method has a bounded spectral radius. This is not a complete proof by any means, but it is easy to see that the change in largest eigenvector becomes smaller as the size increases.
#include "../../matrix/src/matrix/matrix.h"
#include <iostream>
#include <vector>
using Mtx = Matrix :: Matrix < double > ;
int main () {
for ( uint i = 0 ; i < 15 ; ++ i ) {
const auto size = ( i + 1 ) * 5 ;
auto A = Mtx :: genFDMatrix ( size , 2 );
const auto bigEiegen = std :: get < 0 > ( A . largestEigenpair ());
std :: cout << "2nd Order FDM Matrix Spectral Radius for size " ;
std :: cout << size << ":" << std :: endl ;
std :: cout << bigEiegen << std :: endl ;
}
return EXIT_SUCCESS ;
}
Output:
2 nd Order FDM Matrix Spectral Radius for size 5 :
3.73205
2 nd Order FDM Matrix Spectral Radius for size 10 :
3.68251
2 nd Order FDM Matrix Spectral Radius for size 15 :
3.96157
2 nd Order FDM Matrix Spectral Radius for size 20 :
3.91114
2 nd Order FDM Matrix Spectral Radius for size 25 :
3.98256
2 nd Order FDM Matrix Spectral Radius for size 30 :
3.95809
2 nd Order FDM Matrix Spectral Radius for size 35 :
3.97406
2 nd Order FDM Matrix Spectral Radius for size 40 :
3.96918
2 nd Order FDM Matrix Spectral Radius for size 45 :
3.97042
2 nd Order FDM Matrix Spectral Radius for size 50 :
3.9702
2 nd Order FDM Matrix Spectral Radius for size 55 :
3.97023
2 nd Order FDM Matrix Spectral Radius for size 60 :
3.97022
2 nd Order FDM Matrix Spectral Radius for size 65 :
3.97022
2 nd Order FDM Matrix Spectral Radius for size 70 :
3.97022
2 nd Order FDM Matrix Spectral Radius for size 75 :
3.97022
Implementation/Code:
This uses the forward iterative method
\[ \vec{v}_{k+1} = \frac{A \vec{v}_k}{\left\lVert A \vec{v}_k \right\rVert_2} \]
template < typename T >
std :: tuple < T , Matrix < T >> Matrix < T >:: largestEigenpair ( const uint & nIter ) {
const auto M = std :: get < 0 > ( this -> getSize ());
// Starting value
Matrix < T > b ( M , 1 , []( const uint & i , const uint & j ) {
( void ) i ;
( void ) j ;
return 1 ;
});
for ( uint i = 0 ; i < nIter ; ++ i ) {
const auto x = * this * b ;
T mult = 1.0 / Matrix < T >:: vNorm ( x , 2 );
b = mult * x ;
}
const auto axe = * this * b ;
const auto eigenVal = Matrix < T >:: vNorm ( axe , 2 ) / Matrix < T >:: vNorm ( b , 2 );
return std :: tie ( eigenVal , axe );
}