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.Arrays;
021
022 import org.apache.commons.math.linear.InvalidMatrixException;
023 import org.apache.commons.math.linear.MatrixUtils;
024 import org.apache.commons.math.linear.RealMatrix;
025 import org.apache.commons.math.linear.TriDiagonalTransformer;
026
027 import junit.framework.Test;
028 import junit.framework.TestCase;
029 import junit.framework.TestSuite;
030
031 public class TriDiagonalTransformerTest extends TestCase {
032
033 private double[][] testSquare5 = {
034 { 1, 2, 3, 1, 1 },
035 { 2, 1, 1, 3, 1 },
036 { 3, 1, 1, 1, 2 },
037 { 1, 3, 1, 2, 1 },
038 { 1, 1, 2, 1, 3 }
039 };
040
041 private double[][] testSquare3 = {
042 { 1, 3, 4 },
043 { 3, 2, 2 },
044 { 4, 2, 0 }
045 };
046
047 public TriDiagonalTransformerTest(String name) {
048 super(name);
049 }
050
051 public void testNonSquare() {
052 try {
053 new TriDiagonalTransformer(MatrixUtils.createRealMatrix(new double[3][2]));
054 fail("an exception should have been thrown");
055 } catch (InvalidMatrixException ime) {
056 // expected behavior
057 } catch (Exception e) {
058 fail("wrong exception caught");
059 }
060 }
061
062 public void testAEqualQTQt() {
063 checkAEqualQTQt(MatrixUtils.createRealMatrix(testSquare5));
064 checkAEqualQTQt(MatrixUtils.createRealMatrix(testSquare3));
065 }
066
067 private void checkAEqualQTQt(RealMatrix matrix) {
068 TriDiagonalTransformer transformer = new TriDiagonalTransformer(matrix);
069 RealMatrix q = transformer.getQ();
070 RealMatrix qT = transformer.getQT();
071 RealMatrix t = transformer.getT();
072 double norm = q.multiply(t).multiply(qT).subtract(matrix).getNorm();
073 assertEquals(0, norm, 4.0e-15);
074 }
075
076 public void testNoAccessBelowDiagonal() {
077 checkNoAccessBelowDiagonal(testSquare5);
078 checkNoAccessBelowDiagonal(testSquare3);
079 }
080
081 private void checkNoAccessBelowDiagonal(double[][] data) {
082 double[][] modifiedData = new double[data.length][];
083 for (int i = 0; i < data.length; ++i) {
084 modifiedData[i] = data[i].clone();
085 Arrays.fill(modifiedData[i], 0, i, Double.NaN);
086 }
087 RealMatrix matrix = MatrixUtils.createRealMatrix(modifiedData);
088 TriDiagonalTransformer transformer = new TriDiagonalTransformer(matrix);
089 RealMatrix q = transformer.getQ();
090 RealMatrix qT = transformer.getQT();
091 RealMatrix t = transformer.getT();
092 double norm = q.multiply(t).multiply(qT).subtract(MatrixUtils.createRealMatrix(data)).getNorm();
093 assertEquals(0, norm, 4.0e-15);
094 }
095
096 public void testQOrthogonal() {
097 checkOrthogonal(new TriDiagonalTransformer(MatrixUtils.createRealMatrix(testSquare5)).getQ());
098 checkOrthogonal(new TriDiagonalTransformer(MatrixUtils.createRealMatrix(testSquare3)).getQ());
099 }
100
101 public void testQTOrthogonal() {
102 checkOrthogonal(new TriDiagonalTransformer(MatrixUtils.createRealMatrix(testSquare5)).getQT());
103 checkOrthogonal(new TriDiagonalTransformer(MatrixUtils.createRealMatrix(testSquare3)).getQT());
104 }
105
106 private void checkOrthogonal(RealMatrix m) {
107 RealMatrix mTm = m.transpose().multiply(m);
108 RealMatrix id = MatrixUtils.createRealIdentityMatrix(mTm.getRowDimension());
109 assertEquals(0, mTm.subtract(id).getNorm(), 1.0e-15);
110 }
111
112 public void testTTriDiagonal() {
113 checkTriDiagonal(new TriDiagonalTransformer(MatrixUtils.createRealMatrix(testSquare5)).getT());
114 checkTriDiagonal(new TriDiagonalTransformer(MatrixUtils.createRealMatrix(testSquare3)).getT());
115 }
116
117 private void checkTriDiagonal(RealMatrix m) {
118 final int rows = m.getRowDimension();
119 final int cols = m.getColumnDimension();
120 for (int i = 0; i < rows; ++i) {
121 for (int j = 0; j < cols; ++j) {
122 if ((i < j - 1) || (i > j + 1)) {
123 assertEquals(0, m.getEntry(i, j), 1.0e-16);
124 }
125 }
126 }
127 }
128
129 public void testMatricesValues5() {
130 checkMatricesValues(testSquare5,
131 new double[][] {
132 { 1.0, 0.0, 0.0, 0.0, 0.0 },
133 { 0.0, -0.5163977794943222, 0.016748280772542083, 0.839800693771262, 0.16669620021405473 },
134 { 0.0, -0.7745966692414833, -0.4354553000860955, -0.44989322880603355, -0.08930153582895772 },
135 { 0.0, -0.2581988897471611, 0.6364346693566014, -0.30263204032131164, 0.6608313651342882 },
136 { 0.0, -0.2581988897471611, 0.6364346693566009, -0.027289660803112598, -0.7263191580755246 }
137 },
138 new double[] { 1, 4.4, 1.433099579242636, -0.89537362758743, 2.062274048344794 },
139 new double[] { -Math.sqrt(15), -3.0832882879592476, 0.6082710842351517, 1.1786086405912128 });
140 }
141
142 public void testMatricesValues3() {
143 checkMatricesValues(testSquare3,
144 new double[][] {
145 { 1.0, 0.0, 0.0 },
146 { 0.0, -0.6, 0.8 },
147 { 0.0, -0.8, -0.6 },
148 },
149 new double[] { 1, 2.64, -0.64 },
150 new double[] { -5, -1.52 });
151 }
152
153 private void checkMatricesValues(double[][] matrix, double[][] qRef,
154 double[] mainDiagnonal,
155 double[] secondaryDiagonal) {
156 TriDiagonalTransformer transformer =
157 new TriDiagonalTransformer(MatrixUtils.createRealMatrix(matrix));
158
159 // check values against known references
160 RealMatrix q = transformer.getQ();
161 assertEquals(0, q.subtract(MatrixUtils.createRealMatrix(qRef)).getNorm(), 1.0e-14);
162
163 RealMatrix t = transformer.getT();
164 double[][] tData = new double[mainDiagnonal.length][mainDiagnonal.length];
165 for (int i = 0; i < mainDiagnonal.length; ++i) {
166 tData[i][i] = mainDiagnonal[i];
167 if (i > 0) {
168 tData[i][i - 1] = secondaryDiagonal[i - 1];
169 }
170 if (i < secondaryDiagonal.length) {
171 tData[i][i + 1] = secondaryDiagonal[i];
172 }
173 }
174 assertEquals(0, t.subtract(MatrixUtils.createRealMatrix(tData)).getNorm(), 1.0e-14);
175
176 // check the same cached instance is returned the second time
177 assertTrue(q == transformer.getQ());
178 assertTrue(t == transformer.getT());
179
180 }
181
182 public static Test suite() {
183 return new TestSuite(TriDiagonalTransformerTest.class);
184 }
185
186 }