| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.commons.math.linear; |
| |
| import java.util.Arrays; |
| import java.util.Random; |
| |
| import junit.framework.Test; |
| import junit.framework.TestCase; |
| import junit.framework.TestSuite; |
| |
| public class EigenDecompositionImplTest extends TestCase { |
| |
| private double[] refValues; |
| private RealMatrix matrix; |
| |
| public EigenDecompositionImplTest(String name) { |
| super(name); |
| } |
| |
| public static Test suite() { |
| TestSuite suite = new TestSuite(EigenDecompositionImplTest.class); |
| suite.setName("EigenDecompositionImpl Tests"); |
| return suite; |
| } |
| |
| public void testDimension1() { |
| RealMatrix matrix = |
| new RealMatrixImpl(new double[][] { |
| { 1.5 } |
| }, false); |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| assertEquals(1.5, ed.getEigenvalue(0), 1.0e-15); |
| } |
| |
| public void testDimension2() { |
| RealMatrix matrix = |
| new RealMatrixImpl(new double[][] { |
| { 59.0, 12.0 }, |
| { Double.NaN, 66.0 } |
| }, false); |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| assertEquals(75.0, ed.getEigenvalue(0), 1.0e-15); |
| assertEquals(50.0, ed.getEigenvalue(1), 1.0e-15); |
| } |
| |
| public void testDimension3() { |
| RealMatrix matrix = |
| new RealMatrixImpl(new double[][] { |
| { 39632.0, -4824.0, -16560.0 }, |
| { Double.NaN, 8693.0, 7920.0 }, |
| { Double.NaN, Double.NaN, 17300.0 } |
| }, false); |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| assertEquals(50000.0, ed.getEigenvalue(0), 3.0e-11); |
| assertEquals(12500.0, ed.getEigenvalue(1), 3.0e-11); |
| assertEquals( 3125.0, ed.getEigenvalue(2), 3.0e-11); |
| } |
| |
| public void testDimension4WithSplit() { |
| RealMatrix matrix = |
| new RealMatrixImpl(new double[][] { |
| { 0.784, -0.288, 0.000, 0.000 }, |
| { Double.NaN, 0.616, 0.000, 0.000 }, |
| { Double.NaN, Double.NaN, 0.164, -0.048 }, |
| { Double.NaN, Double.NaN, Double.NaN, 0.136 } |
| }, false); |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| assertEquals(1.0, ed.getEigenvalue(0), 1.0e-15); |
| assertEquals(0.4, ed.getEigenvalue(1), 1.0e-15); |
| assertEquals(0.2, ed.getEigenvalue(2), 1.0e-15); |
| assertEquals(0.1, ed.getEigenvalue(3), 1.0e-15); |
| } |
| |
| public void testDimension4WithoutSplit() { |
| RealMatrix matrix = |
| new RealMatrixImpl(new double[][] { |
| { 0.5608, -0.2016, 0.1152, -0.2976 }, |
| { -0.2016, 0.4432, -0.2304, 0.1152 }, |
| { 0.1152, -0.2304, 0.3088, -0.1344 }, |
| { -0.2976, 0.1152, -0.1344, 0.3872 } |
| }, false); |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| assertEquals(1.0, ed.getEigenvalue(0), 1.0e-15); |
| assertEquals(0.4, ed.getEigenvalue(1), 1.0e-15); |
| assertEquals(0.2, ed.getEigenvalue(2), 1.0e-15); |
| assertEquals(0.1, ed.getEigenvalue(3), 1.0e-15); |
| } |
| |
| /** test dimensions */ |
| public void testDimensions() { |
| final int m = matrix.getRowDimension(); |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| assertEquals(m, ed.getV().getRowDimension()); |
| assertEquals(m, ed.getV().getColumnDimension()); |
| assertEquals(m, ed.getD().getColumnDimension()); |
| assertEquals(m, ed.getD().getColumnDimension()); |
| assertEquals(m, ed.getVT().getRowDimension()); |
| assertEquals(m, ed.getVT().getColumnDimension()); |
| } |
| |
| /** test eigenvalues */ |
| public void testEigenvalues() { |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| double[] eigenValues = ed.getEigenvalues(); |
| assertEquals(refValues.length, eigenValues.length); |
| for (int i = 0; i < refValues.length; ++i) { |
| assertEquals(refValues[i], eigenValues[i], 3.0e-15); |
| } |
| } |
| |
| /** test eigenvalues for a big matrix. */ |
| public void testBigMatrix() { |
| Random r = new Random(17748333525117l); |
| double[] bigValues = new double[200]; |
| for (int i = 0; i < bigValues.length; ++i) { |
| bigValues[i] = 2 * r.nextDouble() - 1; |
| } |
| Arrays.sort(bigValues); |
| EigenDecomposition ed = new EigenDecompositionImpl(createTestMatrix(r, bigValues)); |
| double[] eigenValues = ed.getEigenvalues(); |
| assertEquals(bigValues.length, eigenValues.length); |
| for (int i = 0; i < bigValues.length; ++i) { |
| assertEquals(bigValues[bigValues.length - i - 1], eigenValues[i], 2.0e-14); |
| } |
| } |
| |
| /** test eigenvectors */ |
| public void testEigenvectors() { |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| for (int i = 0; i < matrix.getRowDimension(); ++i) { |
| double lambda = ed.getEigenvalue(i); |
| RealVector v = ed.getEigenvector(i); |
| RealVector mV = matrix.operate(v); |
| assertEquals(0, mV.subtract(v.mapMultiplyToSelf(lambda)).getNorm(), 1.0e-13); |
| } |
| } |
| |
| /** test A = VDVt */ |
| public void testAEqualVDVt() { |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| RealMatrix v = ed.getV(); |
| RealMatrix d = ed.getD(); |
| RealMatrix vT = ed.getVT(); |
| double norm = v.multiply(d).multiply(vT).subtract(matrix).getNorm(); |
| assertEquals(0, norm, 6.0e-13); |
| } |
| |
| /** test that V is orthogonal */ |
| public void testVOrthogonal() { |
| RealMatrix v = new EigenDecompositionImpl(matrix).getV(); |
| RealMatrix vTv = v.transpose().multiply(v); |
| RealMatrix id = MatrixUtils.createRealIdentityMatrix(vTv.getRowDimension()); |
| assertEquals(0, vTv.subtract(id).getNorm(), 2.0e-13); |
| } |
| |
| /** test solve dimension errors */ |
| public void testSolveDimensionErrors() { |
| EigenDecomposition ed = new EigenDecompositionImpl(matrix); |
| RealMatrix b = new RealMatrixImpl(new double[2][2]); |
| try { |
| ed.solve(b); |
| fail("an exception should have been thrown"); |
| } catch (IllegalArgumentException iae) { |
| // expected behavior |
| } catch (Exception e) { |
| fail("wrong exception caught"); |
| } |
| try { |
| ed.solve(b.getColumn(0)); |
| fail("an exception should have been thrown"); |
| } catch (IllegalArgumentException iae) { |
| // expected behavior |
| } catch (Exception e) { |
| fail("wrong exception caught"); |
| } |
| try { |
| ed.solve(new RealVectorImplTest.RealVectorTestImpl(b.getColumn(0))); |
| fail("an exception should have been thrown"); |
| } catch (IllegalArgumentException iae) { |
| // expected behavior |
| } catch (Exception e) { |
| fail("wrong exception caught"); |
| } |
| } |
| |
| /** test solve */ |
| public void testSolve() { |
| RealMatrix m = new RealMatrixImpl(new double[][] { |
| { 91, 5, 29, 32, 40, 14 }, |
| { 5, 34, -1, 0, 2, -1 }, |
| { 29, -1, 12, 9, 21, 8 }, |
| { 32, 0, 9, 14, 9, 0 }, |
| { 40, 2, 21, 9, 51, 19 }, |
| { 14, -1, 8, 0, 19, 14 } |
| }); |
| EigenDecomposition ed = new EigenDecompositionImpl(m); |
| assertEquals(184041, ed.getDeterminant(), 2.0e-8); |
| RealMatrix b = new RealMatrixImpl(new double[][] { |
| { 1561, 269, 188 }, |
| { 69, -21, 70 }, |
| { 739, 108, 63 }, |
| { 324, 86, 59 }, |
| { 1624, 194, 107 }, |
| { 796, 69, 36 } |
| }); |
| RealMatrix xRef = new RealMatrixImpl(new double[][] { |
| { 1, 2, 1 }, |
| { 2, -1, 2 }, |
| { 4, 2, 3 }, |
| { 8, -1, 0 }, |
| { 16, 2, 0 }, |
| { 32, -1, 0 } |
| }); |
| |
| // using RealMatrix |
| assertEquals(0, ed.solve(b).subtract(xRef).getNorm(), 2.0e-12); |
| |
| // using double[] |
| for (int i = 0; i < b.getColumnDimension(); ++i) { |
| assertEquals(0, |
| new RealVectorImpl(ed.solve(b.getColumn(i))).subtract(xRef.getColumnVector(i)).getNorm(), |
| 2.0e-11); |
| } |
| |
| // using RealMatrixImpl |
| for (int i = 0; i < b.getColumnDimension(); ++i) { |
| assertEquals(0, |
| ed.solve(b.getColumnVector(i)).subtract(xRef.getColumnVector(i)).getNorm(), |
| 2.0e-11); |
| } |
| |
| // using RealMatrix with an alternate implementation |
| for (int i = 0; i < b.getColumnDimension(); ++i) { |
| RealVectorImplTest.RealVectorTestImpl v = |
| new RealVectorImplTest.RealVectorTestImpl(b.getColumn(i)); |
| assertEquals(0, |
| ed.solve(v).subtract(xRef.getColumnVector(i)).getNorm(), |
| 2.0e-11); |
| } |
| |
| } |
| |
| public void setUp() { |
| refValues = new double[] { |
| 2.003, 2.002, 2.001, 1.001, 1.000, 0.001 |
| }; |
| matrix = createTestMatrix(new Random(35992629946426l), refValues); |
| } |
| |
| public void tearDown() { |
| refValues = null; |
| matrix = null; |
| } |
| |
| private RealMatrix createTestMatrix(final Random r, final double[] eigenValues) { |
| final int n = eigenValues.length; |
| final RealMatrix v = createOrthogonalMatrix(r, n); |
| final RealMatrix d = createDiagonalMatrix(eigenValues, n, n); |
| return v.multiply(d).multiply(v.transpose()); |
| } |
| |
| public static RealMatrix createOrthogonalMatrix(final Random r, final int size) { |
| |
| final double[][] data = new double[size][size]; |
| |
| for (int i = 0; i < size; ++i) { |
| final double[] dataI = data[i]; |
| double norm2 = 0; |
| do { |
| |
| // generate randomly row I |
| for (int j = 0; j < size; ++j) { |
| dataI[j] = 2 * r.nextDouble() - 1; |
| } |
| |
| // project the row in the subspace orthogonal to previous rows |
| for (int k = 0; k < i; ++k) { |
| final double[] dataK = data[k]; |
| double dotProduct = 0; |
| for (int j = 0; j < size; ++j) { |
| dotProduct += dataI[j] * dataK[j]; |
| } |
| for (int j = 0; j < size; ++j) { |
| dataI[j] -= dotProduct * dataK[j]; |
| } |
| } |
| |
| // normalize the row |
| norm2 = 0; |
| for (final double dataIJ : dataI) { |
| norm2 += dataIJ * dataIJ; |
| } |
| final double inv = 1.0 / Math.sqrt(norm2); |
| for (int j = 0; j < size; ++j) { |
| dataI[j] *= inv; |
| } |
| |
| } while (norm2 * size < 0.01); |
| } |
| |
| return new RealMatrixImpl(data, false); |
| |
| } |
| |
| public static RealMatrix createDiagonalMatrix(final double[] diagonal, |
| final int rows, final int columns) { |
| final double[][] dData = new double[rows][columns]; |
| for (int i = 0; i < Math.min(rows, columns); ++i) { |
| dData[i][i] = diagonal[i]; |
| } |
| return new RealMatrixImpl(dData, false); |
| } |
| |
| } |