From 543a3ca57eade833b7bc3d2deec6fc0c16436f41 Mon Sep 17 00:00:00 2001 From: Phil Steitz Date: Mon, 1 Dec 2008 01:34:56 +0000 Subject: [PATCH] Added rigging for checking eigenvalues and eigenvectors and some easy test cases. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/branches/MATH_2_0@721943 13f79535-47bb-0310-9956-ffa450edef68 --- .../linear/EigenDecompositionImplTest.java | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/test/org/apache/commons/math/linear/EigenDecompositionImplTest.java b/src/test/org/apache/commons/math/linear/EigenDecompositionImplTest.java index 2cae9f91f..fed8121b8 100644 --- a/src/test/org/apache/commons/math/linear/EigenDecompositionImplTest.java +++ b/src/test/org/apache/commons/math/linear/EigenDecompositionImplTest.java @@ -255,6 +255,107 @@ public class EigenDecompositionImplTest extends TestCase { } } + + /** + * Matrix with eigenvalues {8, -1, -1} + */ + public void testRepeatedEigenvalue() { + RealMatrix repeated = new RealMatrixImpl(new double[][] { + {3, 2, 4}, + {2, 0, 2}, + {4, 2, 3} + }); + EigenDecomposition ed = new EigenDecompositionImpl(repeated); + checkEigenValues((new double[] {8, -1, -1}), ed, 1E-12); + checkEigenVector((new double[] {2, 1, 2}), ed, 1E-12); + } + + /** + * Matrix with eigenvalues {2, 0, 12} + */ + public void testDistinctEigenvalues() { + RealMatrix distinct = new RealMatrixImpl(new double[][] { + {3, 1, -4}, + {1, 3, -4}, + {-4, -4, 8} + }); + EigenDecomposition ed = new EigenDecompositionImpl(distinct); + checkEigenValues((new double[] {2, 0, 12}), ed, 1E-12); + checkEigenVector((new double[] {1, -1, 0}), ed, 1E-12); + checkEigenVector((new double[] {1, 1, 1}), ed, 1E-12); + checkEigenVector((new double[] {-1, -1, 2}), ed, 1E-12); + } + + /** + * Verifies that the given EigenDecomposition has eigenvalues equivalent to + * the targetValues, ignoring the order of the values and allowing + * values to differ by tolerance. + */ + protected void checkEigenValues(double[] targetValues, + EigenDecomposition ed, double tolerance) { + double[] observed = ed.getEigenvalues(); + for (int i = 0; i < observed.length; i++) { + assertTrue(isIncludedValue(observed[i], targetValues, tolerance)); + assertTrue(isIncludedValue(targetValues[i], observed, tolerance)); + } + } + + /** + * Returns true iff there is an entry within tolerance of value in + * searchArray. + */ + private boolean isIncludedValue(double value, double[] searchArray, + double tolerance) { + boolean found = false; + int i = 0; + while (!found && i < searchArray.length) { + if (Math.abs(value - searchArray[i]) < tolerance) { + found = true; + } + i++; + } + return found; + } + + /** + * Returns true iff eigenVector is a scalar multiple of one of the columns + * of ed.getV(). Does not try linear combinations - i.e., should only be + * used to find vectors in one-dimensional eigenspaces. + */ + protected void checkEigenVector(double[] eigenVector, + EigenDecomposition ed, double tolerance) { + assertTrue(isIncludedColumn(eigenVector, ed.getV(), tolerance)); + } + + /** + * Returns true iff there is a column that is a scalar multiple of column + * in searchMatrix (modulo tolerance) + */ + private boolean isIncludedColumn(double[] column, RealMatrix searchMatrix, + double tolerance) { + boolean found = false; + int i = 0; + while (!found && i < searchMatrix.getColumnDimension()) { + double multiplier = 1d; + boolean matching = true; + int j = 0; + while (matching && j < searchMatrix.getRowDimension()) { + double colEntry = searchMatrix.getEntry(j, i); + // Use the first entry where both are non-zero as scalar + if (multiplier == 1d && Math.abs(colEntry) > 1E-14 + && Math.abs(column[j]) > 1e-14) { + multiplier = colEntry / column[j]; + } + if (Math.abs(column[j] * multiplier - colEntry) > tolerance) { + matching = false; + } + j++; + } + found = matching; + i++; + } + return found; + } public void setUp() { refValues = new double[] {