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 }