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 java.util.Random;
26
27 import org.hipparchus.exception.MathIllegalArgumentException;
28 import org.junit.Assert;
29 import org.junit.Test;
30
31 public class QRSolverTest {
32 double[][] testData3x3NonSingular = {
33 { 12, -51, 4 },
34 { 6, 167, -68 },
35 { -4, 24, -41 }
36 };
37
38 double[][] testData3x3Singular = {
39 { 1, 2, 2 },
40 { 2, 4, 6 },
41 { 4, 8, 12 }
42 };
43
44 double[][] testData3x4 = {
45 { 12, -51, 4, 1 },
46 { 6, 167, -68, 2 },
47 { -4, 24, -41, 3 }
48 };
49
50 double[][] testData4x3 = {
51 { 12, -51, 4 },
52 { 6, 167, -68 },
53 { -4, 24, -41 },
54 { -5, 34, 7 }
55 };
56
57
58 @Test
59 public void testRank() {
60 DecompositionSolver solver =
61 new QRDecomposition(MatrixUtils.createRealMatrix(testData3x3NonSingular)).getSolver();
62 Assert.assertTrue(solver.isNonSingular());
63
64 solver = new QRDecomposition(MatrixUtils.createRealMatrix(testData3x3Singular)).getSolver();
65 Assert.assertFalse(solver.isNonSingular());
66
67 solver = new QRDecomposition(MatrixUtils.createRealMatrix(testData3x4)).getSolver();
68 Assert.assertTrue(solver.isNonSingular());
69
70 solver = new QRDecomposition(MatrixUtils.createRealMatrix(testData4x3)).getSolver();
71 Assert.assertTrue(solver.isNonSingular());
72
73 }
74
75
76 @Test
77 public void testSolveDimensionErrors() {
78 DecompositionSolver solver =
79 new QRDecomposition(MatrixUtils.createRealMatrix(testData3x3NonSingular)).getSolver();
80 RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
81 try {
82 solver.solve(b);
83 Assert.fail("an exception should have been thrown");
84 } catch (MathIllegalArgumentException iae) {
85
86 }
87 try {
88 solver.solve(b.getColumnVector(0));
89 Assert.fail("an exception should have been thrown");
90 } catch (MathIllegalArgumentException iae) {
91
92 }
93 }
94
95
96 @Test
97 public void testSolveRankErrors() {
98 DecompositionSolver solver =
99 new QRDecomposition(MatrixUtils.createRealMatrix(testData3x3Singular)).getSolver();
100 RealMatrix b = MatrixUtils.createRealMatrix(new double[3][2]);
101 try {
102 solver.solve(b);
103 Assert.fail("an exception should have been thrown");
104 } catch (MathIllegalArgumentException iae) {
105
106 }
107 try {
108 solver.solve(b.getColumnVector(0));
109 Assert.fail("an exception should have been thrown");
110 } catch (MathIllegalArgumentException iae) {
111
112 }
113 }
114
115
116 @Test
117 public void testSolve() {
118 QRDecomposition decomposition =
119 new QRDecomposition(MatrixUtils.createRealMatrix(testData3x3NonSingular));
120 DecompositionSolver solver = decomposition.getSolver();
121 RealMatrix b = MatrixUtils.createRealMatrix(new double[][] {
122 { -102, 12250 }, { 544, 24500 }, { 167, -36750 }
123 });
124 RealMatrix xRef = MatrixUtils.createRealMatrix(new double[][] {
125 { 1, 2515 }, { 2, 422 }, { -3, 898 }
126 });
127
128
129 Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm1(), 2.1e-16 * xRef.getNorm1());
130
131
132 for (int i = 0; i < b.getColumnDimension(); ++i) {
133 final RealVector x = solver.solve(b.getColumnVector(i));
134 final double error = x.subtract(xRef.getColumnVector(i)).getNorm();
135 Assert.assertEquals(0, error, 3.0e-16 * xRef.getColumnVector(i).getNorm());
136 }
137
138
139 for (int i = 0; i < b.getColumnDimension(); ++i) {
140 ArrayRealVectorTest.RealVectorTestImpl v =
141 new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(i));
142 final RealVector x = solver.solve(v);
143 final double error = x.subtract(xRef.getColumnVector(i)).getNorm();
144 Assert.assertEquals(0, error, 3.0e-16 * xRef.getColumnVector(i).getNorm());
145 }
146
147 }
148
149 @Test
150 public void testOverdetermined() {
151 final Random r = new Random(5559252868205245l);
152 int p = (7 * BlockRealMatrix.BLOCK_SIZE) / 4;
153 int q = (5 * BlockRealMatrix.BLOCK_SIZE) / 4;
154 RealMatrix a = createTestMatrix(r, p, q);
155 RealMatrix xRef = createTestMatrix(r, q, BlockRealMatrix.BLOCK_SIZE + 3);
156
157
158 RealMatrix b = a.multiply(xRef);
159 final double noise = 0.001;
160 b.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() {
161 @Override
162 public double visit(int row, int column, double value) {
163 return value * (1.0 + noise * (2 * r.nextDouble() - 1));
164 }
165 });
166
167
168 RealMatrix x = new QRDecomposition(a).getSolver().solve(b);
169 Assert.assertEquals(0, x.subtract(xRef).getNorm1(), 0.01 * noise * p * q);
170
171 }
172
173 @Test
174 public void testUnderdetermined() {
175 final Random r = new Random(42185006424567123l);
176 int p = (5 * BlockRealMatrix.BLOCK_SIZE) / 4;
177 int q = (7 * BlockRealMatrix.BLOCK_SIZE) / 4;
178 RealMatrix a = createTestMatrix(r, p, q);
179 RealMatrix xRef = createTestMatrix(r, q, BlockRealMatrix.BLOCK_SIZE + 3);
180 RealMatrix b = a.multiply(xRef);
181 RealMatrix x = new QRDecomposition(a).getSolver().solve(b);
182
183
184 Assert.assertTrue(x.subtract(xRef).getNorm1() / (p * q) > 0.01);
185
186
187 Assert.assertEquals(0.0, x.getSubMatrix(p, q - 1, 0, x.getColumnDimension() - 1).getNorm1(), 0);
188 }
189
190 private RealMatrix createTestMatrix(final Random r, final int rows, final int columns) {
191 RealMatrix m = MatrixUtils.createRealMatrix(rows, columns);
192 m.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() {
193 @Override
194 public double visit(int row, int column, double value) {
195 return 2.0 * r.nextDouble() - 1.0;
196 }
197 });
198 return m;
199 }
200 }