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
53 public class LUDecomposition {
54
55 private static final double DEFAULT_TOO_SMALL = 1e-11;
56
57 private final double[][] lu;
58
59 private final int[] pivot;
60
61 private boolean even;
62
63 private boolean singular;
64
65 private RealMatrix cachedL;
66
67 private RealMatrix cachedU;
68
69 private RealMatrix cachedP;
70
71
72
73
74
75
76
77
78
79 public LUDecomposition(RealMatrix matrix) {
80 this(matrix, DEFAULT_TOO_SMALL);
81 }
82
83
84
85
86
87
88
89
90 public LUDecomposition(RealMatrix matrix, double singularityThreshold) {
91 if (!matrix.isSquare()) {
92 throw new MathIllegalArgumentException(LocalizedCoreFormats.NON_SQUARE_MATRIX,
93 matrix.getRowDimension(), matrix.getColumnDimension());
94 }
95
96 final int m = matrix.getColumnDimension();
97 lu = matrix.getData();
98 pivot = new int[m];
99 cachedL = null;
100 cachedU = null;
101 cachedP = null;
102
103
104 for (int row = 0; row < m; row++) {
105 pivot[row] = row;
106 }
107 even = true;
108 singular = false;
109
110
111 for (int col = 0; col < m; col++) {
112
113
114 for (int row = 0; row < col; row++) {
115 final double[] luRow = lu[row];
116 double sum = luRow[col];
117 for (int i = 0; i < row; i++) {
118 sum -= luRow[i] * lu[i][col];
119 }
120 luRow[col] = sum;
121 }
122
123
124 int max = col;
125 double largest = Double.NEGATIVE_INFINITY;
126 for (int row = col; row < m; row++) {
127 final double[] luRow = lu[row];
128 double sum = luRow[col];
129 for (int i = 0; i < col; i++) {
130 sum -= luRow[i] * lu[i][col];
131 }
132 luRow[col] = sum;
133
134
135 if (FastMath.abs(sum) > largest) {
136 largest = FastMath.abs(sum);
137 max = row;
138 }
139 }
140
141
142 if (FastMath.abs(lu[max][col]) < singularityThreshold) {
143 singular = true;
144 return;
145 }
146
147
148 if (max != col) {
149 final double[] luMax = lu[max];
150 final double[] luCol = lu[col];
151 for (int i = 0; i < m; i++) {
152 final double tmp = luMax[i];
153 luMax[i] = luCol[i];
154 luCol[i] = tmp;
155 }
156 int temp = pivot[max];
157 pivot[max] = pivot[col];
158 pivot[col] = temp;
159 even = !even;
160 }
161
162
163 final double luDiag = lu[col][col];
164 for (int row = col + 1; row < m; row++) {
165 lu[row][col] /= luDiag;
166 }
167 }
168 }
169
170
171
172
173
174
175 public RealMatrix getL() {
176 if ((cachedL == null) && !singular) {
177 final int m = pivot.length;
178 cachedL = MatrixUtils.createRealMatrix(m, m);
179 for (int i = 0; i < m; ++i) {
180 final double[] luI = lu[i];
181 for (int j = 0; j < i; ++j) {
182 cachedL.setEntry(i, j, luI[j]);
183 }
184 cachedL.setEntry(i, i, 1.0);
185 }
186 }
187 return cachedL;
188 }
189
190
191
192
193
194
195 public RealMatrix getU() {
196 if ((cachedU == null) && !singular) {
197 final int m = pivot.length;
198 cachedU = MatrixUtils.createRealMatrix(m, m);
199 for (int i = 0; i < m; ++i) {
200 final double[] luI = lu[i];
201 for (int j = i; j < m; ++j) {
202 cachedU.setEntry(i, j, luI[j]);
203 }
204 }
205 }
206 return cachedU;
207 }
208
209
210
211
212
213
214
215
216
217
218 public RealMatrix getP() {
219 if ((cachedP == null) && !singular) {
220 final int m = pivot.length;
221 cachedP = MatrixUtils.createRealMatrix(m, m);
222 for (int i = 0; i < m; ++i) {
223 cachedP.setEntry(i, pivot[i], 1.0);
224 }
225 }
226 return cachedP;
227 }
228
229
230
231
232
233
234 public int[] getPivot() {
235 return pivot.clone();
236 }
237
238
239
240
241
242 public double getDeterminant() {
243 if (singular) {
244 return 0;
245 } else {
246 final int m = pivot.length;
247 double determinant = even ? 1 : -1;
248 for (int i = 0; i < m; i++) {
249 determinant *= lu[i][i];
250 }
251 return determinant;
252 }
253 }
254
255
256
257
258
259
260 public DecompositionSolver getSolver() {
261 return new Solver();
262 }
263
264
265 private class Solver implements DecompositionSolver {
266
267
268 @Override
269 public boolean isNonSingular() {
270 return !singular;
271 }
272
273
274 @Override
275 public RealVector solve(RealVector b) {
276 final int m = pivot.length;
277 if (b.getDimension() != m) {
278 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
279 b.getDimension(), m);
280 }
281 if (singular) {
282 throw new MathIllegalArgumentException(LocalizedCoreFormats.SINGULAR_MATRIX);
283 }
284
285 final double[] bp = new double[m];
286
287
288 for (int row = 0; row < m; row++) {
289 bp[row] = b.getEntry(pivot[row]);
290 }
291
292
293 for (int col = 0; col < m; col++) {
294 final double bpCol = bp[col];
295 for (int i = col + 1; i < m; i++) {
296 bp[i] -= bpCol * lu[i][col];
297 }
298 }
299
300
301 for (int col = m - 1; col >= 0; col--) {
302 bp[col] /= lu[col][col];
303 final double bpCol = bp[col];
304 for (int i = 0; i < col; i++) {
305 bp[i] -= bpCol * lu[i][col];
306 }
307 }
308
309 return new ArrayRealVector(bp, false);
310 }
311
312
313 @Override
314 public RealMatrix solve(RealMatrix b) {
315
316 final int m = pivot.length;
317 if (b.getRowDimension() != m) {
318 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
319 b.getRowDimension(), m);
320 }
321 if (singular) {
322 throw new MathIllegalArgumentException(LocalizedCoreFormats.SINGULAR_MATRIX);
323 }
324
325 final int nColB = b.getColumnDimension();
326
327
328 final double[][] bp = new double[m][nColB];
329 for (int row = 0; row < m; row++) {
330 final double[] bpRow = bp[row];
331 final int pRow = pivot[row];
332 for (int col = 0; col < nColB; col++) {
333 bpRow[col] = b.getEntry(pRow, col);
334 }
335 }
336
337
338 for (int col = 0; col < m; col++) {
339 final double[] bpCol = bp[col];
340 for (int i = col + 1; i < m; i++) {
341 final double[] bpI = bp[i];
342 final double luICol = lu[i][col];
343 for (int j = 0; j < nColB; j++) {
344 bpI[j] -= bpCol[j] * luICol;
345 }
346 }
347 }
348
349
350 for (int col = m - 1; col >= 0; col--) {
351 final double[] bpCol = bp[col];
352 final double luDiag = lu[col][col];
353 for (int j = 0; j < nColB; j++) {
354 bpCol[j] /= luDiag;
355 }
356 for (int i = 0; i < col; i++) {
357 final double[] bpI = bp[i];
358 final double luICol = lu[i][col];
359 for (int j = 0; j < nColB; j++) {
360 bpI[j] -= bpCol[j] * luICol;
361 }
362 }
363 }
364
365 return new Array2DRowRealMatrix(bp, false);
366 }
367
368
369
370
371
372
373
374 @Override
375 public RealMatrix getInverse() {
376 return solve(MatrixUtils.createRealIdentityMatrix(pivot.length));
377 }
378
379
380 @Override
381 public int getRowDimension() {
382 return lu.length;
383 }
384
385
386 @Override
387 public int getColumnDimension() {
388 return lu[0].length;
389 }
390
391 }
392
393 }