1   /*
2    * Copyright 2004-2005 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: 240244 $ $Date: 2005-08-26 06:40:32 -0700 (Fri, 26 Aug 2005) $
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         try {
178             BigMatrix m4 = new BigMatrixImpl(new String[][] {});
179             fail("Expecting IllegalArgumentException");
180         } catch (IllegalArgumentException ex) {
181             // expected
182         }
183         try {
184             BigMatrix m4 = new BigMatrixImpl(new String[][] {{},{}});
185             fail("Expecting IllegalArgumentException");
186         } catch (IllegalArgumentException ex) {
187             // expected
188         }
189         try {
190             BigMatrix m4 = new BigMatrixImpl(new String[][] {{"a", "b"},{"c"}});
191             fail("Expecting IllegalArgumentException");
192         } catch (IllegalArgumentException ex) {
193             // expected
194         }
195 
196         try {
197             BigMatrix m4 = new BigMatrixImpl(0, 1);
198             fail("Expecting IllegalArgumentException");
199         } catch (IllegalArgumentException ex) {
200             // expected
201         }
202         try {
203             BigMatrix m4 = new BigMatrixImpl(1, 0);
204             fail("Expecting IllegalArgumentException");
205         } catch (IllegalArgumentException ex) {
206             // expected
207         }
208     }
209     
210     /** test add */
211     public void testAdd() {
212         BigMatrixImpl m = new BigMatrixImpl(testData);
213         BigMatrixImpl mInv = new BigMatrixImpl(testDataInv);
214         BigMatrixImpl mPlusMInv = (BigMatrixImpl)m.add(mInv);
215         double[][] sumEntries = asDouble(mPlusMInv.getData());
216         for (int row = 0; row < m.getRowDimension(); row++) {
217             for (int col = 0; col < m.getColumnDimension(); col++) {
218                 assertEquals("sum entry entry",
219                     testDataPlusInv[row][col],sumEntries[row][col],
220                         entryTolerance);
221             }
222         }    
223     }
224     
225     /** test add failure */
226     public void testAddFail() {
227         BigMatrixImpl m = new BigMatrixImpl(testData);
228         BigMatrixImpl m2 = new BigMatrixImpl(testData2);
229         try {
230             BigMatrixImpl mPlusMInv = (BigMatrixImpl)m.add(m2);
231             fail("IllegalArgumentException expected");
232         } catch (IllegalArgumentException ex) {
233             ;
234         }
235     }
236     
237     /** test norm */
238     public void testNorm() {
239         BigMatrixImpl m = new BigMatrixImpl(testData);
240         BigMatrixImpl m2 = new BigMatrixImpl(testData2);
241         assertEquals("testData norm",14d,m.getNorm().doubleValue(),entryTolerance);
242         assertEquals("testData2 norm",7d,m2.getNorm().doubleValue(),entryTolerance);
243     }
244     
245      /** test m-n = m + -n */
246     public void testPlusMinus() {
247         BigMatrixImpl m = new BigMatrixImpl(testData);
248         BigMatrixImpl m2 = new BigMatrixImpl(testDataInv);
249         assertClose("m-n = m + -n",m.subtract(m2),
250             m2.scalarMultiply(new BigDecimal(-1d)).add(m),entryTolerance);
251         try {
252             BigMatrix a = m.subtract(new BigMatrixImpl(testData2));
253             fail("Expecting illegalArgumentException");
254         } catch (IllegalArgumentException ex) {
255             ;
256         }      
257     }
258    
259     /** test multiply */
260      public void testMultiply() {
261         BigMatrixImpl m = new BigMatrixImpl(testData);
262         BigMatrixImpl mInv = new BigMatrixImpl(testDataInv);
263         BigMatrixImpl identity = new BigMatrixImpl(id);
264         BigMatrixImpl m2 = new BigMatrixImpl(testData2);
265         assertClose("inverse multiply",m.multiply(mInv),
266             identity,entryTolerance);
267         assertClose("inverse multiply",mInv.multiply(m),
268             identity,entryTolerance);
269         assertClose("identity multiply",m.multiply(identity),
270             m,entryTolerance);
271         assertClose("identity multiply",identity.multiply(mInv),
272             mInv,entryTolerance);
273         assertClose("identity multiply",m2.multiply(identity),
274             m2,entryTolerance); 
275         try {
276             BigMatrix a = m.multiply(new BigMatrixImpl(bigSingular));
277             fail("Expecting illegalArgumentException");
278         } catch (IllegalArgumentException ex) {
279             ;
280         }      
281     }   
282     
283     //Additional Test for BigMatrixImplTest.testMultiply
284 
285     private double[][] d3 = new double[][] {{1,2,3,4},{5,6,7,8}};
286     private double[][] d4 = new double[][] {{1},{2},{3},{4}};
287     private double[][] d5 = new double[][] {{30},{70}};
288      
289     public void testMultiply2() { 
290        BigMatrix m3 = new BigMatrixImpl(d3);
291        BigMatrix m4 = new BigMatrixImpl(d4);
292        BigMatrix m5 = new BigMatrixImpl(d5);
293        assertClose("m3*m4=m5", m3.multiply(m4), m5, entryTolerance);
294    }  
295         
296     /** test isSingular */
297     public void testIsSingular() {
298         BigMatrixImpl m = new BigMatrixImpl(singular);
299         assertTrue("singular",m.isSingular());
300         m = new BigMatrixImpl(bigSingular);
301         assertTrue("big singular",m.isSingular());
302         m = new BigMatrixImpl(id);
303         assertTrue("identity nonsingular",!m.isSingular());
304         m = new BigMatrixImpl(testData);
305         assertTrue("testData nonsingular",!m.isSingular());
306     }
307         
308     /** test inverse */
309     public void testInverse() {
310         BigMatrixImpl m = new BigMatrixImpl(testData);
311         BigMatrix mInv = new BigMatrixImpl(testDataInv);
312         assertClose("inverse",mInv,m.inverse(),normTolerance);
313         assertClose("inverse^2",m,m.inverse().inverse(),10E-12);
314         
315         // Not square
316         m = new BigMatrixImpl(testData2);
317         try {
318             m.inverse();
319             fail("Expecting InvalidMatrixException");
320         } catch (InvalidMatrixException ex) {
321             // expected
322         }
323         
324         // Singular
325         m = new BigMatrixImpl(singular);
326         try {
327             m.inverse();
328             fail("Expecting InvalidMatrixException");
329         } catch (InvalidMatrixException ex) {
330             // expected
331         }
332     }
333     
334     /** test solve */
335     public void testSolve() {
336         BigMatrixImpl m = new BigMatrixImpl(testData);
337         BigMatrix mInv = new BigMatrixImpl(testDataInv);
338         // being a bit slothful here -- actually testing that X = A^-1 * B
339         assertClose("inverse-operate",
340                     asDouble(mInv.operate(asBigDecimal(testVector))),
341                     asDouble(m.solve(asBigDecimal(testVector))),
342                     normTolerance);
343         try {
344             double[] x = asDouble(m.solve(asBigDecimal(testVector2)));
345             fail("expecting IllegalArgumentException");
346         } catch (IllegalArgumentException ex) {
347             ;
348         }       
349         BigMatrix bs = new BigMatrixImpl(bigSingular);
350         try {
351             BigMatrix a = bs.solve(bs);
352             fail("Expecting InvalidMatrixException");
353         } catch (InvalidMatrixException ex) {
354             ;
355         }
356         try {
357             BigMatrix a = m.solve(bs);
358             fail("Expecting IllegalArgumentException");
359         } catch (IllegalArgumentException ex) {
360             ;
361         }
362         try {
363             BigMatrix a = (new BigMatrixImpl(testData2)).solve(bs);
364             fail("Expecting illegalArgumentException");
365         } catch (IllegalArgumentException ex) {
366             ;
367         } 
368         try {
369             (new BigMatrixImpl(testData2)).luDecompose();
370             fail("Expecting InvalidMatrixException");
371         } catch (InvalidMatrixException ex) {
372             ;
373         }  
374     }
375     
376     /** test determinant */
377     public void testDeterminant() {       
378         BigMatrix m = new BigMatrixImpl(bigSingular);
379         assertEquals("singular determinant",0,m.getDeterminant().doubleValue(),0);
380         m = new BigMatrixImpl(detData);
381         assertEquals("nonsingular test",-3d,m.getDeterminant().doubleValue(),normTolerance);
382         
383         // Examples verified against R (version 1.8.1, Red Hat Linux 9)
384         m = new BigMatrixImpl(detData2);
385         assertEquals("nonsingular R test 1",-2d,m.getDeterminant().doubleValue(),normTolerance);
386         m = new BigMatrixImpl(testData);
387         assertEquals("nonsingular  R test 2",-1d,m.getDeterminant().doubleValue(),normTolerance);
388 
389         try {
390             double a = new BigMatrixImpl(testData2).getDeterminant().doubleValue();
391             fail("Expecting InvalidMatrixException");
392         } catch (InvalidMatrixException ex) {
393             ;
394         }      
395     }
396     
397     /** test trace */
398     public void testTrace() {
399         BigMatrix m = new BigMatrixImpl(id);
400         assertEquals("identity trace",3d,m.getTrace().doubleValue(),entryTolerance);
401         m = new BigMatrixImpl(testData2);
402         try {
403             double x = m.getTrace().doubleValue();
404             fail("Expecting illegalArgumentException");
405         } catch (IllegalArgumentException ex) {
406             ;
407         }      
408     }
409     
410     /** test sclarAdd */
411     public void testScalarAdd() {
412         BigMatrix m = new BigMatrixImpl(testData);
413         assertClose("scalar add",new BigMatrixImpl(testDataPlus2),
414             m.scalarAdd(new BigDecimal(2d)),entryTolerance);
415     }
416                     
417     /** test operate */
418     public void testOperate() {
419         BigMatrix m = new BigMatrixImpl(id);
420         double[] x = asDouble(m.operate(asBigDecimal(testVector)));
421         assertClose("identity operate",testVector,x,entryTolerance);
422         m = new BigMatrixImpl(bigSingular);
423         try {
424             x = asDouble(m.operate(asBigDecimal(testVector)));
425             fail("Expecting illegalArgumentException");
426         } catch (IllegalArgumentException ex) {
427             ;
428         }      
429     }
430     
431     /** test transpose */
432     public void testTranspose() {
433         BigMatrix m = new BigMatrixImpl(testData);
434         assertClose("inverse-transpose",m.inverse().transpose(),
435             m.transpose().inverse(),normTolerance);
436         m = new BigMatrixImpl(testData2);
437         BigMatrix mt = new BigMatrixImpl(testData2T);
438         assertClose("transpose",mt,m.transpose(),normTolerance);
439     }
440     
441     /** test preMultiply by vector */
442     public void testPremultiplyVector() {
443         BigMatrix m = new BigMatrixImpl(testData);
444         assertClose("premultiply",asDouble(m.preMultiply(asBigDecimal(testVector))),preMultTest,normTolerance);
445         m = new BigMatrixImpl(bigSingular);
446         try {
447             m.preMultiply(asBigDecimal(testVector));
448             fail("expecting IllegalArgumentException");
449         } catch (IllegalArgumentException ex) {
450             ;
451         }
452     }
453     
454     public void testPremultiply() {
455         BigMatrix m3 = new BigMatrixImpl(d3);
456         BigMatrix m4 = new BigMatrixImpl(d4);
457         BigMatrix m5 = new BigMatrixImpl(d5);
458         assertClose("m3*m4=m5", m4.preMultiply(m3), m5, entryTolerance);
459         
460         BigMatrixImpl m = new BigMatrixImpl(testData);
461         BigMatrixImpl mInv = new BigMatrixImpl(testDataInv);
462         BigMatrixImpl identity = new BigMatrixImpl(id);
463         BigMatrixImpl m2 = new BigMatrixImpl(testData2);
464         assertClose("inverse multiply",m.preMultiply(mInv),
465                 identity,entryTolerance);
466         assertClose("inverse multiply",mInv.preMultiply(m),
467                 identity,entryTolerance);
468         assertClose("identity multiply",m.preMultiply(identity),
469                 m,entryTolerance);
470         assertClose("identity multiply",identity.preMultiply(mInv),
471                 mInv,entryTolerance);
472         try {
473             BigMatrix a = m.preMultiply(new BigMatrixImpl(bigSingular));
474             fail("Expecting illegalArgumentException");
475         } catch (IllegalArgumentException ex) {
476             ;
477         }      
478     }
479     
480     public void testGetVectors() {
481         BigMatrix m = new BigMatrixImpl(testData);
482         assertClose("get row",m.getRowAsDoubleArray(0),testDataRow1,entryTolerance);
483         assertClose("get col",m.getColumnAsDoubleArray(2),testDataCol3,entryTolerance);
484         try {
485             double[] x = m.getRowAsDoubleArray(10);
486             fail("expecting MatrixIndexException");
487         } catch (MatrixIndexException ex) {
488             ;
489         }
490         try {
491             double[] x = m.getColumnAsDoubleArray(-1);
492             fail("expecting MatrixIndexException");
493         } catch (MatrixIndexException ex) {
494             ;
495         }
496     }
497       
498     public void testLUDecomposition() throws Exception {
499         BigMatrixImpl m = new BigMatrixImpl(testData);
500         BigMatrix lu = m.getLUMatrix();
501         assertClose("LU decomposition", lu, (BigMatrix) new BigMatrixImpl(testDataLU), normTolerance);
502         verifyDecomposition(m, lu);
503         m = new BigMatrixImpl(luData);
504         lu = m.getLUMatrix();
505         assertClose("LU decomposition", lu, (BigMatrix) new BigMatrixImpl(luDataLUDecomposition), normTolerance);
506         verifyDecomposition(m, lu);
507         m = new BigMatrixImpl(testDataMinus);
508         lu = m.getLUMatrix();
509         verifyDecomposition(m, lu);
510         m = new BigMatrixImpl(id);
511         lu = m.getLUMatrix();
512         verifyDecomposition(m, lu);
513         try {
514             m = new BigMatrixImpl(bigSingular); // singular
515             lu = m.getLUMatrix();
516             fail("Expecting InvalidMatrixException");
517         } catch (InvalidMatrixException ex) {
518             // expected
519         }
520         try {
521             m = new BigMatrixImpl(testData2);  // not square
522             lu = m.getLUMatrix();
523             fail("Expecting InvalidMatrixException");
524         } catch (InvalidMatrixException ex) {
525             // expected
526         }
527     }
528     
529    /**
530     * test submatrix accessors
531     */
532     public void testSubMatrix() {
533         BigMatrix m = new BigMatrixImpl(subTestData);
534         BigMatrix mRows23Cols00 = new BigMatrixImpl(subRows23Cols00);
535         BigMatrix mRows00Cols33 = new BigMatrixImpl(subRows00Cols33);
536         BigMatrix mRows01Cols23 = new BigMatrixImpl(subRows01Cols23);
537         BigMatrix mRows02Cols13 = new BigMatrixImpl(subRows02Cols13);
538         BigMatrix mRows03Cols12 = new BigMatrixImpl(subRows03Cols12);
539         BigMatrix mRows03Cols123 = new BigMatrixImpl(subRows03Cols123);
540         BigMatrix mRows20Cols123 = new BigMatrixImpl(subRows20Cols123);
541         BigMatrix mRows31Cols31 = new BigMatrixImpl(subRows31Cols31);
542         assertEquals("Rows23Cols00", mRows23Cols00, 
543                 m.getSubMatrix(2 , 3 , 0, 0));
544         assertEquals("Rows00Cols33", mRows00Cols33, 
545                 m.getSubMatrix(0 , 0 , 3, 3));
546         assertEquals("Rows01Cols23", mRows01Cols23,
547                 m.getSubMatrix(0 , 1 , 2, 3));   
548         assertEquals("Rows02Cols13", mRows02Cols13,
549                 m.getSubMatrix(new int[] {0,2}, new int[] {1,3}));  
550         assertEquals("Rows03Cols12", mRows03Cols12,
551                 m.getSubMatrix(new int[] {0,3}, new int[] {1,2}));  
552         assertEquals("Rows03Cols123", mRows03Cols123,
553                 m.getSubMatrix(new int[] {0,3}, new int[] {1,2,3})); 
554         assertEquals("Rows20Cols123", mRows20Cols123,
555                 m.getSubMatrix(new int[] {2,0}, new int[] {1,2,3})); 
556         assertEquals("Rows31Cols31", mRows31Cols31,
557                 m.getSubMatrix(new int[] {3,1}, new int[] {3,1})); 
558         assertEquals("Rows31Cols31", mRows31Cols31,
559                 m.getSubMatrix(new int[] {3,1}, new int[] {3,1})); 
560         
561         try {
562             m.getSubMatrix(1,0,2,4);
563             fail("Expecting MatrixIndexException");
564         } catch (MatrixIndexException ex) {
565             // expected
566         }
567         try {
568             m.getSubMatrix(-1,1,2,2);
569             fail("Expecting MatrixIndexException");
570         } catch (MatrixIndexException ex) {
571             // expected
572         }
573         try {
574             m.getSubMatrix(1,0,2,2);
575             fail("Expecting MatrixIndexException");
576         } catch (MatrixIndexException ex) {
577             // expected
578         }
579         try {
580             m.getSubMatrix(1,0,2,4);
581             fail("Expecting MatrixIndexException");
582         } catch (MatrixIndexException ex) {
583             // expected
584         }
585         try {
586             m.getSubMatrix(new int[] {}, new int[] {0});
587             fail("Expecting MatrixIndexException");
588         } catch (MatrixIndexException ex) {
589             // expected
590         }
591         try {
592             m.getSubMatrix(new int[] {0}, new int[] {4});
593             fail("Expecting MatrixIndexException");
594         } catch (MatrixIndexException ex) {
595             // expected
596         }
597     }
598     
599     public void testGetColumnMatrix() {
600         BigMatrix m = new BigMatrixImpl(subTestData);
601         BigMatrix mColumn1 = new BigMatrixImpl(subColumn1);
602         BigMatrix mColumn3 = new BigMatrixImpl(subColumn3);
603         assertEquals("Column1", mColumn1, 
604                 m.getColumnMatrix(1));
605         assertEquals("Column3", mColumn3, 
606                 m.getColumnMatrix(3));
607         try {
608             m.getColumnMatrix(-1);
609             fail("Expecting MatrixIndexException");
610         } catch (MatrixIndexException ex) {
611             // expected
612         }
613         try {
614             m.getColumnMatrix(4);
615             fail("Expecting MatrixIndexException");
616         } catch (MatrixIndexException ex) {
617             // expected
618         }
619     }
620     
621     public void testGetRowMatrix() {
622         BigMatrix m = new BigMatrixImpl(subTestData);
623         BigMatrix mRow0 = new BigMatrixImpl(subRow0);
624         BigMatrix mRow3 = new BigMatrixImpl(subRow3);
625         assertEquals("Row0", mRow0, 
626                 m.getRowMatrix(0));
627         assertEquals("Row3", mRow3, 
628                 m.getRowMatrix(3));
629         try {
630             m.getRowMatrix(-1);
631             fail("Expecting MatrixIndexException");
632         } catch (MatrixIndexException ex) {
633             // expected
634         }
635         try {
636             m.getRowMatrix(4);
637             fail("Expecting MatrixIndexException");
638         } catch (MatrixIndexException ex) {
639             // expected
640         }
641     }
642     
643     public void testEqualsAndHashCode() {
644         BigMatrixImpl m = new BigMatrixImpl(testData);
645         BigMatrixImpl m1 = (BigMatrixImpl) m.copy();
646         BigMatrixImpl mt = (BigMatrixImpl) m.transpose();
647         assertTrue(m.hashCode() != mt.hashCode());
648         assertEquals(m.hashCode(), m1.hashCode());
649         assertEquals(m, m);
650         assertEquals(m, m1);
651         assertFalse(m.equals(null));
652         assertFalse(m.equals(mt));
653         assertFalse(m.equals(new BigMatrixImpl(bigSingular)));
654         // Different scales make BigDecimals, so matrices unequal
655         m = new BigMatrixImpl(new String[][] {{"2.0"}});
656         m1 = new BigMatrixImpl(new String[][] {{"2.00"}});
657         assertTrue(m.hashCode() != m1.hashCode());
658         assertFalse(m.equals(m1));
659     }
660     
661     public void testToString() {
662         BigMatrixImpl m = new BigMatrixImpl(testData);
663         assertEquals("BigMatrixImpl{{1,2,3},{2,5,3},{1,0,8}}",
664                 m.toString());
665         m = new BigMatrixImpl();
666         assertEquals("BigMatrixImpl{}",
667                 m.toString());
668     }
669     
670     public void testSetSubMatrix() throws Exception {
671         BigDecimal[][] detData3 = 
672             MatrixUtils.createBigMatrix(detData2).getData();
673         BigMatrixImpl m = new BigMatrixImpl(testData);
674         m.setSubMatrix(detData3,1,1);
675         BigMatrix expected = MatrixUtils.createBigMatrix
676             (new double[][] {{1.0,2.0,3.0},{2.0,1.0,3.0},{1.0,2.0,4.0}});
677         assertEquals(expected, m);  
678         
679         m.setSubMatrix(detData3,0,0);
680         expected = MatrixUtils.createBigMatrix
681             (new double[][] {{1.0,3.0,3.0},{2.0,4.0,3.0},{1.0,2.0,4.0}});
682         assertEquals(expected, m);  
683         
684         BigDecimal[][] testDataPlus3 = 
685             MatrixUtils.createBigMatrix(testDataPlus2).getData();
686         m.setSubMatrix(testDataPlus3,0,0);      
687         expected = MatrixUtils.createBigMatrix
688         (new double[][] {{3.0,4.0,5.0},{4.0,7.0,5.0},{3.0,2.0,10.0}});
689         assertEquals(expected, m);   
690         
691         // javadoc example
692         BigMatrixImpl matrix = (BigMatrixImpl) MatrixUtils.createBigMatrix
693             (new double[][] {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 0, 1 , 2}});
694         matrix.setSubMatrix(new BigDecimal[][] {{new BigDecimal(3),
695             new BigDecimal(4)}, {new BigDecimal(5), new BigDecimal(6)}}, 1, 1);
696         expected = MatrixUtils.createBigMatrix
697             (new BigDecimal[][] {{new BigDecimal(1), new BigDecimal(2),
698              new BigDecimal(3), new BigDecimal(4)}, {new BigDecimal(5),
699              new BigDecimal(3), new BigDecimal(4), new BigDecimal(8)},
700              {new BigDecimal(9), new BigDecimal(5) , new BigDecimal(6),
701               new BigDecimal(2)}});
702         assertEquals(expected, matrix);   
703         
704         // dimension overflow
705         try {  
706             m.setSubMatrix(matrix.getData(),1,1);
707             fail("expecting MatrixIndexException");
708         } catch (MatrixIndexException e) {
709             // expected
710         }
711         
712         // null
713         try {
714             m.setSubMatrix(null,1,1);
715             fail("expecting NullPointerException");
716         } catch (NullPointerException e) {
717             // expected
718         }
719         
720         // ragged
721         try {
722             m.setSubMatrix(new BigDecimal[][] {{new BigDecimal(1)},
723                     {new BigDecimal(2), new BigDecimal(3)}}, 0, 0);
724             fail("expecting IllegalArgumentException");
725         } catch (IllegalArgumentException e) {
726             // expected
727         }
728         
729         // empty
730         try {
731             m.setSubMatrix(new BigDecimal[][] {{}}, 0, 0);
732             fail("expecting IllegalArgumentException");
733         } catch (IllegalArgumentException e) {
734             // expected
735         }
736         
737     }
738     
739     //--------------- -----------------Protected methods
740         
741     /** verifies that two matrices are close (1-norm) */              
742     protected void assertClose(String msg, BigMatrix m, BigMatrix n,
743         double tolerance) {
744         assertTrue(msg,m.subtract(n).getNorm().doubleValue() < tolerance);
745     }
746     
747     /** verifies that two vectors are close (sup norm) */
748     protected void assertClose(String msg, double[] m, double[] n,
749         double tolerance) {
750         if (m.length != n.length) {
751             fail("vectors not same length");
752         }
753         for (int i = 0; i < m.length; i++) {
754             assertEquals(msg + " " +  i + " elements differ", 
755                 m[i],n[i],tolerance);
756         }
757     }
758     
759     /** extracts the l  and u matrices from compact lu representation */
760     protected void splitLU(BigMatrix lu, BigDecimal[][] lowerData, BigDecimal[][] upperData) throws InvalidMatrixException {
761         if (!lu.isSquare() || lowerData.length != lowerData[0].length || upperData.length != upperData[0].length ||
762                 lowerData.length != upperData.length
763                 || lowerData.length != lu.getRowDimension()) {
764             throw new InvalidMatrixException("incorrect dimensions");
765         }    
766         int n = lu.getRowDimension();
767         for (int i = 0; i < n; i++) {
768             for (int j = 0; j < n; j++) {
769                 if (j < i) {
770                     lowerData[i][j] = lu.getEntry(i, j);
771                     upperData[i][j] = new BigDecimal(0);
772                 } else if (i == j) {
773                     lowerData[i][j] = new BigDecimal(1);
774                     upperData[i][j] = lu.getEntry(i, j);
775                 } else {
776                     lowerData[i][j] = new BigDecimal(0);
777                     upperData[i][j] = lu.getEntry(i, j);
778                 }   
779             }
780         }
781     }
782     
783     /** Returns the result of applying the given row permutation to the matrix */
784     protected BigMatrix permuteRows(BigMatrix matrix, int[] permutation) {
785         if (!matrix.isSquare() || matrix.getRowDimension() != permutation.length) {
786             throw new IllegalArgumentException("dimension mismatch");
787         }
788         int n = matrix.getRowDimension();
789         int m = matrix.getColumnDimension();
790         BigDecimal out[][] = new BigDecimal[m][n];
791         for (int i = 0; i < n; i++) {
792             for (int j = 0; j < m; j++) {
793                 out[i][j] = matrix.getEntry(permutation[i], j);
794             }
795         }
796         return new BigMatrixImpl(out);
797     }
798     
799     /** Extracts l and u matrices from lu and verifies that matrix = l times u modulo permutation */
800     protected void verifyDecomposition(BigMatrix matrix, BigMatrix lu) throws Exception{
801         int n = matrix.getRowDimension();
802         BigDecimal[][] lowerData = new BigDecimal[n][n];
803         BigDecimal[][] upperData = new BigDecimal[n][n];
804         splitLU(lu, lowerData, upperData);
805         BigMatrix lower =new BigMatrixImpl(lowerData);
806         BigMatrix upper = new BigMatrixImpl(upperData);
807         int[] permutation = ((BigMatrixImpl) matrix).getPermutation();
808         BigMatrix permuted = permuteRows(matrix, permutation);
809         assertClose("lu decomposition does not work", permuted,
810                 lower.multiply(upper), normTolerance);
811     }
812          
813     /** Useful for debugging */
814     private void dumpMatrix(BigMatrix m) {
815           for (int i = 0; i < m.getRowDimension(); i++) {
816               String os = "";
817               for (int j = 0; j < m.getColumnDimension(); j++) {
818                   os += m.getEntry(i, j) + " ";
819               }
820               System.out.println(os);
821           }
822     }
823         
824 }
825