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    *      http://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  package org.apache.commons.math.linear;
18  
19  import junit.framework.Test;
20  import junit.framework.TestCase;
21  import junit.framework.TestSuite;
22  
23  import java.math.BigDecimal;
24  
25  
26  /**
27   * Test cases for the {@link BigMatrixImpl} class.
28   *
29   * @version $Revision: 790372 $ $Date: 2009-07-01 16:48:19 -0400 (Wed, 01 Jul 2009) $
30   */
31  @Deprecated
32  public final class BigMatrixImplTest extends TestCase {
33      
34      // Test data for String constructors
35      protected  String[][] testDataString = { {"1","2","3"}, {"2","5","3"}, {"1","0","8"} };
36      
37      // 3 x 3 identity matrix
38      protected double[][] id = { {1d,0d,0d}, {0d,1d,0d}, {0d,0d,1d} };
39      
40      // Test data for group operations
41      protected double[][] testData = { {1d,2d,3d}, {2d,5d,3d}, {1d,0d,8d} };
42      protected double[][] testDataLU = {{2d, 5d, 3d}, {.5d, -2.5d, 6.5d}, {0.5d, 0.2d, .2d}};
43      protected double[][] testDataPlus2 = { {3d,4d,5d}, {4d,7d,5d}, {3d,2d,10d} };
44      protected double[][] testDataMinus = { {-1d,-2d,-3d}, {-2d,-5d,-3d}, 
45              {-1d,0d,-8d} };
46      protected double[] testDataRow1 = {1d,2d,3d};
47      protected double[] testDataCol3 = {3d,3d,8d};
48      protected double[][] testDataInv = 
49          { {-40d,16d,9d}, {13d,-5d,-3d}, {5d,-2d,-1d} };
50      protected double[] preMultTest = {8,12,33};
51      protected double[][] testData2 ={ {1d,2d,3d}, {2d,5d,3d}};
52      protected double[][] testData2T = { {1d,2d}, {2d,5d}, {3d,3d}};
53      protected double[][] testDataPlusInv = 
54          { {-39d,18d,12d}, {15d,0d,0d}, {6d,-2d,7d} };
55      
56      // lu decomposition tests
57      protected double[][] luData = { {2d,3d,3d}, {0d,5d,7d}, {6d,9d,8d} };
58      protected double[][] luDataLUDecomposition = { {6d,9d,8d}, {0d,5d,7d},
59              {0.33333333333333,0d,0.33333333333333} };
60      
61      // singular matrices
62      protected double[][] singular = { {2d,3d}, {2d,3d} };
63      protected double[][] bigSingular = {{1d,2d,3d,4d}, {2d,5d,3d,4d},
64              {7d,3d,256d,1930d}, {3d,7d,6d,8d}}; // 4th row = 1st + 2nd
65      protected double[][] detData = { {1d,2d,3d}, {4d,5d,6d}, {7d,8d,10d} };
66      protected double[][] detData2 = { {1d, 3d}, {2d, 4d}};
67      
68      // vectors
69      protected double[] testVector = {1,2,3};
70      protected double[] testVector2 = {1,2,3,4};
71      
72      // submatrix accessor tests
73      protected double[][] subTestData = {{1, 2, 3, 4}, {1.5, 2.5, 3.5, 4.5},
74              {2, 4, 6, 8}, {4, 5, 6, 7}}; 
75      // array selections
76      protected double[][] subRows02Cols13 = { {2, 4}, {4, 8}};
77      protected double[][] subRows03Cols12 = { {2, 3}, {5, 6}};
78      protected double[][] subRows03Cols123 = { {2, 3, 4} , {5, 6, 7}};
79      // effective permutations
80      protected double[][] subRows20Cols123 = { {4, 6, 8} , {2, 3, 4}};
81      protected double[][] subRows31Cols31 = {{7, 5}, {4.5, 2.5}};
82      // contiguous ranges
83      protected double[][] subRows01Cols23 = {{3,4} , {3.5, 4.5}};
84      protected double[][] subRows23Cols00 = {{2} , {4}};
85      protected double[][] subRows00Cols33 = {{4}};
86      // row matrices
87      protected double[][] subRow0 = {{1,2,3,4}};
88      protected double[][] subRow3 = {{4,5,6,7}};
89      // column matrices
90      protected double[][] subColumn1 = {{2}, {2.5}, {4}, {5}};
91      protected double[][] subColumn3 = {{4}, {4.5}, {8}, {7}};
92      
93      // tolerances
94      protected double entryTolerance = 10E-16;
95      protected double normTolerance = 10E-14;
96      
97      public BigMatrixImplTest(String name) {
98          super(name);
99      }
100     
101     public static Test suite() {
102         TestSuite suite = new TestSuite(BigMatrixImplTest.class);
103         suite.setName("BigMatrixImpl Tests");
104         return suite;
105     }
106 
107     public static final double[] asDouble(BigDecimal[] data) {
108         double d[] = new double[data.length];
109         for (int i=0;i<d.length;i++) {
110             d[i] = data[i].doubleValue();
111         }
112         return d;
113     }
114 
115     public static final double[][] asDouble(BigDecimal[][] data) {
116         double d[][] = new double[data.length][data[0].length];
117         for (int i=0;i<d.length;i++) {
118             for (int j=0;j<d[i].length;j++)
119             d[i][j] = data[i][j].doubleValue();
120         }
121         return d;
122     }
123 
124     public static final BigDecimal[] asBigDecimal(double [] data) {
125         BigDecimal d[] = new BigDecimal[data.length];
126         for (int i=0;i<d.length;i++) {
127             d[i] = new BigDecimal(data[i]);
128         }
129         return d;
130     }
131 
132     public static final BigDecimal[][] asBigDecimal(double [][] data) {
133         BigDecimal d[][] = new BigDecimal[data.length][data[0].length];
134         for (int i=0;i<d.length;i++) {
135             for (int j=0;j<data[i].length;j++) {
136                 d[i][j] = new BigDecimal(data[i][j]);
137             }
138         }
139         return d;
140     }
141 
142     /** test dimensions */
143     public void testDimensions() {
144         BigMatrixImpl m = new BigMatrixImpl(testData);
145         BigMatrixImpl m2 = new BigMatrixImpl(testData2);
146         assertEquals("testData row dimension",3,m.getRowDimension());
147         assertEquals("testData column dimension",3,m.getColumnDimension());
148         assertTrue("testData is square",m.isSquare());
149         assertEquals("testData2 row dimension",m2.getRowDimension(),2);
150         assertEquals("testData2 column dimension",m2.getColumnDimension(),3);
151         assertTrue("testData2 is not square",!m2.isSquare());
152     }  
153     
154     /** test copy functions */
155     public void testCopyFunctions() {
156         BigMatrixImpl m1 = new BigMatrixImpl(testData);
157         BigMatrixImpl m2 = new BigMatrixImpl(m1.getData());
158         assertEquals(m2,m1);
159         BigMatrixImpl m3 = new BigMatrixImpl(testData);
160         BigMatrixImpl m4 = new BigMatrixImpl(m3.getData(), false);
161         assertEquals(m4,m3);
162     }
163     
164     /** test constructors */
165     public void testConstructors() {
166         BigMatrix m1 = new BigMatrixImpl(testData);
167         BigMatrix m2 = new BigMatrixImpl(testDataString);
168         BigMatrix m3 = new BigMatrixImpl(asBigDecimal(testData));
169         BigMatrix m4 = new BigMatrixImpl(asBigDecimal(testData), true);
170         BigMatrix m5 = new BigMatrixImpl(asBigDecimal(testData), false);
171         assertClose("double, string", m1, m2, Double.MIN_VALUE);
172         assertClose("double, BigDecimal", m1, m3, Double.MIN_VALUE);
173         assertClose("string, BigDecimal", m2, m3, Double.MIN_VALUE);
174         assertClose("double, BigDecimal/true", m1, m4, Double.MIN_VALUE);
175         assertClose("double, BigDecimal/false", m1, m5, Double.MIN_VALUE);
176         try {
177             new BigMatrixImpl(new String[][] {{"0", "hello", "1"}});
178             fail("Expecting NumberFormatException");
179         } catch (NumberFormatException ex) {
180             // expected
181         }
182         try {
183             new BigMatrixImpl(new String[][] {});
184             fail("Expecting IllegalArgumentException");
185         } catch (IllegalArgumentException ex) {
186             // expected
187         }
188         try {
189             new BigMatrixImpl(new String[][] {{},{}});
190             fail("Expecting IllegalArgumentException");
191         } catch (IllegalArgumentException ex) {
192             // expected
193         }
194         try {
195             new BigMatrixImpl(new String[][] {{"a", "b"},{"c"}});
196             fail("Expecting IllegalArgumentException");
197         } catch (IllegalArgumentException ex) {
198             // expected
199         }
200 
201         try {
202             new BigMatrixImpl(0, 1);
203             fail("Expecting IllegalArgumentException");
204         } catch (IllegalArgumentException ex) {
205             // expected
206         }
207         try {
208             new BigMatrixImpl(1, 0);
209             fail("Expecting IllegalArgumentException");
210         } catch (IllegalArgumentException ex) {
211             // expected
212         }
213     }
214     
215     /** test add */
216     public void testAdd() {
217         BigMatrixImpl m = new BigMatrixImpl(testData);
218         BigMatrixImpl mInv = new BigMatrixImpl(testDataInv);
219         BigMatrix mPlusMInv = m.add(mInv);
220         double[][] sumEntries = asDouble(mPlusMInv.getData());
221         for (int row = 0; row < m.getRowDimension(); row++) {
222             for (int col = 0; col < m.getColumnDimension(); col++) {
223                 assertEquals("sum entry entry",
224                     testDataPlusInv[row][col],sumEntries[row][col],
225                         entryTolerance);
226             }
227         }    
228     }
229     
230     /** test add failure */
231     public void testAddFail() {
232         BigMatrixImpl m = new BigMatrixImpl(testData);
233         BigMatrixImpl m2 = new BigMatrixImpl(testData2);
234         try {
235             m.add(m2);
236             fail("IllegalArgumentException expected");
237         } catch (IllegalArgumentException ex) {
238             // ignored
239         }
240     }
241     
242     /** test norm */
243     public void testNorm() {
244         BigMatrixImpl m = new BigMatrixImpl(testData);
245         BigMatrixImpl m2 = new BigMatrixImpl(testData2);
246         assertEquals("testData norm",14d,m.getNorm().doubleValue(),entryTolerance);
247         assertEquals("testData2 norm",7d,m2.getNorm().doubleValue(),entryTolerance);
248     }
249     
250      /** test m-n = m + -n */
251     public void testPlusMinus() {
252         BigMatrixImpl m = new BigMatrixImpl(testData);
253         BigMatrixImpl m2 = new BigMatrixImpl(testDataInv);
254         assertClose("m-n = m + -n",m.subtract(m2),
255             m2.scalarMultiply(new BigDecimal(-1d)).add(m),entryTolerance);
256         try {
257             m.subtract(new BigMatrixImpl(testData2));
258             fail("Expecting illegalArgumentException");
259         } catch (IllegalArgumentException ex) {
260             // ignored
261         }      
262     }
263    
264     /** test multiply */
265      public void testMultiply() {
266         BigMatrixImpl m = new BigMatrixImpl(testData);
267         BigMatrixImpl mInv = new BigMatrixImpl(testDataInv);
268         BigMatrixImpl identity = new BigMatrixImpl(id);
269         BigMatrixImpl m2 = new BigMatrixImpl(testData2);
270         assertClose("inverse multiply",m.multiply(mInv),
271             identity,entryTolerance);
272         assertClose("inverse multiply",mInv.multiply(m),
273             identity,entryTolerance);
274         assertClose("identity multiply",m.multiply(identity),
275             m,entryTolerance);
276         assertClose("identity multiply",identity.multiply(mInv),
277             mInv,entryTolerance);
278         assertClose("identity multiply",m2.multiply(identity),
279             m2,entryTolerance); 
280         try {
281             m.multiply(new BigMatrixImpl(bigSingular));
282             fail("Expecting illegalArgumentException");
283         } catch (IllegalArgumentException ex) {
284             // ignored
285         }      
286     }   
287     
288     //Additional Test for BigMatrixImplTest.testMultiply
289 
290     private double[][] d3 = new double[][] {{1,2,3,4},{5,6,7,8}};
291     private double[][] d4 = new double[][] {{1},{2},{3},{4}};
292     private double[][] d5 = new double[][] {{30},{70}};
293      
294     public void testMultiply2() { 
295        BigMatrix m3 = new BigMatrixImpl(d3);
296        BigMatrix m4 = new BigMatrixImpl(d4);
297        BigMatrix m5 = new BigMatrixImpl(d5);
298        assertClose("m3*m4=m5", m3.multiply(m4), m5, entryTolerance);
299    }  
300         
301     /** test isSingular */
302     public void testIsSingular() {
303         BigMatrixImpl m = new BigMatrixImpl(singular);
304         assertTrue("singular",m.isSingular());
305         m = new BigMatrixImpl(bigSingular);
306         assertTrue("big singular",m.isSingular());
307         m = new BigMatrixImpl(id);
308         assertTrue("identity nonsingular",!m.isSingular());
309         m = new BigMatrixImpl(testData);
310         assertTrue("testData nonsingular",!m.isSingular());
311     }
312         
313     /** test inverse */
314     public void testInverse() {
315         BigMatrixImpl m = new BigMatrixImpl(testData);
316         BigMatrix mInv = new BigMatrixImpl(testDataInv);
317         assertClose("inverse",mInv,m.inverse(),normTolerance);
318         assertClose("inverse^2",m,m.inverse().inverse(),10E-12);
319         
320         // Not square
321         m = new BigMatrixImpl(testData2);
322         try {
323             m.inverse();
324             fail("Expecting InvalidMatrixException");
325         } catch (InvalidMatrixException ex) {
326             // expected
327         }
328         
329         // Singular
330         m = new BigMatrixImpl(singular);
331         try {
332             m.inverse();
333             fail("Expecting InvalidMatrixException");
334         } catch (InvalidMatrixException ex) {
335             // expected
336         }
337     }
338     
339     /** test solve */
340     public void testSolve() {
341         BigMatrixImpl m = new BigMatrixImpl(testData);
342         BigMatrix mInv = new BigMatrixImpl(testDataInv);
343         // being a bit slothful here -- actually testing that X = A^-1 * B
344         assertClose("inverse-operate",
345                     asDouble(mInv.operate(asBigDecimal(testVector))),
346                     asDouble(m.solve(asBigDecimal(testVector))),
347                     normTolerance);
348         try {
349             asDouble(m.solve(asBigDecimal(testVector2)));
350             fail("expecting IllegalArgumentException");
351         } catch (IllegalArgumentException ex) {
352             // ignored
353         }       
354         BigMatrix bs = new BigMatrixImpl(bigSingular);
355         try {
356             bs.solve(bs);
357             fail("Expecting InvalidMatrixException");
358         } catch (InvalidMatrixException ex) {
359             // ignored
360         }
361         try {
362             m.solve(bs);
363             fail("Expecting IllegalArgumentException");
364         } catch (IllegalArgumentException ex) {
365             // ignored
366         }
367         try {
368             new BigMatrixImpl(testData2).solve(bs);
369             fail("Expecting illegalArgumentException");
370         } catch (IllegalArgumentException ex) {
371             // ignored
372         } 
373         try {
374             (new BigMatrixImpl(testData2)).luDecompose();
375             fail("Expecting InvalidMatrixException");
376         } catch (InvalidMatrixException ex) {
377             // ignored
378         }  
379     }
380     
381     /** test determinant */
382     public void testDeterminant() {       
383         BigMatrix m = new BigMatrixImpl(bigSingular);
384         assertEquals("singular determinant",0,m.getDeterminant().doubleValue(),0);
385         m = new BigMatrixImpl(detData);
386         assertEquals("nonsingular test",-3d,m.getDeterminant().doubleValue(),normTolerance);
387         
388         // Examples verified against R (version 1.8.1, Red Hat Linux 9)
389         m = new BigMatrixImpl(detData2);
390         assertEquals("nonsingular R test 1",-2d,m.getDeterminant().doubleValue(),normTolerance);
391         m = new BigMatrixImpl(testData);
392         assertEquals("nonsingular  R test 2",-1d,m.getDeterminant().doubleValue(),normTolerance);
393 
394         try {
395             double d = new BigMatrixImpl(testData2).getDeterminant().doubleValue();
396             fail("Expecting InvalidMatrixException, got " + d);
397         } catch (InvalidMatrixException ex) {
398             // ignored
399         }      
400     }
401     
402     /** test trace */
403     public void testTrace() {
404         BigMatrix m = new BigMatrixImpl(id);
405         assertEquals("identity trace",3d,m.getTrace().doubleValue(),entryTolerance);
406         m = new BigMatrixImpl(testData2);
407         try {
408             double t = m.getTrace().doubleValue();
409             fail("Expecting NonSquareMatrixException, got " + t);
410         } catch (NonSquareMatrixException ex) {
411             // ignored
412         }      
413     }
414     
415     /** test sclarAdd */
416     public void testScalarAdd() {
417         BigMatrix m = new BigMatrixImpl(testData);
418         assertClose("scalar add",new BigMatrixImpl(testDataPlus2),
419             m.scalarAdd(new BigDecimal(2d)),entryTolerance);
420     }
421                     
422     /** test operate */
423     public void testOperate() {
424         BigMatrix m = new BigMatrixImpl(id);
425         double[] x = asDouble(m.operate(asBigDecimal(testVector)));
426         assertClose("identity operate",testVector,x,entryTolerance);
427         m = new BigMatrixImpl(bigSingular);
428         try {
429             asDouble(m.operate(asBigDecimal(testVector)));
430             fail("Expecting illegalArgumentException");
431         } catch (IllegalArgumentException ex) {
432             // ignored
433         }      
434     }
435 
436     /** test issue MATH-209 */
437     public void testMath209() {
438         BigMatrix a = new BigMatrixImpl(new BigDecimal[][] {
439                 { new BigDecimal(1), new BigDecimal(2) },
440                 { new BigDecimal(3), new BigDecimal(4) },
441                 { new BigDecimal(5), new BigDecimal(6) }
442         }, false);
443         BigDecimal[] b = a.operate(new BigDecimal[] { new BigDecimal(1), new BigDecimal(1) });
444         assertEquals(a.getRowDimension(), b.length);
445         assertEquals( 3.0, b[0].doubleValue(), 1.0e-12);
446         assertEquals( 7.0, b[1].doubleValue(), 1.0e-12);
447         assertEquals(11.0, b[2].doubleValue(), 1.0e-12);
448     }
449     
450     /** test transpose */
451     public void testTranspose() {
452         BigMatrix m = new BigMatrixImpl(testData);
453         assertClose("inverse-transpose",m.inverse().transpose(),
454             m.transpose().inverse(),normTolerance);
455         m = new BigMatrixImpl(testData2);
456         BigMatrix mt = new BigMatrixImpl(testData2T);
457         assertClose("transpose",mt,m.transpose(),normTolerance);
458     }
459     
460     /** test preMultiply by vector */
461     public void testPremultiplyVector() {
462         BigMatrix m = new BigMatrixImpl(testData);
463         assertClose("premultiply",asDouble(m.preMultiply(asBigDecimal(testVector))),preMultTest,normTolerance);
464         m = new BigMatrixImpl(bigSingular);
465         try {
466             m.preMultiply(asBigDecimal(testVector));
467             fail("expecting IllegalArgumentException");
468         } catch (IllegalArgumentException ex) {
469             // ignored
470         }
471     }
472     
473     public void testPremultiply() {
474         BigMatrix m3 = new BigMatrixImpl(d3);
475         BigMatrix m4 = new BigMatrixImpl(d4);
476         BigMatrix m5 = new BigMatrixImpl(d5);
477         assertClose("m3*m4=m5", m4.preMultiply(m3), m5, entryTolerance);
478         
479         BigMatrixImpl m = new BigMatrixImpl(testData);
480         BigMatrixImpl mInv = new BigMatrixImpl(testDataInv);
481         BigMatrixImpl identity = new BigMatrixImpl(id);
482         new BigMatrixImpl(testData2);
483         assertClose("inverse multiply",m.preMultiply(mInv),
484                 identity,entryTolerance);
485         assertClose("inverse multiply",mInv.preMultiply(m),
486                 identity,entryTolerance);
487         assertClose("identity multiply",m.preMultiply(identity),
488                 m,entryTolerance);
489         assertClose("identity multiply",identity.preMultiply(mInv),
490                 mInv,entryTolerance);
491         try {
492             m.preMultiply(new BigMatrixImpl(bigSingular));
493             fail("Expecting illegalArgumentException");
494         } catch (IllegalArgumentException ex) {
495             // ignored
496         }      
497     }
498     
499     public void testGetVectors() {
500         BigMatrix m = new BigMatrixImpl(testData);
501         assertClose("get row",m.getRowAsDoubleArray(0),testDataRow1,entryTolerance);
502         assertClose("get col",m.getColumnAsDoubleArray(2),testDataCol3,entryTolerance);
503         try {
504             m.getRowAsDoubleArray(10);
505             fail("expecting MatrixIndexException");
506         } catch (MatrixIndexException ex) {
507             // ignored
508         }
509         try {
510             m.getColumnAsDoubleArray(-1);
511             fail("expecting MatrixIndexException");
512         } catch (MatrixIndexException ex) {
513             // ignored
514         }
515     }
516       
517     public void testLUDecomposition() throws Exception {
518         BigMatrixImpl m = new BigMatrixImpl(testData);
519         BigMatrix lu = m.getLUMatrix();
520         assertClose("LU decomposition", lu, new BigMatrixImpl(testDataLU), normTolerance);
521         verifyDecomposition(m, lu);
522         m = new BigMatrixImpl(luData);
523         lu = m.getLUMatrix();
524         assertClose("LU decomposition", lu, new BigMatrixImpl(luDataLUDecomposition), normTolerance);
525         verifyDecomposition(m, lu);
526         m = new BigMatrixImpl(testDataMinus);
527         lu = m.getLUMatrix();
528         verifyDecomposition(m, lu);
529         m = new BigMatrixImpl(id);
530         lu = m.getLUMatrix();
531         verifyDecomposition(m, lu);
532         try {
533             m = new BigMatrixImpl(bigSingular); // singular
534             lu = m.getLUMatrix();
535             fail("Expecting InvalidMatrixException");
536         } catch (InvalidMatrixException ex) {
537             // expected
538         }
539         try {
540             m = new BigMatrixImpl(testData2);  // not square
541             lu = m.getLUMatrix();
542             fail("Expecting InvalidMatrixException");
543         } catch (InvalidMatrixException ex) {
544             // expected
545         }
546     }
547     
548    /**
549     * test submatrix accessors
550     */
551     public void testSubMatrix() {
552         BigMatrix m = new BigMatrixImpl(subTestData);
553         BigMatrix mRows23Cols00 = new BigMatrixImpl(subRows23Cols00);
554         BigMatrix mRows00Cols33 = new BigMatrixImpl(subRows00Cols33);
555         BigMatrix mRows01Cols23 = new BigMatrixImpl(subRows01Cols23);
556         BigMatrix mRows02Cols13 = new BigMatrixImpl(subRows02Cols13);
557         BigMatrix mRows03Cols12 = new BigMatrixImpl(subRows03Cols12);
558         BigMatrix mRows03Cols123 = new BigMatrixImpl(subRows03Cols123);
559         BigMatrix mRows20Cols123 = new BigMatrixImpl(subRows20Cols123);
560         BigMatrix mRows31Cols31 = new BigMatrixImpl(subRows31Cols31);
561         assertEquals("Rows23Cols00", mRows23Cols00, 
562                 m.getSubMatrix(2 , 3 , 0, 0));
563         assertEquals("Rows00Cols33", mRows00Cols33, 
564                 m.getSubMatrix(0 , 0 , 3, 3));
565         assertEquals("Rows01Cols23", mRows01Cols23,
566                 m.getSubMatrix(0 , 1 , 2, 3));   
567         assertEquals("Rows02Cols13", mRows02Cols13,
568                 m.getSubMatrix(new int[] {0,2}, new int[] {1,3}));  
569         assertEquals("Rows03Cols12", mRows03Cols12,
570                 m.getSubMatrix(new int[] {0,3}, new int[] {1,2}));  
571         assertEquals("Rows03Cols123", mRows03Cols123,
572                 m.getSubMatrix(new int[] {0,3}, new int[] {1,2,3})); 
573         assertEquals("Rows20Cols123", mRows20Cols123,
574                 m.getSubMatrix(new int[] {2,0}, new int[] {1,2,3})); 
575         assertEquals("Rows31Cols31", mRows31Cols31,
576                 m.getSubMatrix(new int[] {3,1}, new int[] {3,1})); 
577         assertEquals("Rows31Cols31", mRows31Cols31,
578                 m.getSubMatrix(new int[] {3,1}, new int[] {3,1})); 
579         
580         try {
581             m.getSubMatrix(1,0,2,4);
582             fail("Expecting MatrixIndexException");
583         } catch (MatrixIndexException ex) {
584             // expected
585         }
586         try {
587             m.getSubMatrix(-1,1,2,2);
588             fail("Expecting MatrixIndexException");
589         } catch (MatrixIndexException ex) {
590             // expected
591         }
592         try {
593             m.getSubMatrix(1,0,2,2);
594             fail("Expecting MatrixIndexException");
595         } catch (MatrixIndexException ex) {
596             // expected
597         }
598         try {
599             m.getSubMatrix(1,0,2,4);
600             fail("Expecting MatrixIndexException");
601         } catch (MatrixIndexException ex) {
602             // expected
603         }
604         try {
605             m.getSubMatrix(new int[] {}, new int[] {0});
606             fail("Expecting MatrixIndexException");
607         } catch (MatrixIndexException ex) {
608             // expected
609         }
610         try {
611             m.getSubMatrix(new int[] {0}, new int[] {4});
612             fail("Expecting MatrixIndexException");
613         } catch (MatrixIndexException ex) {
614             // expected
615         }
616     }
617     
618     public void testGetColumnMatrix() {
619         BigMatrix m = new BigMatrixImpl(subTestData);
620         BigMatrix mColumn1 = new BigMatrixImpl(subColumn1);
621         BigMatrix mColumn3 = new BigMatrixImpl(subColumn3);
622         assertEquals("Column1", mColumn1, 
623                 m.getColumnMatrix(1));
624         assertEquals("Column3", mColumn3, 
625                 m.getColumnMatrix(3));
626         try {
627             m.getColumnMatrix(-1);
628             fail("Expecting MatrixIndexException");
629         } catch (MatrixIndexException ex) {
630             // expected
631         }
632         try {
633             m.getColumnMatrix(4);
634             fail("Expecting MatrixIndexException");
635         } catch (MatrixIndexException ex) {
636             // expected
637         }
638     }
639     
640     public void testGetRowMatrix() {
641         BigMatrix m = new BigMatrixImpl(subTestData);
642         BigMatrix mRow0 = new BigMatrixImpl(subRow0);
643         BigMatrix mRow3 = new BigMatrixImpl(subRow3);
644         assertEquals("Row0", mRow0, 
645                 m.getRowMatrix(0));
646         assertEquals("Row3", mRow3, 
647                 m.getRowMatrix(3));
648         try {
649             m.getRowMatrix(-1);
650             fail("Expecting MatrixIndexException");
651         } catch (MatrixIndexException ex) {
652             // expected
653         }
654         try {
655             m.getRowMatrix(4);
656             fail("Expecting MatrixIndexException");
657         } catch (MatrixIndexException ex) {
658             // expected
659         }
660     }
661     
662     public void testEqualsAndHashCode() {
663         BigMatrixImpl m = new BigMatrixImpl(testData);
664         BigMatrixImpl m1 = (BigMatrixImpl) m.copy();
665         BigMatrixImpl mt = (BigMatrixImpl) m.transpose();
666         assertTrue(m.hashCode() != mt.hashCode());
667         assertEquals(m.hashCode(), m1.hashCode());
668         assertEquals(m, m);
669         assertEquals(m, m1);
670         assertFalse(m.equals(null));
671         assertFalse(m.equals(mt));
672         assertFalse(m.equals(new BigMatrixImpl(bigSingular)));
673         // Different scales make BigDecimals, so matrices unequal
674         m = new BigMatrixImpl(new String[][] {{"2.0"}});
675         m1 = new BigMatrixImpl(new String[][] {{"2.00"}});
676         assertTrue(m.hashCode() != m1.hashCode());
677         assertFalse(m.equals(m1));
678     }
679     
680     public void testToString() {
681         BigMatrixImpl m = new BigMatrixImpl(testData);
682         assertEquals("BigMatrixImpl{{1,2,3},{2,5,3},{1,0,8}}",
683                 m.toString());
684         m = new BigMatrixImpl();
685         assertEquals("BigMatrixImpl{}",
686                 m.toString());
687     }
688     
689     public void testSetSubMatrix() throws Exception {
690         BigDecimal[][] detData3 = 
691             MatrixUtils.createBigMatrix(detData2).getData();
692         BigMatrixImpl m = new BigMatrixImpl(testData);
693         m.setSubMatrix(detData3,1,1);
694         BigMatrix expected = MatrixUtils.createBigMatrix
695             (new double[][] {{1.0,2.0,3.0},{2.0,1.0,3.0},{1.0,2.0,4.0}});
696         assertEquals(expected, m);  
697         
698         m.setSubMatrix(detData3,0,0);
699         expected = MatrixUtils.createBigMatrix
700             (new double[][] {{1.0,3.0,3.0},{2.0,4.0,3.0},{1.0,2.0,4.0}});
701         assertEquals(expected, m);  
702         
703         BigDecimal[][] testDataPlus3 = 
704             MatrixUtils.createBigMatrix(testDataPlus2).getData();
705         m.setSubMatrix(testDataPlus3,0,0);      
706         expected = MatrixUtils.createBigMatrix
707         (new double[][] {{3.0,4.0,5.0},{4.0,7.0,5.0},{3.0,2.0,10.0}});
708         assertEquals(expected, m);   
709         
710         // javadoc example
711         BigMatrixImpl matrix = (BigMatrixImpl) MatrixUtils.createBigMatrix
712             (new double[][] {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 0, 1 , 2}});
713         matrix.setSubMatrix(new BigDecimal[][] {{new BigDecimal(3),
714             new BigDecimal(4)}, {new BigDecimal(5), new BigDecimal(6)}}, 1, 1);
715         expected = MatrixUtils.createBigMatrix
716             (new BigDecimal[][] {{new BigDecimal(1), new BigDecimal(2),
717              new BigDecimal(3), new BigDecimal(4)}, {new BigDecimal(5),
718              new BigDecimal(3), new BigDecimal(4), new BigDecimal(8)},
719              {new BigDecimal(9), new BigDecimal(5) , new BigDecimal(6),
720               new BigDecimal(2)}});
721         assertEquals(expected, matrix);   
722         
723         // dimension overflow
724         try {  
725             m.setSubMatrix(matrix.getData(),1,1);
726             fail("expecting MatrixIndexException");
727         } catch (MatrixIndexException e) {
728             // expected
729         }
730         
731         // null
732         try {
733             m.setSubMatrix(null,1,1);
734             fail("expecting NullPointerException");
735         } catch (NullPointerException e) {
736             // expected
737         }
738         
739         // ragged
740         try {
741             m.setSubMatrix(new BigDecimal[][] {{new BigDecimal(1)},
742                     {new BigDecimal(2), new BigDecimal(3)}}, 0, 0);
743             fail("expecting IllegalArgumentException");
744         } catch (IllegalArgumentException e) {
745             // expected
746         }
747         
748         // empty
749         try {
750             m.setSubMatrix(new BigDecimal[][] {{}}, 0, 0);
751             fail("expecting IllegalArgumentException");
752         } catch (IllegalArgumentException e) {
753             // expected
754         }
755         
756     }
757     
758     //--------------- -----------------Protected methods
759         
760     /** verifies that two matrices are close (1-norm) */              
761     protected void assertClose(String msg, BigMatrix m, BigMatrix n,
762         double tolerance) {
763         assertTrue(msg,m.subtract(n).getNorm().doubleValue() < tolerance);
764     }
765     
766     /** verifies that two vectors are close (sup norm) */
767     protected void assertClose(String msg, double[] m, double[] n,
768         double tolerance) {
769         if (m.length != n.length) {
770             fail("vectors not same length");
771         }
772         for (int i = 0; i < m.length; i++) {
773             assertEquals(msg + " " +  i + " elements differ", 
774                 m[i],n[i],tolerance);
775         }
776     }
777     
778     /** extracts the l  and u matrices from compact lu representation */
779     protected void splitLU(BigMatrix lu, BigDecimal[][] lowerData, BigDecimal[][] upperData) throws InvalidMatrixException {
780         if (!lu.isSquare() || lowerData.length != lowerData[0].length || upperData.length != upperData[0].length ||
781                 lowerData.length != upperData.length
782                 || lowerData.length != lu.getRowDimension()) {
783             throw new InvalidMatrixException("incorrect dimensions");
784         }    
785         int n = lu.getRowDimension();
786         for (int i = 0; i < n; i++) {
787             for (int j = 0; j < n; j++) {
788                 if (j < i) {
789                     lowerData[i][j] = lu.getEntry(i, j);
790                     upperData[i][j] = new BigDecimal(0);
791                 } else if (i == j) {
792                     lowerData[i][j] = new BigDecimal(1);
793                     upperData[i][j] = lu.getEntry(i, j);
794                 } else {
795                     lowerData[i][j] = new BigDecimal(0);
796                     upperData[i][j] = lu.getEntry(i, j);
797                 }   
798             }
799         }
800     }
801     
802     /** Returns the result of applying the given row permutation to the matrix */
803     protected BigMatrix permuteRows(BigMatrix matrix, int[] permutation) {
804         if (!matrix.isSquare() || matrix.getRowDimension() != permutation.length) {
805             throw new IllegalArgumentException("dimension mismatch");
806         }
807         int n = matrix.getRowDimension();
808         int m = matrix.getColumnDimension();
809         BigDecimal out[][] = new BigDecimal[m][n];
810         for (int i = 0; i < n; i++) {
811             for (int j = 0; j < m; j++) {
812                 out[i][j] = matrix.getEntry(permutation[i], j);
813             }
814         }
815         return new BigMatrixImpl(out);
816     }
817     
818     /** Extracts l and u matrices from lu and verifies that matrix = l times u modulo permutation */
819     protected void verifyDecomposition(BigMatrix matrix, BigMatrix lu) throws Exception{
820         int n = matrix.getRowDimension();
821         BigDecimal[][] lowerData = new BigDecimal[n][n];
822         BigDecimal[][] upperData = new BigDecimal[n][n];
823         splitLU(lu, lowerData, upperData);
824         BigMatrix lower =new BigMatrixImpl(lowerData);
825         BigMatrix upper = new BigMatrixImpl(upperData);
826         int[] permutation = ((BigMatrixImpl) matrix).getPermutation();
827         BigMatrix permuted = permuteRows(matrix, permutation);
828         assertClose("lu decomposition does not work", permuted,
829                 lower.multiply(upper), normTolerance);
830     }
831          
832 //    /** Useful for debugging */
833 //    private void dumpMatrix(BigMatrix m) {
834 //          for (int i = 0; i < m.getRowDimension(); i++) {
835 //              String os = "";
836 //              for (int j = 0; j < m.getColumnDimension(); j++) {
837 //                  os += m.getEntry(i, j) + " ";
838 //              }
839 //              System.out.println(os);
840 //          }
841 //    }
842         
843 }
844