View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.linear;
24  
25  import org.hipparchus.exception.MathIllegalArgumentException;
26  import org.junit.Assert;
27  import org.junit.Test;
28  
29  public class LUSolverTest {
30      private double[][] testData = {
31              { 1.0, 2.0, 3.0},
32              { 2.0, 5.0, 3.0},
33              { 1.0, 0.0, 8.0}
34      };
35      private double[][] luData = {
36              { 2.0, 3.0, 3.0 },
37              { 0.0, 5.0, 7.0 },
38              { 6.0, 9.0, 8.0 }
39      };
40  
41      // singular matrices
42      private double[][] singular = {
43              { 2.0, 3.0 },
44              { 2.0, 3.0 }
45      };
46      private double[][] bigSingular = {
47              { 1.0, 2.0,   3.0,    4.0 },
48              { 2.0, 5.0,   3.0,    4.0 },
49              { 7.0, 3.0, 256.0, 1930.0 },
50              { 3.0, 7.0,   6.0,    8.0 }
51      }; // 4th row = 1st + 2nd
52  
53      /** test threshold impact */
54      @Test
55      public void testThreshold() {
56          final RealMatrix matrix = MatrixUtils.createRealMatrix(new double[][] {
57                                                         { 1.0, 2.0, 3.0},
58                                                         { 2.0, 5.0, 3.0},
59                                                         { 4.000001, 9.0, 9.0}
60                                                       });
61          Assert.assertFalse(new LUDecomposer(1.0e-5).decompose(matrix).isNonSingular());
62          Assert.assertTrue(new LUDecomposer(1.0e-10).decompose(matrix).isNonSingular());
63      }
64  
65      /** test singular */
66      @Test
67      public void testSingular() {
68          DecompositionSolver solver =
69              new LUDecomposition(MatrixUtils.createRealMatrix(testData)).getSolver();
70          Assert.assertTrue(solver.isNonSingular());
71          solver = new LUDecomposition(MatrixUtils.createRealMatrix(singular)).getSolver();
72          Assert.assertFalse(solver.isNonSingular());
73          solver = new LUDecomposition(MatrixUtils.createRealMatrix(bigSingular)).getSolver();
74          Assert.assertFalse(solver.isNonSingular());
75      }
76  
77      /** test solve dimension errors */
78      @Test
79      public void testSolveDimensionErrors() {
80          DecompositionSolver solver =
81              new LUDecomposition(MatrixUtils.createRealMatrix(testData)).getSolver();
82          RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
83          try {
84              solver.solve(b);
85              Assert.fail("an exception should have been thrown");
86          } catch (MathIllegalArgumentException iae) {
87              // expected behavior
88          }
89          try {
90              solver.solve(b.getColumnVector(0));
91              Assert.fail("an exception should have been thrown");
92          } catch (MathIllegalArgumentException iae) {
93              // expected behavior
94          }
95          try {
96              solver.solve(new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(0)));
97              Assert.fail("an exception should have been thrown");
98          } catch (MathIllegalArgumentException iae) {
99              // expected behavior
100         }
101     }
102 
103     /** test solve singularity errors */
104     @Test
105     public void testSolveSingularityErrors() {
106         DecompositionSolver solver =
107             new LUDecomposition(MatrixUtils.createRealMatrix(singular)).getSolver();
108         RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
109         try {
110             solver.solve(b);
111             Assert.fail("an exception should have been thrown");
112         } catch (MathIllegalArgumentException ime) {
113             // expected behavior
114         }
115         try {
116             solver.solve(b.getColumnVector(0));
117             Assert.fail("an exception should have been thrown");
118         } catch (MathIllegalArgumentException ime) {
119             // expected behavior
120         }
121         try {
122             solver.solve(new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(0)));
123             Assert.fail("an exception should have been thrown");
124         } catch (MathIllegalArgumentException ime) {
125             // expected behavior
126         }
127     }
128 
129     /** test solve */
130     @Test
131     public void testSolve() {
132         DecompositionSolver solver =
133             new LUDecomposition(MatrixUtils.createRealMatrix(testData)).getSolver();
134         RealMatrix b = MatrixUtils.createRealMatrix(new double[][] {
135                 { 1, 0 }, { 2, -5 }, { 3, 1 }
136         });
137         RealMatrix xRef = MatrixUtils.createRealMatrix(new double[][] {
138                 { 19, -71 }, { -6, 22 }, { -2, 9 }
139         });
140 
141         // using RealMatrix
142         Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm1(), 1.0e-13);
143 
144         // using ArrayRealVector
145         for (int i = 0; i < b.getColumnDimension(); ++i) {
146             Assert.assertEquals(0,
147                          solver.solve(b.getColumnVector(i)).subtract(xRef.getColumnVector(i)).getNorm(),
148                          1.0e-13);
149         }
150 
151         // using RealVector with an alternate implementation
152         for (int i = 0; i < b.getColumnDimension(); ++i) {
153             ArrayRealVectorTest.RealVectorTestImpl v =
154                 new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(i));
155             Assert.assertEquals(0,
156                          solver.solve(v).subtract(xRef.getColumnVector(i)).getNorm(),
157                          1.0e-13);
158         }
159     }
160 
161     /** test determinant */
162     @Test
163     public void testDeterminant() {
164         Assert.assertEquals( -1, getDeterminant(MatrixUtils.createRealMatrix(testData)), 1.0e-15);
165         Assert.assertEquals(-10, getDeterminant(MatrixUtils.createRealMatrix(luData)), 1.0e-14);
166         Assert.assertEquals(  0, getDeterminant(MatrixUtils.createRealMatrix(singular)), 1.0e-17);
167         Assert.assertEquals(  0, getDeterminant(MatrixUtils.createRealMatrix(bigSingular)), 1.0e-10);
168     }
169 
170     private double getDeterminant(RealMatrix m) {
171         return new LUDecomposition(m).getDeterminant();
172     }
173 }