1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math.linear;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertTrue;
22  
23  import org.apache.commons.math.MathException;
24  import org.apache.commons.math.linear.CholeskyDecomposition;
25  import org.apache.commons.math.linear.CholeskyDecompositionImpl;
26  import org.apache.commons.math.linear.MatrixUtils;
27  import org.apache.commons.math.linear.NonSquareMatrixException;
28  import org.apache.commons.math.linear.NotPositiveDefiniteMatrixException;
29  import org.apache.commons.math.linear.NotSymmetricMatrixException;
30  import org.apache.commons.math.linear.RealMatrix;
31  import org.junit.Test;
32  
33  public class CholeskyDecompositionImplTest {
34  
35      private double[][] testData = new double[][] {
36              {  1,  2,   4,   7,  11 },
37              {  2, 13,  23,  38,  58 },
38              {  4, 23,  77, 122, 182 },
39              {  7, 38, 122, 294, 430 },
40              { 11, 58, 182, 430, 855 }
41      };
42  
43      /** test dimensions */
44      @Test
45      public void testDimensions() throws MathException {
46          CholeskyDecomposition llt =
47              new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(testData));
48          assertEquals(testData.length, llt.getL().getRowDimension());
49          assertEquals(testData.length, llt.getL().getColumnDimension());
50          assertEquals(testData.length, llt.getLT().getRowDimension());
51          assertEquals(testData.length, llt.getLT().getColumnDimension());
52      }
53  
54      /** test non-square matrix */
55      @Test(expected = NonSquareMatrixException.class)
56      public void testNonSquare() throws MathException {
57          new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(new double[3][2]));
58      }
59  
60      /** test non-symmetric matrix */
61      @Test(expected = NotSymmetricMatrixException.class)
62      public void testNotSymmetricMatrixException() throws MathException {
63          double[][] changed = testData.clone();
64          changed[0][changed[0].length - 1] += 1.0e-5;
65          new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(changed));
66      }
67  
68      /** test non positive definite matrix */
69      @Test(expected = NotPositiveDefiniteMatrixException.class)
70      public void testNotPositiveDefinite() throws MathException {
71          new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(new double[][] {
72                  { 14, 11, 13, 15, 24 },
73                  { 11, 34, 13, 8,  25 },
74                  { 13, 13, 14, 15, 21 },
75                  { 15, 8,  15, 18, 23 },
76                  { 24, 25, 21, 23, 45 }
77          }));
78      }
79  
80      @Test(expected = NotPositiveDefiniteMatrixException.class)
81      public void testMath274() throws MathException {
82          new CholeskyDecompositionImpl(MatrixUtils.createRealMatrix(new double[][] {
83                  { 0.40434286, -0.09376327, 0.30328980, 0.04909388 },
84                  {-0.09376327,  0.10400408, 0.07137959, 0.04762857 },
85                  { 0.30328980,  0.07137959, 0.30458776, 0.04882449 },
86                  { 0.04909388,  0.04762857, 0.04882449, 0.07543265 }
87              
88          }));
89      }
90  
91      /** test A = LLT */
92      @Test
93      public void testAEqualLLT() throws MathException {
94          RealMatrix matrix = MatrixUtils.createRealMatrix(testData);
95          CholeskyDecomposition llt = new CholeskyDecompositionImpl(matrix);
96          RealMatrix l  = llt.getL();
97          RealMatrix lt = llt.getLT();
98          double norm = l.multiply(lt).subtract(matrix).getNorm();
99          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 }