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    
018    package org.apache.commons.math.linear;
019    
020    import java.util.Random;
021    
022    import junit.framework.Test;
023    import junit.framework.TestCase;
024    import junit.framework.TestSuite;
025    
026    import org.apache.commons.math.linear.DecompositionSolver;
027    import org.apache.commons.math.linear.EigenDecompositionImpl;
028    import org.apache.commons.math.linear.InvalidMatrixException;
029    import org.apache.commons.math.linear.MatrixUtils;
030    import org.apache.commons.math.linear.RealMatrix;
031    import org.apache.commons.math.linear.ArrayRealVector;
032    import org.apache.commons.math.util.MathUtils;
033    
034    public class EigenSolverTest extends TestCase {
035    
036        private double[] refValues;
037        private RealMatrix matrix;
038    
039        public EigenSolverTest(String name) {
040            super(name);
041        }
042    
043        public static Test suite() {
044            TestSuite suite = new TestSuite(EigenSolverTest.class);
045            suite.setName("EigenSolver Tests");
046            return suite;
047        }
048    
049        /** test non invertible matrix */
050        public void testNonInvertible() {
051            Random r = new Random(9994100315209l);
052            RealMatrix m =
053                EigenDecompositionImplTest.createTestMatrix(r, new double[] { 1.0, 0.0, -1.0, -2.0, -3.0 });
054            DecompositionSolver es = new EigenDecompositionImpl(m, MathUtils.SAFE_MIN).getSolver();
055            assertFalse(es.isNonSingular());
056            try {
057                es.getInverse();
058                fail("an exception should have been thrown");
059            } catch (InvalidMatrixException ime) {
060                // expected behavior
061            } catch (Exception e) {
062                fail("wrong exception caught");
063            }
064        }
065    
066        /** test invertible matrix */
067        public void testInvertible() {
068            Random r = new Random(9994100315209l);
069            RealMatrix m =
070                EigenDecompositionImplTest.createTestMatrix(r, new double[] { 1.0, 0.5, -1.0, -2.0, -3.0 });
071            DecompositionSolver es = new EigenDecompositionImpl(m, MathUtils.SAFE_MIN).getSolver();
072            assertTrue(es.isNonSingular());
073            RealMatrix inverse = es.getInverse();
074            RealMatrix error =
075                m.multiply(inverse).subtract(MatrixUtils.createRealIdentityMatrix(m.getRowDimension()));
076            assertEquals(0, error.getNorm(), 4.0e-15);
077        }
078    
079        /** test solve dimension errors */
080        public void testSolveDimensionErrors() {
081            DecompositionSolver es = new EigenDecompositionImpl(matrix, MathUtils.SAFE_MIN).getSolver();
082            RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
083            try {
084                es.solve(b);
085                fail("an exception should have been thrown");
086            } catch (IllegalArgumentException iae) {
087                // expected behavior
088            } catch (Exception e) {
089                fail("wrong exception caught");
090            }
091            try {
092                es.solve(b.getColumn(0));
093                fail("an exception should have been thrown");
094            } catch (IllegalArgumentException iae) {
095                // expected behavior
096            } catch (Exception e) {
097                fail("wrong exception caught");
098            }
099            try {
100                es.solve(new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(0)));
101                fail("an exception should have been thrown");
102            } catch (IllegalArgumentException iae) {
103                // expected behavior
104            } catch (Exception e) {
105                fail("wrong exception caught");
106            }
107        }
108    
109        /** test solve */
110        public void testSolve() {
111            RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {
112                    { 91,  5, 29, 32, 40, 14 },
113                    {  5, 34, -1,  0,  2, -1 },
114                    { 29, -1, 12,  9, 21,  8 },
115                    { 32,  0,  9, 14,  9,  0 },
116                    { 40,  2, 21,  9, 51, 19 },
117                    { 14, -1,  8,  0, 19, 14 }
118            });
119            DecompositionSolver es = new EigenDecompositionImpl(m, MathUtils.SAFE_MIN).getSolver();
120            RealMatrix b = MatrixUtils.createRealMatrix(new double[][] {
121                    { 1561, 269, 188 },
122                    {   69, -21,  70 },
123                    {  739, 108,  63 },
124                    {  324,  86,  59 },
125                    { 1624, 194, 107 },
126                    {  796,  69,  36 }
127            });
128            RealMatrix xRef = MatrixUtils.createRealMatrix(new double[][] {
129                    { 1,   2, 1 },
130                    { 2,  -1, 2 },
131                    { 4,   2, 3 },
132                    { 8,  -1, 0 },
133                    { 16,  2, 0 },
134                    { 32, -1, 0 }
135            });
136    
137            // using RealMatrix
138            assertEquals(0, es.solve(b).subtract(xRef).getNorm(), 2.0e-12);
139    
140            // using double[]
141            for (int i = 0; i < b.getColumnDimension(); ++i) {
142                assertEquals(0,
143                             new ArrayRealVector(es.solve(b.getColumn(i))).subtract(xRef.getColumnVector(i)).getNorm(),
144                             2.0e-11);
145            }
146    
147            // using Array2DRowRealMatrix
148            for (int i = 0; i < b.getColumnDimension(); ++i) {
149                assertEquals(0,
150                             es.solve(b.getColumnVector(i)).subtract(xRef.getColumnVector(i)).getNorm(),
151                             2.0e-11);
152            }
153    
154            // using RealMatrix with an alternate implementation
155            for (int i = 0; i < b.getColumnDimension(); ++i) {
156                ArrayRealVectorTest.RealVectorTestImpl v =
157                    new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(i));
158                assertEquals(0,
159                             es.solve(v).subtract(xRef.getColumnVector(i)).getNorm(),
160                             2.0e-11);
161            }
162    
163        }
164    
165        @Override
166        public void setUp() {
167            refValues = new double[] {
168                    2.003, 2.002, 2.001, 1.001, 1.000, 0.001
169            };
170            matrix = EigenDecompositionImplTest.createTestMatrix(new Random(35992629946426l), refValues);
171        }
172    
173        @Override
174        public void tearDown() {
175            refValues = null;
176            matrix    = null;
177        }
178    
179    }