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