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