From 04d36411d5cef5aaca764c64ebbd9551c6c3ae7f Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Sat, 1 Mar 2014 11:52:58 +0100 Subject: [PATCH] LA: slightly reworked EVD unit tests --- .../LinearAlgebra/Factorization/Evd.cs | 8 +- src/UnitTests/AssertHelpers.cs | 155 +++++++- .../Complex/Factorization/EvdTests.cs | 374 ++++++------------ .../Complex/Factorization/UserEvdTests.cs | 195 +++------ .../Complex32/Factorization/EvdTests.cs | 371 ++++++----------- .../Complex32/Factorization/UserEvdTests.cs | 185 +++------ .../Double/Factorization/EvdTests.cs | 373 ++++++----------- .../Double/Factorization/UserEvdTests.cs | 195 +++------ .../Single/Factorization/EvdTests.cs | 361 ++++++----------- .../Single/Factorization/UserEvdTests.cs | 195 +++------ 10 files changed, 906 insertions(+), 1506 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Factorization/Evd.cs b/src/Numerics/LinearAlgebra/Factorization/Evd.cs index dd9260a1..b51c1ca4 100644 --- a/src/Numerics/LinearAlgebra/Factorization/Evd.cs +++ b/src/Numerics/LinearAlgebra/Factorization/Evd.cs @@ -103,7 +103,7 @@ namespace MathNet.Numerics.LinearAlgebra.Factorization public Matrix D { get; private set; } /// - /// Solves a system of linear equations, AX = B, with A SVD factorized. + /// Solves a system of linear equations, AX = B, with A EVD factorized. /// /// The right hand side , B. /// The left hand side , X. @@ -115,14 +115,14 @@ namespace MathNet.Numerics.LinearAlgebra.Factorization } /// - /// Solves a system of linear equations, AX = B, with A SVD factorized. + /// Solves a system of linear equations, AX = B, with A EVD factorized. /// /// The right hand side , B. /// The left hand side , X. public abstract void Solve(Matrix input, Matrix result); /// - /// Solves a system of linear equations, Ax = b, with A SVD factorized. + /// Solves a system of linear equations, Ax = b, with A EVD factorized. /// /// The right hand side vector, b. /// The left hand side , x. @@ -134,7 +134,7 @@ namespace MathNet.Numerics.LinearAlgebra.Factorization } /// - /// Solves a system of linear equations, Ax = b, with A SVD factorized. + /// Solves a system of linear equations, Ax = b, with A EVD factorized. /// /// The right hand side vector, b. /// The left hand side , x. diff --git a/src/UnitTests/AssertHelpers.cs b/src/UnitTests/AssertHelpers.cs index 5a0c2f7f..abb79129 100644 --- a/src/UnitTests/AssertHelpers.cs +++ b/src/UnitTests/AssertHelpers.cs @@ -25,6 +25,7 @@ // using System.Collections.Generic; +using MathNet.Numerics.LinearAlgebra; using NUnit.Framework; namespace MathNet.Numerics.UnitTests @@ -38,7 +39,7 @@ namespace MathNet.Numerics.UnitTests /// /// A class which includes some assertion helper methods particularly for numerical code. /// - internal class AssertHelpers + internal static class AssertHelpers { public static void AlmostEqual(Complex expected, Complex actual) { @@ -269,5 +270,157 @@ namespace MathNet.Numerics.UnitTests } } } + + public static void AlmostEqual(Matrix expected, Matrix actual, int decimalPlaces) + { + if (expected.ColumnCount != actual.ColumnCount || expected.RowCount != actual.RowCount) + { + Assert.Fail("Matrix dimensions mismatch. Expected: {0}; Actual: {1}", expected.ToTypeString(), actual.ToTypeString()); + } + + for (var i = 0; i < expected.RowCount; i++) + { + for (var j = 0; j < expected.ColumnCount; j++) + { + if (!actual.At(i, j).AlmostEqual(expected.At(i, j), decimalPlaces)) + { + Assert.Fail("Not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.At(i, j), actual.At(i, j)); + } + } + } + } + + public static void AlmostEqual(Matrix expected, Matrix actual, int decimalPlaces) + { + if (expected.ColumnCount != actual.ColumnCount || expected.RowCount != actual.RowCount) + { + Assert.Fail("Matrix dimensions mismatch. Expected: {0}; Actual: {1}", expected.ToTypeString(), actual.ToTypeString()); + } + + for (var i = 0; i < expected.RowCount; i++) + { + for (var j = 0; j < expected.ColumnCount; j++) + { + if (!actual.At(i, j).AlmostEqual(expected.At(i, j), decimalPlaces)) + { + Assert.Fail("Not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.At(i, j), actual.At(i, j)); + } + } + } + } + + public static void AlmostEqual(Matrix expected, Matrix actual, int decimalPlaces) + { + if (expected.ColumnCount != actual.ColumnCount || expected.RowCount != actual.RowCount) + { + Assert.Fail("Matrix dimensions mismatch. Expected: {0}; Actual: {1}", expected.ToTypeString(), actual.ToTypeString()); + } + + for (var i = 0; i < expected.RowCount; i++) + { + for (var j = 0; j < expected.ColumnCount; j++) + { + if (!actual.At(i, j).AlmostEqual(expected.At(i, j), decimalPlaces)) + { + Assert.Fail("Not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.At(i, j), actual.At(i, j)); + } + } + } + } + + public static void AlmostEqual(Matrix expected, Matrix actual, int decimalPlaces) + { + if (expected.ColumnCount != actual.ColumnCount || expected.RowCount != actual.RowCount) + { + Assert.Fail("Matrix dimensions mismatch. Expected: {0}; Actual: {1}", expected.ToTypeString(), actual.ToTypeString()); + } + + for (var i = 0; i < expected.RowCount; i++) + { + for (var j = 0; j < expected.ColumnCount; j++) + { + if (!actual.At(i, j).AlmostEqual(expected.At(i, j), decimalPlaces)) + { + Assert.Fail("Not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.At(i, j), actual.At(i, j)); + } + } + } + } + + public static void AlmostEqualRelative(Matrix expected, Matrix actual, int decimalPlaces) + { + if (expected.ColumnCount != actual.ColumnCount || expected.RowCount != actual.RowCount) + { + Assert.Fail("Matrix dimensions mismatch. Expected: {0}; Actual: {1}", expected.ToTypeString(), actual.ToTypeString()); + } + + for (var i = 0; i < expected.RowCount; i++) + { + for (var j = 0; j < expected.ColumnCount; j++) + { + if (!actual.At(i, j).AlmostEqualRelative(expected.At(i, j), decimalPlaces)) + { + Assert.Fail("Not equal within {0} relative places. Expected:{1}; Actual:{2}", decimalPlaces, expected.At(i, j), actual.At(i, j)); + } + } + } + } + + public static void AlmostEqualRelative(Matrix expected, Matrix actual, int decimalPlaces) + { + if (expected.ColumnCount != actual.ColumnCount || expected.RowCount != actual.RowCount) + { + Assert.Fail("Matrix dimensions mismatch. Expected: {0}; Actual: {1}", expected.ToTypeString(), actual.ToTypeString()); + } + + for (var i = 0; i < expected.RowCount; i++) + { + for (var j = 0; j < expected.ColumnCount; j++) + { + if (!actual.At(i, j).AlmostEqualRelative(expected.At(i, j), decimalPlaces)) + { + Assert.Fail("Not equal within {0} relative places. Expected:{1}; Actual:{2}", decimalPlaces, expected.At(i, j), actual.At(i, j)); + } + } + } + } + + public static void AlmostEqualRelative(Matrix expected, Matrix actual, int decimalPlaces) + { + if (expected.ColumnCount != actual.ColumnCount || expected.RowCount != actual.RowCount) + { + Assert.Fail("Matrix dimensions mismatch. Expected: {0}; Actual: {1}", expected.ToTypeString(), actual.ToTypeString()); + } + + for (var i = 0; i < expected.RowCount; i++) + { + for (var j = 0; j < expected.ColumnCount; j++) + { + if (!actual.At(i, j).AlmostEqualRelative(expected.At(i, j), decimalPlaces)) + { + Assert.Fail("Not equal within {0} relative places. Expected:{1}; Actual:{2}", decimalPlaces, expected.At(i, j), actual.At(i, j)); + } + } + } + } + + public static void AlmostEqualRelative(Matrix expected, Matrix actual, int decimalPlaces) + { + if (expected.ColumnCount != actual.ColumnCount || expected.RowCount != actual.RowCount) + { + Assert.Fail("Matrix dimensions mismatch. Expected: {0}; Actual: {1}", expected.ToTypeString(), actual.ToTypeString()); + } + + for (var i = 0; i < expected.RowCount; i++) + { + for (var j = 0; j < expected.ColumnCount; j++) + { + if (!actual.At(i, j).AlmostEqualRelative(expected.At(i, j), decimalPlaces)) + { + Assert.Fail("Not equal within {0} relative places. Expected:{1}; Actual:{2}", decimalPlaces, expected.At(i, j), actual.At(i, j)); + } + } + } + } } } diff --git a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs index e52d7c04..62028ed5 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs @@ -3,7 +3,9 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com -// Copyright (c) 2009-2010 Math.NET +// +// Copyright (c) 2009-2014 Math.NET +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -12,8 +14,10 @@ // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -42,26 +46,19 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization [TestFixture, Category("LAFactorization")] public class EvdTests { - /// - /// Can factorize identity matrix. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(10)] - [TestCase(100)] - public void CanFactorizeIdentity(int order) + [Test] + public void CanFactorizeIdentityMatrix([Values(1, 10, 100)] int order) { - var matrixI = DenseMatrix.CreateIdentity(order); - var factorEvd = matrixI.Evd(); + var matrix = Matrix.Build.DenseIdentity(order); + var factorEvd = matrix.Evd(); var eigenValues = factorEvd.EigenValues; var eigenVectors = factorEvd.EigenVectors; var d = factorEvd.D; - Assert.AreEqual(matrixI.RowCount, eigenVectors.RowCount); - Assert.AreEqual(matrixI.RowCount, eigenVectors.ColumnCount); - - Assert.AreEqual(matrixI.ColumnCount, d.RowCount); - Assert.AreEqual(matrixI.ColumnCount, d.ColumnCount); + Assert.AreEqual(matrix.RowCount, eigenVectors.RowCount); + Assert.AreEqual(matrix.RowCount, eigenVectors.ColumnCount); + Assert.AreEqual(matrix.ColumnCount, d.RowCount); + Assert.AreEqual(matrix.ColumnCount, d.ColumnCount); for (var i = 0; i < eigenValues.Count; i++) { @@ -69,126 +66,75 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization } } - /// - /// Can factorize a random square matrix. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanFactorizeRandomMatrix(int order) + [Test] + public void CanFactorizeRandomSquareMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.Random(order, order, 1); - var factorEvd = matrixA.Evd(); - var eigenVectors = factorEvd.EigenVectors; - - Assert.AreEqual(order, eigenVectors.RowCount); - Assert.AreEqual(order, eigenVectors.ColumnCount); - - Assert.AreEqual(order, factorEvd.D.RowCount); - Assert.AreEqual(order, factorEvd.D.ColumnCount); - - // Make sure the A*V = λ*V - var matrixAv = matrixA * eigenVectors; - var matrixLv = eigenVectors * factorEvd.D; - - for (var i = 0; i < matrixAv.RowCount; i++) - { - for (var j = 0; j < matrixAv.ColumnCount; j++) - { - AssertHelpers.AlmostEqualRelative(matrixAv[i, j], matrixLv[i, j], 7); - } - } + var A = Matrix.Build.Random(order, order, 1); + var factorEvd = A.Evd(); + var V = factorEvd.EigenVectors; + var λ = factorEvd.D; + + Assert.AreEqual(order, V.RowCount); + Assert.AreEqual(order, V.ColumnCount); + Assert.AreEqual(order, λ.RowCount); + Assert.AreEqual(order, λ.ColumnCount); + + // Verify A*V = λ*V + var Av = A * V; + var Lv = V * λ; + AssertHelpers.AlmostEqual(Av, Lv, 10); + AssertHelpers.AlmostEqualRelative(Av, Lv, 8); } - /// - /// Can factorize a symmetric random square matrix. - /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanFactorizeRandomSymmetricMatrix(int order) + public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var factorEvd = matrixA.Evd(); - var eigenVectors = factorEvd.EigenVectors; - var d = factorEvd.D; - - Assert.AreEqual(order, eigenVectors.RowCount); - Assert.AreEqual(order, eigenVectors.ColumnCount); - - Assert.AreEqual(order, d.RowCount); - Assert.AreEqual(order, d.ColumnCount); - - // Make sure the A = V*λ*VT - var matrix = eigenVectors * d * eigenVectors.ConjugateTranspose(); - - for (var i = 0; i < matrix.RowCount; i++) - { - for (var j = 0; j < matrix.ColumnCount; j++) - { - AssertHelpers.AlmostEqualRelative(matrix[i, j], matrixA[i, j], 7); - } - } + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var factorEvd = A.Evd(); + var V = factorEvd.EigenVectors; + var λ = factorEvd.D; + + Assert.AreEqual(order, V.RowCount); + Assert.AreEqual(order, V.ColumnCount); + Assert.AreEqual(order, λ.RowCount); + Assert.AreEqual(order, λ.ColumnCount); + + // Verify A = V*λ*VT + var matrix = V*λ*V.ConjugateTranspose(); + AssertHelpers.AlmostEqual(matrix, A, 10); + AssertHelpers.AlmostEqualRelative(matrix, A, 10); } - /// - /// Can check rank of square matrix. - /// - /// Matrix order. - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanCheckRankSquare(int order) + [Test] + public void CanCheckRankSquare([Values(10, 50, 100)] int order) { - var matrixA = Matrix.Build.Random(order, order, 1); - var factorEvd = matrixA.Evd(); - - Assert.AreEqual(factorEvd.Rank, order); + var A = Matrix.Build.Random(order, order, 1); + Assert.AreEqual(A.Evd().Rank, order); } - /// - /// Can check rank of square singular matrix. - /// - /// Matrix order. - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanCheckRankOfSquareSingular(int order) + [Test] + public void CanCheckRankOfSquareSingular([Values(10, 50, 100)] int order) { - var matrixA = new DenseMatrix(order, order); - matrixA[0, 0] = 1; - matrixA[order - 1, order - 1] = 1; + var A = new DenseMatrix(order, order); + A[0, 0] = 1; + A[order - 1, order - 1] = 1; for (var i = 1; i < order - 1; i++) { - matrixA[i, i - 1] = 1; - matrixA[i, i + 1] = 1; - matrixA[i - 1, i] = 1; - matrixA[i + 1, i] = 1; + A[i, i - 1] = 1; + A[i, i + 1] = 1; + A[i - 1, i] = 1; + A[i + 1, i] = 1; } - var factorEvd = matrixA.Evd(); + var factorEvd = A.Evd(); Assert.AreEqual(factorEvd.Determinant, Complex.Zero); Assert.AreEqual(factorEvd.Rank, order - 1); } - /// - /// Identity determinant is one. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(10)] - [TestCase(100)] - public void IdentityDeterminantIsOne(int order) + [Test] + public void IdentityDeterminantIsOne([Values(1, 10, 100)] int order) { var matrixI = DenseMatrix.CreateIdentity(order); var factorEvd = matrixI.Evd(); @@ -200,40 +146,26 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrix(int order) + public void CanSolveForRandomVectorAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var vectorb = Vector.Build.Random(order, 1); - var resultx = factorEvd.Solve(vectorb); + var b = Vector.Build.Random(order, 2); + var bCopy = b.Clone(); - Assert.AreEqual(matrixA.ColumnCount, resultx.Count); + var x = evd.Solve(b); - var matrixBReconstruct = matrixA * resultx; + var bReconstruct = A * x; // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - AssertHelpers.AlmostEqual(vectorb[i], matrixBReconstruct[i], 10); - } + AssertHelpers.ListAlmostEqual(b, bReconstruct, 9); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.ListAlmostEqual(bCopy, b, 14); } /// @@ -241,47 +173,33 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrix(int order) + public void CanSolveForRandomMatrixAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); - var matrixB = Matrix.Build.Random(order, order, 1); - var matrixX = factorEvd.Solve(matrixB); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); + + var B = Matrix.Build.Random(order, order, 2); + var BCopy = B.Clone(); + + var X = evd.Solve(B); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - AssertHelpers.AlmostEqual(matrixB[i, j], matrixBReconstruct[i, j], 10); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 9); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } /// @@ -289,45 +207,27 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven(int order) + public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); - var vectorb = Vector.Build.Random(order, 1); - var vectorbCopy = vectorb.Clone(); - var resultx = new DenseVector(order); - factorEvd.Solve(vectorb, resultx); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixBReconstruct = matrixA * resultx; + var b = Vector.Build.Random(order, 2); + var bCopy = b.Clone(); - // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - AssertHelpers.AlmostEqual(vectorb[i], matrixBReconstruct[i], 10); - } + var x = new DenseVector(order); + evd.Solve(b, x); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + var bReconstruct = A * x; - // Make sure b didn't change. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorbCopy[i], vectorb[i]); - } + // Check the reconstruction. + AssertHelpers.ListAlmostEqual(b, bReconstruct, 9); + + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.ListAlmostEqual(bCopy, b, 14); } /// @@ -335,59 +235,33 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven(int order) + public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixB = Matrix.Build.Random(order, order, 1); - var matrixBCopy = matrixB.Clone(); + var B = Matrix.Build.Random(order, order, 2); + var BCopy = B.Clone(); - var matrixX = new DenseMatrix(order, order); - factorEvd.Solve(matrixB, matrixX); + var X = new DenseMatrix(order, order); + evd.Solve(B, X); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - AssertHelpers.AlmostEqual(matrixB[i, j], matrixBReconstruct[i, j], 10); - } - } - - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 9); - // Make sure B didn't change. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } } } diff --git a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserEvdTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserEvdTests.cs index 6dbe378d..76b3bea5 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserEvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserEvdTests.cs @@ -198,187 +198,122 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b). /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrix(int order) + [Test] + public void CanSolveForRandomVectorAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var vectorb = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); - var resultx = factorEvd.Solve(vectorb); + var b = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); + var bCopy = b.Clone(); - Assert.AreEqual(matrixA.ColumnCount, resultx.Count); + var x = evd.Solve(b); - var matrixBReconstruct = matrixA * resultx; + var bReconstruct = A * x; // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - AssertHelpers.AlmostEqual(vectorb[i], matrixBReconstruct[i], 10); - } + AssertHelpers.AlmostEqual(b, bReconstruct, 9); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(bCopy, b, 14); } /// /// Can solve a system of linear equations for a random matrix and symmetric matrix (AX=B). /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrix(int order) + [Test] + public void CanSolveForRandomMatrixAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); + + var B = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); + var BCopy = B.Clone(); - var matrixB = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); - var matrixX = factorEvd.Solve(matrixB); + var X = evd.Solve(B); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - AssertHelpers.AlmostEqual(matrixB[i, j], matrixBReconstruct[i, j], 10); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 9); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } /// /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b) into a result matrix. /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven(int order) + [Test] + public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); - var vectorb = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); - var vectorbCopy = vectorb.Clone(); - var resultx = new UserDefinedVector(order); - factorEvd.Solve(vectorb, resultx); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixBReconstruct = matrixA * resultx; + var b = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); + var bCopy = b.Clone(); - // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - AssertHelpers.AlmostEqual(vectorb[i], matrixBReconstruct[i], 10); - } + var x = new UserDefinedVector(order); + evd.Solve(b, x); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + var bReconstruct = A * x; - // Make sure b didn't change. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorbCopy[i], vectorb[i]); - } + // Check the reconstruction. + AssertHelpers.AlmostEqual(b, bReconstruct, 9); + + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(bCopy, b, 14); } /// /// Can solve a system of linear equations for a random matrix and symmetric matrix (AX=B) into result matrix. /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven(int order) + [Test] + public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixB = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); - var matrixBCopy = matrixB.Clone(); + var B = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); + var BCopy = B.Clone(); - var matrixX = new UserDefinedMatrix(order, order); - factorEvd.Solve(matrixB, matrixX); + var X = new UserDefinedMatrix(order, order); + evd.Solve(B, X); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - AssertHelpers.AlmostEqual(matrixB[i, j], matrixBReconstruct[i, j], 10); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 9); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } - - // Make sure B didn't change. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } } } diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs index 5fe851f0..e5a439a3 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs @@ -3,7 +3,9 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com -// Copyright (c) 2009-2010 Math.NET +// +// Copyright (c) 2009-2014 Math.NET +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -12,8 +14,10 @@ // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -44,149 +48,94 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization [TestFixture, Category("LAFactorization")] public class EvdTests { - /// - /// Can factorize identity matrix. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(10)] - [TestCase(100)] - public void CanFactorizeIdentity(int order) + [Test] + public void CanFactorizeIdentityMatrix([Values(1, 10, 100)] int order) { - var matrixI = DenseMatrix.CreateIdentity(order); - var factorEvd = matrixI.Evd(); + var matrix = Matrix.Build.DenseIdentity(order); + var factorEvd = matrix.Evd(); var eigenValues = factorEvd.EigenValues; var eigenVectors = factorEvd.EigenVectors; var d = factorEvd.D; - Assert.AreEqual(matrixI.RowCount, eigenVectors.RowCount); - Assert.AreEqual(matrixI.RowCount, eigenVectors.ColumnCount); - - Assert.AreEqual(matrixI.ColumnCount, d.RowCount); - Assert.AreEqual(matrixI.ColumnCount, d.ColumnCount); + Assert.AreEqual(matrix.RowCount, eigenVectors.RowCount); + Assert.AreEqual(matrix.RowCount, eigenVectors.ColumnCount); + Assert.AreEqual(matrix.ColumnCount, d.RowCount); + Assert.AreEqual(matrix.ColumnCount, d.ColumnCount); - for (var i = 0; i < factorEvd.EigenValues.Count; i++) + for (var i = 0; i < eigenValues.Count; i++) { Assert.AreEqual(Complex.One, eigenValues[i]); } } - /// - /// Can factorize a random square matrix. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanFactorizeRandomMatrix(int order) + [Test] + public void CanFactorizeRandomSquareMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.Random(order, order, 1); - var factorEvd = matrixA.Evd(); - var eigenVectors = factorEvd.EigenVectors; - var d = factorEvd.D; - - Assert.AreEqual(order, eigenVectors.RowCount); - Assert.AreEqual(order, eigenVectors.ColumnCount); - - Assert.AreEqual(order, d.RowCount); - Assert.AreEqual(order, d.ColumnCount); - - // Make sure the A*V = λ*V - var matrixAv = matrixA * eigenVectors; - var matrixLv = eigenVectors * factorEvd.D; - - for (var i = 0; i < matrixAv.RowCount; i++) - { - for (var j = 0; j < matrixAv.ColumnCount; j++) - { - Assert.AreEqual(matrixAv[i, j].Real, matrixLv[i, j].Real, 1e-3f); - Assert.AreEqual(matrixAv[i, j].Imaginary, matrixLv[i, j].Imaginary, 1e-3f); - } - } + var A = Matrix.Build.Random(order, order, 1); + var factorEvd = A.Evd(); + var V = factorEvd.EigenVectors; + var λ = factorEvd.D; + + Assert.AreEqual(order, V.RowCount); + Assert.AreEqual(order, V.ColumnCount); + Assert.AreEqual(order, λ.RowCount); + Assert.AreEqual(order, λ.ColumnCount); + + // Verify A*V = λ*V + var Av = A * V; + var Lv = V * λ; + AssertHelpers.AlmostEqual(Av, Lv, 4); } - /// - /// Can factorize a symmetric random square matrix. - /// Matrix order. [Test] - public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10)] int order) + public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var factorEvd = matrixA.Evd(); - var eigenVectors = factorEvd.EigenVectors; - var d = factorEvd.D; - - Assert.AreEqual(order, eigenVectors.RowCount); - Assert.AreEqual(order, eigenVectors.ColumnCount); - - Assert.AreEqual(order, d.RowCount); - Assert.AreEqual(order, d.ColumnCount); - - // Make sure the A = V*λ*VT - var matrix = eigenVectors * d * eigenVectors.ConjugateTranspose(); - - for (var i = 0; i < matrix.RowCount; i++) - { - for (var j = 0; j < matrix.ColumnCount; j++) - { - AssertHelpers.AlmostEqual(matrix[i, j], matrixA[i, j], 3); - } - } + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var factorEvd = A.Evd(); + var V = factorEvd.EigenVectors; + var λ = factorEvd.D; + + Assert.AreEqual(order, V.RowCount); + Assert.AreEqual(order, V.ColumnCount); + Assert.AreEqual(order, λ.RowCount); + Assert.AreEqual(order, λ.ColumnCount); + + // Verify A = V*λ*VT + var matrix = V*λ*V.ConjugateTranspose(); + AssertHelpers.AlmostEqual(matrix, A, 3); + AssertHelpers.AlmostEqualRelative(matrix, A, 1); } - /// - /// Can check rank of square matrix. - /// - /// Matrix order. - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanCheckRankSquare(int order) + [Test] + public void CanCheckRankSquare([Values(10, 50, 100)] int order) { - var matrixA = Matrix.Build.Random(order, order, 1); - var factorEvd = matrixA.Evd(); - - Assert.AreEqual(factorEvd.Rank, order); + var A = Matrix.Build.Random(order, order, 1); + Assert.AreEqual(A.Evd().Rank, order); } - /// - /// Can check rank of square singular matrix. - /// - /// Matrix order. - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanCheckRankOfSquareSingular(int order) + [Test] + public void CanCheckRankOfSquareSingular([Values(10, 50, 100)] int order) { - var matrixA = new DenseMatrix(order, order); - matrixA[0, 0] = 1; - matrixA[order - 1, order - 1] = 1; + var A = new DenseMatrix(order, order); + A[0, 0] = 1; + A[order - 1, order - 1] = 1; for (var i = 1; i < order - 1; i++) { - matrixA[i, i - 1] = 1; - matrixA[i, i + 1] = 1; - matrixA[i - 1, i] = 1; - matrixA[i + 1, i] = 1; + A[i, i - 1] = 1; + A[i, i + 1] = 1; + A[i - 1, i] = 1; + A[i + 1, i] = 1; } - var factorEvd = matrixA.Evd(); + var factorEvd = A.Evd(); Assert.AreEqual(factorEvd.Determinant, Complex32.Zero); Assert.AreEqual(factorEvd.Rank, order - 1); } - /// - /// Identity determinant is one. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(10)] - [TestCase(100)] - public void IdentityDeterminantIsOne(int order) + [Test] + public void IdentityDeterminantIsOne([Values(1, 10, 100)] int order) { var matrixI = DenseMatrix.CreateIdentity(order); var factorEvd = matrixI.Evd(); @@ -198,40 +147,26 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - public void CanSolveForRandomVectorAndSymmetricMatrix(int order) + public void CanSolveForRandomVectorAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var vectorb = Vector.Build.Random(order, 1); - var resultx = factorEvd.Solve(vectorb); + var b = Vector.Build.Random(order, 2); + var bCopy = b.Clone(); - Assert.AreEqual(matrixA.ColumnCount, resultx.Count); + var x = evd.Solve(b); - var matrixBReconstruct = matrixA * resultx; + var bReconstruct = A * x; // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i].Real, matrixBReconstruct[i].Real, 1e-2f); - Assert.AreEqual(vectorb[i].Imaginary, matrixBReconstruct[i].Imaginary, 1e-2f); - } + AssertHelpers.ListAlmostEqual(b, bReconstruct, 2); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.ListAlmostEqual(bCopy, b, 14); } /// @@ -239,47 +174,32 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - public void CanSolveForRandomMatrixAndSymmetricMatrix(int order) + public void CanSolveForRandomMatrixAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); + + var B = Matrix.Build.Random(order, order, 2); + var BCopy = B.Clone(); - var matrixB = Matrix.Build.Random(order, order, 1); - var matrixX = factorEvd.Solve(matrixB); + var X = evd.Solve(B); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-2f); - Assert.AreEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-2f); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 1); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } /// @@ -287,45 +207,27 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven(int order) + public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); - var vectorb = Vector.Build.Random(order, 1); - var vectorbCopy = vectorb.Clone(); - var resultx = new DenseVector(order); - factorEvd.Solve(vectorb, resultx); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixBReconstruct = matrixA * resultx; + var b = Vector.Build.Random(order, 2); + var bCopy = b.Clone(); - // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i].Real, matrixBReconstruct[i].Real, 1e-2f); - Assert.AreEqual(vectorb[i].Imaginary, matrixBReconstruct[i].Imaginary, 1e-2f); - } + var x = new DenseVector(order); + evd.Solve(b, x); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + var bReconstruct = A * x; - // Make sure b didn't change. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorbCopy[i], vectorb[i]); - } + // Check the reconstruction. + AssertHelpers.ListAlmostEqual(b, bReconstruct, 2); + + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.ListAlmostEqual(bCopy, b, 14); } /// @@ -333,60 +235,33 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven(int order) + public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceConjugateSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixB = Matrix.Build.Random(order, order, 1); - var matrixBCopy = matrixB.Clone(); + var B = Matrix.Build.Random(order, order, 2); + var BCopy = B.Clone(); - var matrixX = new DenseMatrix(order, order); - factorEvd.Solve(matrixB, matrixX); + var X = new DenseMatrix(order, order); + evd.Solve(B, X); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-1f); - Assert.AreEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-1f); - } - } - - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 1); - // Make sure B didn't change. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } } } diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserEvdTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserEvdTests.cs index ce590f63..42116af7 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserEvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserEvdTests.cs @@ -197,181 +197,122 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b). /// /// Matrix order. - [Test, Ignore] + [Test] public void CanSolveForRandomVectorAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var vectorb = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); - var resultx = factorEvd.Solve(vectorb); + var b = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); + var bCopy = b.Clone(); - Assert.AreEqual(matrixA.ColumnCount, resultx.Count); + var x = evd.Solve(b); - var matrixBReconstruct = matrixA * resultx; + var bReconstruct = A * x; // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i].Real, matrixBReconstruct[i].Real, 1e-3f); - Assert.AreEqual(vectorb[i].Imaginary, matrixBReconstruct[i].Imaginary, 1e-3f); - } + AssertHelpers.AlmostEqual(b, bReconstruct, 2); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(bCopy, b, 14); } /// /// Can solve a system of linear equations for a random matrix and symmetric matrix (AX=B). /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrix(int order) + [Test] + public void CanSolveForRandomMatrixAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); + + var B = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); + var BCopy = B.Clone(); - var matrixB = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); - var matrixX = factorEvd.Solve(matrixB); + var X = evd.Solve(B); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-1f); - Assert.AreEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-1f); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 1); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } /// /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b) into a result matrix. /// /// Matrix order. - [Test, Ignore] + [Test] public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); - var vectorb = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); - var vectorbCopy = vectorb.Clone(); - var resultx = new UserDefinedVector(order); - factorEvd.Solve(vectorb, resultx); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixBReconstruct = matrixA * resultx; + var b = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); + var bCopy = b.Clone(); - // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i].Real, matrixBReconstruct[i].Real, 1e-3f); - Assert.AreEqual(vectorb[i].Imaginary, matrixBReconstruct[i].Imaginary, 1e-3f); - } + var x = new UserDefinedVector(order); + evd.Solve(b, x); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + var bReconstruct = A * x; - // Make sure b didn't change. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorbCopy[i], vectorb[i]); - } + // Check the reconstruction. + AssertHelpers.AlmostEqual(b, bReconstruct, 2); + + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(bCopy, b, 14); } /// /// Can solve a system of linear equations for a random matrix and symmetric matrix (AX=B) into result matrix. /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven(int order) + [Test] + public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceConjugateSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixB = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); - var matrixBCopy = matrixB.Clone(); + var B = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); + var BCopy = B.Clone(); - var matrixX = new UserDefinedMatrix(order, order); - factorEvd.Solve(matrixB, matrixX); + var X = new UserDefinedMatrix(order, order); + evd.Solve(B, X); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-1f); - Assert.AreEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-1f); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 1); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } - - // Make sure B didn't change. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } } } diff --git a/src/UnitTests/LinearAlgebraTests/Double/Factorization/EvdTests.cs b/src/UnitTests/LinearAlgebraTests/Double/Factorization/EvdTests.cs index f3f4a823..139161b4 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/Factorization/EvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/Factorization/EvdTests.cs @@ -3,7 +3,9 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com -// Copyright (c) 2009-2010 Math.NET +// +// Copyright (c) 2009-2014 Math.NET +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -12,8 +14,10 @@ // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -42,26 +46,19 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization [TestFixture, Category("LAFactorization")] public class EvdTests { - /// - /// Can factorize identity matrix. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(10)] - [TestCase(100)] - public void CanFactorizeIdentity(int order) + [Test] + public void CanFactorizeIdentityMatrix([Values(1, 10, 100)] int order) { - var matrixI = Matrix.Build.DenseIdentity(order); - var factorEvd = matrixI.Evd(); + var matrix = Matrix.Build.DenseIdentity(order); + var factorEvd = matrix.Evd(); var eigenValues = factorEvd.EigenValues; var eigenVectors = factorEvd.EigenVectors; var d = factorEvd.D; - Assert.AreEqual(matrixI.RowCount, eigenVectors.RowCount); - Assert.AreEqual(matrixI.RowCount, eigenVectors.ColumnCount); - - Assert.AreEqual(matrixI.ColumnCount, d.RowCount); - Assert.AreEqual(matrixI.ColumnCount, d.ColumnCount); + Assert.AreEqual(matrix.RowCount, eigenVectors.RowCount); + Assert.AreEqual(matrix.RowCount, eigenVectors.ColumnCount); + Assert.AreEqual(matrix.ColumnCount, d.RowCount); + Assert.AreEqual(matrix.ColumnCount, d.ColumnCount); for (var i = 0; i < eigenValues.Count; i++) { @@ -69,127 +66,75 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization } } - /// - /// Can factorize a random square matrix. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanFactorizeRandomMatrix(int order) + [Test] + public void CanFactorizeRandomSquareMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.Random(order, order, 1); - var factorEvd = matrixA.Evd(); - var eigenVectors = factorEvd.EigenVectors; - var d = factorEvd.D; - - Assert.AreEqual(order, eigenVectors.RowCount); - Assert.AreEqual(order, eigenVectors.ColumnCount); - - Assert.AreEqual(order, d.RowCount); - Assert.AreEqual(order, d.ColumnCount); - - // Make sure the A*V = λ*V - var matrixAv = matrixA * eigenVectors; - var matrixLv = eigenVectors * factorEvd.D; - - for (var i = 0; i < matrixAv.RowCount; i++) - { - for (var j = 0; j < matrixAv.ColumnCount; j++) - { - Assert.AreEqual(matrixAv[i, j], matrixLv[i, j], 1.0e-10); - } - } + var A = Matrix.Build.Random(order, order, 1); + var factorEvd = A.Evd(); + var V = factorEvd.EigenVectors; + var λ = factorEvd.D; + + Assert.AreEqual(order, V.RowCount); + Assert.AreEqual(order, V.ColumnCount); + Assert.AreEqual(order, λ.RowCount); + Assert.AreEqual(order, λ.ColumnCount); + + // Verify A*V = λ*V + var Av = A * V; + var Lv = V * λ; + AssertHelpers.AlmostEqual(Av, Lv, 10); + AssertHelpers.AlmostEqualRelative(Av, Lv, 8); } - /// - /// Can factorize a symmetric random square matrix. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanFactorizeRandomSymmetricMatrix(int order) + [Test] + public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var factorEvd = matrixA.Evd(); - var eigenVectors = factorEvd.EigenVectors; - var d = factorEvd.D; + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var factorEvd = A.Evd(); + var V = factorEvd.EigenVectors; + var λ = factorEvd.D; - Assert.AreEqual(order, eigenVectors.RowCount); - Assert.AreEqual(order, eigenVectors.ColumnCount); - - Assert.AreEqual(order, d.RowCount); - Assert.AreEqual(order, d.ColumnCount); - - // Make sure the A = V*λ*VT - var matrix = eigenVectors * d * eigenVectors.Transpose(); - - for (var i = 0; i < matrix.RowCount; i++) - { - for (var j = 0; j < matrix.ColumnCount; j++) - { - Assert.AreEqual(matrix[i, j], matrixA[i, j], 1.0e-10); - } - } + Assert.AreEqual(order, V.RowCount); + Assert.AreEqual(order, V.ColumnCount); + Assert.AreEqual(order, λ.RowCount); + Assert.AreEqual(order, λ.ColumnCount); + + // Verify A = V*λ*VT + var matrix = V * λ * V.Transpose(); + AssertHelpers.AlmostEqual(matrix, A, 10); + AssertHelpers.AlmostEqualRelative(matrix, A, 10); } - /// - /// Can check rank of square matrix. - /// - /// Matrix order. - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanCheckRankSquare(int order) + [Test] + public void CanCheckRankSquare([Values(10, 50, 100)] int order) { - var matrixA = Matrix.Build.Random(order, order, 1); - var factorEvd = matrixA.Evd(); - - Assert.AreEqual(factorEvd.Rank, order); + var A = Matrix.Build.Random(order, order, 1); + Assert.AreEqual(A.Evd().Rank, order); } - /// - /// Can check rank of square singular matrix. - /// - /// Matrix order. - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanCheckRankOfSquareSingular(int order) + [Test] + public void CanCheckRankOfSquareSingular([Values(10, 50, 100)] int order) { - var matrixA = new DenseMatrix(order, order); - matrixA[0, 0] = 1; - matrixA[order - 1, order - 1] = 1; + var A = new DenseMatrix(order, order); + A[0, 0] = 1; + A[order - 1, order - 1] = 1; for (var i = 1; i < order - 1; i++) { - matrixA[i, i - 1] = 1; - matrixA[i, i + 1] = 1; - matrixA[i - 1, i] = 1; - matrixA[i + 1, i] = 1; + A[i, i - 1] = 1; + A[i, i + 1] = 1; + A[i - 1, i] = 1; + A[i + 1, i] = 1; } - var factorEvd = matrixA.Evd(); + var factorEvd = A.Evd(); Assert.AreEqual(factorEvd.Determinant, 0); Assert.AreEqual(factorEvd.Rank, order - 1); } - /// - /// Identity determinant is one. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(10)] - [TestCase(100)] - public void IdentityDeterminantIsOne(int order) + [Test] + public void IdentityDeterminantIsOne([Values(1, 10, 100)] int order) { var matrixI = Matrix.Build.DenseIdentity(order); var factorEvd = matrixI.Evd(); @@ -201,40 +146,26 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrix(int order) + public void CanSolveForRandomVectorAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var vectorb = Vector.Build.Random(order, 1); - var resultx = factorEvd.Solve(vectorb); + var b = Vector.Build.Random(order, 2); + var bCopy = b.Clone(); - Assert.AreEqual(matrixA.ColumnCount, resultx.Count); + var x = evd.Solve(b); - var matrixBReconstruct = matrixA * resultx; + var bReconstruct = A * x; // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-9); - } + AssertHelpers.ListAlmostEqual(b, bReconstruct, 9); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.ListAlmostEqual(bCopy, b, 14); } //private @@ -243,48 +174,32 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrix(int order) + public void CanSolveForRandomMatrixAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixB = Matrix.Build.Random(order, order, 1); + var B = Matrix.Build.Random(order, order, 2); + var BCopy = B.Clone(); - var matrixX = factorEvd.Solve(matrixB); + var X = evd.Solve(B); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1e-9); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 9); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } /// @@ -292,45 +207,27 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven(int order) + public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); - var vectorb = Vector.Build.Random(order, 1); - var vectorbCopy = vectorb.Clone(); - var resultx = new DenseVector(order); - factorEvd.Solve(vectorb, resultx); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixBReconstruct = matrixA * resultx; + var b = Vector.Build.Random(order, 2); + var bCopy = b.Clone(); - // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-9); - } + var x = new DenseVector(order); + evd.Solve(b, x); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + var bReconstruct = A * x; - // Make sure b didn't change. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorbCopy[i], vectorb[i]); - } + // Check the reconstruction. + AssertHelpers.ListAlmostEqual(b, bReconstruct, 9); + + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.ListAlmostEqual(bCopy, b, 14); } /// @@ -338,59 +235,33 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven(int order) + public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixB = Matrix.Build.Random(order, order, 1); - var matrixBCopy = matrixB.Clone(); + var B = Matrix.Build.Random(order, order, 2); + var BCopy = B.Clone(); - var matrixX = new DenseMatrix(order, order); - factorEvd.Solve(matrixB, matrixX); + var X = new DenseMatrix(order, order); + evd.Solve(B, X); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1e-9); - } - } - - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 9); - // Make sure B didn't change. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } } } diff --git a/src/UnitTests/LinearAlgebraTests/Double/Factorization/UserEvdTests.cs b/src/UnitTests/LinearAlgebraTests/Double/Factorization/UserEvdTests.cs index b8ebdfd4..865a08cb 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/Factorization/UserEvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/Factorization/UserEvdTests.cs @@ -198,187 +198,122 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b). /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrix(int order) + [Test] + public void CanSolveForRandomVectorAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var vectorb = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); - var resultx = factorEvd.Solve(vectorb); + var b = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); + var bCopy = b.Clone(); - Assert.AreEqual(matrixA.ColumnCount, resultx.Count); + var x = evd.Solve(b); - var matrixBReconstruct = matrixA * resultx; + var bReconstruct = A * x; // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-9); - } + AssertHelpers.AlmostEqual(b, bReconstruct, 9); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(bCopy, b, 14); } /// /// Can solve a system of linear equations for a random matrix and symmetric matrix (AX=B). /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrix(int order) + [Test] + public void CanSolveForRandomMatrixAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); + + var B = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); + var BCopy = B.Clone(); - var matrixB = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); - var matrixX = factorEvd.Solve(matrixB); + var X = evd.Solve(B); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1e-9); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 8); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } /// /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b) into a result matrix. /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven(int order) + [Test] + public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); - var vectorb = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); - var vectorbCopy = vectorb.Clone(); - var resultx = new UserDefinedVector(order); - factorEvd.Solve(vectorb, resultx); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixBReconstruct = matrixA * resultx; + var b = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); + var bCopy = b.Clone(); - // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-9); - } + var x = new UserDefinedVector(order); + evd.Solve(b, x); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + var bReconstruct = A * x; - // Make sure b didn't change. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorbCopy[i], vectorb[i]); - } + // Check the reconstruction. + AssertHelpers.AlmostEqual(b, bReconstruct, 9); + + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(bCopy, b, 14); } /// /// Can solve a system of linear equations for a random matrix and symmetric matrix (AX=B) into result matrix. /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven(int order) + [Test] + public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixB = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); - var matrixBCopy = matrixB.Clone(); + var B = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); + var BCopy = B.Clone(); - var matrixX = new UserDefinedMatrix(order, order); - factorEvd.Solve(matrixB, matrixX); + var X = new UserDefinedMatrix(order, order); + evd.Solve(B, X); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1e-9); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 8); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } - - // Make sure B didn't change. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } } } diff --git a/src/UnitTests/LinearAlgebraTests/Single/Factorization/EvdTests.cs b/src/UnitTests/LinearAlgebraTests/Single/Factorization/EvdTests.cs index adb4740a..ceec68c0 100644 --- a/src/UnitTests/LinearAlgebraTests/Single/Factorization/EvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Single/Factorization/EvdTests.cs @@ -3,7 +3,9 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com -// Copyright (c) 2009-2010 Math.NET +// +// Copyright (c) 2009-2014 Math.NET +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -12,8 +14,10 @@ // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -42,26 +46,19 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization [TestFixture, Category("LAFactorization")] public class EvdTests { - /// - /// Can factorize identity matrix. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(10)] - [TestCase(100)] - public void CanFactorizeIdentity(int order) + [Test] + public void CanFactorizeIdentityMatrix([Values(1, 10, 100)] int order) { - var matrixI = DenseMatrix.CreateIdentity(order); - var factorEvd = matrixI.Evd(); + var matrix = Matrix.Build.DenseIdentity(order); + var factorEvd = matrix.Evd(); var eigenValues = factorEvd.EigenValues; var eigenVectors = factorEvd.EigenVectors; var d = factorEvd.D; - Assert.AreEqual(matrixI.RowCount, eigenVectors.RowCount); - Assert.AreEqual(matrixI.RowCount, eigenVectors.ColumnCount); - - Assert.AreEqual(matrixI.ColumnCount, d.RowCount); - Assert.AreEqual(matrixI.ColumnCount, d.ColumnCount); + Assert.AreEqual(matrix.RowCount, eigenVectors.RowCount); + Assert.AreEqual(matrix.RowCount, eigenVectors.ColumnCount); + Assert.AreEqual(matrix.ColumnCount, d.RowCount); + Assert.AreEqual(matrix.ColumnCount, d.ColumnCount); for (var i = 0; i < eigenValues.Count; i++) { @@ -69,116 +66,73 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization } } - /// - /// Can factorize a random square matrix. - /// - /// Matrix order. [Test] - public void CanFactorizeRandomMatrix([Values(1, 2, 5, 10, 50, 100)] int order) + public void CanFactorizeRandomSquareMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.Random(order, order, 1); - var factorEvd = matrixA.Evd(); - var eigenVectors = factorEvd.EigenVectors; - var d = factorEvd.D; - - Assert.AreEqual(order, eigenVectors.RowCount); - Assert.AreEqual(order, eigenVectors.ColumnCount); - - Assert.AreEqual(order, d.RowCount); - Assert.AreEqual(order, d.ColumnCount); - - // Make sure the A*V = λ*V - var matrixAv = matrixA * eigenVectors; - var matrixLv = eigenVectors * d; - - for (var i = 0; i < matrixAv.RowCount; i++) - { - for (var j = 0; j < matrixAv.ColumnCount; j++) - { - Assert.AreEqual(matrixAv[i, j], matrixLv[i, j], 1e-3); - } - } + var A = Matrix.Build.Random(order, order, 1); + var factorEvd = A.Evd(); + var V = factorEvd.EigenVectors; + var λ = factorEvd.D; + + Assert.AreEqual(order, V.RowCount); + Assert.AreEqual(order, V.ColumnCount); + Assert.AreEqual(order, λ.RowCount); + Assert.AreEqual(order, λ.ColumnCount); + + // Verify A*V = λ*V + var Av = A * V; + var Lv = V * λ; + AssertHelpers.AlmostEqual(Av, Lv, 4); } - /// - /// Can factorize a symmetric random square matrix. - /// - /// Matrix order. [Test] - public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10, 50)] int order) + public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var factorEvd = matrixA.Evd(); - var eigenVectors = factorEvd.EigenVectors; - var d = factorEvd.D; - - Assert.AreEqual(order, eigenVectors.RowCount); - Assert.AreEqual(order, eigenVectors.ColumnCount); - - Assert.AreEqual(order, d.RowCount); - Assert.AreEqual(order, d.ColumnCount); - - // Make sure the A = V*λ*VT - var matrix = eigenVectors * d * eigenVectors.Transpose(); - - for (var i = 0; i < matrix.RowCount; i++) - { - for (var j = 0; j < matrix.ColumnCount; j++) - { - Assert.AreEqual(matrix[i, j], matrixA[i, j], 1e-3); - } - } + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var factorEvd = A.Evd(); + var V = factorEvd.EigenVectors; + var λ = factorEvd.D; + + Assert.AreEqual(order, V.RowCount); + Assert.AreEqual(order, V.ColumnCount); + Assert.AreEqual(order, λ.RowCount); + Assert.AreEqual(order, λ.ColumnCount); + + // Verify A = V*λ*VT + var matrix = V * λ * V.Transpose(); + AssertHelpers.AlmostEqual(matrix, A, 3); + AssertHelpers.AlmostEqualRelative(matrix, A, 1); } - /// - /// Can check rank of square matrix. - /// - /// Matrix order. - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanCheckRankSquare(int order) + [Test] + public void CanCheckRankSquare([Values(10, 50, 100)] int order) { - var matrixA = Matrix.Build.Random(order, order, 1); - var factorEvd = matrixA.Evd(); - - Assert.AreEqual(factorEvd.Rank, order); + var A = Matrix.Build.Random(order, order, 1); + Assert.AreEqual(A.Evd().Rank, order); } - /// - /// Can check rank of square singular matrix. - /// - /// Matrix order. - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanCheckRankOfSquareSingular(int order) + [Test] + public void CanCheckRankOfSquareSingular([Values(10, 50, 100)] int order) { - var matrixA = new DenseMatrix(order, order); - matrixA[0, 0] = 1; - matrixA[order - 1, order - 1] = 1; + var A = new DenseMatrix(order, order); + A[0, 0] = 1; + A[order - 1, order - 1] = 1; for (var i = 1; i < order - 1; i++) { - matrixA[i, i - 1] = 1; - matrixA[i, i + 1] = 1; - matrixA[i - 1, i] = 1; - matrixA[i + 1, i] = 1; + A[i, i - 1] = 1; + A[i, i + 1] = 1; + A[i - 1, i] = 1; + A[i + 1, i] = 1; } - var factorEvd = matrixA.Evd(); + var factorEvd = A.Evd(); Assert.AreEqual(factorEvd.Determinant, 0); Assert.AreEqual(factorEvd.Rank, order - 1); } - /// - /// Identity determinant is one. - /// - /// Matrix order. - [TestCase(1)] - [TestCase(10)] - [TestCase(100)] - public void IdentityDeterminantIsOne(int order) + [Test] + public void IdentityDeterminantIsOne([Values(1, 10, 100)] int order) { var matrixI = DenseMatrix.CreateIdentity(order); var factorEvd = matrixI.Evd(); @@ -190,40 +144,26 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrix(int order) + public void CanSolveForRandomVectorAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var vectorb = Vector.Build.Random(order, 1); - var resultx = factorEvd.Solve(vectorb); + var b = Vector.Build.Random(order, 2); + var bCopy = b.Clone(); - Assert.AreEqual(matrixA.ColumnCount, resultx.Count); + var x = evd.Solve(b); - var matrixBReconstruct = matrixA * resultx; + var bReconstruct = A * x; // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-1); - } + AssertHelpers.ListAlmostEqual(b, bReconstruct, 0); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.ListAlmostEqual(bCopy, b, 14); } /// @@ -231,47 +171,32 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrix(int order) + public void CanSolveForRandomMatrixAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); + + var B = Matrix.Build.Random(order, order, 2); + var BCopy = B.Clone(); - var matrixB = Matrix.Build.Random(order, order, 1); - var matrixX = factorEvd.Solve(matrixB); + var X = evd.Solve(B); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 0); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } /// @@ -279,45 +204,27 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven(int order) + public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); - var vectorb = Vector.Build.Random(order, 1); - var vectorbCopy = vectorb.Clone(); - var resultx = new DenseVector(order); - factorEvd.Solve(vectorb, resultx); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixBReconstruct = matrixA * resultx; + var b = Vector.Build.Random(order, 2); + var bCopy = b.Clone(); - // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-1); - } + var x = new DenseVector(order); + evd.Solve(b, x); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + var bReconstruct = A * x; - // Make sure b didn't change. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorbCopy[i], vectorb[i]); - } + // Check the reconstruction. + AssertHelpers.ListAlmostEqual(b, bReconstruct, 0); + + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.ListAlmostEqual(bCopy, b, 14); } /// @@ -325,59 +232,33 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization /// /// Matrix order. [Test] - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven(int order) + public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = Matrix.Build.RandomPositiveDefinite(order, 1); - MatrixHelpers.ForceSymmetric(matrixA); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = Matrix.Build.RandomPositiveDefinite(order, 1); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixB = Matrix.Build.Random(order, order, 1); - var matrixBCopy = matrixB.Clone(); + var B = Matrix.Build.Random(order, order, 2); + var BCopy = B.Clone(); - var matrixX = new DenseMatrix(order, order); - factorEvd.Solve(matrixB, matrixX); + var X = new DenseMatrix(order, order); + evd.Solve(B, X); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1); - } - } - - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 0); - // Make sure B didn't change. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } } } diff --git a/src/UnitTests/LinearAlgebraTests/Single/Factorization/UserEvdTests.cs b/src/UnitTests/LinearAlgebraTests/Single/Factorization/UserEvdTests.cs index 15ce76fe..44edda67 100644 --- a/src/UnitTests/LinearAlgebraTests/Single/Factorization/UserEvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Single/Factorization/UserEvdTests.cs @@ -193,187 +193,122 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b). /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrix(int order) + [Test] + public void CanSolveForRandomVectorAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var vectorb = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); - var resultx = factorEvd.Solve(vectorb); + var b = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); + var bCopy = b.Clone(); - Assert.AreEqual(matrixA.ColumnCount, resultx.Count); + var x = evd.Solve(b); - var matrixBReconstruct = matrixA * resultx; + var bReconstruct = A * x; // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-1); - } + AssertHelpers.AlmostEqual(b, bReconstruct, 0); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(bCopy, b, 14); } /// /// Can solve a system of linear equations for a random matrix and symmetric matrix (AX=B). /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrix(int order) + [Test] + public void CanSolveForRandomMatrixAndSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); + + var B = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); + var BCopy = B.Clone(); - var matrixB = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); - var matrixX = factorEvd.Solve(matrixB); + var X = evd.Solve(B); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 0); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } /// /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b) into a result matrix. /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven(int order) + [Test] + public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); - var vectorb = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); - var vectorbCopy = vectorb.Clone(); - var resultx = new UserDefinedVector(order); - factorEvd.Solve(vectorb, resultx); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixBReconstruct = matrixA * resultx; + var b = new UserDefinedVector(Vector.Build.Random(order, 1).ToArray()); + var bCopy = b.Clone(); - // Check the reconstruction. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-1); - } + var x = new UserDefinedVector(order); + evd.Solve(b, x); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } + var bReconstruct = A * x; - // Make sure b didn't change. - for (var i = 0; i < vectorb.Count; i++) - { - Assert.AreEqual(vectorbCopy[i], vectorb[i]); - } + // Check the reconstruction. + AssertHelpers.AlmostEqual(b, bReconstruct, 0); + + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(bCopy, b, 14); } /// /// Can solve a system of linear equations for a random matrix and symmetric matrix (AX=B) into result matrix. /// /// Matrix order. - [TestCase(1)] - [TestCase(2)] - [TestCase(5)] - [TestCase(10)] - [TestCase(50)] - [TestCase(100)] - public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven(int order) + [Test] + public void CanSolveForRandomMatrixAndSymmetricMatrixWhenResultMatrixGiven([Values(1, 2, 5, 10, 50, 100)] int order) { - var matrixA = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); - var matrixACopy = matrixA.Clone(); - var factorEvd = matrixA.Evd(); + var A = new UserDefinedMatrix(Matrix.Build.RandomPositiveDefinite(order, 1).ToArray()); + MatrixHelpers.ForceSymmetric(A); + var ACopy = A.Clone(); + var evd = A.Evd(); - var matrixB = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); - var matrixBCopy = matrixB.Clone(); + var B = new UserDefinedMatrix(Matrix.Build.Random(order, order, 1).ToArray()); + var BCopy = B.Clone(); - var matrixX = new UserDefinedMatrix(order, order); - factorEvd.Solve(matrixB, matrixX); + var X = new UserDefinedMatrix(order, order); + evd.Solve(B, X); // The solution X row dimension is equal to the column dimension of A - Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); + Assert.AreEqual(A.ColumnCount, X.RowCount); // The solution X has the same number of columns as B - Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); + Assert.AreEqual(B.ColumnCount, X.ColumnCount); - var matrixBReconstruct = matrixA * matrixX; + var BReconstruct = A * X; // Check the reconstruction. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1); - } - } + AssertHelpers.AlmostEqual(B, BReconstruct, 0); - // Make sure A didn't change. - for (var i = 0; i < matrixA.RowCount; i++) - { - for (var j = 0; j < matrixA.ColumnCount; j++) - { - Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]); - } - } - - // Make sure B didn't change. - for (var i = 0; i < matrixB.RowCount; i++) - { - for (var j = 0; j < matrixB.ColumnCount; j++) - { - Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]); - } - } + // Make sure A/B didn't change. + AssertHelpers.AlmostEqual(ACopy, A, 14); + AssertHelpers.AlmostEqual(BCopy, B, 14); } } }