forked from DanWBR/dwsim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCholeskyDecomposition.cs
160 lines (138 loc) · 5.09 KB
/
CholeskyDecomposition.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
namespace Mapack
{
using System;
/// <summary>Cholesky Decomposition of a symmetric, positive definite matrix.</summary>
/// <remarks>
/// For a symmetric, positive definite matrix <c>A</c>, the Cholesky decomposition is a
/// lower triangular matrix <c>L</c> so that <c>A = L * L'</c>.
/// If the matrix is not symmetric or positive definite, the constructor returns a partial
/// decomposition and sets two internal variables that can be queried using the
/// <see cref="Symmetric"/> and <see cref="PositiveDefinite"/> properties.
/// </remarks>
public class CholeskyDecomposition
{
private Matrix L;
private bool symmetric;
private bool positiveDefinite;
/// <summary>Construct a Cholesky Decomposition.</summary>
public CholeskyDecomposition(Matrix value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (!value.Square)
{
throw new ArgumentException("Matrix is not square.", "value");
}
int dimension = value.Rows;
L = new Matrix(dimension, dimension);
double[][] a = value.Array;
double[][] l = L.Array;
this.positiveDefinite = true;
this.symmetric = true;
for (int j = 0; j < dimension; j++)
{
double[] Lrowj = l[j];
double d = 0.0;
for (int k = 0; k < j; k++)
{
double[] Lrowk = l[k];
double s = 0.0;
for (int i = 0; i < k; i++)
{
s += Lrowk[i] * Lrowj[i];
}
Lrowj[k] = s = (a[j][k] - s) / l[k][k];
d = d + s*s;
this.symmetric = this.symmetric & (a[k][j] == a[j][k]);
}
d = a[j][j] - d;
this.positiveDefinite = this.positiveDefinite & (d > 0.0);
l[j][j] = Math.Sqrt(Math.Max(d,0.0));
for (int k = j + 1; k < dimension; k++)
{
l[j][k] = 0.0;
}
}
}
/// <summary>Returns <see langword="true"/> if the matrix is symmetric.</summary>
public bool Symmetric
{
get
{
return this.symmetric;
}
}
/// <summary>Returns <see langword="true"/> if the matrix is positive definite.</summary>
public bool PositiveDefinite
{
get
{
return this.positiveDefinite;
}
}
/// <summary>Returns the left triangular factor <c>L</c> so that <c>A = L * L'</c>.</summary>
public Matrix LeftTriangularFactor
{
get
{
return this.L;
}
}
/// <summary>Solves a set of equation systems of type <c>A * X = B</c>.</summary>
/// <param name="value">Right hand side matrix with as many rows as <c>A</c> and any number of columns.</param>
/// <returns>Matrix <c>X</c> so that <c>L * L' * X = B</c>.</returns>
/// <exception cref="T:System.ArgumentException">Matrix dimensions do not match.</exception>
/// <exception cref="T:System.InvalidOperationException">Matrix is not symmetrix and positive definite.</exception>
public Matrix Solve(Matrix value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (value.Rows != L.Rows)
{
throw new ArgumentException("Matrix dimensions do not match.");
}
if (!this.symmetric)
{
throw new InvalidOperationException("Matrix is not symmetric.");
}
if (!this.positiveDefinite)
{
throw new InvalidOperationException("Matrix is not positive definite.");
}
// Solve L*Y = B;
int dimension = L.Rows;
int count = value.Columns;
Matrix B = (Matrix)value.Clone();
double[][] l = L.Array;
// Solve L*Y = B;
for (int k = 0; k < dimension; k++)
{
for (int j = 0; j < count; j++)
{
for (int i = 0; i < k; i++)
{
B[k, j] -= B[i, j] * l[k][i];
}
B[k, j] /= l[k][k];
}
}
// Solve L'*X = Y;
for (int k = dimension - 1; k >= 0; k--)
{
for (int j = 0; j < count; j++)
{
for (int i = k + 1; i < dimension; i++)
{
B[k, j] -= B[i, j] * L[i, k];
}
B[k, j] /= l[k][k];
}
}
return B;
}
}
}