001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.math.linear;
018    
019    import junit.framework.Test;
020    import junit.framework.TestCase;
021    import junit.framework.TestSuite;
022    
023    import java.math.BigDecimal;
024    
025    
026    /**
027     * Test cases for the {@link BigMatrixImpl} class.
028     *
029     * @version $Revision: 790372 $ $Date: 2009-07-01 16:48:19 -0400 (Wed, 01 Jul 2009) $
030     */
031    @Deprecated
032    public final class BigMatrixImplTest extends TestCase {
033        
034        // Test data for String constructors
035        protected  String[][] testDataString = { {"1","2","3"}, {"2","5","3"}, {"1","0","8"} };
036        
037        // 3 x 3 identity matrix
038        protected double[][] id = { {1d,0d,0d}, {0d,1d,0d}, {0d,0d,1d} };
039        
040        // Test data for group operations
041        protected double[][] testData = { {1d,2d,3d}, {2d,5d,3d}, {1d,0d,8d} };
042        protected double[][] testDataLU = {{2d, 5d, 3d}, {.5d, -2.5d, 6.5d}, {0.5d, 0.2d, .2d}};
043        protected double[][] testDataPlus2 = { {3d,4d,5d}, {4d,7d,5d}, {3d,2d,10d} };
044        protected double[][] testDataMinus = { {-1d,-2d,-3d}, {-2d,-5d,-3d}, 
045                {-1d,0d,-8d} };
046        protected double[] testDataRow1 = {1d,2d,3d};
047        protected double[] testDataCol3 = {3d,3d,8d};
048        protected double[][] testDataInv = 
049            { {-40d,16d,9d}, {13d,-5d,-3d}, {5d,-2d,-1d} };
050        protected double[] preMultTest = {8,12,33};
051        protected double[][] testData2 ={ {1d,2d,3d}, {2d,5d,3d}};
052        protected double[][] testData2T = { {1d,2d}, {2d,5d}, {3d,3d}};
053        protected double[][] testDataPlusInv = 
054            { {-39d,18d,12d}, {15d,0d,0d}, {6d,-2d,7d} };
055        
056        // lu decomposition tests
057        protected double[][] luData = { {2d,3d,3d}, {0d,5d,7d}, {6d,9d,8d} };
058        protected double[][] luDataLUDecomposition = { {6d,9d,8d}, {0d,5d,7d},
059                {0.33333333333333,0d,0.33333333333333} };
060        
061        // singular matrices
062        protected double[][] singular = { {2d,3d}, {2d,3d} };
063        protected double[][] bigSingular = {{1d,2d,3d,4d}, {2d,5d,3d,4d},
064                {7d,3d,256d,1930d}, {3d,7d,6d,8d}}; // 4th row = 1st + 2nd
065        protected double[][] detData = { {1d,2d,3d}, {4d,5d,6d}, {7d,8d,10d} };
066        protected double[][] detData2 = { {1d, 3d}, {2d, 4d}};
067        
068        // vectors
069        protected double[] testVector = {1,2,3};
070        protected double[] testVector2 = {1,2,3,4};
071        
072        // submatrix accessor tests
073        protected double[][] subTestData = {{1, 2, 3, 4}, {1.5, 2.5, 3.5, 4.5},
074                {2, 4, 6, 8}, {4, 5, 6, 7}}; 
075        // array selections
076        protected double[][] subRows02Cols13 = { {2, 4}, {4, 8}};
077        protected double[][] subRows03Cols12 = { {2, 3}, {5, 6}};
078        protected double[][] subRows03Cols123 = { {2, 3, 4} , {5, 6, 7}};
079        // effective permutations
080        protected double[][] subRows20Cols123 = { {4, 6, 8} , {2, 3, 4}};
081        protected double[][] subRows31Cols31 = {{7, 5}, {4.5, 2.5}};
082        // contiguous ranges
083        protected double[][] subRows01Cols23 = {{3,4} , {3.5, 4.5}};
084        protected double[][] subRows23Cols00 = {{2} , {4}};
085        protected double[][] subRows00Cols33 = {{4}};
086        // row matrices
087        protected double[][] subRow0 = {{1,2,3,4}};
088        protected double[][] subRow3 = {{4,5,6,7}};
089        // column matrices
090        protected double[][] subColumn1 = {{2}, {2.5}, {4}, {5}};
091        protected double[][] subColumn3 = {{4}, {4.5}, {8}, {7}};
092        
093        // tolerances
094        protected double entryTolerance = 10E-16;
095        protected double normTolerance = 10E-14;
096        
097        public BigMatrixImplTest(String name) {
098            super(name);
099        }
100        
101        public static Test suite() {
102            TestSuite suite = new TestSuite(BigMatrixImplTest.class);
103            suite.setName("BigMatrixImpl Tests");
104            return suite;
105        }
106    
107        public static final double[] asDouble(BigDecimal[] data) {
108            double d[] = new double[data.length];
109            for (int i=0;i<d.length;i++) {
110                d[i] = data[i].doubleValue();
111            }
112            return d;
113        }
114    
115        public static final double[][] asDouble(BigDecimal[][] data) {
116            double d[][] = new double[data.length][data[0].length];
117            for (int i=0;i<d.length;i++) {
118                for (int j=0;j<d[i].length;j++)
119                d[i][j] = data[i][j].doubleValue();
120            }
121            return d;
122        }
123    
124        public static final BigDecimal[] asBigDecimal(double [] data) {
125            BigDecimal d[] = new BigDecimal[data.length];
126            for (int i=0;i<d.length;i++) {
127                d[i] = new BigDecimal(data[i]);
128            }
129            return d;
130        }
131    
132        public static final BigDecimal[][] asBigDecimal(double [][] data) {
133            BigDecimal d[][] = new BigDecimal[data.length][data[0].length];
134            for (int i=0;i<d.length;i++) {
135                for (int j=0;j<data[i].length;j++) {
136                    d[i][j] = new BigDecimal(data[i][j]);
137                }
138            }
139            return d;
140        }
141    
142        /** test dimensions */
143        public void testDimensions() {
144            BigMatrixImpl m = new BigMatrixImpl(testData);
145            BigMatrixImpl m2 = new BigMatrixImpl(testData2);
146            assertEquals("testData row dimension",3,m.getRowDimension());
147            assertEquals("testData column dimension",3,m.getColumnDimension());
148            assertTrue("testData is square",m.isSquare());
149            assertEquals("testData2 row dimension",m2.getRowDimension(),2);
150            assertEquals("testData2 column dimension",m2.getColumnDimension(),3);
151            assertTrue("testData2 is not square",!m2.isSquare());
152        }  
153        
154        /** test copy functions */
155        public void testCopyFunctions() {
156            BigMatrixImpl m1 = new BigMatrixImpl(testData);
157            BigMatrixImpl m2 = new BigMatrixImpl(m1.getData());
158            assertEquals(m2,m1);
159            BigMatrixImpl m3 = new BigMatrixImpl(testData);
160            BigMatrixImpl m4 = new BigMatrixImpl(m3.getData(), false);
161            assertEquals(m4,m3);
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            BigMatrix m4 = new BigMatrixImpl(asBigDecimal(testData), true);
170            BigMatrix m5 = new BigMatrixImpl(asBigDecimal(testData), false);
171            assertClose("double, string", m1, m2, Double.MIN_VALUE);
172            assertClose("double, BigDecimal", m1, m3, Double.MIN_VALUE);
173            assertClose("string, BigDecimal", m2, m3, Double.MIN_VALUE);
174            assertClose("double, BigDecimal/true", m1, m4, Double.MIN_VALUE);
175            assertClose("double, BigDecimal/false", m1, m5, Double.MIN_VALUE);
176            try {
177                new BigMatrixImpl(new String[][] {{"0", "hello", "1"}});
178                fail("Expecting NumberFormatException");
179            } catch (NumberFormatException ex) {
180                // expected
181            }
182            try {
183                new BigMatrixImpl(new String[][] {});
184                fail("Expecting IllegalArgumentException");
185            } catch (IllegalArgumentException ex) {
186                // expected
187            }
188            try {
189                new BigMatrixImpl(new String[][] {{},{}});
190                fail("Expecting IllegalArgumentException");
191            } catch (IllegalArgumentException ex) {
192                // expected
193            }
194            try {
195                new BigMatrixImpl(new String[][] {{"a", "b"},{"c"}});
196                fail("Expecting IllegalArgumentException");
197            } catch (IllegalArgumentException ex) {
198                // expected
199            }
200    
201            try {
202                new BigMatrixImpl(0, 1);
203                fail("Expecting IllegalArgumentException");
204            } catch (IllegalArgumentException ex) {
205                // expected
206            }
207            try {
208                new BigMatrixImpl(1, 0);
209                fail("Expecting IllegalArgumentException");
210            } catch (IllegalArgumentException ex) {
211                // expected
212            }
213        }
214        
215        /** test add */
216        public void testAdd() {
217            BigMatrixImpl m = new BigMatrixImpl(testData);
218            BigMatrixImpl mInv = new BigMatrixImpl(testDataInv);
219            BigMatrix mPlusMInv = m.add(mInv);
220            double[][] sumEntries = asDouble(mPlusMInv.getData());
221            for (int row = 0; row < m.getRowDimension(); row++) {
222                for (int col = 0; col < m.getColumnDimension(); col++) {
223                    assertEquals("sum entry entry",
224                        testDataPlusInv[row][col],sumEntries[row][col],
225                            entryTolerance);
226                }
227            }    
228        }
229        
230        /** test add failure */
231        public void testAddFail() {
232            BigMatrixImpl m = new BigMatrixImpl(testData);
233            BigMatrixImpl m2 = new BigMatrixImpl(testData2);
234            try {
235                m.add(m2);
236                fail("IllegalArgumentException expected");
237            } catch (IllegalArgumentException ex) {
238                // ignored
239            }
240        }
241        
242        /** test norm */
243        public void testNorm() {
244            BigMatrixImpl m = new BigMatrixImpl(testData);
245            BigMatrixImpl m2 = new BigMatrixImpl(testData2);
246            assertEquals("testData norm",14d,m.getNorm().doubleValue(),entryTolerance);
247            assertEquals("testData2 norm",7d,m2.getNorm().doubleValue(),entryTolerance);
248        }
249        
250         /** test m-n = m + -n */
251        public void testPlusMinus() {
252            BigMatrixImpl m = new BigMatrixImpl(testData);
253            BigMatrixImpl m2 = new BigMatrixImpl(testDataInv);
254            assertClose("m-n = m + -n",m.subtract(m2),
255                m2.scalarMultiply(new BigDecimal(-1d)).add(m),entryTolerance);
256            try {
257                m.subtract(new BigMatrixImpl(testData2));
258                fail("Expecting illegalArgumentException");
259            } catch (IllegalArgumentException ex) {
260                // ignored
261            }      
262        }
263       
264        /** test multiply */
265         public void testMultiply() {
266            BigMatrixImpl m = new BigMatrixImpl(testData);
267            BigMatrixImpl mInv = new BigMatrixImpl(testDataInv);
268            BigMatrixImpl identity = new BigMatrixImpl(id);
269            BigMatrixImpl m2 = new BigMatrixImpl(testData2);
270            assertClose("inverse multiply",m.multiply(mInv),
271                identity,entryTolerance);
272            assertClose("inverse multiply",mInv.multiply(m),
273                identity,entryTolerance);
274            assertClose("identity multiply",m.multiply(identity),
275                m,entryTolerance);
276            assertClose("identity multiply",identity.multiply(mInv),
277                mInv,entryTolerance);
278            assertClose("identity multiply",m2.multiply(identity),
279                m2,entryTolerance); 
280            try {
281                m.multiply(new BigMatrixImpl(bigSingular));
282                fail("Expecting illegalArgumentException");
283            } catch (IllegalArgumentException ex) {
284                // ignored
285            }      
286        }   
287        
288        //Additional Test for BigMatrixImplTest.testMultiply
289    
290        private double[][] d3 = new double[][] {{1,2,3,4},{5,6,7,8}};
291        private double[][] d4 = new double[][] {{1},{2},{3},{4}};
292        private double[][] d5 = new double[][] {{30},{70}};
293         
294        public void testMultiply2() { 
295           BigMatrix m3 = new BigMatrixImpl(d3);
296           BigMatrix m4 = new BigMatrixImpl(d4);
297           BigMatrix m5 = new BigMatrixImpl(d5);
298           assertClose("m3*m4=m5", m3.multiply(m4), m5, entryTolerance);
299       }  
300            
301        /** test isSingular */
302        public void testIsSingular() {
303            BigMatrixImpl m = new BigMatrixImpl(singular);
304            assertTrue("singular",m.isSingular());
305            m = new BigMatrixImpl(bigSingular);
306            assertTrue("big singular",m.isSingular());
307            m = new BigMatrixImpl(id);
308            assertTrue("identity nonsingular",!m.isSingular());
309            m = new BigMatrixImpl(testData);
310            assertTrue("testData nonsingular",!m.isSingular());
311        }
312            
313        /** test inverse */
314        public void testInverse() {
315            BigMatrixImpl m = new BigMatrixImpl(testData);
316            BigMatrix mInv = new BigMatrixImpl(testDataInv);
317            assertClose("inverse",mInv,m.inverse(),normTolerance);
318            assertClose("inverse^2",m,m.inverse().inverse(),10E-12);
319            
320            // Not square
321            m = new BigMatrixImpl(testData2);
322            try {
323                m.inverse();
324                fail("Expecting InvalidMatrixException");
325            } catch (InvalidMatrixException ex) {
326                // expected
327            }
328            
329            // Singular
330            m = new BigMatrixImpl(singular);
331            try {
332                m.inverse();
333                fail("Expecting InvalidMatrixException");
334            } catch (InvalidMatrixException ex) {
335                // expected
336            }
337        }
338        
339        /** test solve */
340        public void testSolve() {
341            BigMatrixImpl m = new BigMatrixImpl(testData);
342            BigMatrix mInv = new BigMatrixImpl(testDataInv);
343            // being a bit slothful here -- actually testing that X = A^-1 * B
344            assertClose("inverse-operate",
345                        asDouble(mInv.operate(asBigDecimal(testVector))),
346                        asDouble(m.solve(asBigDecimal(testVector))),
347                        normTolerance);
348            try {
349                asDouble(m.solve(asBigDecimal(testVector2)));
350                fail("expecting IllegalArgumentException");
351            } catch (IllegalArgumentException ex) {
352                // ignored
353            }       
354            BigMatrix bs = new BigMatrixImpl(bigSingular);
355            try {
356                bs.solve(bs);
357                fail("Expecting InvalidMatrixException");
358            } catch (InvalidMatrixException ex) {
359                // ignored
360            }
361            try {
362                m.solve(bs);
363                fail("Expecting IllegalArgumentException");
364            } catch (IllegalArgumentException ex) {
365                // ignored
366            }
367            try {
368                new BigMatrixImpl(testData2).solve(bs);
369                fail("Expecting illegalArgumentException");
370            } catch (IllegalArgumentException ex) {
371                // ignored
372            } 
373            try {
374                (new BigMatrixImpl(testData2)).luDecompose();
375                fail("Expecting InvalidMatrixException");
376            } catch (InvalidMatrixException ex) {
377                // ignored
378            }  
379        }
380        
381        /** test determinant */
382        public void testDeterminant() {       
383            BigMatrix m = new BigMatrixImpl(bigSingular);
384            assertEquals("singular determinant",0,m.getDeterminant().doubleValue(),0);
385            m = new BigMatrixImpl(detData);
386            assertEquals("nonsingular test",-3d,m.getDeterminant().doubleValue(),normTolerance);
387            
388            // Examples verified against R (version 1.8.1, Red Hat Linux 9)
389            m = new BigMatrixImpl(detData2);
390            assertEquals("nonsingular R test 1",-2d,m.getDeterminant().doubleValue(),normTolerance);
391            m = new BigMatrixImpl(testData);
392            assertEquals("nonsingular  R test 2",-1d,m.getDeterminant().doubleValue(),normTolerance);
393    
394            try {
395                double d = new BigMatrixImpl(testData2).getDeterminant().doubleValue();
396                fail("Expecting InvalidMatrixException, got " + d);
397            } catch (InvalidMatrixException ex) {
398                // ignored
399            }      
400        }
401        
402        /** test trace */
403        public void testTrace() {
404            BigMatrix m = new BigMatrixImpl(id);
405            assertEquals("identity trace",3d,m.getTrace().doubleValue(),entryTolerance);
406            m = new BigMatrixImpl(testData2);
407            try {
408                double t = m.getTrace().doubleValue();
409                fail("Expecting NonSquareMatrixException, got " + t);
410            } catch (NonSquareMatrixException ex) {
411                // ignored
412            }      
413        }
414        
415        /** test sclarAdd */
416        public void testScalarAdd() {
417            BigMatrix m = new BigMatrixImpl(testData);
418            assertClose("scalar add",new BigMatrixImpl(testDataPlus2),
419                m.scalarAdd(new BigDecimal(2d)),entryTolerance);
420        }
421                        
422        /** test operate */
423        public void testOperate() {
424            BigMatrix m = new BigMatrixImpl(id);
425            double[] x = asDouble(m.operate(asBigDecimal(testVector)));
426            assertClose("identity operate",testVector,x,entryTolerance);
427            m = new BigMatrixImpl(bigSingular);
428            try {
429                asDouble(m.operate(asBigDecimal(testVector)));
430                fail("Expecting illegalArgumentException");
431            } catch (IllegalArgumentException ex) {
432                // ignored
433            }      
434        }
435    
436        /** test issue MATH-209 */
437        public void testMath209() {
438            BigMatrix a = new BigMatrixImpl(new BigDecimal[][] {
439                    { new BigDecimal(1), new BigDecimal(2) },
440                    { new BigDecimal(3), new BigDecimal(4) },
441                    { new BigDecimal(5), new BigDecimal(6) }
442            }, false);
443            BigDecimal[] b = a.operate(new BigDecimal[] { new BigDecimal(1), new BigDecimal(1) });
444            assertEquals(a.getRowDimension(), b.length);
445            assertEquals( 3.0, b[0].doubleValue(), 1.0e-12);
446            assertEquals( 7.0, b[1].doubleValue(), 1.0e-12);
447            assertEquals(11.0, b[2].doubleValue(), 1.0e-12);
448        }
449        
450        /** test transpose */
451        public void testTranspose() {
452            BigMatrix m = new BigMatrixImpl(testData);
453            assertClose("inverse-transpose",m.inverse().transpose(),
454                m.transpose().inverse(),normTolerance);
455            m = new BigMatrixImpl(testData2);
456            BigMatrix mt = new BigMatrixImpl(testData2T);
457            assertClose("transpose",mt,m.transpose(),normTolerance);
458        }
459        
460        /** test preMultiply by vector */
461        public void testPremultiplyVector() {
462            BigMatrix m = new BigMatrixImpl(testData);
463            assertClose("premultiply",asDouble(m.preMultiply(asBigDecimal(testVector))),preMultTest,normTolerance);
464            m = new BigMatrixImpl(bigSingular);
465            try {
466                m.preMultiply(asBigDecimal(testVector));
467                fail("expecting IllegalArgumentException");
468            } catch (IllegalArgumentException ex) {
469                // ignored
470            }
471        }
472        
473        public void testPremultiply() {
474            BigMatrix m3 = new BigMatrixImpl(d3);
475            BigMatrix m4 = new BigMatrixImpl(d4);
476            BigMatrix m5 = new BigMatrixImpl(d5);
477            assertClose("m3*m4=m5", m4.preMultiply(m3), m5, entryTolerance);
478            
479            BigMatrixImpl m = new BigMatrixImpl(testData);
480            BigMatrixImpl mInv = new BigMatrixImpl(testDataInv);
481            BigMatrixImpl identity = new BigMatrixImpl(id);
482            new BigMatrixImpl(testData2);
483            assertClose("inverse multiply",m.preMultiply(mInv),
484                    identity,entryTolerance);
485            assertClose("inverse multiply",mInv.preMultiply(m),
486                    identity,entryTolerance);
487            assertClose("identity multiply",m.preMultiply(identity),
488                    m,entryTolerance);
489            assertClose("identity multiply",identity.preMultiply(mInv),
490                    mInv,entryTolerance);
491            try {
492                m.preMultiply(new BigMatrixImpl(bigSingular));
493                fail("Expecting illegalArgumentException");
494            } catch (IllegalArgumentException ex) {
495                // ignored
496            }      
497        }
498        
499        public void testGetVectors() {
500            BigMatrix m = new BigMatrixImpl(testData);
501            assertClose("get row",m.getRowAsDoubleArray(0),testDataRow1,entryTolerance);
502            assertClose("get col",m.getColumnAsDoubleArray(2),testDataCol3,entryTolerance);
503            try {
504                m.getRowAsDoubleArray(10);
505                fail("expecting MatrixIndexException");
506            } catch (MatrixIndexException ex) {
507                // ignored
508            }
509            try {
510                m.getColumnAsDoubleArray(-1);
511                fail("expecting MatrixIndexException");
512            } catch (MatrixIndexException ex) {
513                // ignored
514            }
515        }
516          
517        public void testLUDecomposition() throws Exception {
518            BigMatrixImpl m = new BigMatrixImpl(testData);
519            BigMatrix lu = m.getLUMatrix();
520            assertClose("LU decomposition", lu, new BigMatrixImpl(testDataLU), normTolerance);
521            verifyDecomposition(m, lu);
522            m = new BigMatrixImpl(luData);
523            lu = m.getLUMatrix();
524            assertClose("LU decomposition", lu, new BigMatrixImpl(luDataLUDecomposition), normTolerance);
525            verifyDecomposition(m, lu);
526            m = new BigMatrixImpl(testDataMinus);
527            lu = m.getLUMatrix();
528            verifyDecomposition(m, lu);
529            m = new BigMatrixImpl(id);
530            lu = m.getLUMatrix();
531            verifyDecomposition(m, lu);
532            try {
533                m = new BigMatrixImpl(bigSingular); // singular
534                lu = m.getLUMatrix();
535                fail("Expecting InvalidMatrixException");
536            } catch (InvalidMatrixException ex) {
537                // expected
538            }
539            try {
540                m = new BigMatrixImpl(testData2);  // not square
541                lu = m.getLUMatrix();
542                fail("Expecting InvalidMatrixException");
543            } catch (InvalidMatrixException ex) {
544                // expected
545            }
546        }
547        
548       /**
549        * test submatrix accessors
550        */
551        public void testSubMatrix() {
552            BigMatrix m = new BigMatrixImpl(subTestData);
553            BigMatrix mRows23Cols00 = new BigMatrixImpl(subRows23Cols00);
554            BigMatrix mRows00Cols33 = new BigMatrixImpl(subRows00Cols33);
555            BigMatrix mRows01Cols23 = new BigMatrixImpl(subRows01Cols23);
556            BigMatrix mRows02Cols13 = new BigMatrixImpl(subRows02Cols13);
557            BigMatrix mRows03Cols12 = new BigMatrixImpl(subRows03Cols12);
558            BigMatrix mRows03Cols123 = new BigMatrixImpl(subRows03Cols123);
559            BigMatrix mRows20Cols123 = new BigMatrixImpl(subRows20Cols123);
560            BigMatrix mRows31Cols31 = new BigMatrixImpl(subRows31Cols31);
561            assertEquals("Rows23Cols00", mRows23Cols00, 
562                    m.getSubMatrix(2 , 3 , 0, 0));
563            assertEquals("Rows00Cols33", mRows00Cols33, 
564                    m.getSubMatrix(0 , 0 , 3, 3));
565            assertEquals("Rows01Cols23", mRows01Cols23,
566                    m.getSubMatrix(0 , 1 , 2, 3));   
567            assertEquals("Rows02Cols13", mRows02Cols13,
568                    m.getSubMatrix(new int[] {0,2}, new int[] {1,3}));  
569            assertEquals("Rows03Cols12", mRows03Cols12,
570                    m.getSubMatrix(new int[] {0,3}, new int[] {1,2}));  
571            assertEquals("Rows03Cols123", mRows03Cols123,
572                    m.getSubMatrix(new int[] {0,3}, new int[] {1,2,3})); 
573            assertEquals("Rows20Cols123", mRows20Cols123,
574                    m.getSubMatrix(new int[] {2,0}, new int[] {1,2,3})); 
575            assertEquals("Rows31Cols31", mRows31Cols31,
576                    m.getSubMatrix(new int[] {3,1}, new int[] {3,1})); 
577            assertEquals("Rows31Cols31", mRows31Cols31,
578                    m.getSubMatrix(new int[] {3,1}, new int[] {3,1})); 
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(-1,1,2,2);
588                fail("Expecting MatrixIndexException");
589            } catch (MatrixIndexException ex) {
590                // expected
591            }
592            try {
593                m.getSubMatrix(1,0,2,2);
594                fail("Expecting MatrixIndexException");
595            } catch (MatrixIndexException ex) {
596                // expected
597            }
598            try {
599                m.getSubMatrix(1,0,2,4);
600                fail("Expecting MatrixIndexException");
601            } catch (MatrixIndexException ex) {
602                // expected
603            }
604            try {
605                m.getSubMatrix(new int[] {}, new int[] {0});
606                fail("Expecting MatrixIndexException");
607            } catch (MatrixIndexException ex) {
608                // expected
609            }
610            try {
611                m.getSubMatrix(new int[] {0}, new int[] {4});
612                fail("Expecting MatrixIndexException");
613            } catch (MatrixIndexException ex) {
614                // expected
615            }
616        }
617        
618        public void testGetColumnMatrix() {
619            BigMatrix m = new BigMatrixImpl(subTestData);
620            BigMatrix mColumn1 = new BigMatrixImpl(subColumn1);
621            BigMatrix mColumn3 = new BigMatrixImpl(subColumn3);
622            assertEquals("Column1", mColumn1, 
623                    m.getColumnMatrix(1));
624            assertEquals("Column3", mColumn3, 
625                    m.getColumnMatrix(3));
626            try {
627                m.getColumnMatrix(-1);
628                fail("Expecting MatrixIndexException");
629            } catch (MatrixIndexException ex) {
630                // expected
631            }
632            try {
633                m.getColumnMatrix(4);
634                fail("Expecting MatrixIndexException");
635            } catch (MatrixIndexException ex) {
636                // expected
637            }
638        }
639        
640        public void testGetRowMatrix() {
641            BigMatrix m = new BigMatrixImpl(subTestData);
642            BigMatrix mRow0 = new BigMatrixImpl(subRow0);
643            BigMatrix mRow3 = new BigMatrixImpl(subRow3);
644            assertEquals("Row0", mRow0, 
645                    m.getRowMatrix(0));
646            assertEquals("Row3", mRow3, 
647                    m.getRowMatrix(3));
648            try {
649                m.getRowMatrix(-1);
650                fail("Expecting MatrixIndexException");
651            } catch (MatrixIndexException ex) {
652                // expected
653            }
654            try {
655                m.getRowMatrix(4);
656                fail("Expecting MatrixIndexException");
657            } catch (MatrixIndexException ex) {
658                // expected
659            }
660        }
661        
662        public void testEqualsAndHashCode() {
663            BigMatrixImpl m = new BigMatrixImpl(testData);
664            BigMatrixImpl m1 = (BigMatrixImpl) m.copy();
665            BigMatrixImpl mt = (BigMatrixImpl) m.transpose();
666            assertTrue(m.hashCode() != mt.hashCode());
667            assertEquals(m.hashCode(), m1.hashCode());
668            assertEquals(m, m);
669            assertEquals(m, m1);
670            assertFalse(m.equals(null));
671            assertFalse(m.equals(mt));
672            assertFalse(m.equals(new BigMatrixImpl(bigSingular)));
673            // Different scales make BigDecimals, so matrices unequal
674            m = new BigMatrixImpl(new String[][] {{"2.0"}});
675            m1 = new BigMatrixImpl(new String[][] {{"2.00"}});
676            assertTrue(m.hashCode() != m1.hashCode());
677            assertFalse(m.equals(m1));
678        }
679        
680        public void testToString() {
681            BigMatrixImpl m = new BigMatrixImpl(testData);
682            assertEquals("BigMatrixImpl{{1,2,3},{2,5,3},{1,0,8}}",
683                    m.toString());
684            m = new BigMatrixImpl();
685            assertEquals("BigMatrixImpl{}",
686                    m.toString());
687        }
688        
689        public void testSetSubMatrix() throws Exception {
690            BigDecimal[][] detData3 = 
691                MatrixUtils.createBigMatrix(detData2).getData();
692            BigMatrixImpl m = new BigMatrixImpl(testData);
693            m.setSubMatrix(detData3,1,1);
694            BigMatrix expected = MatrixUtils.createBigMatrix
695                (new double[][] {{1.0,2.0,3.0},{2.0,1.0,3.0},{1.0,2.0,4.0}});
696            assertEquals(expected, m);  
697            
698            m.setSubMatrix(detData3,0,0);
699            expected = MatrixUtils.createBigMatrix
700                (new double[][] {{1.0,3.0,3.0},{2.0,4.0,3.0},{1.0,2.0,4.0}});
701            assertEquals(expected, m);  
702            
703            BigDecimal[][] testDataPlus3 = 
704                MatrixUtils.createBigMatrix(testDataPlus2).getData();
705            m.setSubMatrix(testDataPlus3,0,0);      
706            expected = MatrixUtils.createBigMatrix
707            (new double[][] {{3.0,4.0,5.0},{4.0,7.0,5.0},{3.0,2.0,10.0}});
708            assertEquals(expected, m);   
709            
710            // javadoc example
711            BigMatrixImpl matrix = (BigMatrixImpl) MatrixUtils.createBigMatrix
712                (new double[][] {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 0, 1 , 2}});
713            matrix.setSubMatrix(new BigDecimal[][] {{new BigDecimal(3),
714                new BigDecimal(4)}, {new BigDecimal(5), new BigDecimal(6)}}, 1, 1);
715            expected = MatrixUtils.createBigMatrix
716                (new BigDecimal[][] {{new BigDecimal(1), new BigDecimal(2),
717                 new BigDecimal(3), new BigDecimal(4)}, {new BigDecimal(5),
718                 new BigDecimal(3), new BigDecimal(4), new BigDecimal(8)},
719                 {new BigDecimal(9), new BigDecimal(5) , new BigDecimal(6),
720                  new BigDecimal(2)}});
721            assertEquals(expected, matrix);   
722            
723            // dimension overflow
724            try {  
725                m.setSubMatrix(matrix.getData(),1,1);
726                fail("expecting MatrixIndexException");
727            } catch (MatrixIndexException e) {
728                // expected
729            }
730            
731            // null
732            try {
733                m.setSubMatrix(null,1,1);
734                fail("expecting NullPointerException");
735            } catch (NullPointerException e) {
736                // expected
737            }
738            
739            // ragged
740            try {
741                m.setSubMatrix(new BigDecimal[][] {{new BigDecimal(1)},
742                        {new BigDecimal(2), new BigDecimal(3)}}, 0, 0);
743                fail("expecting IllegalArgumentException");
744            } catch (IllegalArgumentException e) {
745                // expected
746            }
747            
748            // empty
749            try {
750                m.setSubMatrix(new BigDecimal[][] {{}}, 0, 0);
751                fail("expecting IllegalArgumentException");
752            } catch (IllegalArgumentException e) {
753                // expected
754            }
755            
756        }
757        
758        //--------------- -----------------Protected methods
759            
760        /** verifies that two matrices are close (1-norm) */              
761        protected void assertClose(String msg, BigMatrix m, BigMatrix n,
762            double tolerance) {
763            assertTrue(msg,m.subtract(n).getNorm().doubleValue() < tolerance);
764        }
765        
766        /** verifies that two vectors are close (sup norm) */
767        protected void assertClose(String msg, double[] m, double[] n,
768            double tolerance) {
769            if (m.length != n.length) {
770                fail("vectors not same length");
771            }
772            for (int i = 0; i < m.length; i++) {
773                assertEquals(msg + " " +  i + " elements differ", 
774                    m[i],n[i],tolerance);
775            }
776        }
777        
778        /** extracts the l  and u matrices from compact lu representation */
779        protected void splitLU(BigMatrix lu, BigDecimal[][] lowerData, BigDecimal[][] upperData) throws InvalidMatrixException {
780            if (!lu.isSquare() || lowerData.length != lowerData[0].length || upperData.length != upperData[0].length ||
781                    lowerData.length != upperData.length
782                    || lowerData.length != lu.getRowDimension()) {
783                throw new InvalidMatrixException("incorrect dimensions");
784            }    
785            int n = lu.getRowDimension();
786            for (int i = 0; i < n; i++) {
787                for (int j = 0; j < n; j++) {
788                    if (j < i) {
789                        lowerData[i][j] = lu.getEntry(i, j);
790                        upperData[i][j] = new BigDecimal(0);
791                    } else if (i == j) {
792                        lowerData[i][j] = new BigDecimal(1);
793                        upperData[i][j] = lu.getEntry(i, j);
794                    } else {
795                        lowerData[i][j] = new BigDecimal(0);
796                        upperData[i][j] = lu.getEntry(i, j);
797                    }   
798                }
799            }
800        }
801        
802        /** Returns the result of applying the given row permutation to the matrix */
803        protected BigMatrix permuteRows(BigMatrix matrix, int[] permutation) {
804            if (!matrix.isSquare() || matrix.getRowDimension() != permutation.length) {
805                throw new IllegalArgumentException("dimension mismatch");
806            }
807            int n = matrix.getRowDimension();
808            int m = matrix.getColumnDimension();
809            BigDecimal out[][] = new BigDecimal[m][n];
810            for (int i = 0; i < n; i++) {
811                for (int j = 0; j < m; j++) {
812                    out[i][j] = matrix.getEntry(permutation[i], j);
813                }
814            }
815            return new BigMatrixImpl(out);
816        }
817        
818        /** Extracts l and u matrices from lu and verifies that matrix = l times u modulo permutation */
819        protected void verifyDecomposition(BigMatrix matrix, BigMatrix lu) throws Exception{
820            int n = matrix.getRowDimension();
821            BigDecimal[][] lowerData = new BigDecimal[n][n];
822            BigDecimal[][] upperData = new BigDecimal[n][n];
823            splitLU(lu, lowerData, upperData);
824            BigMatrix lower =new BigMatrixImpl(lowerData);
825            BigMatrix upper = new BigMatrixImpl(upperData);
826            int[] permutation = ((BigMatrixImpl) matrix).getPermutation();
827            BigMatrix permuted = permuteRows(matrix, permutation);
828            assertClose("lu decomposition does not work", permuted,
829                    lower.multiply(upper), normTolerance);
830        }
831             
832    //    /** Useful for debugging */
833    //    private void dumpMatrix(BigMatrix m) {
834    //          for (int i = 0; i < m.getRowDimension(); i++) {
835    //              String os = "";
836    //              for (int j = 0; j < m.getColumnDimension(); j++) {
837    //                  os += m.getEntry(i, j) + " ";
838    //              }
839    //              System.out.println(os);
840    //          }
841    //    }
842            
843    }
844