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