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.math3.linear;
019
020 import org.apache.commons.math3.exception.MathIllegalArgumentException;
021
022 import org.junit.Test;
023 import org.junit.Assert;
024
025 public class LUSolverTest {
026 private double[][] testData = {
027 { 1.0, 2.0, 3.0},
028 { 2.0, 5.0, 3.0},
029 { 1.0, 0.0, 8.0}
030 };
031 private double[][] luData = {
032 { 2.0, 3.0, 3.0 },
033 { 0.0, 5.0, 7.0 },
034 { 6.0, 9.0, 8.0 }
035 };
036
037 // singular matrices
038 private double[][] singular = {
039 { 2.0, 3.0 },
040 { 2.0, 3.0 }
041 };
042 private double[][] bigSingular = {
043 { 1.0, 2.0, 3.0, 4.0 },
044 { 2.0, 5.0, 3.0, 4.0 },
045 { 7.0, 3.0, 256.0, 1930.0 },
046 { 3.0, 7.0, 6.0, 8.0 }
047 }; // 4th row = 1st + 2nd
048
049 /** test threshold impact */
050 @Test
051 public void testThreshold() {
052 final RealMatrix matrix = MatrixUtils.createRealMatrix(new double[][] {
053 { 1.0, 2.0, 3.0},
054 { 2.0, 5.0, 3.0},
055 { 4.000001, 9.0, 9.0}
056 });
057 Assert.assertFalse(new LUDecomposition(matrix, 1.0e-5).getSolver().isNonSingular());
058 Assert.assertTrue(new LUDecomposition(matrix, 1.0e-10).getSolver().isNonSingular());
059 }
060
061 /** test singular */
062 @Test
063 public void testSingular() {
064 DecompositionSolver solver =
065 new LUDecomposition(MatrixUtils.createRealMatrix(testData)).getSolver();
066 Assert.assertTrue(solver.isNonSingular());
067 solver = new LUDecomposition(MatrixUtils.createRealMatrix(singular)).getSolver();
068 Assert.assertFalse(solver.isNonSingular());
069 solver = new LUDecomposition(MatrixUtils.createRealMatrix(bigSingular)).getSolver();
070 Assert.assertFalse(solver.isNonSingular());
071 }
072
073 /** test solve dimension errors */
074 @Test
075 public void testSolveDimensionErrors() {
076 DecompositionSolver solver =
077 new LUDecomposition(MatrixUtils.createRealMatrix(testData)).getSolver();
078 RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
079 try {
080 solver.solve(b);
081 Assert.fail("an exception should have been thrown");
082 } catch (MathIllegalArgumentException iae) {
083 // expected behavior
084 }
085 try {
086 solver.solve(b.getColumnVector(0));
087 Assert.fail("an exception should have been thrown");
088 } catch (MathIllegalArgumentException iae) {
089 // expected behavior
090 }
091 try {
092 solver.solve(new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(0)));
093 Assert.fail("an exception should have been thrown");
094 } catch (MathIllegalArgumentException iae) {
095 // expected behavior
096 }
097 }
098
099 /** test solve singularity errors */
100 @Test
101 public void testSolveSingularityErrors() {
102 DecompositionSolver solver =
103 new LUDecomposition(MatrixUtils.createRealMatrix(singular)).getSolver();
104 RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
105 try {
106 solver.solve(b);
107 Assert.fail("an exception should have been thrown");
108 } catch (SingularMatrixException ime) {
109 // expected behavior
110 }
111 try {
112 solver.solve(b.getColumnVector(0));
113 Assert.fail("an exception should have been thrown");
114 } catch (SingularMatrixException ime) {
115 // expected behavior
116 }
117 try {
118 solver.solve(new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(0)));
119 Assert.fail("an exception should have been thrown");
120 } catch (SingularMatrixException ime) {
121 // expected behavior
122 }
123 }
124
125 /** test solve */
126 @Test
127 public void testSolve() {
128 DecompositionSolver solver =
129 new LUDecomposition(MatrixUtils.createRealMatrix(testData)).getSolver();
130 RealMatrix b = MatrixUtils.createRealMatrix(new double[][] {
131 { 1, 0 }, { 2, -5 }, { 3, 1 }
132 });
133 RealMatrix xRef = MatrixUtils.createRealMatrix(new double[][] {
134 { 19, -71 }, { -6, 22 }, { -2, 9 }
135 });
136
137 // using RealMatrix
138 Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 1.0e-13);
139
140 // using ArrayRealVector
141 for (int i = 0; i < b.getColumnDimension(); ++i) {
142 Assert.assertEquals(0,
143 solver.solve(b.getColumnVector(i)).subtract(xRef.getColumnVector(i)).getNorm(),
144 1.0e-13);
145 }
146
147 // using RealVector with an alternate implementation
148 for (int i = 0; i < b.getColumnDimension(); ++i) {
149 ArrayRealVectorTest.RealVectorTestImpl v =
150 new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(i));
151 Assert.assertEquals(0,
152 solver.solve(v).subtract(xRef.getColumnVector(i)).getNorm(),
153 1.0e-13);
154 }
155 }
156
157 /** test determinant */
158 @Test
159 public void testDeterminant() {
160 Assert.assertEquals( -1, getDeterminant(MatrixUtils.createRealMatrix(testData)), 1.0e-15);
161 Assert.assertEquals(-10, getDeterminant(MatrixUtils.createRealMatrix(luData)), 1.0e-14);
162 Assert.assertEquals( 0, getDeterminant(MatrixUtils.createRealMatrix(singular)), 1.0e-17);
163 Assert.assertEquals( 0, getDeterminant(MatrixUtils.createRealMatrix(bigSingular)), 1.0e-10);
164 }
165
166 private double getDeterminant(RealMatrix m) {
167 return new LUDecomposition(m).getDeterminant();
168 }
169 }