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 junit.framework.Test;
021    import junit.framework.TestCase;
022    import junit.framework.TestSuite;
023    
024    import org.apache.commons.math.MathException;
025    import org.apache.commons.math.linear.CholeskyDecompositionImpl;
026    import org.apache.commons.math.linear.DecompositionSolver;
027    import org.apache.commons.math.linear.MatrixUtils;
028    import org.apache.commons.math.linear.RealMatrix;
029    import org.apache.commons.math.linear.ArrayRealVector;
030    
031    public class CholeskySolverTest extends TestCase {
032    
033        private double[][] testData = new double[][] {
034                {  1,  2,   4,   7,  11 },
035                {  2, 13,  23,  38,  58 },
036                {  4, 23,  77, 122, 182 },
037                {  7, 38, 122, 294, 430 },
038                { 11, 58, 182, 430, 855 }
039        };
040    
041        public CholeskySolverTest(String name) {
042            super(name);
043        }
044    
045        public static Test suite() {
046            TestSuite suite = new TestSuite(CholeskySolverTest.class);
047            suite.setName("LUSolver Tests");
048            return suite;
049        }
050    
051        /** test solve dimension errors */
052        public void testSolveDimensionErrors() throws MathException {
053            DecompositionSolver solver =
054                new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(testData)).getSolver();
055            RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]);
056            try {
057                solver.solve(b);
058                fail("an exception should have been thrown");
059            } catch (IllegalArgumentException iae) {
060                // expected behavior
061            } catch (Exception e) {
062                fail("wrong exception caught");
063            }
064            try {
065                solver.solve(b.getColumn(0));
066                fail("an exception should have been thrown");
067            } catch (IllegalArgumentException iae) {
068                // expected behavior
069            } catch (Exception e) {
070                fail("wrong exception caught");
071            }
072            try {
073                solver.solve(new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(0)));
074                fail("an exception should have been thrown");
075            } catch (IllegalArgumentException iae) {
076                // expected behavior
077            } catch (Exception e) {
078                fail("wrong exception caught");
079            }
080        }
081    
082        /** test solve */
083        public void testSolve() throws MathException {
084            DecompositionSolver solver =
085                new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(testData)).getSolver();
086            RealMatrix b = MatrixUtils.createRealMatrix(new double[][] {
087                    {   78,  -13,    1 },
088                    {  414,  -62,   -1 },
089                    { 1312, -202,  -37 },
090                    { 2989, -542,  145 },
091                    { 5510, -1465, 201 }
092            });
093            RealMatrix xRef = MatrixUtils.createRealMatrix(new double[][] {
094                    { 1,  0,  1 },
095                    { 0,  1,  1 },
096                    { 2,  1, -4 },
097                    { 2,  2,  2 },
098                    { 5, -3,  0 }
099            });
100    
101            // using RealMatrix
102            assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 1.0e-13);
103    
104            // using double[]
105            for (int i = 0; i < b.getColumnDimension(); ++i) {
106                assertEquals(0,
107                             new ArrayRealVector(solver.solve(b.getColumn(i))).subtract(xRef.getColumnVector(i)).getNorm(),
108                             1.0e-13);
109            }
110    
111            // using ArrayRealVector
112            for (int i = 0; i < b.getColumnDimension(); ++i) {
113                assertEquals(0,
114                             solver.solve(b.getColumnVector(i)).subtract(xRef.getColumnVector(i)).getNorm(),
115                             1.0e-13);
116            }
117    
118            // using RealVector with an alternate implementation
119            for (int i = 0; i < b.getColumnDimension(); ++i) {
120                ArrayRealVectorTest.RealVectorTestImpl v =
121                    new ArrayRealVectorTest.RealVectorTestImpl(b.getColumn(i));
122                assertEquals(0,
123                             solver.solve(v).subtract(xRef.getColumnVector(i)).getNorm(),
124                             1.0e-13);
125            }
126    
127        }
128    
129        /** test determinant */
130        public void testDeterminant() throws MathException {
131            assertEquals(7290000.0, getDeterminant(MatrixUtils.createRealMatrix(testData)), 1.0e-15);
132        }
133    
134        private double getDeterminant(RealMatrix m) throws MathException {
135            return new CholeskyDecompositionImpl(m).getDeterminant();
136        }
137    
138    }