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  package org.hipparchus.linear;
23  
24  import org.hipparchus.Field;
25  import org.hipparchus.exception.LocalizedCoreFormats;
26  import org.hipparchus.exception.MathIllegalArgumentException;
27  import org.hipparchus.exception.NullArgumentException;
28  import org.hipparchus.fraction.Fraction;
29  import org.hipparchus.fraction.FractionField;
30  import org.hipparchus.random.RandomGenerator;
31  import org.hipparchus.random.Well1024a;
32  import org.hipparchus.util.Binary64;
33  import org.hipparchus.util.Binary64Field;
34  import org.junit.jupiter.api.Test;
35  
36  import static org.junit.jupiter.api.Assertions.assertEquals;
37  import static org.junit.jupiter.api.Assertions.assertFalse;
38  import static org.junit.jupiter.api.Assertions.assertNotEquals;
39  import static org.junit.jupiter.api.Assertions.assertTrue;
40  import static org.junit.jupiter.api.Assertions.fail;
41  
42  /**
43   * Test cases for the {@link SparseFieldMatrix} class.
44   *
45   */
46  public class SparseFieldMatrixTest {
47      // 3 x 3 identity matrix
48      protected Fraction[][] id = { {new Fraction(1), new Fraction(0), new Fraction(0) }, { new Fraction(0), new Fraction(1), new Fraction(0) }, { new Fraction(0), new Fraction(0), new Fraction(1) } };
49      // Test data for group operations
50      protected Fraction[][] testData = { { new Fraction(1), new Fraction(2), new Fraction(3) }, { new Fraction(2), new Fraction(5), new Fraction(3) },
51              { new Fraction(1), new Fraction(0), new Fraction(8) } };
52      protected Fraction[][] testDataLU = null;
53      protected Fraction[][] testDataPlus2 = { { new Fraction(3), new Fraction(4), new Fraction(5) }, { new Fraction(4), new Fraction(7), new Fraction(5) },
54              { new Fraction(3), new Fraction(2), new Fraction(10) } };
55      protected Fraction[][] testDataMinus = { { new Fraction(-1), new Fraction(-2), new Fraction(-3) },
56              { new Fraction(-2), new Fraction(-5), new Fraction(-3) }, { new Fraction(-1), new Fraction(0), new Fraction(-8) } };
57      protected Fraction[] testDataRow1 = { new Fraction(1), new Fraction(2), new Fraction(3) };
58      protected Fraction[] testDataCol3 = { new Fraction(3), new Fraction(3), new Fraction(8) };
59      protected Fraction[][] testDataInv = { { new Fraction(-40), new Fraction(16), new Fraction(9) }, { new Fraction(13), new Fraction(-5), new Fraction(-3) },
60              { new Fraction(5), new Fraction(-2), new Fraction(-1) } };
61      protected Fraction[] preMultTest = { new Fraction(8), new Fraction(12), new Fraction(33) };
62      protected Fraction[][] testData2 = { { new Fraction(1), new Fraction(2), new Fraction(3) }, { new Fraction(2), new Fraction(5), new Fraction(3) } };
63      protected Fraction[][] testData2T = { { new Fraction(1), new Fraction(2) }, { new Fraction(2), new Fraction(5) }, { new Fraction(3), new Fraction(3) } };
64      protected Fraction[][] testDataPlusInv = { { new Fraction(-39), new Fraction(18), new Fraction(12) },
65              { new Fraction(15), new Fraction(0), new Fraction(0) }, { new Fraction(6), new Fraction(-2), new Fraction(7) } };
66  
67      // lu decomposition tests
68      protected Fraction[][] luData = { { new Fraction(2), new Fraction(3), new Fraction(3) }, { new Fraction(0), new Fraction(5), new Fraction(7) }, { new Fraction(6), new Fraction(9), new Fraction(8) } };
69      protected Fraction[][] luDataLUDecomposition = null;
70  
71      // singular matrices
72      protected Fraction[][] singular = { { new Fraction(2), new Fraction(3) }, { new Fraction(2), new Fraction(3) } };
73      protected Fraction[][] bigSingular = { { new Fraction(1), new Fraction(2), new Fraction(3), new Fraction(4) },
74              { new Fraction(2), new Fraction(5), new Fraction(3), new Fraction(4) }, { new Fraction(7), new Fraction(3), new Fraction(256), new Fraction(1930) }, { new Fraction(3), new Fraction(7), new Fraction(6), new Fraction(8) } }; // 4th
75  
76      // row
77      // =
78      // 1st
79      // +
80      // 2nd
81      protected Fraction[][] detData = { { new Fraction(1), new Fraction(2), new Fraction(3) }, { new Fraction(4), new Fraction(5), new Fraction(6) },
82              { new Fraction(7), new Fraction(8), new Fraction(10) } };
83      protected Fraction[][] detData2 = { { new Fraction(1), new Fraction(3) }, { new Fraction(2), new Fraction(4) } };
84  
85      // vectors
86      protected Fraction[] testVector = { new Fraction(1), new Fraction(2), new Fraction(3) };
87      protected Fraction[] testVector2 = { new Fraction(1), new Fraction(2), new Fraction(3), new Fraction(4) };
88  
89      // submatrix accessor tests
90      protected Fraction[][] subTestData = null;
91  
92      // array selections
93      protected Fraction[][] subRows02Cols13 = { {new Fraction(2), new Fraction(4) }, { new Fraction(4), new Fraction(8) } };
94      protected Fraction[][] subRows03Cols12 = { { new Fraction(2), new Fraction(3) }, { new Fraction(5), new Fraction(6) } };
95      protected Fraction[][] subRows03Cols123 = { { new Fraction(2), new Fraction(3), new Fraction(4) }, { new Fraction(5), new Fraction(6), new Fraction(7) } };
96  
97      // effective permutations
98      protected Fraction[][] subRows20Cols123 = { { new Fraction(4), new Fraction(6), new Fraction(8) }, { new Fraction(2), new Fraction(3), new Fraction(4) } };
99      protected Fraction[][] subRows31Cols31 = null;
100 
101     // contiguous ranges
102     protected Fraction[][] subRows01Cols23 = null;
103     protected Fraction[][] subRows23Cols00 = { { new Fraction(2) }, { new Fraction(4) } };
104     protected Fraction[][] subRows00Cols33 = { { new Fraction(4) } };
105 
106     // row matrices
107     protected Fraction[][] subRow0 = { { new Fraction(1), new Fraction(2), new Fraction(3), new Fraction(4) } };
108     protected Fraction[][] subRow3 = { { new Fraction(4), new Fraction(5), new Fraction(6), new Fraction(7) } };
109 
110     // column matrices
111     protected Fraction[][] subColumn1 = null;
112     protected Fraction[][] subColumn3 = null;
113 
114     // tolerances
115     protected double entryTolerance = 10E-16;
116     protected double normTolerance = 10E-14;
117     protected Field<Fraction> field = FractionField.getInstance();
118 
119     public SparseFieldMatrixTest() {
120             testDataLU = new Fraction[][]{ { new Fraction(2), new Fraction(5), new Fraction(3) }, { new Fraction(.5d), new Fraction(-2.5d), new Fraction(6.5d) },
121                     { new Fraction(0.5d), new Fraction(0.2d), new Fraction(.2d) } };
122             luDataLUDecomposition = new Fraction[][]{ { new Fraction(6), new Fraction(9), new Fraction(8) },
123                 { new Fraction(0), new Fraction(5), new Fraction(7) }, { new Fraction(0.33333333333333), new Fraction(0), new Fraction(0.33333333333333) } };
124             subTestData = new Fraction [][]{ { new Fraction(1), new Fraction(2), new Fraction(3), new Fraction(4) },
125                     { new Fraction(1.5), new Fraction(2.5), new Fraction(3.5), new Fraction(4.5) }, { new Fraction(2), new Fraction(4), new Fraction(6), new Fraction(8) }, { new Fraction(4), new Fraction(5), new Fraction(6), new Fraction(7) } };
126             subRows31Cols31 = new Fraction[][]{ { new Fraction(7), new Fraction(5) }, { new Fraction(4.5), new Fraction(2.5) } };
127             subRows01Cols23 = new Fraction[][]{ { new Fraction(3), new Fraction(4) }, { new Fraction(3.5), new Fraction(4.5) } };
128             subColumn1 = new Fraction [][]{ { new Fraction(2) }, { new Fraction(2.5) }, { new Fraction(4) }, { new Fraction(5) } };
129             subColumn3 = new Fraction[][]{ { new Fraction(4) }, { new Fraction(4.5) }, { new Fraction(8) }, { new Fraction(7) } };
130     }
131 
132     /** test dimensions */
133     @Test
134     void testDimensions() {
135         SparseFieldMatrix<Fraction> m = createSparseMatrix(testData);
136         SparseFieldMatrix<Fraction> m2 = createSparseMatrix(testData2);
137         assertEquals(3, m.getRowDimension(), "testData row dimension");
138         assertEquals(3, m.getColumnDimension(), "testData column dimension");
139         assertTrue(m.isSquare(), "testData is square");
140         assertEquals(2, m2.getRowDimension(), "testData2 row dimension");
141         assertEquals(3, m2.getColumnDimension(), "testData2 column dimension");
142         assertFalse(m2.isSquare(), "testData2 is not square");
143     }
144 
145     /** test copy functions */
146     @Test
147     void testCopyFunctions() {
148         SparseFieldMatrix<Fraction> m1 = createSparseMatrix(testData);
149         FieldMatrix<Fraction> m2 = m1.copy();
150         assertEquals(m1.getClass(), m2.getClass());
151         assertEquals((m2), m1);
152         SparseFieldMatrix<Fraction> m3 = createSparseMatrix(testData);
153         FieldMatrix<Fraction> m4 = m3.copy();
154         assertEquals(m3.getClass(), m4.getClass());
155         assertEquals((m4), m3);
156     }
157 
158     /** test add */
159     @Test
160     void testAdd() {
161         SparseFieldMatrix<Fraction> m = createSparseMatrix(testData);
162         SparseFieldMatrix<Fraction> mInv = createSparseMatrix(testDataInv);
163         SparseFieldMatrix<Fraction> mDataPlusInv = createSparseMatrix(testDataPlusInv);
164         FieldMatrix<Fraction> mPlusMInv = m.add(mInv);
165         for (int row = 0; row < m.getRowDimension(); row++) {
166             for (int col = 0; col < m.getColumnDimension(); col++) {
167                 assertEquals(mDataPlusInv.getEntry(row, col).doubleValue(), mPlusMInv.getEntry(row, col).doubleValue(),
168                     entryTolerance,
169                     "sum entry entry");
170             }
171         }
172     }
173 
174     /** test add failure */
175     @Test
176     void testAddFail() {
177         SparseFieldMatrix<Fraction> m = createSparseMatrix(testData);
178         SparseFieldMatrix<Fraction> m2 = createSparseMatrix(testData2);
179         try {
180             m.add(m2);
181             fail("MathIllegalArgumentException expected");
182         } catch (MathIllegalArgumentException ex) {
183             // ignored
184         }
185     }
186 
187 
188     /** test m-n = m + -n */
189     @Test
190     void testPlusMinus() {
191         SparseFieldMatrix<Fraction> m = createSparseMatrix(testData);
192         SparseFieldMatrix<Fraction> n = createSparseMatrix(testDataInv);
193         customAssertClose("m-n = m + -n", m.subtract(n),
194                           n.scalarMultiply(new Fraction(-1)).add(m), entryTolerance);
195         try {
196             m.subtract(createSparseMatrix(testData2));
197             fail("Expecting illegalArgumentException");
198         } catch (MathIllegalArgumentException ex) {
199             // ignored
200         }
201     }
202 
203     /** test multiply */
204     @Test
205     void testMultiply() {
206         SparseFieldMatrix<Fraction> m = createSparseMatrix(testData);
207         SparseFieldMatrix<Fraction> mInv = createSparseMatrix(testDataInv);
208         SparseFieldMatrix<Fraction> identity = createSparseMatrix(id);
209         SparseFieldMatrix<Fraction> m2 = createSparseMatrix(testData2);
210         customAssertClose("inverse multiply", m.multiply(mInv), identity,
211                           entryTolerance);
212         customAssertClose("inverse multiply", m.multiply(new Array2DRowFieldMatrix<Fraction>(FractionField.getInstance(), testDataInv)), identity,
213                           entryTolerance);
214         customAssertClose("inverse multiply", mInv.multiply(m), identity,
215                           entryTolerance);
216         customAssertClose("identity multiply", m.multiply(identity), m,
217                           entryTolerance);
218         customAssertClose("identity multiply", identity.multiply(mInv), mInv,
219                           entryTolerance);
220         customAssertClose("identity multiply", m2.multiply(identity), m2,
221                           entryTolerance);
222         try {
223             m.multiply(createSparseMatrix(bigSingular));
224             fail("Expecting illegalArgumentException");
225         } catch (MathIllegalArgumentException ex) {
226             // ignored
227         }
228     }
229 
230     // Additional Test for Array2DRowRealMatrixTest.testMultiply
231 
232     private Fraction[][] d3 = new Fraction[][] { { new Fraction(1), new Fraction(2), new Fraction(3), new Fraction(4) }, { new Fraction(5), new Fraction(6), new Fraction(7), new Fraction(8) } };
233     private Fraction[][] d4 = new Fraction[][] { { new Fraction(1) }, { new Fraction(2) }, { new Fraction(3) }, { new Fraction(4) } };
234     private Fraction[][] d5 = new Fraction[][] { { new Fraction(30) }, { new Fraction(70) } };
235 
236     @Test
237     void testMultiply2() {
238         FieldMatrix<Fraction> m3 = createSparseMatrix(d3);
239         FieldMatrix<Fraction> m4 = createSparseMatrix(d4);
240         FieldMatrix<Fraction> m5 = createSparseMatrix(d5);
241         customAssertClose("m3*m4=m5", m3.multiply(m4), m5, entryTolerance);
242     }
243 
244     @Test
245     void testMultiplyTransposedSparseFieldMatrix() {
246         RandomGenerator randomGenerator = new Well1024a(0x5f31d5645cf821efl);
247         final FieldMatrixChangingVisitor<Binary64> randomSetter = new DefaultFieldMatrixChangingVisitor<Binary64>(Binary64Field.getInstance().getZero()) {
248             public Binary64 visit(final int row, final int column, final Binary64 value) {
249                 return new Binary64(randomGenerator.nextDouble());
250             }
251         };
252         final FieldMatrixPreservingVisitor<Binary64> zeroChecker = new DefaultFieldMatrixPreservingVisitor<Binary64>(Binary64Field.getInstance().getZero()) {
253             public void visit(final int row, final int column, final Binary64 value) {
254                 assertEquals(0.0, value.doubleValue(), 3.0e-14);
255             }
256         };
257         for (int rows = 1; rows <= 64; rows += 7) {
258             for (int cols = 1; cols <= 64; cols += 7) {
259                 final SparseFieldMatrix<Binary64> a = new SparseFieldMatrix<>(Binary64Field.getInstance(), rows, cols);
260                 a.walkInOptimizedOrder(randomSetter);
261                 for (int interm = 1; interm <= 64; interm += 7) {
262                     final SparseFieldMatrix<Binary64> b = new SparseFieldMatrix<>(Binary64Field.getInstance(), interm, cols);
263                     b.walkInOptimizedOrder(randomSetter);
264                    a.multiplyTransposed(b).subtract(a.multiply(b.transpose())).walkInOptimizedOrder(zeroChecker);
265                 }
266             }
267         }
268     }
269 
270     @Test
271     void testMultiplyTransposedWrongDimensions() {
272         try {
273             new SparseFieldMatrix<>(Binary64Field.getInstance(), 2, 3).
274             multiplyTransposed(new SparseFieldMatrix<>(Binary64Field.getInstance(), 3, 2));
275             fail("an exception should have been thrown");
276         } catch (MathIllegalArgumentException miae) {
277             assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
278             assertEquals(3, ((Integer) miae.getParts()[0]).intValue());
279             assertEquals(2, ((Integer) miae.getParts()[1]).intValue());
280         }
281     }
282 
283     @Test
284     void testTransposeMultiplySparseFieldMatrix() {
285         RandomGenerator randomGenerator = new Well1024a(0x5f31d5645cf821efl);
286         final FieldMatrixChangingVisitor<Binary64> randomSetter = new DefaultFieldMatrixChangingVisitor<Binary64>(Binary64Field.getInstance().getZero()) {
287             public Binary64 visit(final int row, final int column, final Binary64 value) {
288                 return new Binary64(randomGenerator.nextDouble());
289             }
290         };
291         final FieldMatrixPreservingVisitor<Binary64> zeroChecker = new DefaultFieldMatrixPreservingVisitor<Binary64>(Binary64Field.getInstance().getZero()) {
292             public void visit(final int row, final int column, final Binary64 value) {
293                 assertEquals(0.0, value.doubleValue(), 3.0e-14);
294             }
295         };
296         for (int rows = 1; rows <= 64; rows += 7) {
297             for (int cols = 1; cols <= 64; cols += 7) {
298                 final SparseFieldMatrix<Binary64> a = new SparseFieldMatrix<>(Binary64Field.getInstance(), rows, cols);
299                 a.walkInOptimizedOrder(randomSetter);
300                 for (int interm = 1; interm <= 64; interm += 7) {
301                     final SparseFieldMatrix<Binary64> b = new SparseFieldMatrix<>(Binary64Field.getInstance(), rows, interm);
302                     b.walkInOptimizedOrder(randomSetter);
303                    a.transposeMultiply(b).subtract(a.transpose().multiply(b)).walkInOptimizedOrder(zeroChecker);
304                 }
305             }
306         }
307     }
308 
309     @Test
310     void testTransposeMultiplyWrongDimensions() {
311         try {
312             new SparseFieldMatrix<>(Binary64Field.getInstance(), 2, 3).
313             transposeMultiply(new SparseFieldMatrix<>(Binary64Field.getInstance(), 3, 2));
314             fail("an exception should have been thrown");
315         } catch (MathIllegalArgumentException miae) {
316             assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
317             assertEquals(2, ((Integer) miae.getParts()[0]).intValue());
318             assertEquals(3, ((Integer) miae.getParts()[1]).intValue());
319         }
320     }
321 
322     /** test trace */
323     @Test
324     void testTrace() {
325         FieldMatrix<Fraction> m = createSparseMatrix(id);
326         assertEquals(3d, m.getTrace().doubleValue(), entryTolerance, "identity trace");
327         m = createSparseMatrix(testData2);
328         try {
329             m.getTrace();
330             fail("Expecting MathIllegalArgumentException");
331         } catch (MathIllegalArgumentException ex) {
332             // ignored
333         }
334     }
335 
336     /** test sclarAdd */
337     @Test
338     void testScalarAdd() {
339         FieldMatrix<Fraction> m = createSparseMatrix(testData);
340         customAssertClose("scalar add", createSparseMatrix(testDataPlus2),
341                           m.scalarAdd(new Fraction(2)), entryTolerance);
342     }
343 
344     /** test operate */
345     @Test
346     void testOperate() {
347         FieldMatrix<Fraction> m = createSparseMatrix(id);
348         customAssertClose("identity operate", testVector, m.operate(testVector),
349                           entryTolerance);
350         customAssertClose("identity operate", testVector, m.operate(
351                 new ArrayFieldVector<Fraction>(testVector)).toArray(), entryTolerance);
352         m = createSparseMatrix(bigSingular);
353         try {
354             m.operate(testVector);
355             fail("Expecting illegalArgumentException");
356         } catch (MathIllegalArgumentException ex) {
357             // ignored
358         }
359     }
360 
361     /** test issue MATH-209 */
362     @Test
363     void testMath209() {
364         FieldMatrix<Fraction> a = createSparseMatrix(new Fraction[][] {
365                 { new Fraction(1), new Fraction(2) }, { new Fraction(3), new Fraction(4) }, { new Fraction(5), new Fraction(6) } });
366         Fraction[] b = a.operate(new Fraction[] { new Fraction(1), new Fraction(1) });
367         assertEquals(a.getRowDimension(), b.length);
368         assertEquals(3.0, b[0].doubleValue(), 1.0e-12);
369         assertEquals(7.0, b[1].doubleValue(), 1.0e-12);
370         assertEquals(11.0, b[2].doubleValue(), 1.0e-12);
371     }
372 
373     /** test transpose */
374     @Test
375     void testTranspose() {
376         FieldMatrix<Fraction> m = createSparseMatrix(testData);
377         FieldMatrix<Fraction> mIT = new FieldLUDecomposition<Fraction>(m).getSolver().getInverse().transpose();
378         FieldMatrix<Fraction> mTI = new FieldLUDecomposition<Fraction>(m.transpose()).getSolver().getInverse();
379         customAssertClose("inverse-transpose", mIT, mTI, normTolerance);
380         m = createSparseMatrix(testData2);
381         FieldMatrix<Fraction> mt = createSparseMatrix(testData2T);
382         customAssertClose("transpose", mt, m.transpose(), normTolerance);
383     }
384 
385     /** test preMultiply by vector */
386     @Test
387     void testPremultiplyVector() {
388         FieldMatrix<Fraction> m = createSparseMatrix(testData);
389         customAssertClose("premultiply", m.preMultiply(testVector), preMultTest,
390                           normTolerance);
391         customAssertClose("premultiply", m.preMultiply(
392             new ArrayFieldVector<Fraction>(testVector).toArray()), preMultTest, normTolerance);
393         m = createSparseMatrix(bigSingular);
394         try {
395             m.preMultiply(testVector);
396             fail("expecting MathIllegalArgumentException");
397         } catch (MathIllegalArgumentException ex) {
398             // ignored
399         }
400     }
401 
402     @Test
403     void testPremultiply() {
404         FieldMatrix<Fraction> m3 = createSparseMatrix(d3);
405         FieldMatrix<Fraction> m4 = createSparseMatrix(d4);
406         FieldMatrix<Fraction> m5 = createSparseMatrix(d5);
407         customAssertClose("m3*m4=m5", m4.preMultiply(m3), m5, entryTolerance);
408 
409         SparseFieldMatrix<Fraction> m = createSparseMatrix(testData);
410         SparseFieldMatrix<Fraction> mInv = createSparseMatrix(testDataInv);
411         SparseFieldMatrix<Fraction> identity = createSparseMatrix(id);
412         customAssertClose("inverse multiply", m.preMultiply(mInv), identity,
413                           entryTolerance);
414         customAssertClose("inverse multiply", mInv.preMultiply(m), identity,
415                           entryTolerance);
416         customAssertClose("identity multiply", m.preMultiply(identity), m,
417                           entryTolerance);
418         customAssertClose("identity multiply", identity.preMultiply(mInv), mInv,
419                           entryTolerance);
420         try {
421             m.preMultiply(createSparseMatrix(bigSingular));
422             fail("Expecting illegalArgumentException");
423         } catch (MathIllegalArgumentException ex) {
424             // ignored
425         }
426     }
427 
428     @Test
429     void testGetVectors() {
430         FieldMatrix<Fraction> m = createSparseMatrix(testData);
431         customAssertClose("get row", m.getRow(0), testDataRow1, entryTolerance);
432         customAssertClose("get col", m.getColumn(2), testDataCol3, entryTolerance);
433         try {
434             m.getRow(10);
435             fail("expecting MathIllegalArgumentException");
436         } catch (MathIllegalArgumentException ex) {
437             // ignored
438         }
439         try {
440             m.getColumn(-1);
441             fail("expecting MathIllegalArgumentException");
442         } catch (MathIllegalArgumentException ex) {
443             // ignored
444         }
445     }
446 
447     @Test
448     void testGetEntry() {
449         FieldMatrix<Fraction> m = createSparseMatrix(testData);
450         assertEquals(2d, m.getEntry(0, 1).doubleValue(), entryTolerance, "get entry");
451         try {
452             m.getEntry(10, 4);
453             fail("Expecting MathIllegalArgumentException");
454         } catch (MathIllegalArgumentException ex) {
455             // expected
456         }
457     }
458 
459     /** test examples in user guide */
460     @Test
461     void testExamples() {
462         // Create a real matrix with two rows and three columns
463         Fraction[][] matrixData = { { new Fraction(1), new Fraction(2), new Fraction(3) }, { new Fraction(2), new Fraction(5), new Fraction(3) } };
464         FieldMatrix<Fraction> m = createSparseMatrix(matrixData);
465         // One more with three rows, two columns
466         Fraction[][] matrixData2 = { { new Fraction(1), new Fraction(2) }, { new Fraction(2), new Fraction(5) }, { new Fraction(1), new Fraction(7) } };
467         FieldMatrix<Fraction> n = createSparseMatrix(matrixData2);
468         // Now multiply m by n
469         FieldMatrix<Fraction> p = m.multiply(n);
470         assertEquals(2, p.getRowDimension());
471         assertEquals(2, p.getColumnDimension());
472         // Invert p
473         FieldMatrix<Fraction> pInverse = new FieldLUDecomposition<Fraction>(p).getSolver().getInverse();
474         assertEquals(2, pInverse.getRowDimension());
475         assertEquals(2, pInverse.getColumnDimension());
476 
477         // Solve example
478         Fraction[][] coefficientsData = { { new Fraction(2), new Fraction(3), new Fraction(-2) }, { new Fraction(-1), new Fraction(7), new Fraction(6) },
479                 { new Fraction(4), new Fraction(-3), new Fraction(-5) } };
480         FieldMatrix<Fraction> coefficients = createSparseMatrix(coefficientsData);
481         Fraction[] constants = { new Fraction(1), new Fraction(-2), new Fraction(1) };
482         Fraction[] solution;
483         solution = new FieldLUDecomposition<Fraction>(coefficients)
484             .getSolver()
485             .solve(new ArrayFieldVector<Fraction>(constants, false)).toArray();
486         assertEquals((new Fraction(2).multiply((solution[0])).add(new Fraction(3).multiply(solution[1])).subtract(new Fraction(2).multiply(solution[2]))).doubleValue(),
487                 constants[0].doubleValue(), 1E-12);
488         assertEquals(((new Fraction(-1).multiply(solution[0])).add(new Fraction(7).multiply(solution[1])).add(new Fraction(6).multiply(solution[2]))).doubleValue(),
489                 constants[1].doubleValue(), 1E-12);
490         assertEquals(((new Fraction(4).multiply(solution[0])).subtract(new Fraction(3).multiply( solution[1])).subtract(new Fraction(5).multiply(solution[2]))).doubleValue(),
491                 constants[2].doubleValue(), 1E-12);
492 
493     }
494 
495     // test submatrix accessors
496     @Test
497     void testSubMatrix() {
498         FieldMatrix<Fraction> m = createSparseMatrix(subTestData);
499         FieldMatrix<Fraction> mRows23Cols00 = createSparseMatrix(subRows23Cols00);
500         FieldMatrix<Fraction> mRows00Cols33 = createSparseMatrix(subRows00Cols33);
501         FieldMatrix<Fraction> mRows01Cols23 = createSparseMatrix(subRows01Cols23);
502         FieldMatrix<Fraction> mRows02Cols13 = createSparseMatrix(subRows02Cols13);
503         FieldMatrix<Fraction> mRows03Cols12 = createSparseMatrix(subRows03Cols12);
504         FieldMatrix<Fraction> mRows03Cols123 = createSparseMatrix(subRows03Cols123);
505         FieldMatrix<Fraction> mRows20Cols123 = createSparseMatrix(subRows20Cols123);
506         FieldMatrix<Fraction> mRows31Cols31 = createSparseMatrix(subRows31Cols31);
507         assertEquals(mRows23Cols00, m.getSubMatrix(2, 3, 0, 0), "Rows23Cols00");
508         assertEquals(mRows00Cols33, m.getSubMatrix(0, 0, 3, 3), "Rows00Cols33");
509         assertEquals(mRows01Cols23, m.getSubMatrix(0, 1, 2, 3), "Rows01Cols23");
510         assertEquals(mRows02Cols13,
511             m.getSubMatrix(new int[] { 0, 2 }, new int[] { 1, 3 }),
512             "Rows02Cols13");
513         assertEquals(mRows03Cols12,
514             m.getSubMatrix(new int[] { 0, 3 }, new int[] { 1, 2 }),
515             "Rows03Cols12");
516         assertEquals(mRows03Cols123,
517             m.getSubMatrix(new int[] { 0, 3 }, new int[] { 1, 2, 3 }),
518             "Rows03Cols123");
519         assertEquals(mRows20Cols123,
520             m.getSubMatrix(new int[] { 2, 0 }, new int[] { 1, 2, 3 }),
521             "Rows20Cols123");
522         assertEquals(mRows31Cols31,
523             m.getSubMatrix(new int[] { 3, 1 }, new int[] { 3, 1 }),
524             "Rows31Cols31");
525         assertEquals(mRows31Cols31,
526             m.getSubMatrix(new int[] { 3, 1 }, new int[] { 3, 1 }),
527             "Rows31Cols31");
528 
529         try {
530             m.getSubMatrix(1, 0, 2, 4);
531             fail("Expecting MathIllegalArgumentException");
532         } catch (MathIllegalArgumentException ex) {
533             // expected
534         }
535         try {
536             m.getSubMatrix(-1, 1, 2, 2);
537             fail("Expecting MathIllegalArgumentException");
538         } catch (MathIllegalArgumentException ex) {
539             // expected
540         }
541         try {
542             m.getSubMatrix(1, 0, 2, 2);
543             fail("Expecting MathIllegalArgumentException");
544         } catch (MathIllegalArgumentException ex) {
545             // expected
546         }
547         try {
548             m.getSubMatrix(1, 0, 2, 4);
549             fail("Expecting MathIllegalArgumentException");
550         } catch (MathIllegalArgumentException ex) {
551             // expected
552         }
553         try {
554             m.getSubMatrix(new int[] {}, new int[] { 0 });
555             fail("Expecting MathIllegalArgumentException");
556         } catch (MathIllegalArgumentException ex) {
557             // expected
558         }
559         try {
560             m.getSubMatrix(new int[] { 0 }, new int[] { 4 });
561             fail("Expecting MathIllegalArgumentException");
562         } catch (MathIllegalArgumentException ex) {
563             // expected
564         }
565     }
566 
567     @Test
568     void testGetRowMatrix() {
569         FieldMatrix<Fraction> m = createSparseMatrix(subTestData);
570         FieldMatrix<Fraction> mRow0 = createSparseMatrix(subRow0);
571         FieldMatrix<Fraction> mRow3 = createSparseMatrix(subRow3);
572         assertEquals(mRow0, m.getRowMatrix(0), "Row0");
573         assertEquals(mRow3, m.getRowMatrix(3), "Row3");
574         try {
575             m.getRowMatrix(-1);
576             fail("Expecting MathIllegalArgumentException");
577         } catch (MathIllegalArgumentException ex) {
578             // expected
579         }
580         try {
581             m.getRowMatrix(4);
582             fail("Expecting MathIllegalArgumentException");
583         } catch (MathIllegalArgumentException ex) {
584             // expected
585         }
586     }
587 
588     @Test
589     void testGetColumnMatrix() {
590         FieldMatrix<Fraction> m = createSparseMatrix(subTestData);
591         FieldMatrix<Fraction> mColumn1 = createSparseMatrix(subColumn1);
592         FieldMatrix<Fraction> mColumn3 = createSparseMatrix(subColumn3);
593         assertEquals(mColumn1, m.getColumnMatrix(1), "Column1");
594         assertEquals(mColumn3, m.getColumnMatrix(3), "Column3");
595         try {
596             m.getColumnMatrix(-1);
597             fail("Expecting MathIllegalArgumentException");
598         } catch (MathIllegalArgumentException ex) {
599             // expected
600         }
601         try {
602             m.getColumnMatrix(4);
603             fail("Expecting MathIllegalArgumentException");
604         } catch (MathIllegalArgumentException ex) {
605             // expected
606         }
607     }
608 
609     @Test
610     void testGetRowVector() {
611         FieldMatrix<Fraction> m = createSparseMatrix(subTestData);
612         FieldVector<Fraction> mRow0 = new ArrayFieldVector<Fraction>(subRow0[0]);
613         FieldVector<Fraction> mRow3 = new ArrayFieldVector<Fraction>(subRow3[0]);
614         assertEquals(mRow0, m.getRowVector(0), "Row0");
615         assertEquals(mRow3, m.getRowVector(3), "Row3");
616         try {
617             m.getRowVector(-1);
618             fail("Expecting MathIllegalArgumentException");
619         } catch (MathIllegalArgumentException ex) {
620             // expected
621         }
622         try {
623             m.getRowVector(4);
624             fail("Expecting MathIllegalArgumentException");
625         } catch (MathIllegalArgumentException ex) {
626             // expected
627         }
628     }
629 
630     @Test
631     void testGetColumnVector() {
632         FieldMatrix<Fraction> m = createSparseMatrix(subTestData);
633         FieldVector<Fraction> mColumn1 = columnToVector(subColumn1);
634         FieldVector<Fraction> mColumn3 = columnToVector(subColumn3);
635         assertEquals(mColumn1, m.getColumnVector(1), "Column1");
636         assertEquals(mColumn3, m.getColumnVector(3), "Column3");
637         try {
638             m.getColumnVector(-1);
639             fail("Expecting MathIllegalArgumentException");
640         } catch (MathIllegalArgumentException ex) {
641             // expected
642         }
643         try {
644             m.getColumnVector(4);
645             fail("Expecting MathIllegalArgumentException");
646         } catch (MathIllegalArgumentException ex) {
647             // expected
648         }
649     }
650 
651     private FieldVector<Fraction> columnToVector(Fraction[][] column) {
652         Fraction[] data = new Fraction[column.length];
653         for (int i = 0; i < data.length; ++i) {
654             data[i] = column[i][0];
655         }
656         return new ArrayFieldVector<Fraction>(data, false);
657     }
658 
659     @Test
660     void testEqualsAndHashCode() {
661         SparseFieldMatrix<Fraction> m = createSparseMatrix(testData);
662         SparseFieldMatrix<Fraction> m1 = (SparseFieldMatrix<Fraction>) m.copy();
663         SparseFieldMatrix<Fraction> mt = (SparseFieldMatrix<Fraction>) m.transpose();
664         assertTrue(m.hashCode() != mt.hashCode());
665         assertEquals(m.hashCode(), m1.hashCode());
666         assertEquals(m, m);
667         assertEquals(m, m1);
668         assertNotEquals(null, m);
669         assertNotEquals(m, mt);
670         assertNotEquals(m, createSparseMatrix(bigSingular));
671     }
672 
673     /* Disable for now
674     @Test
675     public void testToString() {
676         SparseFieldMatrix<Fraction> m = createSparseMatrix(testData);
677         Assertions.assertEquals("SparseFieldMatrix<Fraction>{{1.0,2.0,3.0},{2.0,5.0,3.0},{1.0,0.0,8.0}}",
678             m.toString());
679         m = new SparseFieldMatrix<Fraction>(field, 1, 1);
680         Assertions.assertEquals("SparseFieldMatrix<Fraction>{{0.0}}", m.toString());
681     }
682     */
683 
684     @Test
685     void testSetSubMatrix() {
686         SparseFieldMatrix<Fraction> m = createSparseMatrix(testData);
687         m.setSubMatrix(detData2, 1, 1);
688         FieldMatrix<Fraction> expected = createSparseMatrix(new Fraction[][] {
689                 { new Fraction(1), new Fraction(2), new Fraction(3) }, { new Fraction(2), new Fraction(1), new Fraction(3) }, { new Fraction(1), new Fraction(2), new Fraction(4) } });
690         assertEquals(expected, m);
691 
692         m.setSubMatrix(detData2, 0, 0);
693         expected = createSparseMatrix(new Fraction[][] {
694                 { new Fraction(1), new Fraction(3), new Fraction(3) }, { new Fraction(2), new Fraction(4), new Fraction(3) }, { new Fraction(1), new Fraction(2), new Fraction(4) } });
695         assertEquals(expected, m);
696 
697         m.setSubMatrix(testDataPlus2, 0, 0);
698         expected = createSparseMatrix(new Fraction[][] {
699                 { new Fraction(3), new Fraction(4), new Fraction(5) }, { new Fraction(4), new Fraction(7), new Fraction(5) }, { new Fraction(3), new Fraction(2), new Fraction(10) } });
700         assertEquals(expected, m);
701 
702         // javadoc example
703         SparseFieldMatrix<Fraction> matrix =
704             createSparseMatrix(new Fraction[][] {
705         { new Fraction(1), new Fraction(2), new Fraction(3), new Fraction(4) }, { new Fraction(5), new Fraction(6), new Fraction(7), new Fraction(8) }, { new Fraction(9), new Fraction(0), new Fraction(1), new Fraction(2) } });
706         matrix.setSubMatrix(new Fraction[][] { { new Fraction(3), new Fraction(4) }, { new Fraction(5), new Fraction(6) } }, 1, 1);
707         expected = createSparseMatrix(new Fraction[][] {
708                 { new Fraction(1), new Fraction(2), new Fraction(3), new Fraction(4) }, { new Fraction(5), new Fraction(3), new Fraction(4), new Fraction(8) }, { new Fraction(9), new Fraction(5), new Fraction(6), new Fraction(2) } });
709         assertEquals(expected, matrix);
710 
711         // dimension overflow
712         try {
713             m.setSubMatrix(testData, 1, 1);
714             fail("expecting MathIllegalArgumentException");
715         } catch (MathIllegalArgumentException e) {
716             // expected
717         }
718         // dimension underflow
719         try {
720             m.setSubMatrix(testData, -1, 1);
721             fail("expecting MathIllegalArgumentException");
722         } catch (MathIllegalArgumentException e) {
723             // expected
724         }
725         try {
726             m.setSubMatrix(testData, 1, -1);
727             fail("expecting MathIllegalArgumentException");
728         } catch (MathIllegalArgumentException e) {
729             // expected
730         }
731 
732         // null
733         try {
734             m.setSubMatrix(null, 1, 1);
735             fail("expecting NullArgumentException");
736         } catch (NullArgumentException e) {
737             // expected
738         }
739         try {
740             new SparseFieldMatrix<Fraction>(field, 0, 0);
741             fail("expecting MathIllegalArgumentException");
742         } catch (MathIllegalArgumentException e) {
743             // expected
744         }
745 
746         // ragged
747         try {
748             m.setSubMatrix(new Fraction[][] { { new Fraction(1) }, { new Fraction(2), new Fraction(3) } }, 0, 0);
749             fail("expecting MathIllegalArgumentException");
750         } catch (MathIllegalArgumentException e) {
751             // expected
752         }
753 
754         // empty
755         try {
756             m.setSubMatrix(new Fraction[][] { {} }, 0, 0);
757             fail("expecting MathIllegalArgumentException");
758         } catch (MathIllegalArgumentException e) {
759             // expected
760         }
761     }
762 
763     // --------------- -----------------Protected methods
764 
765     /** verifies that two matrices are close (1-norm) */
766     protected void customAssertClose(String msg, FieldMatrix<Fraction> m, FieldMatrix<Fraction> n,
767                                      double tolerance) {
768         for(int i=0; i < m.getRowDimension(); i++){
769             for(int j=0; j < m.getColumnDimension(); j++){
770                 assertEquals(m.getEntry(i,j).doubleValue(), n.getEntry(i,j).doubleValue(), tolerance, msg);
771             }
772 
773         }
774     }
775 
776     /** verifies that two vectors are close (sup norm) */
777     protected void customAssertClose(String msg, Fraction[] m, Fraction[] n,
778                                      double tolerance) {
779         if (m.length != n.length) {
780             fail("vectors not same length");
781         }
782         for (int i = 0; i < m.length; i++) {
783             assertEquals(m[i].doubleValue(), n[i].doubleValue(),
784                     tolerance,
785                     msg + " " + i + " elements differ");
786         }
787     }
788 
789     private SparseFieldMatrix<Fraction> createSparseMatrix(Fraction[][] data) {
790         SparseFieldMatrix<Fraction> matrix = new SparseFieldMatrix<Fraction>(field, data.length, data[0].length);
791         for (int row = 0; row < data.length; row++) {
792             for (int col = 0; col < data[row].length; col++) {
793                 matrix.setEntry(row, col, data[row][col]);
794             }
795         }
796         return matrix;
797     }
798 }