- Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathPowerIteration.cs
86 lines (77 loc) · 3.82 KB
/
PowerIteration.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
usingSystem;
usingSystem.Linq;
usingUtilities.Extensions;
namespaceAlgorithms.LinearAlgebra.Eigenvalue;
/// <summary>
/// Power iteration method - eigenvalue numeric algorithm, based on recurrent relation:
/// Li+1 = (A * Li) / || A * Li ||, where Li - eigenvector approximation.
/// </summary>
publicstaticclassPowerIteration
{
/// <summary>
/// Returns approximation of the dominant eigenvalue and eigenvector of <paramref name="source" /> matrix.
/// </summary>
/// <list type="bullet">
/// <item>
/// <description>The algorithm will not converge if the start vector is orthogonal to the eigenvector.</description>
/// </item>
/// <item>
/// <description>The <paramref name="source" /> matrix must be square-shaped.</description>
/// </item>
/// </list>
/// <param name="source">Source square-shaped matrix.</param>
/// <param name="startVector">Start vector.</param>
/// <param name="error">Accuracy of the result.</param>
/// <returns>Dominant eigenvalue and eigenvector pair.</returns>
/// <exception cref="ArgumentException">The <paramref name="source" /> matrix is not square-shaped.</exception>
/// <exception cref="ArgumentException">The length of the start vector doesn't equal the size of the source matrix.</exception>
publicstatic(doubleEigenvalue,double[]Eigenvector)Dominant(
double[,]source,
double[]startVector,
doubleerror=0.00001)
{
if(source.GetLength(0)!=source.GetLength(1))
{
thrownewArgumentException("The source matrix is not square-shaped.");
}
if(source.GetLength(0)!=startVector.Length)
{
thrownewArgumentException(
"The length of the start vector doesn't equal the size of the source matrix.");
}
doubleeigenNorm;
double[]previousEigenVector;
double[]currentEigenVector=startVector;
do
{
previousEigenVector=currentEigenVector;
currentEigenVector=source.Multiply(
previousEigenVector.ToColumnVector())
.ToRowVector();
eigenNorm=currentEigenVector.Magnitude();
currentEigenVector=currentEigenVector.Select(x =>x/eigenNorm).ToArray();
}
while(Math.Abs(currentEigenVector.Dot(previousEigenVector))<1.0-error);
vareigenvalue=source.Multiply(currentEigenVector.ToColumnVector()).ToRowVector().Magnitude();
return(eigenvalue,Eigenvector:currentEigenVector);
}
/// <summary>
/// Returns approximation of the dominant eigenvalue and eigenvector of <paramref name="source" /> matrix.
/// Random normalized vector is used as the start vector to decrease chance of orthogonality to the eigenvector.
/// </summary>
/// <list type="bullet">
/// <item>
/// <description>The algorithm will not converge if the start vector is orthogonal to the eigenvector.</description>
/// </item>
/// <item>
/// <description>The <paramref name="source" /> matrix should be square-shaped.</description>
/// </item>
/// </list>
/// <param name="source">Source square-shaped matrix.</param>
/// <param name="error">Accuracy of the result.</param>
/// <returns>Dominant eigenvalue and eigenvector pair.</returns>
/// <exception cref="ArgumentException">The <paramref name="source" /> matrix is not square-shaped.</exception>
/// <exception cref="ArgumentException">The length of the start vector doesn't equal the size of the source matrix.</exception>
publicstatic(doubleEigenvalue,double[]Eigenvector)Dominant(double[,]source,doubleerror=0.00001)=>
Dominant(source,newRandom().NextVector(source.GetLength(1)),error);
}