1   /*
2    * Copyright 2003-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  /**
23   * Test cases for the {@link RealMatrixImpl} class.
24   *
25   * @version $Revision: 240244 $ $Date: 2005-08-26 06:40:32 -0700 (Fri, 26 Aug 2005) $
26   */
27  
28  public final class RealMatrixImplTest extends TestCase {
29      
30      // 3 x 3 identity matrix
31      protected double[][] id = { {1d,0d,0d}, {0d,1d,0d}, {0d,0d,1d} };
32      
33      // Test data for group operations
34      protected double[][] testData = { {1d,2d,3d}, {2d,5d,3d}, {1d,0d,8d} };
35      protected double[][] testDataLU = {{2d, 5d, 3d}, {.5d, -2.5d, 6.5d}, {0.5d, 0.2d, .2d}};
36      protected double[][] testDataPlus2 = { {3d,4d,5d}, {4d,7d,5d}, {3d,2d,10d} };
37      protected double[][] testDataMinus = { {-1d,-2d,-3d}, {-2d,-5d,-3d}, 
38         {-1d,0d,-8d} };
39      protected double[] testDataRow1 = {1d,2d,3d};
40      protected double[] testDataCol3 = {3d,3d,8d};
41      protected double[][] testDataInv = 
42          { {-40d,16d,9d}, {13d,-5d,-3d}, {5d,-2d,-1d} };
43      protected double[] preMultTest = {8,12,33};
44      protected double[][] testData2 ={ {1d,2d,3d}, {2d,5d,3d}};
45      protected double[][] testData2T = { {1d,2d}, {2d,5d}, {3d,3d}};
46      protected double[][] testDataPlusInv = 
47          { {-39d,18d,12d}, {15d,0d,0d}, {6d,-2d,7d} };
48      
49      // lu decomposition tests
50      protected double[][] luData = { {2d,3d,3d}, {0d,5d,7d}, {6d,9d,8d} };
51      protected double[][] luDataLUDecomposition = { {6d,9d,8d}, {0d,5d,7d},
52              {0.33333333333333,0d,0.33333333333333} };
53      
54      // singular matrices
55      protected double[][] singular = { {2d,3d}, {2d,3d} };
56      protected double[][] bigSingular = {{1d,2d,3d,4d}, {2d,5d,3d,4d},
57          {7d,3d,256d,1930d}, {3d,7d,6d,8d}}; // 4th row = 1st + 2nd
58      protected double[][] detData = { {1d,2d,3d}, {4d,5d,6d}, {7d,8d,10d} };
59      protected double[][] detData2 = { {1d, 3d}, {2d, 4d}};
60      
61      // vectors
62      protected double[] testVector = {1,2,3};
63      protected double[] testVector2 = {1,2,3,4};
64      
65      // submatrix accessor tests
66      protected double[][] subTestData = {{1, 2, 3, 4}, {1.5, 2.5, 3.5, 4.5},
67              {2, 4, 6, 8}, {4, 5, 6, 7}}; 
68      // array selections
69      protected double[][] subRows02Cols13 = { {2, 4}, {4, 8}};
70      protected double[][] subRows03Cols12 = { {2, 3}, {5, 6}};
71      protected double[][] subRows03Cols123 = { {2, 3, 4} , {5, 6, 7}};
72      // effective permutations
73      protected double[][] subRows20Cols123 = { {4, 6, 8} , {2, 3, 4}};
74      protected double[][] subRows31Cols31 = {{7, 5}, {4.5, 2.5}};
75      // contiguous ranges
76      protected double[][] subRows01Cols23 = {{3,4} , {3.5, 4.5}};
77      protected double[][] subRows23Cols00 = {{2} , {4}};
78      protected double[][] subRows00Cols33 = {{4}};
79      // row matrices
80      protected double[][] subRow0 = {{1,2,3,4}};
81      protected double[][] subRow3 = {{4,5,6,7}};
82      // column matrices
83      protected double[][] subColumn1 = {{2}, {2.5}, {4}, {5}};
84      protected double[][] subColumn3 = {{4}, {4.5}, {8}, {7}};
85      
86      // tolerances
87      protected double entryTolerance = 10E-16;
88      protected double normTolerance = 10E-14;
89      
90      public RealMatrixImplTest(String name) {
91          super(name);
92      }
93      
94      public void setUp() {
95          
96      }
97      
98      public static Test suite() {
99          TestSuite suite = new TestSuite(RealMatrixImplTest.class);
100         suite.setName("RealMatrixImpl Tests");
101         return suite;
102     }
103     
104     /** test dimensions */
105     public void testDimensions() {
106         RealMatrixImpl m = new RealMatrixImpl(testData);
107         RealMatrixImpl m2 = new RealMatrixImpl(testData2);
108         assertEquals("testData row dimension",3,m.getRowDimension());
109         assertEquals("testData column dimension",3,m.getColumnDimension());
110         assertTrue("testData is square",m.isSquare());
111         assertEquals("testData2 row dimension",m2.getRowDimension(),2);
112         assertEquals("testData2 column dimension",m2.getColumnDimension(),3);
113         assertTrue("testData2 is not square",!m2.isSquare());
114     } 
115     
116     /** test copy functions */
117     public void testCopyFunctions() {
118         RealMatrixImpl m = new RealMatrixImpl(testData);
119         RealMatrixImpl m2 = new RealMatrixImpl(m.getData());
120         assertEquals(m2,m);
121     }           
122     
123     /** test add */
124     public void testAdd() {
125         RealMatrixImpl m = new RealMatrixImpl(testData);
126         RealMatrixImpl mInv = new RealMatrixImpl(testDataInv);
127         RealMatrixImpl mPlusMInv = (RealMatrixImpl)m.add(mInv);
128         double[][] sumEntries = mPlusMInv.getData();
129         for (int row = 0; row < m.getRowDimension(); row++) {
130             for (int col = 0; col < m.getColumnDimension(); col++) {
131                 assertEquals("sum entry entry",
132                     testDataPlusInv[row][col],sumEntries[row][col],
133                         entryTolerance);
134             }
135         }    
136     }
137     
138     /** test add failure */
139     public void testAddFail() {
140         RealMatrixImpl m = new RealMatrixImpl(testData);
141         RealMatrixImpl m2 = new RealMatrixImpl(testData2);
142         try {
143             RealMatrixImpl mPlusMInv = (RealMatrixImpl)m.add(m2);
144             fail("IllegalArgumentException expected");
145         } catch (IllegalArgumentException ex) {
146             ;
147         }
148     }
149     
150     /** test norm */
151     public void testNorm() {
152         RealMatrixImpl m = new RealMatrixImpl(testData);
153         RealMatrixImpl m2 = new RealMatrixImpl(testData2);
154         assertEquals("testData norm",14d,m.getNorm(),entryTolerance);
155         assertEquals("testData2 norm",7d,m2.getNorm(),entryTolerance);
156     }
157     
158      /** test m-n = m + -n */
159     public void testPlusMinus() {
160         RealMatrixImpl m = new RealMatrixImpl(testData);
161         RealMatrixImpl m2 = new RealMatrixImpl(testDataInv);
162         assertClose("m-n = m + -n",m.subtract(m2),
163             m2.scalarMultiply(-1d).add(m),entryTolerance);        
164         try {
165             RealMatrix a = m.subtract(new RealMatrixImpl(testData2));
166             fail("Expecting illegalArgumentException");
167         } catch (IllegalArgumentException ex) {
168             ;
169         }      
170     }
171    
172     /** test multiply */
173      public void testMultiply() {
174         RealMatrixImpl m = new RealMatrixImpl(testData);
175         RealMatrixImpl mInv = new RealMatrixImpl(testDataInv);
176         RealMatrixImpl identity = new RealMatrixImpl(id);
177         RealMatrixImpl m2 = new RealMatrixImpl(testData2);
178         assertClose("inverse multiply",m.multiply(mInv),
179             identity,entryTolerance);
180         assertClose("inverse multiply",mInv.multiply(m),
181             identity,entryTolerance);
182         assertClose("identity multiply",m.multiply(identity),
183             m,entryTolerance);
184         assertClose("identity multiply",identity.multiply(mInv),
185             mInv,entryTolerance);
186         assertClose("identity multiply",m2.multiply(identity),
187             m2,entryTolerance); 
188         try {
189             RealMatrix a = m.multiply(new RealMatrixImpl(bigSingular));
190             fail("Expecting illegalArgumentException");
191         } catch (IllegalArgumentException ex) {
192             ;
193         }      
194     }   
195     
196     //Additional Test for RealMatrixImplTest.testMultiply
197 
198     private double[][] d3 = new double[][] {{1,2,3,4},{5,6,7,8}};
199     private double[][] d4 = new double[][] {{1},{2},{3},{4}};
200     private double[][] d5 = new double[][] {{30},{70}};
201      
202     public void testMultiply2() { 
203        RealMatrix m3 = new RealMatrixImpl(d3);   
204        RealMatrix m4 = new RealMatrixImpl(d4);
205        RealMatrix m5 = new RealMatrixImpl(d5);
206        assertClose("m3*m4=m5", m3.multiply(m4), m5, entryTolerance);
207    }  
208         
209     /** test isSingular */
210     public void testIsSingular() {
211         RealMatrixImpl m = new RealMatrixImpl(singular);
212         assertTrue("singular",m.isSingular());
213         m = new RealMatrixImpl(bigSingular);
214         assertTrue("big singular",m.isSingular());
215         m = new RealMatrixImpl(id);
216         assertTrue("identity nonsingular",!m.isSingular());
217         m = new RealMatrixImpl(testData);
218         assertTrue("testData nonsingular",!m.isSingular());
219     }
220         
221     /** test inverse */
222     public void testInverse() {
223         RealMatrixImpl m = new RealMatrixImpl(testData);
224         RealMatrix mInv = new RealMatrixImpl(testDataInv);
225         assertClose("inverse",mInv,m.inverse(),normTolerance);
226         assertClose("inverse^2",m,m.inverse().inverse(),10E-12);
227         
228         // Not square
229         m = new RealMatrixImpl(testData2);
230         try {
231             m.inverse();
232             fail("Expecting InvalidMatrixException");
233         } catch (InvalidMatrixException ex) {
234             // expected
235         }
236         
237         // Singular
238         m = new RealMatrixImpl(singular);
239         try {
240             m.inverse();
241             fail("Expecting InvalidMatrixException");
242         } catch (InvalidMatrixException ex) {
243             // expected
244         }
245     }
246     
247     /** test solve */
248     public void testSolve() {
249         RealMatrixImpl m = new RealMatrixImpl(testData);
250         RealMatrix mInv = new RealMatrixImpl(testDataInv);
251         // being a bit slothful here -- actually testing that X = A^-1 * B
252         assertClose("inverse-operate",mInv.operate(testVector),
253             m.solve(testVector),normTolerance);
254         try {
255             double[] x = m.solve(testVector2);
256             fail("expecting IllegalArgumentException");
257         } catch (IllegalArgumentException ex) {
258             ;
259         }       
260         RealMatrix bs = new RealMatrixImpl(bigSingular);
261         try {
262             RealMatrix a = bs.solve(bs);
263             fail("Expecting InvalidMatrixException");
264         } catch (InvalidMatrixException ex) {
265             ;
266         }
267         try {
268             RealMatrix a = m.solve(bs);
269             fail("Expecting IllegalArgumentException");
270         } catch (IllegalArgumentException ex) {
271             ;
272         }
273         try {
274             RealMatrix a = (new RealMatrixImpl(testData2)).solve(bs);
275             fail("Expecting illegalArgumentException");
276         } catch (IllegalArgumentException ex) {
277             ;
278         } 
279         try {
280             (new RealMatrixImpl(testData2)).luDecompose();
281             fail("Expecting InvalidMatrixException");
282         } catch (InvalidMatrixException ex) {
283             ;
284         }  
285     }
286     
287     /** test determinant */
288     public void testDeterminant() {       
289         RealMatrix m = new RealMatrixImpl(bigSingular);
290         assertEquals("singular determinant",0,m.getDeterminant(),0);
291         m = new RealMatrixImpl(detData);
292         assertEquals("nonsingular test",-3d,m.getDeterminant(),normTolerance);
293         
294         // Examples verified against R (version 1.8.1, Red Hat Linux 9)
295         m = new RealMatrixImpl(detData2);
296         assertEquals("nonsingular R test 1",-2d,m.getDeterminant(),normTolerance);
297         m = new RealMatrixImpl(testData);
298         assertEquals("nonsingular  R test 2",-1d,m.getDeterminant(),normTolerance);
299 
300         try {
301             double a = new RealMatrixImpl(testData2).getDeterminant();
302             fail("Expecting InvalidMatrixException");
303         } catch (InvalidMatrixException ex) {
304             ;
305         }      
306     }
307     
308     /** test trace */
309     public void testTrace() {
310         RealMatrix m = new RealMatrixImpl(id);
311         assertEquals("identity trace",3d,m.getTrace(),entryTolerance);
312         m = new RealMatrixImpl(testData2);
313         try {
314             double x = m.getTrace();
315             fail("Expecting illegalArgumentException");
316         } catch (IllegalArgumentException ex) {
317             ;
318         }      
319     }
320     
321     /** test sclarAdd */
322     public void testScalarAdd() {
323         RealMatrix m = new RealMatrixImpl(testData);
324         assertClose("scalar add",new RealMatrixImpl(testDataPlus2),
325             m.scalarAdd(2d),entryTolerance);
326     }
327                     
328     /** test operate */
329     public void testOperate() {
330         RealMatrix m = new RealMatrixImpl(id);
331         double[] x = m.operate(testVector);
332         assertClose("identity operate",testVector,x,entryTolerance);
333         m = new RealMatrixImpl(bigSingular);
334         try {
335             x = m.operate(testVector);
336             fail("Expecting illegalArgumentException");
337         } catch (IllegalArgumentException ex) {
338             ;
339         }      
340     }
341     
342     /** test transpose */
343     public void testTranspose() {
344         RealMatrix m = new RealMatrixImpl(testData); 
345         assertClose("inverse-transpose",m.inverse().transpose(),
346             m.transpose().inverse(),normTolerance);
347         m = new RealMatrixImpl(testData2);
348         RealMatrix mt = new RealMatrixImpl(testData2T);
349         assertClose("transpose",mt,m.transpose(),normTolerance);
350     }
351     
352     /** test preMultiply by vector */
353     public void testPremultiplyVector() {
354         RealMatrix m = new RealMatrixImpl(testData);
355         assertClose("premultiply",m.preMultiply(testVector),preMultTest,normTolerance);
356         m = new RealMatrixImpl(bigSingular);
357         try {
358             m.preMultiply(testVector);
359             fail("expecting IllegalArgumentException");
360         } catch (IllegalArgumentException ex) {
361             ;
362         }
363     }
364     
365     public void testPremultiply() {
366         RealMatrix m3 = new RealMatrixImpl(d3);   
367         RealMatrix m4 = new RealMatrixImpl(d4);
368         RealMatrix m5 = new RealMatrixImpl(d5);
369         assertClose("m3*m4=m5", m4.preMultiply(m3), m5, entryTolerance);
370         
371         RealMatrixImpl m = new RealMatrixImpl(testData);
372         RealMatrixImpl mInv = new RealMatrixImpl(testDataInv);
373         RealMatrixImpl identity = new RealMatrixImpl(id);
374         RealMatrixImpl m2 = new RealMatrixImpl(testData2);
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             RealMatrix a = 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             double[] x = m.getRow(10);
397             fail("expecting MatrixIndexException");
398         } catch (MatrixIndexException ex) {
399             ;
400         }
401         try {
402             double[] x = 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