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 java.util.Random;
26  
27  import org.hipparchus.exception.MathIllegalArgumentException;
28  import org.hipparchus.util.Precision;
29  import org.junit.Assert;
30  import org.junit.Test;
31  
32  public class EigenSolverTest {
33  
34      private double[][] bigSingular = {
35          { 1.0, 2.0,   3.0,    4.0 },
36          { 2.0, 5.0,   3.0,    4.0 },
37          { 7.0, 3.0, 256.0, 1930.0 },
38          { 3.0, 7.0,   6.0,    8.0 }
39      }; // 4th row = 1st + 2nd
40  
41      /** test non invertible matrix */
42      @Test
43      public void testNonInvertible() {
44          Random r = new Random(9994100315209l);
45          RealMatrix m =
46              EigenDecompositionSymmetricTest.createTestMatrix(r, new double[] { 1.0, 0.0, -1.0, -2.0, -3.0 });
47          DecompositionSolver es = new EigenDecompositionSymmetric(m).getSolver();
48          Assert.assertFalse(es.isNonSingular());
49          try {
50              es.getInverse();
51              Assert.fail("an exception should have been thrown");
52          } catch (MathIllegalArgumentException ime) {
53              // expected behavior
54          }
55      }
56  
57      /** test invertible matrix */
58      @Test
59      public void testInvertible() {
60          Random r = new Random(9994100315209l);
61          RealMatrix m =
62              EigenDecompositionSymmetricTest.createTestMatrix(r, new double[] { 1.0, 0.5, -1.0, -2.0, -3.0 });
63          DecompositionSolver es = new EigenDecompositionSymmetric(m).getSolver();
64          Assert.assertTrue(es.isNonSingular());
65          RealMatrix inverse = es.getInverse();
66          RealMatrix error =
67              m.multiply(inverse).subtract(MatrixUtils.createRealIdentityMatrix(m.getRowDimension()));
68          Assert.assertEquals(0, error.getNorm1(), 4.0e-15);
69      }
70  
71      /**
72       * Verifies operation on very small values.
73       * Matrix with eigenvalues {8e-100, -1e-100, -1e-100}
74       */
75      @Test
76      public void testInvertibleTinyValues() {
77          final double tiny = 1e-100;
78          RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {
79                  {3,  2,  4},
80                  {2,  0,  2},
81                  {4,  2,  3}
82          });
83          m = m.scalarMultiply(tiny);
84  
85          final EigenDecompositionSymmetric ed = new EigenDecompositionSymmetric(m);
86          RealMatrix inv = ed.getSolver().getInverse();
87  
88          final RealMatrix id = m.multiply(inv);
89          for (int i = 0; i < m.getRowDimension(); i++) {
90              for (int j = 0; j < m.getColumnDimension(); j++) {
91                  if (i == j) {
92                      Assert.assertTrue(Precision.equals(1, id.getEntry(i, j), 1e-15));
93                  } else {
94                      Assert.assertTrue(Precision.equals(0, id.getEntry(i, j), 1e-15));
95                  }
96              }
97          }
98      }
99  
100     @Test(expected=MathIllegalArgumentException.class)
101     public void testNonInvertibleMath1045() {
102         EigenDecompositionSymmetric eigen =
103             new EigenDecompositionSymmetric(MatrixUtils.createRealMatrix(bigSingular));
104         eigen.getSolver().getInverse();
105     }
106 
107     @Test(expected=MathIllegalArgumentException.class)
108     public void testZeroMatrix() {
109         EigenDecompositionSymmetric eigen =
110             new EigenDecompositionSymmetric(MatrixUtils.createRealMatrix(new double[][] {{0}}));
111         eigen.getSolver().getInverse();
112     }
113 
114     /** test solve dimension errors */
115     @Test
116     public void testSolveDimensionErrors() {
117         final double[] refValues = new double[] {
118             2.003, 2.002, 2.001, 1.001, 1.000, 0.001
119         };
120         final RealMatrix matrix = EigenDecompositionSymmetricTest.createTestMatrix(new Random(35992629946426l), refValues);
121 
122         DecompositionSolver es = new EigenDecompositionSymmetric(matrix).getSolver();
123         RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
124         try {
125             es.solve(b);
126             Assert.fail("an exception should have been thrown");
127         } catch (MathIllegalArgumentException iae) {
128             // expected behavior
129         }
130         try {
131             es.solve(b.getColumnVector(0));
132             Assert.fail("an exception should have been thrown");
133         } catch (MathIllegalArgumentException iae) {
134             // expected behavior
135         }
136         try {
137             es.solve(new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(0)));
138             Assert.fail("an exception should have been thrown");
139         } catch (MathIllegalArgumentException iae) {
140             // expected behavior
141         }
142     }
143 
144     /** test solve */
145     @Test
146     public void testSolve() {
147         RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {
148                 { 91,  5, 29, 32, 40, 14 },
149                 {  5, 34, -1,  0,  2, -1 },
150                 { 29, -1, 12,  9, 21,  8 },
151                 { 32,  0,  9, 14,  9,  0 },
152                 { 40,  2, 21,  9, 51, 19 },
153                 { 14, -1,  8,  0, 19, 14 }
154         });
155         DecompositionSolver es = new EigenDecompositionSymmetric(m).getSolver();
156         RealMatrix b = MatrixUtils.createRealMatrix(new double[][] {
157                 { 1561, 269, 188 },
158                 {   69, -21,  70 },
159                 {  739, 108,  63 },
160                 {  324,  86,  59 },
161                 { 1624, 194, 107 },
162                 {  796,  69,  36 }
163         });
164         RealMatrix xRef = MatrixUtils.createRealMatrix(new double[][] {
165                 { 1,   2, 1 },
166                 { 2,  -1, 2 },
167                 { 4,   2, 3 },
168                 { 8,  -1, 0 },
169                 { 16,  2, 0 },
170                 { 32, -1, 0 }
171         });
172 
173         // using RealMatrix
174         RealMatrix solution=es.solve(b);
175         Assert.assertEquals(0, solution.subtract(xRef).getNorm1(), 2.5e-12);
176 
177         // using RealVector
178         for (int i = 0; i < b.getColumnDimension(); ++i) {
179             Assert.assertEquals(0,
180                          es.solve(b.getColumnVector(i)).subtract(xRef.getColumnVector(i)).getNorm(),
181                          2.0e-11);
182         }
183 
184         // using RealVector with an alternate implementation
185         for (int i = 0; i < b.getColumnDimension(); ++i) {
186             ArrayRealVectorTest.RealVectorTestImpl v =
187                 new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(i));
188             Assert.assertEquals(0,
189                          es.solve(v).subtract(xRef.getColumnVector(i)).getNorm(),
190                          2.0e-11);
191         }
192     }
193 }