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 static org.junit.Assert.assertEquals;
021    import static org.junit.Assert.assertTrue;
022    
023    import org.apache.commons.math.MathException;
024    import org.apache.commons.math.linear.CholeskyDecomposition;
025    import org.apache.commons.math.linear.CholeskyDecompositionImpl;
026    import org.apache.commons.math.linear.MatrixUtils;
027    import org.apache.commons.math.linear.NonSquareMatrixException;
028    import org.apache.commons.math.linear.NotPositiveDefiniteMatrixException;
029    import org.apache.commons.math.linear.NotSymmetricMatrixException;
030    import org.apache.commons.math.linear.RealMatrix;
031    import org.junit.Test;
032    
033    public class CholeskyDecompositionImplTest {
034    
035        private double[][] testData = new double[][] {
036                {  1,  2,   4,   7,  11 },
037                {  2, 13,  23,  38,  58 },
038                {  4, 23,  77, 122, 182 },
039                {  7, 38, 122, 294, 430 },
040                { 11, 58, 182, 430, 855 }
041        };
042    
043        /** test dimensions */
044        @Test
045        public void testDimensions() throws MathException {
046            CholeskyDecomposition llt =
047                new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(testData));
048            assertEquals(testData.length, llt.getL().getRowDimension());
049            assertEquals(testData.length, llt.getL().getColumnDimension());
050            assertEquals(testData.length, llt.getLT().getRowDimension());
051            assertEquals(testData.length, llt.getLT().getColumnDimension());
052        }
053    
054        /** test non-square matrix */
055        @Test(expected = NonSquareMatrixException.class)
056        public void testNonSquare() throws MathException {
057            new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(new double[3][2]));
058        }
059    
060        /** test non-symmetric matrix */
061        @Test(expected = NotSymmetricMatrixException.class)
062        public void testNotSymmetricMatrixException() throws MathException {
063            double[][] changed = testData.clone();
064            changed[0][changed[0].length - 1] += 1.0e-5;
065            new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(changed));
066        }
067    
068        /** test non positive definite matrix */
069        @Test(expected = NotPositiveDefiniteMatrixException.class)
070        public void testNotPositiveDefinite() throws MathException {
071            new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(new double[][] {
072                    { 14, 11, 13, 15, 24 },
073                    { 11, 34, 13, 8,  25 },
074                    { 13, 13, 14, 15, 21 },
075                    { 15, 8,  15, 18, 23 },
076                    { 24, 25, 21, 23, 45 }
077            }));
078        }
079    
080        @Test(expected = NotPositiveDefiniteMatrixException.class)
081        public void testMath274() throws MathException {
082            new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(new double[][] {
083                    { 0.40434286, -0.09376327, 0.30328980, 0.04909388 },
084                    {-0.09376327,  0.10400408, 0.07137959, 0.04762857 },
085                    { 0.30328980,  0.07137959, 0.30458776, 0.04882449 },
086                    { 0.04909388,  0.04762857, 0.04882449, 0.07543265 }
087                
088            }));
089        }
090    
091        /** test A = LLT */
092        @Test
093        public void testAEqualLLT() throws MathException {
094            RealMatrix matrix = MatrixUtils.createRealMatrix(testData);
095            CholeskyDecomposition llt = new CholeskyDecompositionImpl(matrix);
096            RealMatrix l  = llt.getL();
097            RealMatrix lt = llt.getLT();
098            double norm = l.multiply(lt).subtract(matrix).getNorm();
099            assertEquals(0, norm, 1.0e-15);
100        }
101    
102        /** test that L is lower triangular */
103        @Test
104        public void testLLowerTriangular() throws MathException {
105            RealMatrix matrix = MatrixUtils.createRealMatrix(testData);
106            RealMatrix l = new CholeskyDecompositionImpl(matrix).getL();
107            for (int i = 0; i < l.getRowDimension(); i++) {
108                for (int j = i + 1; j < l.getColumnDimension(); j++) {
109                    assertEquals(0.0, l.getEntry(i, j), 0.0);
110                }
111            }
112        }
113    
114        /** test that LT is transpose of L */
115        @Test
116        public void testLTTransposed() throws MathException {
117            RealMatrix matrix = MatrixUtils.createRealMatrix(testData);
118            CholeskyDecomposition llt = new CholeskyDecompositionImpl(matrix);
119            RealMatrix l  = llt.getL();
120            RealMatrix lt = llt.getLT();
121            double norm = l.subtract(lt.transpose()).getNorm();
122            assertEquals(0, norm, 1.0e-15);
123        }
124    
125        /** test matrices values */
126        @Test
127        public void testMatricesValues() throws MathException {
128            RealMatrix lRef = MatrixUtils.createRealMatrix(new double[][] {
129                    {  1,  0,  0,  0,  0 },
130                    {  2,  3,  0,  0,  0 },
131                    {  4,  5,  6,  0,  0 },
132                    {  7,  8,  9, 10,  0 },
133                    { 11, 12, 13, 14, 15 }
134            });
135           CholeskyDecomposition llt =
136                new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(testData));
137    
138            // check values against known references
139            RealMatrix l = llt.getL();
140            assertEquals(0, l.subtract(lRef).getNorm(), 1.0e-13);
141            RealMatrix lt = llt.getLT();
142            assertEquals(0, lt.subtract(lRef.transpose()).getNorm(), 1.0e-13);
143    
144            // check the same cached instance is returned the second time
145            assertTrue(l  == llt.getL());
146            assertTrue(lt == llt.getLT());
147            
148        }
149    
150    }