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