From 4cd1c829c5a7adfbf3218222ecc7fc01de11a62b Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 15:51:16 +0200 Subject: [PATCH] Add Unit tests for Single version of Symmetric matrix Signed-off-by: Alexander Karatarakis --- .../Single/SymmetricDenseMatrixTests.cs | 215 ++++++++++++++++++ .../Single/SymmetricMatrixTests.Arithmetic.cs | 191 ++++++++++++++++ .../Single/SymmetricMatrixTests.cs | 123 ++++++++++ src/UnitTests/UnitTests.csproj | 3 + 4 files changed, 532 insertions(+) create mode 100644 src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs diff --git a/src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs new file mode 100644 index 00000000..5ec190c2 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs @@ -0,0 +1,215 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// http://mathnetnumerics.codeplex.com +// Copyright (c) 2009-2010 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single +{ + using System; + using System.Collections.Generic; + + using MathNet.Numerics.LinearAlgebra.Single; + + using NUnit.Framework; + + /// + /// Symmetric Dense matrix tests. + /// + public class SymmetricDenseMatrixTests : SymmetricMatrixTests + { + /// + /// Creates a matrix for the given number of rows and columns. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// + /// A matrix with the given dimensions. + /// + protected override Matrix CreateMatrix(int rows, int columns) + { + return new DenseMatrix(rows, columns); + } + + /// + /// Creates a matrix from a 2D array. + /// + /// + /// The 2D array to create this matrix from. + /// + /// + /// A matrix with the given values. + /// + protected override Matrix CreateMatrix(float[,] data) + { + if (SymmetricMatrix.CheckIfSymmetric(data)) + { + return new SymmetricDenseMatrix(data); + } + + return new DenseMatrix(data); + } + + /// + /// Creates a vector of the given size. + /// + /// + /// The size of the vector to create. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(int size) + { + return new DenseVector(size); + } + + /// + /// Creates a vector from an array. + /// + /// + /// The array to create this vector from. + /// + /// + /// The new vector. + /// + protected override Vector CreateVector(float[] data) + { + return new DenseVector(data); + } + + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom1DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(3, new[] { 1.0f, 2.0f, 0.0f, 3.0f, 0.0f, 0.0f }) }, + { "Square3x3", new SymmetricDenseMatrix(3, new[] { -1.1f, 2.0f, 1.1f, 3.0f, 0.0f, 6.6f }) }, + { "Square4x4", new SymmetricDenseMatrix(4, new[] { 1.1f, 2.0f, 5.0f, -3.0f, -6.0f, 8.0f, 4.4f, 7.0f, 9.0f, 10.0f }) }, + { "Singular4x4", new SymmetricDenseMatrix(4, new[] { 1.0f, 2.0f, 5.0f, 0.0f, 0.0f, 0.0f, 4.0f, 7.0f, 0.0f, 10.0f }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(3, new[] { 1.0f, 2.0f, 2.0f, 3.0f, 0.0f, 3.0f }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(4, new [] { 0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } + + /// + /// Matrix from array is a reference. + /// + [Test] + public void MatrixFrom1DArrayIsReference() + { + var data = new float[] { 1, 1, 1, 1, 1, 1 }; + var matrix = new SymmetricDenseMatrix(3, data); + matrix[0, 0] = 10.0f; + Assert.AreEqual(10.0f, data[0]); + } + + /// + /// Can create a matrix form array. + /// + [Test] + public void CanCreateMatrixFrom2DArray() + { + var testData = new Dictionary + { + { "Singular3x3", new SymmetricDenseMatrix(new[,] { { 1.0f, 2.0f, 3.0f }, { 2.0f, 0.0f, 0.0f }, { 3.0f, 0.0f, 0.0f } }) }, + { "Square3x3", new SymmetricDenseMatrix(new[,] { { -1.1f, 2.0f, 3.0f }, { 2.0f, 1.1f, 0.0f }, { 3.0f, 0.0f, 6.6f } }) }, + { "Square4x4", new SymmetricDenseMatrix(new[,] { { 1.1f, 2.0f, -3.0f, 4.4f }, { 2.0f, 5.0f, -6.0f, 7.0f }, { -3.0f, -6.0f, 8.0f, 9.0f }, { 4.4f, 7.0f, 9.0f, 10.0f } }) }, + { "Singular4x4", new SymmetricDenseMatrix(new[,] { { 1.0f, 2.0f, 0.0f, 4.0f }, { 2.0f, 5.0f, 0.0f, 7.0f }, { 0.0f, 0.0f, 0.0f, 0.0f }, { 4.0f, 7.0f, 0.0f, 10.0f } }) }, + { "Symmetric3x3", new SymmetricDenseMatrix(new[,] { { 1.0f, 2.0f, 3.0f }, { 2.0f, 2.0f, 0.0f }, { 3.0f, 0.0f, 3.0f } }) }, + { "IndexTester4x4", new SymmetricDenseMatrix(new [,] { { 0f, 1f, 3f, 6f }, { 1f, 2f, 4f, 7f }, { 3f, 4f, 5f, 8f }, { 6f, 7f, 8f, 9f } }) } + }; + + foreach (var name in testData.Keys) + { + Assert.AreEqual(TestMatrices[name], testData[name]); + } + } + + /// + /// Matrix from two-dimensional array is a copy. + /// + [Test] + public void MatrixFrom2DArrayIsCopy() + { + var matrix = new DenseMatrix(TestData2D["Singular3x3"]); + matrix[0, 0] = 10.0f; + Assert.AreEqual(1.0f, TestData2D["Singular3x3"][0, 0]); + } + + /// + /// Can create a matrix with uniform values. + /// + [Test] + public void CanCreateMatrixWithUniformValues() + { + var matrix = new SymmetricDenseMatrix(10, 10.0f); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], 10.0f); + } + } + } + + /// + /// Can create an identity matrix. + /// + [Test] + public void CanCreateIdentity() + { + var matrix = SymmetricDenseMatrix.Identity(5); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(i == j ? 1.0f : 0.0f, matrix[i, j]); + } + } + } + + /// + /// Identity with wrong order throws ArgumentOutOfRangeException. + /// + /// The size of the square matrix + [TestCase(0)] + [TestCase(-1)] + public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException(int order) + { + Assert.Throws(() => SymmetricDenseMatrix.Identity(order)); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs new file mode 100644 index 00000000..331ac876 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs @@ -0,0 +1,191 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// http://mathnetnumerics.codeplex.com +// Copyright (c) 2009-2010 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single +{ + using System.Collections.Generic; + using LinearAlgebra.Single; + using NUnit.Framework; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices + /// + public abstract partial class SymmetricMatrixTests + { + /// + /// Setup test matrices. + /// Singular and Square matrices are overridden here with symmetric ones so that calls to base methods work as intended. + /// Additional NonSymmetric matrices are defined for some tests. + /// + [SetUp] + public override void SetupMatrices() + { + TestData2D = new Dictionary + { + { "Singular3x3", new[,] { { 1.0f, 2.0f, 3.0f }, { 2.0f, 0.0f, 0.0f }, { 3.0f, 0.0f, 0.0f } } }, + { "Square3x3", new[,] { { -1.1f, 2.0f, 3.0f }, { 2.0f, 1.1f, 0.0f }, { 3.0f, 0.0f, 6.6f } } }, + { "Square4x4", new[,] { { 1.1f, 2.0f, -3.0f, 4.4f }, { 2.0f, 5.0f, -6.0f, 7.0f }, { -3.0f, -6.0f, 8.0f, 9.0f }, { 4.4f, 7.0f, 9.0f, 10.0f } } }, + { "Singular4x4", new[,] { { 1.0f, 2.0f, 0.0f, 4.0f }, { 2.0f, 5.0f, 0.0f, 7.0f }, { 0.0f, 0.0f, 0.0f, 0.0f }, { 4.0f, 7.0f, 0.0f, 10.0f } } }, + { "Tall3x2", new[,] { { -1.1f, -2.2f }, { 0.0f, 1.1f }, { -4.4f, 5.5f } } }, + { "Wide2x3", new[,] { { -1.1f, -2.2f, -3.3f }, { 0.0f, 1.1f, 2.2f } } }, + { "Symmetric3x3", new[,] { { 1.0f, 2.0f, 3.0f }, { 2.0f, 2.0f, 0.0f }, { 3.0f, 0.0f, 3.0f } } }, + { "NonSymmetric3x3", new[,] { { -1.1f, -2.2f, -3.3f }, { 0.0f, 1.1f, 2.2f }, { -4.4f, 5.5f, 6.6f } } }, + { "NonSymmetric4x4", new[,] { { -1.1f, -2.2f, -3.3f, -4.4f }, { 0.0f, 1.1f, 2.2f, 3.3f }, { 1.0f, 2.1f, 6.2f, 4.3f }, { -4.4f, 5.5f, 6.6f, -7.7f } } }, + { "IndexTester4x4", new [,] { { 0f, 1f, 3f, 6f }, { 1f, 2f, 4f, 7f }, { 3f, 4f, 5f, 8f }, { 6f, 7f, 8f, 9f } } } + }; + + TestMatrices = new Dictionary(); + + foreach (var name in TestData2D.Keys) + { + TestMatrices.Add(name, CreateMatrix(TestData2D[name])); + } + } + + /// + /// Can add a non-symmetric matrix to this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanAddNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Add(matrixB); + + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] + matrixB[i, j]); + } + } + } + + /// + /// Can subtract a non-symmetric matrix from this symmetric matrix. + /// + /// Matrix A name. + /// Matrix B name. + [Test, Sequential] + public void CanSubtractNonSymmetricMatrix([Values("Square3x3", "Square4x4")] string mtxA, [Values("NonSymmetric3x3", "NonSymmetric4x4")] string mtxB) + { + var matrixA = TestMatrices[mtxA]; + var matrixB = TestMatrices[mtxB]; + + var matrix = matrixA.Clone(); + matrix = matrix.Subtract(matrixB); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(matrix[i, j], matrixA[i, j] - matrixB[i, j]); + } + } + } + + /// + /// Can compute Frobenius norm. + /// + public override void CanComputeFrobeniusNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.FrobeniusNorm(), matrix.FrobeniusNorm(), 14); + } + + + + /// + /// Can compute Infinity norm. + /// + public override void CanComputeInfinityNorm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.InfinityNorm(), matrix.InfinityNorm(), 14); + } + + + + /// + /// Can compute L1 norm. + /// + public override void CanComputeL1Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L1Norm(), matrix.L1Norm(), 14); + } + + + + /// + /// Can compute L2 norm. + /// + public override void CanComputeL2Norm() + { + var matrix = TestMatrices["Square3x3"]; + var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Wide2x3"]; + denseMatrix = new DenseMatrix(TestData2D["Wide2x3"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + + matrix = TestMatrices["Tall3x2"]; + denseMatrix = new DenseMatrix(TestData2D["Tall3x2"]); + AssertHelpers.AlmostEqual(denseMatrix.L2Norm(), matrix.L2Norm(), 14); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs b/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs new file mode 100644 index 00000000..a0b9d4e5 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs @@ -0,0 +1,123 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// http://mathnetnumerics.codeplex.com +// Copyright (c) 2009-2010 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 +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// 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 +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single +{ + using MathNet.Numerics.LinearAlgebra.Single; + using NUnit.Framework; + + /// + /// Abstract class with the common set of matrix tests for symmetric matrices. + /// + public abstract partial class SymmetricMatrixTests : MatrixTests + { + /// + /// Can check if a matrix is symmetric. + /// + [Test] + public override void CanCheckIfMatrixIsSymmetric() + { + var matrix = TestMatrices["Square3x3"]; + Assert.IsTrue(matrix.IsSymmetric); + + matrix = TestMatrices["NonSymmetric3x3"]; + Assert.IsFalse(matrix.IsSymmetric); + } + + /// + /// Can check if a [,] array is symmetric. + /// + [Test] + public void CanCheckIfArrayIsSymmetric() + { + Assert.IsTrue(SymmetricMatrix.CheckIfSymmetric(TestData2D["Square3x3"])); + Assert.IsFalse(SymmetricMatrix.CheckIfSymmetric(TestData2D["NonSymmetric3x3"])); + } + + /// + /// Test whether the index enumerator returns the correct values. + /// + [Test] + public void CanUseIndexedEnumerator() + { + var matrix = TestMatrices["Singular3x3"]; + var enumerator = matrix.IndexedEnumerator().GetEnumerator(); + enumerator.MoveNext(); + var item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(1.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(2.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(0, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(3.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(2.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(0.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(1, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(0.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(0, item.Item2); + Assert.AreEqual(3.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(1, item.Item2); + Assert.AreEqual(0.0, item.Item3); + + enumerator.MoveNext(); + item = enumerator.Current; + Assert.AreEqual(2, item.Item1); + Assert.AreEqual(2, item.Item2); + Assert.AreEqual(0.0, item.Item3); + } + } +} \ No newline at end of file diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index e8b5f237..aa47b7eb 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -721,6 +721,9 @@ Code + + + Code