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.fraction.Fraction;
28 import org.junit.jupiter.api.Test;
29
30 import static org.junit.jupiter.api.Assertions.assertEquals;
31 import static org.junit.jupiter.api.Assertions.assertFalse;
32 import static org.junit.jupiter.api.Assertions.assertNull;
33 import static org.junit.jupiter.api.Assertions.assertTrue;
34 import static org.junit.jupiter.api.Assertions.fail;
35
36 class LUDecompositionTest {
37 private double[][] testData = {
38 { 1.0, 2.0, 3.0},
39 { 2.0, 5.0, 3.0},
40 { 1.0, 0.0, 8.0}
41 };
42 private double[][] testDataMinus = {
43 { -1.0, -2.0, -3.0},
44 { -2.0, -5.0, -3.0},
45 { -1.0, 0.0, -8.0}
46 };
47 private double[][] luData = {
48 { 2.0, 3.0, 3.0 },
49 { 0.0, 5.0, 7.0 },
50 { 6.0, 9.0, 8.0 }
51 };
52
53
54 private double[][] singular = {
55 { 2.0, 3.0 },
56 { 2.0, 3.0 }
57 };
58 private double[][] bigSingular = {
59 { 1.0, 2.0, 3.0, 4.0 },
60 { 2.0, 5.0, 3.0, 4.0 },
61 { 7.0, 3.0, 256.0, 1930.0 },
62 { 3.0, 7.0, 6.0, 8.0 }
63 };
64
65 private static final double entryTolerance = 10e-16;
66
67 private static final double normTolerance = 10e-14;
68
69
70 @Test
71 void testDimensions() {
72 RealMatrix matrix = MatrixUtils.createRealMatrix(testData);
73 LUDecomposition LU = new LUDecomposition(matrix);
74 assertEquals(testData.length, LU.getL().getRowDimension());
75 assertEquals(testData.length, LU.getL().getColumnDimension());
76 assertEquals(testData.length, LU.getU().getRowDimension());
77 assertEquals(testData.length, LU.getU().getColumnDimension());
78 assertEquals(testData.length, LU.getP().getRowDimension());
79 assertEquals(testData.length, LU.getP().getColumnDimension());
80
81 }
82
83
84 @Test
85 void testNonSquare() {
86 try {
87 new LUDecomposition(MatrixUtils.createRealMatrix(new double[3][2]));
88 fail("Expecting MathIllegalArgumentException");
89 } catch (MathIllegalArgumentException ime) {
90 assertEquals(LocalizedCoreFormats.NON_SQUARE_MATRIX, ime.getSpecifier());
91 }
92 }
93
94
95 @Test
96 void testPAEqualLU() {
97 RealMatrix matrix = MatrixUtils.createRealMatrix(testData);
98 LUDecomposition lu = new LUDecomposition(matrix);
99 RealMatrix l = lu.getL();
100 RealMatrix u = lu.getU();
101 RealMatrix p = lu.getP();
102 double norm = l.multiply(u).subtract(p.multiply(matrix)).getNorm1();
103 assertEquals(0, norm, normTolerance);
104
105 matrix = MatrixUtils.createRealMatrix(testDataMinus);
106 lu = new LUDecomposition(matrix);
107 l = lu.getL();
108 u = lu.getU();
109 p = lu.getP();
110 norm = l.multiply(u).subtract(p.multiply(matrix)).getNorm1();
111 assertEquals(0, norm, normTolerance);
112
113 matrix = MatrixUtils.createRealIdentityMatrix(17);
114 lu = new LUDecomposition(matrix);
115 l = lu.getL();
116 u = lu.getU();
117 p = lu.getP();
118 norm = l.multiply(u).subtract(p.multiply(matrix)).getNorm1();
119 assertEquals(0, norm, normTolerance);
120
121 matrix = MatrixUtils.createRealMatrix(singular);
122 lu = new LUDecomposition(matrix);
123 assertFalse(lu.getSolver().isNonSingular());
124 assertNull(lu.getL());
125 assertNull(lu.getU());
126 assertNull(lu.getP());
127
128 matrix = MatrixUtils.createRealMatrix(bigSingular);
129 lu = new LUDecomposition(matrix);
130 assertFalse(lu.getSolver().isNonSingular());
131 assertNull(lu.getL());
132 assertNull(lu.getU());
133 assertNull(lu.getP());
134
135 }
136
137
138 @Test
139 void testLLowerTriangular() {
140 RealMatrix matrix = MatrixUtils.createRealMatrix(testData);
141 RealMatrix l = new LUDecomposition(matrix).getL();
142 for (int i = 0; i < l.getRowDimension(); i++) {
143 assertEquals(1, l.getEntry(i, i), entryTolerance);
144 for (int j = i + 1; j < l.getColumnDimension(); j++) {
145 assertEquals(0, l.getEntry(i, j), entryTolerance);
146 }
147 }
148 }
149
150
151 @Test
152 void testUUpperTriangular() {
153 RealMatrix matrix = MatrixUtils.createRealMatrix(testData);
154 RealMatrix u = new LUDecomposition(matrix).getU();
155 for (int i = 0; i < u.getRowDimension(); i++) {
156 for (int j = 0; j < i; j++) {
157 assertEquals(0, u.getEntry(i, j), entryTolerance);
158 }
159 }
160 }
161
162
163 @Test
164 void testPPermutation() {
165 RealMatrix matrix = MatrixUtils.createRealMatrix(testData);
166 RealMatrix p = new LUDecomposition(matrix).getP();
167
168 RealMatrix ppT = p.multiplyTransposed(p);
169 RealMatrix id = MatrixUtils.createRealIdentityMatrix(p.getRowDimension());
170 assertEquals(0, ppT.subtract(id).getNorm1(), normTolerance);
171
172 for (int i = 0; i < p.getRowDimension(); i++) {
173 int zeroCount = 0;
174 int oneCount = 0;
175 int otherCount = 0;
176 for (int j = 0; j < p.getColumnDimension(); j++) {
177 final double e = p.getEntry(i, j);
178 if (e == 0) {
179 ++zeroCount;
180 } else if (e == 1) {
181 ++oneCount;
182 } else {
183 ++otherCount;
184 }
185 }
186 assertEquals(p.getColumnDimension() - 1, zeroCount);
187 assertEquals(1, oneCount);
188 assertEquals(0, otherCount);
189 }
190
191 for (int j = 0; j < p.getColumnDimension(); j++) {
192 int zeroCount = 0;
193 int oneCount = 0;
194 int otherCount = 0;
195 for (int i = 0; i < p.getRowDimension(); i++) {
196 final double e = p.getEntry(i, j);
197 if (e == 0) {
198 ++zeroCount;
199 } else if (e == 1) {
200 ++oneCount;
201 } else {
202 ++otherCount;
203 }
204 }
205 assertEquals(p.getRowDimension() - 1, zeroCount);
206 assertEquals(1, oneCount);
207 assertEquals(0, otherCount);
208 }
209
210 }
211
212
213 @Test
214 void testSingular() {
215 final RealMatrix m = MatrixUtils.createRealMatrix(testData);
216 LUDecomposition lu = new LUDecomposition(m);
217 assertTrue(lu.getSolver().isNonSingular());
218 assertEquals(-1.0, lu.getDeterminant(), 1.0e-15);
219 lu = new LUDecomposition(m.getSubMatrix(0, 1, 0, 1));
220 assertTrue(lu.getSolver().isNonSingular());
221 assertEquals(+1.0, lu.getDeterminant(), 1.0e-15);
222 lu = new LUDecomposition(MatrixUtils.createRealMatrix(singular));
223 assertFalse(lu.getSolver().isNonSingular());
224 assertEquals(0.0, lu.getDeterminant(), 1.0e-15);
225 lu = new LUDecomposition(MatrixUtils.createRealMatrix(bigSingular));
226 assertFalse(lu.getSolver().isNonSingular());
227 assertEquals(0.0, lu.getDeterminant(), 1.0e-15);
228 try {
229 lu.getSolver().solve(new ArrayRealVector(new double[] { 1, 1, 1, 1 }));
230 fail("an exception should have been thrown");
231 } catch (MathIllegalArgumentException miae) {
232 assertEquals(LocalizedCoreFormats.SINGULAR_MATRIX, miae.getSpecifier());
233 }
234 }
235
236
237 @Test
238 void testMatricesValues1() {
239 LUDecomposition lu =
240 new LUDecomposition(MatrixUtils.createRealMatrix(testData));
241 RealMatrix lRef = MatrixUtils.createRealMatrix(new double[][] {
242 { 1.0, 0.0, 0.0 },
243 { 0.5, 1.0, 0.0 },
244 { 0.5, 0.2, 1.0 }
245 });
246 RealMatrix uRef = MatrixUtils.createRealMatrix(new double[][] {
247 { 2.0, 5.0, 3.0 },
248 { 0.0, -2.5, 6.5 },
249 { 0.0, 0.0, 0.2 }
250 });
251 RealMatrix pRef = MatrixUtils.createRealMatrix(new double[][] {
252 { 0.0, 1.0, 0.0 },
253 { 0.0, 0.0, 1.0 },
254 { 1.0, 0.0, 0.0 }
255 });
256 int[] pivotRef = { 1, 2, 0 };
257
258
259 RealMatrix l = lu.getL();
260 assertEquals(0, l.subtract(lRef).getNorm1(), 1.0e-13);
261 RealMatrix u = lu.getU();
262 assertEquals(0, u.subtract(uRef).getNorm1(), 1.0e-13);
263 RealMatrix p = lu.getP();
264 assertEquals(0, p.subtract(pRef).getNorm1(), 1.0e-13);
265 int[] pivot = lu.getPivot();
266 for (int i = 0; i < pivotRef.length; ++i) {
267 assertEquals(pivotRef[i], pivot[i]);
268 }
269
270
271 assertTrue(l == lu.getL());
272 assertTrue(u == lu.getU());
273 assertTrue(p == lu.getP());
274
275 }
276
277
278 @Test
279 void testMatricesValues2() {
280 LUDecomposition lu =
281 new LUDecomposition(MatrixUtils.createRealMatrix(luData));
282 RealMatrix lRef = MatrixUtils.createRealMatrix(new double[][] {
283 { 1.0, 0.0, 0.0 },
284 { 0.0, 1.0, 0.0 },
285 { 1.0 / 3.0, 0.0, 1.0 }
286 });
287 RealMatrix uRef = MatrixUtils.createRealMatrix(new double[][] {
288 { 6.0, 9.0, 8.0 },
289 { 0.0, 5.0, 7.0 },
290 { 0.0, 0.0, 1.0 / 3.0 }
291 });
292 RealMatrix pRef = MatrixUtils.createRealMatrix(new double[][] {
293 { 0.0, 0.0, 1.0 },
294 { 0.0, 1.0, 0.0 },
295 { 1.0, 0.0, 0.0 }
296 });
297 int[] pivotRef = { 2, 1, 0 };
298
299
300 RealMatrix l = lu.getL();
301 assertEquals(0, l.subtract(lRef).getNorm1(), 1.0e-13);
302 RealMatrix u = lu.getU();
303 assertEquals(0, u.subtract(uRef).getNorm1(), 1.0e-13);
304 RealMatrix p = lu.getP();
305 assertEquals(0, p.subtract(pRef).getNorm1(), 1.0e-13);
306 int[] pivot = lu.getPivot();
307 for (int i = 0; i < pivotRef.length; ++i) {
308 assertEquals(pivotRef[i], pivot[i]);
309 }
310
311
312 assertTrue(l == lu.getL());
313 assertTrue(u == lu.getU());
314 assertTrue(p == lu.getP());
315 }
316
317 @Test
318 void testSolve() {
319 LUDecomposition lu =
320 new LUDecomposition(new Array2DRowRealMatrix(testData));
321 DecompositionSolver solver = lu.getSolver();
322 RealVector solution = solver.solve(new ArrayRealVector(new double[] {
323 new Fraction(1, 2).doubleValue(), new Fraction(2, 3).doubleValue(), new Fraction(3,4).doubleValue()
324 }));
325 assertEquals(testData.length, solution.getDimension());
326 assertEquals(new Fraction(-31, 12).doubleValue(), solution.getEntry(0), 1.0e-14);
327 assertEquals(new Fraction( 11, 12).doubleValue(), solution.getEntry(1), 1.0e-14);
328 assertEquals(new Fraction( 5, 12).doubleValue(), solution.getEntry(2), 1.0e-14);
329 assertEquals(testData.length, solver.getRowDimension());
330 assertEquals(testData[0].length, solver.getColumnDimension());
331 try {
332 solver.solve(new ArrayRealVector(new double[] { 1, 1 }));
333 fail("an exception should have been thrown");
334 } catch (MathIllegalArgumentException miae) {
335 assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
336 }
337 }
338
339 }