001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.math.linear;
019
020 import junit.framework.Test;
021 import junit.framework.TestCase;
022 import junit.framework.TestSuite;
023
024 import org.apache.commons.math.linear.DecompositionSolver;
025 import org.apache.commons.math.linear.InvalidMatrixException;
026 import org.apache.commons.math.linear.LUDecompositionImpl;
027 import org.apache.commons.math.linear.MatrixUtils;
028 import org.apache.commons.math.linear.RealMatrix;
029 import org.apache.commons.math.linear.ArrayRealVector;
030
031 public class LUSolverTest extends TestCase {
032 private double[][] testData = {
033 { 1.0, 2.0, 3.0},
034 { 2.0, 5.0, 3.0},
035 { 1.0, 0.0, 8.0}
036 };
037 private double[][] luData = {
038 { 2.0, 3.0, 3.0 },
039 { 0.0, 5.0, 7.0 },
040 { 6.0, 9.0, 8.0 }
041 };
042
043 // singular matrices
044 private double[][] singular = {
045 { 2.0, 3.0 },
046 { 2.0, 3.0 }
047 };
048 private double[][] bigSingular = {
049 { 1.0, 2.0, 3.0, 4.0 },
050 { 2.0, 5.0, 3.0, 4.0 },
051 { 7.0, 3.0, 256.0, 1930.0 },
052 { 3.0, 7.0, 6.0, 8.0 }
053 }; // 4th row = 1st + 2nd
054
055 public LUSolverTest(String name) {
056 super(name);
057 }
058
059 public static Test suite() {
060 TestSuite suite = new TestSuite(LUSolverTest.class);
061 suite.setName("LUSolver Tests");
062 return suite;
063 }
064
065 /** test threshold impact */
066 public void testThreshold() {
067 final RealMatrix matrix = MatrixUtils.createRealMatrix(new double[][] {
068 { 1.0, 2.0, 3.0},
069 { 2.0, 5.0, 3.0},
070 { 4.000001, 9.0, 9.0}
071 });
072 assertFalse(new LUDecompositionImpl(matrix, 1.0e-5).getSolver().isNonSingular());
073 assertTrue(new LUDecompositionImpl(matrix, 1.0e-10).getSolver().isNonSingular());
074 }
075
076 /** test singular */
077 public void testSingular() {
078 DecompositionSolver solver =
079 new LUDecompositionImpl(MatrixUtils.createRealMatrix(testData)).getSolver();
080 assertTrue(solver.isNonSingular());
081 solver = new LUDecompositionImpl(MatrixUtils.createRealMatrix(singular)).getSolver();
082 assertFalse(solver.isNonSingular());
083 solver = new LUDecompositionImpl(MatrixUtils.createRealMatrix(bigSingular)).getSolver();
084 assertFalse(solver.isNonSingular());
085 }
086
087 /** test solve dimension errors */
088 public void testSolveDimensionErrors() {
089 DecompositionSolver solver =
090 new LUDecompositionImpl(MatrixUtils.createRealMatrix(testData)).getSolver();
091 RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
092 try {
093 solver.solve(b);
094 fail("an exception should have been thrown");
095 } catch (IllegalArgumentException iae) {
096 // expected behavior
097 } catch (Exception e) {
098 fail("wrong exception caught");
099 }
100 try {
101 solver.solve(b.getColumn(0));
102 fail("an exception should have been thrown");
103 } catch (IllegalArgumentException iae) {
104 // expected behavior
105 } catch (Exception e) {
106 fail("wrong exception caught");
107 }
108 try {
109 solver.solve(new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(0)));
110 fail("an exception should have been thrown");
111 } catch (IllegalArgumentException iae) {
112 // expected behavior
113 } catch (Exception e) {
114 fail("wrong exception caught");
115 }
116 }
117
118 /** test solve singularity errors */
119 public void testSolveSingularityErrors() {
120 DecompositionSolver solver =
121 new LUDecompositionImpl(MatrixUtils.createRealMatrix(singular)).getSolver();
122 RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
123 try {
124 solver.solve(b);
125 fail("an exception should have been thrown");
126 } catch (InvalidMatrixException ime) {
127 // expected behavior
128 } catch (Exception e) {
129 fail("wrong exception caught");
130 }
131 try {
132 solver.solve(b.getColumn(0));
133 fail("an exception should have been thrown");
134 } catch (InvalidMatrixException ime) {
135 // expected behavior
136 } catch (Exception e) {
137 fail("wrong exception caught");
138 }
139 try {
140 solver.solve(b.getColumnVector(0));
141 fail("an exception should have been thrown");
142 } catch (InvalidMatrixException ime) {
143 // expected behavior
144 } catch (Exception e) {
145 fail("wrong exception caught");
146 }
147 try {
148 solver.solve(new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(0)));
149 fail("an exception should have been thrown");
150 } catch (InvalidMatrixException ime) {
151 // expected behavior
152 } catch (Exception e) {
153 fail("wrong exception caught");
154 }
155 }
156
157 /** test solve */
158 public void testSolve() {
159 DecompositionSolver solver =
160 new LUDecompositionImpl(MatrixUtils.createRealMatrix(testData)).getSolver();
161 RealMatrix b = MatrixUtils.createRealMatrix(new double[][] {
162 { 1, 0 }, { 2, -5 }, { 3, 1 }
163 });
164 RealMatrix xRef = MatrixUtils.createRealMatrix(new double[][] {
165 { 19, -71 }, { -6, 22 }, { -2, 9 }
166 });
167
168 // using RealMatrix
169 assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 1.0e-13);
170
171 // using double[]
172 for (int i = 0; i < b.getColumnDimension(); ++i) {
173 assertEquals(0,
174 new ArrayRealVector(solver.solve(b.getColumn(i))).subtract(xRef.getColumnVector(i)).getNorm(),
175 1.0e-13);
176 }
177
178 // using ArrayRealVector
179 for (int i = 0; i < b.getColumnDimension(); ++i) {
180 assertEquals(0,
181 solver.solve(b.getColumnVector(i)).subtract(xRef.getColumnVector(i)).getNorm(),
182 1.0e-13);
183 }
184
185 // using RealVector with an alternate implementation
186 for (int i = 0; i < b.getColumnDimension(); ++i) {
187 ArrayRealVectorTest.RealVectorTestImpl v =
188 new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(i));
189 assertEquals(0,
190 solver.solve(v).subtract(xRef.getColumnVector(i)).getNorm(),
191 1.0e-13);
192 }
193
194 }
195
196 /** test determinant */
197 public void testDeterminant() {
198 assertEquals( -1, getDeterminant(MatrixUtils.createRealMatrix(testData)), 1.0e-15);
199 assertEquals(-10, getDeterminant(MatrixUtils.createRealMatrix(luData)), 1.0e-14);
200 assertEquals( 0, getDeterminant(MatrixUtils.createRealMatrix(singular)), 1.0e-17);
201 assertEquals( 0, getDeterminant(MatrixUtils.createRealMatrix(bigSingular)), 1.0e-10);
202 }
203
204 private double getDeterminant(RealMatrix m) {
205 return new LUDecompositionImpl(m).getDeterminant();
206 }
207
208 }