// // 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 Distributions; using LinearAlgebra.Generic; using LinearAlgebra.Single; using NUnit.Framework; /// /// Abstract class with the common set of matrix tests /// public abstract partial class MatrixTests { /// /// Can multiply with a scalar. /// /// Scalar value. [TestCase(0)] [TestCase(1)] [TestCase(2.2f)] public void CanMultiplyWithScalar(float scalar) { var matrix = TestMatrices["Singular3x3"]; var clone = matrix.Clone(); clone = clone.Multiply(scalar); for (var i = 0; i < matrix.RowCount; i++) { for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j] * scalar, clone[i, j]); } } } /// /// Can multiply with a vector. /// [Test] public void CanMultiplyWithVector() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); var y = matrix * x; Assert.AreEqual(matrix.RowCount, y.Count); for (var i = 0; i < matrix.RowCount; i++) { var ar = matrix.Row(i); var dot = ar * x; Assert.AreEqual(dot, y[i]); } } /// /// Can multiply with a vector into a result. /// [Test] public void CanMultiplyWithVectorIntoResult() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); var y = new DenseVector(3); matrix.Multiply(x, y); for (var i = 0; i < matrix.RowCount; i++) { var ar = matrix.Row(i); var dot = ar * x; Assert.AreEqual(dot, y[i]); } } /// /// Can multiply with a vector into result when updating input argument. /// [Test] public void CanMultiplyWithVectorIntoResultWhenUpdatingInputArgument() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); var y = x; matrix.Multiply(x, x); Assert.AreSame(y, x); y = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); for (var i = 0; i < matrix.RowCount; i++) { var ar = matrix.Row(i); var dot = ar * y; Assert.AreEqual(dot, x[i]); } } /// /// Multiply with vector into result fails when result is null. /// [Test] public void MultiplyWithVectorIntoNullResultThrowsArgumentNullException() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); Vector y = null; Assert.Throws(() => matrix.Multiply(x, y)); } /// /// Multiply with a vector into too large result throws ArgumentException. /// [Test] public void MultiplyWithVectorIntoLargerResultThrowsArgumentException() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); Vector y = new DenseVector(4); Assert.Throws(() => matrix.Multiply(x, y)); } /// /// Can left multiply with a scalar. /// /// Scalar value. [TestCase(0)] [TestCase(1)] [TestCase(2.2f)] public void CanOperatorLeftMultiplyWithScalar(float scalar) { var matrix = TestMatrices["Singular3x3"]; var clone = scalar * matrix; for (var i = 0; i < matrix.RowCount; i++) { for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(scalar * matrix[i, j], clone[i, j]); } } } /// /// Can right multiply with a scalar. /// /// Scalar value. [TestCase(0)] [TestCase(1)] [TestCase(2.2f)] public void CanOperatorRightMultiplyWithScalar(float scalar) { var matrix = TestMatrices["Singular3x3"]; var clone = matrix * scalar; for (var i = 0; i < matrix.RowCount; i++) { for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j] * scalar, clone[i, j]); } } } /// /// Can multiply with a scalar into result. /// /// Scalar value. [TestCase(0)] [TestCase(1)] [TestCase(2.2f)] public void CanMultiplyWithScalarIntoResult(float scalar) { var matrix = TestMatrices["Singular3x3"]; var result = matrix.Clone(); matrix.Multiply(scalar, result); for (var i = 0; i < matrix.RowCount; i++) { for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(matrix[i, j] * scalar, result[i, j]); } } } /// /// Multiply with a scalar into null result throws ArgumentNullException. /// [Test] public void MultiplyWithScalarIntoNullResultThrowsArgumentNullException() { var matrix = TestMatrices["Singular3x3"]; Matrix result = null; Assert.Throws(() => matrix.Multiply(2.3f, result)); } /// /// Multiply with a scalar when result has more rows throws ArgumentException. /// [Test] public void MultiplyWithScalarWhenResultHasMoreRowsThrowsArgumentException() { var matrix = TestMatrices["Singular3x3"]; var result = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); Assert.Throws(() => matrix.Multiply(2.3f, result)); } /// /// Multiply with a scalar when result has more columns throws ArgumentException. /// [Test] public void MultiplyWithScalarWhenResultHasMoreColumnsThrowsArgumentException() { var matrix = TestMatrices["Singular3x3"]; var result = CreateMatrix(matrix.RowCount, matrix.ColumnCount + 1); Assert.Throws(() => matrix.Multiply(2.3f, result)); } /// /// Operator left multiply with a scalar when matrix is null throws ArgumentNullException. /// [Test] public void OperatorLeftMultiplyWithScalarWhenMatrixIsNullThrowsArgumentNullException() { Matrix matrix = null; Assert.Throws(() => { var result = 2.3f * matrix; }); } /// /// Operator right multiply with a scalar when matrix is null throws ArgumentNullException. /// [Test] public void OperatorRightMultiplyWithScalarWhenMatrixIsNullThrowsArgumentNullException() { Matrix matrix = null; Assert.Throws(() => { var result = matrix * 2.3f; }); } /// /// Can add a matrix. /// /// Matrix A name. /// Matrix B name. [TestCase("Singular3x3", "Square3x3")] [TestCase("Singular4x4", "Square4x4")] public void CanAddMatrix(string mtxA, 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]); } } } /// /// Adding a matrix when argument is null throws ArgumentNullException. /// [Test] public void AddNullMatrixThrowsArgumentNullException() { var matrix = TestMatrices["Singular4x4"]; Matrix other = null; Assert.Throws(() => matrix.Add(other)); } /// /// Adding a matrix with fewer columns throws ArgumentOutOfRangeException. /// [Test] public void AddMatrixWithFewerColumnsThrowsArgumentOutOfRangeException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Tall3x2"]; Assert.Throws(() => matrix.Add(other)); } /// /// Adding a matrix with fewer rows throws ArgumentOutOfRangeException. /// [Test] public void AddMatrixWithFewerRowsThrowsArgumentOutOfRangeException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Wide2x3"]; Assert.Throws(() => matrix.Add(other)); } /// /// Add matrices using "+" operator. /// /// Matrix A name. /// Matrix B name. [TestCase("Singular3x3", "Square3x3")] [TestCase("Singular4x4", "Square4x4")] public void CanAddUsingOperator(string mtxA, string mtxB) { var matrixA = TestMatrices[mtxA]; var matrixB = TestMatrices[mtxB]; var result = matrixA + matrixB; for (var i = 0; i < matrixA.RowCount; i++) { for (var j = 0; j < matrixA.ColumnCount; j++) { Assert.AreEqual(result[i, j], matrixA[i, j] + matrixB[i, j]); } } } /// /// Add operator when left side is null throws ArgumentNullException. /// [Test] public void AddOperatorWhenLeftSideIsNullThrowsArgumentNullException() { Matrix matrix = null; var other = TestMatrices["Singular3x3"]; Assert.Throws(() => { var result = matrix + other; }); } /// /// Add operator when right side is null throws ArgumentNullException. /// [Test] public void AddOperatorWhenRightSideIsNullThrowsArgumentNullException() { var matrix = TestMatrices["Singular3x3"]; Matrix other = null; Assert.Throws(() => { var result = matrix + other; }); } /// /// Add operator when right side has fewer columns throws ArgumentOutOfRangeException. /// [Test] public void AddOperatorWhenRightSideHasFewerColumnsThrowsArgumentOutOfRangeException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Tall3x2"]; Assert.Throws(() => { var result = matrix + other; }); } /// /// Add operator when right side has fewer rows throws ArgumentOutOfRangeException. /// [Test] public void AddOperatorWhenRightSideHasFewerRowsThrowsArgumentOutOfRangeException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Wide2x3"]; Assert.Throws(() => { var result = matrix + other; }); } /// /// Can subtract a matrix. /// /// Matrix A name. /// Matrix B name. [TestCase("Singular3x3", "Square3x3")] [TestCase("Singular4x4", "Square4x4")] public void CanSubtractMatrix(string mtxA, 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]); } } } /// /// Subtract null matrix throws ArgumentNullException. /// [Test] public void SubtractNullMatrixThrowsArgumentNullException() { var matrix = TestMatrices["Singular4x4"]; Matrix other = null; Assert.Throws(() => matrix.Subtract(other)); } /// /// Subtract a matrix when right side has fewer columns throws ArgumentOutOfRangeException. /// [Test] public void SubtractMatrixWithFewerColumnsThrowsArgumentOutOfRangeException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Tall3x2"]; Assert.Throws(() => matrix.Subtract(other)); } /// /// Subtract a matrix when right side has fewer rows throws ArgumentOutOfRangeException. /// [Test] public void SubtractMatrixWithFewerRowsThrowsArgumentOutOfRangeException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Wide2x3"]; Assert.Throws(() => matrix.Subtract(other)); } /// /// Can subtract a matrix using "-" operator. /// /// Matrix A name. /// Matrix B name. [TestCase("Singular3x3", "Square3x3")] [TestCase("Singular4x4", "Square4x4")] public void CanSubtractUsingOperator(string mtxA, string mtxB) { var matrixA = TestMatrices[mtxA]; var matrixB = TestMatrices[mtxB]; var result = matrixA - matrixB; for (var i = 0; i < matrixA.RowCount; i++) { for (var j = 0; j < matrixA.ColumnCount; j++) { Assert.AreEqual(result[i, j], matrixA[i, j] - matrixB[i, j]); } } } /// /// Subtract operator when left side is null throws ArgumentNullException. /// [Test] public void SubtractOperatorWhenLeftSideIsNullThrowsArgumentNullException() { Matrix matrix = null; var other = TestMatrices["Singular3x3"]; Assert.Throws(() => { var result = matrix - other; }); } /// /// Subtract operator when right side is null throws ArgumentNullException. /// [Test] public void SubtractOperatorWhenRightSideIsNullThrowsArgumentNullException() { var matrix = TestMatrices["Singular3x3"]; Matrix other = null; Assert.Throws(() => { var result = matrix - other; }); } /// /// Subtract operator when right side has fewer columns throws ArgumentOutOfRangeException /// [Test] public void SubtractOperatorWhenRightSideHasFewerColumnsThrowsArgumentOutOfRangeException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Tall3x2"]; Assert.Throws(() => { var result = matrix - other; }); } /// /// Subtract operator when right side has fewer rows throws ArgumentOutOfRangeException /// [Test] public void SubtractOperatorWhenRightSideHasFewerRowsThrowsArgumentOutOfRangeException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Wide2x3"]; Assert.Throws(() => { var result = matrix - other; }); } /// /// Can multiply a matrix with matrix. /// /// Matrix A name. /// Matrix B name. [TestCase("Singular3x3", "Square3x3")] [TestCase("Singular4x4", "Square4x4")] [TestCase("Wide2x3", "Square3x3")] [TestCase("Wide2x3", "Tall3x2")] [TestCase("Tall3x2", "Wide2x3")] public void CanMultiplyMatrixWithMatrix(string nameA, string nameB) { var matrixA = TestMatrices[nameA]; var matrixB = TestMatrices[nameB]; var matrixC = matrixA * matrixB; Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); Assert.AreEqual(matrixC.ColumnCount, matrixB.ColumnCount); for (var i = 0; i < matrixC.RowCount; i++) { for (var j = 0; j < matrixC.ColumnCount; j++) { AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Column(j), matrixC[i, j], 7); } } } /// /// Can transpose and multiply a matrix with matrix. /// /// Matrix name. [TestCase("Singular3x3")] [TestCase("Singular4x4")] [TestCase("Wide2x3")] [TestCase("Tall3x2")] public void CanTransposeAndMultiplyMatrixWithMatrix(string nameA) { var matrixA = TestMatrices[nameA]; var matrixB = TestMatrices[nameA]; var matrixC = matrixA.TransposeAndMultiply(matrixB); Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); Assert.AreEqual(matrixC.ColumnCount, matrixB.RowCount); for (var i = 0; i < matrixC.RowCount; i++) { for (var j = 0; j < matrixC.ColumnCount; j++) { AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Row(j), matrixC[i, j], 7); } } } /// /// Can transpose and multiply a matrix with differing dimensions. /// [Test] public void CanTransposeAndMultiplyWithDifferingDimensions() { var matrixA = TestMatrices["Tall3x2"]; var matrixB = CreateMatrix(5, 2); var count = 1; for (var row = 0; row < matrixB.RowCount; row++) { for (var col = 0; col < matrixB.ColumnCount; col++) { if (row == col) { matrixB[row, col] = count++; } } } var matrixC = matrixA.TransposeAndMultiply(matrixB); Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); Assert.AreEqual(matrixC.ColumnCount, matrixB.RowCount); for (var i = 0; i < matrixC.RowCount; i++) { for (var j = 0; j < matrixC.ColumnCount; j++) { AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Row(j), matrixC[i, j], 7); } } } /// /// Transpose and multiply a matrix with matrix of incompatible size throws ArgumentException. /// [Test] public void TransposeAndMultiplyMatrixMatrixWithIncompatibleSizesThrowsArgumentException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Tall3x2"]; Assert.Throws(() => matrix.TransposeAndMultiply(other)); } /// /// Transpose and multiply a matrix with null matrix throws ArgumentNullException. /// [Test] public void TransposeAndMultiplyMatrixWithNullMatrixThrowsArgumentNullException() { var matrix = TestMatrices["Wide2x3"]; Matrix other = null; Assert.Throws(() => matrix.TransposeAndMultiply(other)); } /// /// Can transpose and multiply a matrix with matrix into a result matrix. /// /// Matrix name. [TestCase("Singular3x3")] [TestCase("Singular4x4")] [TestCase("Wide2x3")] [TestCase("Tall3x2")] public void CanTransposeAndMultiplyMatrixWithMatrixIntoResult(string nameA) { var matrixA = TestMatrices[nameA]; var matrixB = TestMatrices[nameA]; var matrixC = CreateMatrix(matrixA.RowCount, matrixB.RowCount); matrixA.TransposeAndMultiply(matrixB, matrixC); Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); Assert.AreEqual(matrixC.ColumnCount, matrixB.RowCount); for (var i = 0; i < matrixC.RowCount; i++) { for (var j = 0; j < matrixC.ColumnCount; j++) { AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Row(j), matrixC[i, j], 7); } } } /// /// Multiply a matrix with incompatible size matrix throws ArgumentException. /// [Test] public void MultiplyMatrixMatrixWithIncompatibleSizesThrowsArgumentException() { var matrix = TestMatrices["Singular3x3"]; var other = TestMatrices["Wide2x3"]; Assert.Throws(() => { var result = matrix * other; }); } /// /// Multiply null matrix with matrix throws ArgumentNullException. /// [Test] public void MultiplyNullMatrixWithMatrixThrowsArgumentNullException() { Matrix matrix = null; var other = TestMatrices["Wide2x3"]; Assert.Throws(() => { var result = matrix * other; }); } /// /// Multiply a matrix with null matrix throws ArgumentNullException. /// [Test] public void MultiplyMatrixWithNullMatrixThrowsArgumentNullException() { var matrix = TestMatrices["Wide2x3"]; Matrix other = null; Assert.Throws(() => { var result = matrix * other; }); } /// /// Can multiply a matrix with matrix into a result matrix. /// /// Matrix A name. /// Matrix B name. [TestCase("Singular3x3", "Square3x3")] [TestCase("Singular4x4", "Square4x4")] [TestCase("Wide2x3", "Square3x3")] [TestCase("Wide2x3", "Tall3x2")] [TestCase("Tall3x2", "Wide2x3")] public virtual void CanMultiplyMatrixWithMatrixIntoResult(string nameA, string nameB) { var matrixA = TestMatrices[nameA]; var matrixB = TestMatrices[nameB]; var matrixC = CreateMatrix(matrixA.RowCount, matrixB.ColumnCount); matrixA.Multiply(matrixB, matrixC); Assert.AreEqual(matrixC.RowCount, matrixA.RowCount); Assert.AreEqual(matrixC.ColumnCount, matrixB.ColumnCount); for (var i = 0; i < matrixC.RowCount; i++) { for (var j = 0; j < matrixC.ColumnCount; j++) { AssertHelpers.AlmostEqual(matrixA.Row(i) * matrixB.Column(j), matrixC[i, j], 6); } } } /// /// Can multiply transposed matrix with a vector. /// [Test] public void CanTransposeThisAndMultiplyWithVector() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); var y = matrix.TransposeThisAndMultiply(x); Assert.AreEqual(matrix.ColumnCount, y.Count); for (var j = 0; j < matrix.ColumnCount; j++) { var ar = matrix.Column(j); var dot = ar * x; Assert.AreEqual(dot, y[j]); } } /// /// Can multiply transposed matrix with a vector into a result. /// [Test] public void CanTransposeThisAndMultiplyWithVectorIntoResult() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); var y = new DenseVector(3); matrix.TransposeThisAndMultiply(x, y); for (var j = 0; j < matrix.ColumnCount; j++) { var ar = matrix.Column(j); var dot = ar * x; Assert.AreEqual(dot, y[j]); } } /// /// Can multiply transposed matrix with a vector into result when updating input argument. /// [Test] public void CanTransposeThisAndMultiplyWithVectorIntoResultWhenUpdatingInputArgument() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); var y = x; matrix.TransposeThisAndMultiply(x, x); Assert.AreSame(y, x); y = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); for (var j = 0; j < matrix.ColumnCount; j++) { var ar = matrix.Column(j); var dot = ar * y; Assert.AreEqual(dot, x[j]); } } /// /// Multiply transposed matrix with vector into result fails when result is null. /// [Test] public void TransposeThisAndMultiplyWithVectorIntoNullResultThrowsArgumentNullException() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); Vector y = null; Assert.Throws(() => matrix.TransposeThisAndMultiply(x, y)); } /// /// Multiply transposed matrix with a vector into too large result throws ArgumentException. /// [Test] public void TransposeThisAndMultiplyWithVectorIntoLargerResultThrowsArgumentException() { var matrix = TestMatrices["Singular3x3"]; var x = new DenseVector(new[] { 1.0f, 2.0f, 3.0f }); Vector y = new DenseVector(4); Assert.Throws(() => matrix.TransposeThisAndMultiply(x, y)); } /// /// Can multiply transposed matrix with another matrix. /// /// Matrix name. [TestCase("Singular3x3")] [TestCase("Singular4x4")] [TestCase("Wide2x3")] [TestCase("Tall3x2")] public void CanTransposeThisAndMultiplyMatrixWithMatrix(string nameA) { var matrixA = TestMatrices[nameA]; var matrixB = TestMatrices[nameA]; var matrixC = matrixA.TransposeThisAndMultiply(matrixB); Assert.AreEqual(matrixC.RowCount, matrixA.ColumnCount); Assert.AreEqual(matrixC.ColumnCount, matrixB.ColumnCount); for (var i = 0; i < matrixC.RowCount; i++) { for (var j = 0; j < matrixC.ColumnCount; j++) { AssertHelpers.AlmostEqual(matrixA.Column(i) * matrixB.Column(j), matrixC[i, j], 7); } } } /// /// Multiply the transpose of matrix with another matrix of incompatible size throws ArgumentException. /// [Test] public void TransposeThisAndMultiplyMatrixMatrixWithIncompatibleSizesThrowsArgumentException() { var matrix = TestMatrices["Wide2x3"]; var other = TestMatrices["Singular3x3"]; Assert.Throws(() => matrix.TransposeThisAndMultiply(other)); } /// /// Multiply the transpose of matrix with another matrix null matrix throws ArgumentNullException. /// [Test] public void TransposeThisAndMultiplyMatrixWithNullMatrixThrowsArgumentNullException() { var matrix = TestMatrices["Wide2x3"]; Matrix other = null; Assert.Throws(() => matrix.TransposeThisAndMultiply(other)); } /// /// Multiply transpose of this matrix with another matrix into a result matrix. /// /// Matrix name. [TestCase("Singular3x3")] [TestCase("Singular4x4")] [TestCase("Wide2x3")] [TestCase("Tall3x2")] public void CanTransposeThisAndMultiplyMatrixWithMatrixIntoResult(string nameA) { var matrixA = TestMatrices[nameA]; var matrixB = TestMatrices[nameA]; var matrixC = CreateMatrix(matrixA.ColumnCount, matrixB.ColumnCount); matrixA.TransposeThisAndMultiply(matrixB, matrixC); Assert.AreEqual(matrixC.RowCount, matrixA.ColumnCount); Assert.AreEqual(matrixC.ColumnCount, matrixB.ColumnCount); for (var i = 0; i < matrixC.RowCount; i++) { for (var j = 0; j < matrixC.ColumnCount; j++) { AssertHelpers.AlmostEqual(matrixA.Column(i) * matrixB.Column(j), matrixC[i, j], 7); } } } /// /// Can negate a matrix. /// /// Matrix name. [TestCase("Singular3x3")] [TestCase("Singular4x4")] [TestCase("Wide2x3")] [TestCase("Wide2x3")] [TestCase("Tall3x2")] public void CanNegate(string name) { var matrix = TestMatrices[name]; var copy = matrix.Clone(); copy = copy.Negate(); for (var i = 0; i < matrix.RowCount; i++) { for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(-matrix[i, j], copy[i, j]); } } } /// /// Can negate a matrix into a result matrix. /// /// Matrix name. [TestCase("Singular3x3")] [TestCase("Singular4x4")] [TestCase("Wide2x3")] [TestCase("Wide2x3")] [TestCase("Tall3x2")] public void CanNegateIntoResult(string name) { var matrix = TestMatrices[name]; var copy = matrix.Clone(); matrix.Negate(copy); for (var i = 0; i < matrix.RowCount; i++) { for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(-matrix[i, j], copy[i, j]); } } } /// /// Negate into null result throws ArgumentNullException. /// [Test] public void NegateIntoNullResultThrowsArgumentNullException() { var matrix = TestMatrices["Singular3x3"]; Matrix copy = null; Assert.Throws(() => matrix.Negate(copy)); } /// /// Negate into a result matrix with more rows throws ArgumentException. /// [Test] public void NegateIntoResultWithMoreRowsThrowsArgumentException() { var matrix = TestMatrices["Singular3x3"]; var target = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); Assert.Throws(() => matrix.Negate(target)); } /// /// Negate into a result matrix with more rows throws ArgumentException. /// [Test] public void NegateIntoResultWithMoreColumnsThrowsArgumentException() { var matrix = TestMatrices["Singular3x3"]; var target = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); Assert.Throws(() => matrix.Negate(target)); } /// /// Can calculate Kronecker product. /// [Test] public void CanKroneckerProduct() { var matrixA = TestMatrices["Wide2x3"]; var matrixB = TestMatrices["Square3x3"]; var result = CreateMatrix(matrixA.RowCount * matrixB.RowCount, matrixA.ColumnCount * matrixB.ColumnCount); matrixA.KroneckerProduct(matrixB, result); for (var i = 0; i < matrixA.RowCount; i++) { for (var j = 0; j < matrixA.ColumnCount; j++) { for (var ii = 0; ii < matrixB.RowCount; ii++) { for (var jj = 0; jj < matrixB.ColumnCount; jj++) { Assert.AreEqual(result[(i * matrixB.RowCount) + ii, (j * matrixB.ColumnCount) + jj], matrixA[i, j] * matrixB[ii, jj]); } } } } } /// /// Can calculate Kronecker product into a result matrix. /// [Test] public void CanKroneckerProductIntoResult() { var matrixA = TestMatrices["Wide2x3"]; var matrixB = TestMatrices["Square3x3"]; var result = matrixA.KroneckerProduct(matrixB); for (var i = 0; i < matrixA.RowCount; i++) { for (var j = 0; j < matrixA.ColumnCount; j++) { for (var ii = 0; ii < matrixB.RowCount; ii++) { for (var jj = 0; jj < matrixB.ColumnCount; jj++) { Assert.AreEqual(result[(i * matrixB.RowCount) + ii, (j * matrixB.ColumnCount) + jj], matrixA[i, j] * matrixB[ii, jj]); } } } } } /// /// Can normalize columns of a matrix. /// /// The norm under which to normalize the columns under. [TestCase(1)] [TestCase(2)] public void CanNormalizeColumns(int p) { var matrix = TestMatrices["Square4x4"]; var result = matrix.NormalizeColumns(p); for (var j = 0; j < result.ColumnCount; j++) { var col = result.Column(j); Assert.AreEqual(1.0f, col.Norm(p), 10e-6f); } } /// /// Normalize columns with wrong parameter throws ArgumentOutOfRangeException. /// [Test] public void NormalizeColumnsWithWrongParameterThrowsArgumentOutOfRangeException() { Assert.Throws(() => TestMatrices["Square4x4"].NormalizeColumns(-4)); } /// /// Can normalize rows of a matrix. /// /// The norm under which to normalize the rows under. [TestCase(1)] [TestCase(2)] public void CanNormalizeRows(int p) { var matrix = TestMatrices["Square4x4"].NormalizeRows(p); for (var i = 0; i < matrix.RowCount; i++) { var row = matrix.Row(i); Assert.AreEqual(1.0f, row.Norm(p), 10e-6f); } } /// /// Normalize rows with wrong parameter throws ArgumentOutOfRangeException. /// [Test] public void NormalizeRowsWithWrongParameterThrowsArgumentOutOfRangeException() { Assert.Throws(() => TestMatrices["Square4x4"].NormalizeRows(-4)); } /// /// Can pointwise multiply matrices into a result matrix. /// [Test] public void CanPointwiseMultiplyIntoResult() { foreach (var data in TestMatrices.Values) { var other = data.Clone(); var result = data.Clone(); data.PointwiseMultiply(other, result); for (var i = 0; i < data.RowCount; i++) { for (var j = 0; j < data.ColumnCount; j++) { Assert.AreEqual(data[i, j] * other[i, j], result[i, j]); } } result = data.PointwiseMultiply(other); for (var i = 0; i < data.RowCount; i++) { for (var j = 0; j < data.ColumnCount; j++) { Assert.AreEqual(data[i, j] * other[i, j], result[i, j]); } } } } /// /// Pointwise multiply null matrices into a result throws ArgumentNullException. /// [Test] public void PointwiseMultiplyNullIntoResultThrowsArgumentNullException() { var matrix = TestMatrices["Wide2x3"]; Matrix other = null; var result = matrix.Clone(); Assert.Throws(() => matrix.PointwiseMultiply(other, result)); } /// /// Pointwise multiply matrices into null result throws ArgumentNullException. /// [Test] public void PointwiseMultiplyIntoNullResultThrowsArgumentNullException() { var matrix = TestMatrices["Wide2x3"]; var other = matrix.Clone(); Assert.Throws(() => matrix.PointwiseMultiply(other, null)); } /// /// Pointwise multiply matrices with invalid dimensions into a result throws ArgumentException. /// [Test] public void PointwiseMultiplyWithInvalidDimensionsIntoResultThrowsArgumentException() { var matrix = TestMatrices["Wide2x3"]; var other = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); var result = matrix.Clone(); Assert.Throws(() => matrix.PointwiseMultiply(other, result)); } /// /// Pointwise multiply matrices with invalid result dimensions throws ArgumentException. /// [Test] public void PointwiseMultiplyWithInvalidResultDimensionsThrowsArgumentException() { var matrix = TestMatrices["Wide2x3"]; var other = matrix.Clone(); var result = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); Assert.Throws(() => matrix.PointwiseMultiply(other, result)); } /// /// Can pointwise divide matrices into a result matrix. /// [Test] public virtual void CanPointwiseDivideIntoResult() { var data = TestMatrices["Singular3x3"]; var other = data.Clone(); var result = data.Clone(); data.PointwiseDivide(other, result); for (var i = 0; i < data.RowCount; i++) { for (var j = 0; j < data.ColumnCount; j++) { Assert.AreEqual(data[i, j] / other[i, j], result[i, j]); } } result = data.PointwiseDivide(other); for (var i = 0; i < data.RowCount; i++) { for (var j = 0; j < data.ColumnCount; j++) { Assert.AreEqual(data[i, j] / other[i, j], result[i, j]); } } } /// /// Pointwise divide null matrices into a result throws ArgumentNullException. /// [Test] public void PointwiseDivideNullIntoResultThrowsArgumentNullException() { var matrix = TestMatrices["Wide2x3"]; Matrix other = null; var result = matrix.Clone(); Assert.Throws(() => matrix.PointwiseDivide(other, result)); } /// /// Pointwise divide matrices into null result throws ArgumentNullException. /// [Test] public void PointwiseDivideIntoNullResultThrowsArgumentNullException() { var matrix = TestMatrices["Wide2x3"]; var other = matrix.Clone(); Assert.Throws(() => matrix.PointwiseDivide(other, null)); } /// /// Pointwise divide matrices with invalid dimensions into a result throws ArgumentException. /// [Test] public void PointwiseDivideWithInvalidDimensionsIntoResultThrowsArgumentException() { var matrix = TestMatrices["Wide2x3"]; var other = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); var result = matrix.Clone(); Assert.Throws(() => matrix.PointwiseDivide(other, result)); } /// /// Pointwise divide matrices with invalid result dimensions throws ArgumentException. /// [Test] public void PointwiseDivideWithInvalidResultDimensionsThrowsArgumentException() { var matrix = TestMatrices["Wide2x3"]; var other = matrix.Clone(); var result = CreateMatrix(matrix.RowCount + 1, matrix.ColumnCount); Assert.Throws(() => matrix.PointwiseDivide(other, result)); } /// /// Create random matrix with non-positive number of rows throw ArgumentException. /// /// Number of rows. [TestCase(0)] [TestCase(-2)] public void RandomWithNonPositiveNumberOfRowsThrowsArgumentException(int numberOfRows) { var matrix = CreateMatrix(2, 3); Assert.Throws(() => matrix.Random(numberOfRows, 4, new ContinuousUniform())); Assert.Throws(() => matrix.Random(numberOfRows, 4, new DiscreteUniform(0, 2))); } /// /// Can trace. /// [Test] public void CanTrace() { var matrix = TestMatrices["Square3x3"]; var trace = matrix.Trace(); Assert.AreEqual(6.6f, trace); } /// /// Trace of non-square matrix throws ArgumentException. /// [Test] public void TraceOfNonSquareMatrixThrowsArgumentException() { var matrix = TestMatrices["Wide2x3"]; Assert.Throws(() => matrix.Trace()); } /// /// Can compute the modules of each element of vector. /// [Test] public void CanComputeModulus() { var matrix = TestMatrices["Square3x3"]; var mod = matrix.Modulus(3.2f); for (var row = 0; row < matrix.RowCount; row++) { for (var column = 0; column < matrix.ColumnCount; column++) { AssertHelpers.AlmostEqual(matrix[row, column] % 3.2f, mod[row, column], 7); } } } /// /// Can compute the modules of each element of vector using a result vector. /// [Test] public void CanComputeModulusUsingResultVector() { var matrix = TestMatrices["Square3x3"]; var mod = CreateMatrix(matrix.RowCount, matrix.ColumnCount); matrix.Modulus(3.2f, mod); for (var row = 0; row < matrix.RowCount; row++) { for (var column = 0; column < matrix.ColumnCount; column++) { AssertHelpers.AlmostEqual(matrix[row, column] % 3.2f, mod[row, column], 7); } } } /// /// Can compute the modules of each element of vector using a result vector. /// [Test] public void CanComputeModulusUsingSameResultVector() { var matrix = TestMatrices["Square3x3"].Clone(); matrix.Modulus(3.2f, matrix); var data = TestMatrices["Square3x3"]; for (var row = 0; row < matrix.RowCount; row++) { for (var column = 0; column < matrix.ColumnCount; column++) { AssertHelpers.AlmostEqual(data[row, column] % 3.2f, matrix[row, column], 7); } } } /// /// Can compute the modules of each element of vector using the operator %. /// [Test] public void CanComputeModulusUsingOperator() { var matrix = TestMatrices["Square3x3"]; var mod = matrix % 3.2f; for (var row = 0; row < matrix.RowCount; row++) { for (var column = 0; column < matrix.ColumnCount; column++) { AssertHelpers.AlmostEqual(matrix[row, column] % 3.2f, mod[row, column], 7); } } } } }