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