1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.hipparchus.linear;
24
25 import org.hipparchus.exception.LocalizedCoreFormats;
26 import org.hipparchus.exception.MathIllegalArgumentException;
27 import org.hipparchus.util.FastMath;
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 public class CholeskyDecomposition {
53
54
55
56
57 public static final double DEFAULT_RELATIVE_SYMMETRY_THRESHOLD = 1.0e-15;
58
59
60
61
62 public static final double DEFAULT_ABSOLUTE_POSITIVITY_THRESHOLD = 1.0e-10;
63
64 private final double[][] lTData;
65
66 private RealMatrix cachedL;
67
68 private RealMatrix cachedLT;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 public CholeskyDecomposition(final RealMatrix matrix) {
89 this(matrix, DEFAULT_RELATIVE_SYMMETRY_THRESHOLD,
90 DEFAULT_ABSOLUTE_POSITIVITY_THRESHOLD);
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public CholeskyDecomposition(final RealMatrix matrix,
109 final double relativeSymmetryThreshold,
110 final double absolutePositivityThreshold) {
111 if (!matrix.isSquare()) {
112 throw new MathIllegalArgumentException(LocalizedCoreFormats.NON_SQUARE_MATRIX,
113 matrix.getRowDimension(), matrix.getColumnDimension());
114 }
115
116 final int order = matrix.getRowDimension();
117 lTData = matrix.getData();
118 cachedL = null;
119 cachedLT = null;
120
121
122 for (int i = 0; i < order; ++i) {
123 final double[] lI = lTData[i];
124
125
126 for (int j = i + 1; j < order; ++j) {
127 final double[] lJ = lTData[j];
128 final double lIJ = lI[j];
129 final double lJI = lJ[i];
130 final double maxDelta =
131 relativeSymmetryThreshold * FastMath.max(FastMath.abs(lIJ), FastMath.abs(lJI));
132 if (FastMath.abs(lIJ - lJI) > maxDelta) {
133 throw new MathIllegalArgumentException(LocalizedCoreFormats.NON_SYMMETRIC_MATRIX,
134 i, j, relativeSymmetryThreshold);
135 }
136 lJ[i] = 0;
137 }
138 }
139
140
141 for (int i = 0; i < order; ++i) {
142
143 final double[] ltI = lTData[i];
144
145
146 if (ltI[i] <= absolutePositivityThreshold) {
147 throw new MathIllegalArgumentException(LocalizedCoreFormats.NOT_POSITIVE_DEFINITE_MATRIX);
148 }
149
150 ltI[i] = FastMath.sqrt(ltI[i]);
151 final double inverse = 1.0 / ltI[i];
152
153 for (int q = order - 1; q > i; --q) {
154 ltI[q] *= inverse;
155 final double[] ltQ = lTData[q];
156 for (int p = q; p < order; ++p) {
157 ltQ[p] -= ltI[q] * ltI[p];
158 }
159 }
160 }
161 }
162
163
164
165
166
167
168 public RealMatrix getL() {
169 if (cachedL == null) {
170 cachedL = getLT().transpose();
171 }
172 return cachedL;
173 }
174
175
176
177
178
179
180 public RealMatrix getLT() {
181
182 if (cachedLT == null) {
183 cachedLT = MatrixUtils.createRealMatrix(lTData);
184 }
185
186
187 return cachedLT;
188 }
189
190
191
192
193
194 public double getDeterminant() {
195 double determinant = 1.0;
196 for (int i = 0; i < lTData.length; ++i) {
197 double lTii = lTData[i][i];
198 determinant *= lTii * lTii;
199 }
200 return determinant;
201 }
202
203
204
205
206
207 public DecompositionSolver getSolver() {
208 return new Solver();
209 }
210
211
212 private class Solver implements DecompositionSolver {
213
214
215 @Override
216 public boolean isNonSingular() {
217
218 return true;
219 }
220
221
222 @Override
223 public RealVector solve(final RealVector b) {
224 final int m = lTData.length;
225 if (b.getDimension() != m) {
226 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
227 b.getDimension(), m);
228 }
229
230 final double[] x = b.toArray();
231
232
233 for (int j = 0; j < m; j++) {
234 final double[] lJ = lTData[j];
235 x[j] /= lJ[j];
236 final double xJ = x[j];
237 for (int i = j + 1; i < m; i++) {
238 x[i] -= xJ * lJ[i];
239 }
240 }
241
242
243 for (int j = m - 1; j >= 0; j--) {
244 x[j] /= lTData[j][j];
245 final double xJ = x[j];
246 for (int i = 0; i < j; i++) {
247 x[i] -= xJ * lTData[i][j];
248 }
249 }
250
251 return new ArrayRealVector(x, false);
252 }
253
254
255 @Override
256 public RealMatrix solve(RealMatrix b) {
257 final int m = lTData.length;
258 if (b.getRowDimension() != m) {
259 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
260 b.getRowDimension(), m);
261 }
262
263 final int nColB = b.getColumnDimension();
264 final double[][] x = b.getData();
265
266
267 for (int j = 0; j < m; j++) {
268 final double[] lJ = lTData[j];
269 final double lJJ = lJ[j];
270 final double[] xJ = x[j];
271 for (int k = 0; k < nColB; ++k) {
272 xJ[k] /= lJJ;
273 }
274 for (int i = j + 1; i < m; i++) {
275 final double[] xI = x[i];
276 final double lJI = lJ[i];
277 for (int k = 0; k < nColB; ++k) {
278 xI[k] -= xJ[k] * lJI;
279 }
280 }
281 }
282
283
284 for (int j = m - 1; j >= 0; j--) {
285 final double lJJ = lTData[j][j];
286 final double[] xJ = x[j];
287 for (int k = 0; k < nColB; ++k) {
288 xJ[k] /= lJJ;
289 }
290 for (int i = 0; i < j; i++) {
291 final double[] xI = x[i];
292 final double lIJ = lTData[i][j];
293 for (int k = 0; k < nColB; ++k) {
294 xI[k] -= xJ[k] * lIJ;
295 }
296 }
297 }
298
299 return new Array2DRowRealMatrix(x);
300 }
301
302
303
304
305
306
307 @Override
308 public RealMatrix getInverse() {
309 return solve(MatrixUtils.createRealIdentityMatrix(lTData.length));
310 }
311
312
313 @Override
314 public int getRowDimension() {
315 return lTData.length;
316 }
317
318
319 @Override
320 public int getColumnDimension() {
321 return lTData[0].length;
322 }
323
324 }
325
326 }