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.hipparchus.fraction.Fraction;
27  import org.hipparchus.fraction.FractionField;
28  import org.junit.jupiter.api.Test;
29  
30  import static org.junit.jupiter.api.Assertions.assertEquals;
31  import static org.junit.jupiter.api.Assertions.assertFalse;
32  import static org.junit.jupiter.api.Assertions.assertTrue;
33  import static org.junit.jupiter.api.Assertions.fail;
34  
35  public class FieldLUSolverTest {
36      private int[][] testData = {
37              { 1, 2, 3},
38              { 2, 5, 3},
39              { 1, 0, 8}
40      };
41      private int[][] luData = {
42              { 2, 3, 3 },
43              { 0, 5, 7 },
44              { 6, 9, 8 }
45      };
46  
47      // singular matrices
48      private int[][] singular = {
49              { 2, 3 },
50              { 2, 3 }
51      };
52      private int[][] bigSingular = {
53              { 1, 2,   3,    4 },
54              { 2, 5,   3,    4 },
55              { 7, 3, 256, 1930 },
56              { 3, 7,   6,    8 }
57      }; // 4th row = 1st + 2nd
58  
59      public static FieldMatrix<Fraction> createFractionMatrix(final int[][] data) {
60          final int numRows = data.length;
61          final int numCols = data[0].length;
62          final Array2DRowFieldMatrix<Fraction> m;
63          m = new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(),
64                                                  numRows, numCols);
65          for (int i = 0; i < numRows; i++) {
66              for (int j = 0; j < numCols; j++) {
67                  m.setEntry(i, j, new Fraction(data[i][j], 1));
68              }
69          }
70          return m;
71      }
72  
73      /** test singular */
74      @Test
75      void testSingular() {
76          FieldDecompositionSolver<Fraction> solver;
77          solver = new FieldLUDecomposition<Fraction>(createFractionMatrix(testData))
78              .getSolver();
79          assertTrue(solver.isNonSingular());
80          solver = new FieldLUDecomposition<Fraction>(createFractionMatrix(singular))
81              .getSolver();
82          assertFalse(solver.isNonSingular());
83          solver = new FieldLUDecomposition<Fraction>(createFractionMatrix(bigSingular))
84              .getSolver();
85          assertFalse(solver.isNonSingular());
86      }
87  
88      /** test solve dimension errors */
89      @Test
90      void testSolveDimensionErrors() {
91          FieldDecompositionSolver<Fraction> solver;
92          solver = new FieldLUDecomposition<Fraction>(createFractionMatrix(testData))
93              .getSolver();
94          FieldMatrix<Fraction> b = createFractionMatrix(new int[2][2]);
95          try {
96              solver.solve(b);
97              fail("an exception should have been thrown");
98          } catch (MathIllegalArgumentException iae) {
99              // expected behavior
100         }
101         try {
102             solver.solve(b.getColumnVector(0));
103             fail("an exception should have been thrown");
104         } catch (MathIllegalArgumentException iae) {
105             // expected behavior
106         }
107     }
108 
109     /** test solve singularity errors */
110     @Test
111     void testSolveSingularityErrors() {
112         FieldDecompositionSolver<Fraction> solver;
113         solver = new FieldLUDecomposition<Fraction>(createFractionMatrix(singular))
114             .getSolver();
115         FieldMatrix<Fraction> b = createFractionMatrix(new int[2][2]);
116         try {
117             solver.solve(b);
118             fail("an exception should have been thrown");
119         } catch (MathIllegalArgumentException ime) {
120             // expected behavior
121         }
122         try {
123             solver.solve(b.getColumnVector(0));
124             fail("an exception should have been thrown");
125         } catch (MathIllegalArgumentException ime) {
126             // expected behavior
127         }
128     }
129 
130     /** test solve */
131     @Test
132     void testSolve() {
133         FieldDecompositionSolver<Fraction> solver;
134         solver = new FieldLUDecomposition<Fraction>(createFractionMatrix(testData))
135             .getSolver();
136         FieldMatrix<Fraction> b = createFractionMatrix(new int[][] {
137                 { 1, 0 }, { 2, -5 }, { 3, 1 }
138         });
139         FieldMatrix<Fraction> xRef = createFractionMatrix(new int[][] {
140                 { 19, -71 }, { -6, 22 }, { -2, 9 }
141         });
142 
143         // using FieldMatrix
144         FieldMatrix<Fraction> x = solver.solve(b);
145         for (int i = 0; i < x.getRowDimension(); i++){
146             for (int j = 0; j < x.getColumnDimension(); j++){
147                 assertEquals(xRef.getEntry(i, j), x.getEntry(i, j), "(" + i + ", " + j + ")");
148             }
149         }
150 
151         // using ArrayFieldVector
152         for (int j = 0; j < b.getColumnDimension(); j++) {
153             final FieldVector<Fraction> xj = solver.solve(b.getColumnVector(j));
154             for (int i = 0; i < xj.getDimension(); i++){
155                 assertEquals(xRef.getEntry(i, j), xj.getEntry(i), "(" + i + ", " + j + ")");
156             }
157         }
158 
159         // using SparseFieldVector
160         for (int j = 0; j < b.getColumnDimension(); j++) {
161             final SparseFieldVector<Fraction> bj;
162             bj = new SparseFieldVector<Fraction>(FractionField.getInstance(),
163                                                  b.getColumn(j));
164             final FieldVector<Fraction> xj = solver.solve(bj);
165             for (int i = 0; i < xj.getDimension(); i++) {
166                 assertEquals(xRef.getEntry(i, j), xj.getEntry(i), "(" + i + ", " + j + ")");
167             }
168         }
169     }
170 
171     /** test determinant */
172     @Test
173     void testDeterminant() {
174         assertEquals( -1, getDeterminant(createFractionMatrix(testData)), 1E-15);
175         assertEquals(-10, getDeterminant(createFractionMatrix(luData)), 1E-14);
176         assertEquals(  0, getDeterminant(createFractionMatrix(singular)), 1E-15);
177         assertEquals(  0, getDeterminant(createFractionMatrix(bigSingular)), 1E-15);
178     }
179 
180     private double getDeterminant(final FieldMatrix<Fraction> m) {
181         return new FieldLUDecomposition<Fraction>(m).getDeterminant().doubleValue();
182     }
183 }