// // 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.Complex32 { using System; using System.Collections.Generic; using System.Linq; using LinearAlgebra.Complex32; using NUnit.Framework; using Complex32 = Numerics.Complex32; /// /// Diagonal matrix tests. /// public class DiagonalMatrixTests : MatrixTests { /// /// Setup test matrices. /// [SetUp] public override void SetupMatrices() { TestData2D = new Dictionary { { "Singular3x3", new[,] { { new Complex32(1.0f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, Complex32.Zero, Complex32.Zero }, { Complex32.Zero, Complex32.Zero, new Complex32(3.0f, 1) } } }, { "Square3x3", new[,] { { new Complex32(-1.1f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, new Complex32(1.1f, 1), Complex32.Zero }, { Complex32.Zero, Complex32.Zero, new Complex32(6.6f, 1) } } }, { "Square4x4", new[,] { { new Complex32(-1.1f, 1), Complex32.Zero, Complex32.Zero, Complex32.Zero }, { Complex32.Zero, new Complex32(1.1f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, Complex32.Zero, new Complex32(6.2f, 1), Complex32.Zero }, { Complex32.Zero, Complex32.Zero, Complex32.Zero, new Complex32(-7.7f, 1) } } }, { "Singular4x4", new[,] { { new Complex32(-1.1f, 1), Complex32.Zero, Complex32.Zero, Complex32.Zero }, { Complex32.Zero, new Complex32(-2.2f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, Complex32.Zero, Complex32.Zero, Complex32.Zero }, { Complex32.Zero, Complex32.Zero, Complex32.Zero, new Complex32(-4.4f, 1) } } }, { "Tall3x2", new[,] { { new Complex32(-1.1f, 1), Complex32.Zero }, { Complex32.Zero, new Complex32(1.1f, 1) }, { Complex32.Zero, Complex32.Zero } } }, { "Wide2x3", new[,] { { new Complex32(-1.1f, 1), Complex32.Zero, Complex32.Zero }, { Complex32.Zero, new Complex32(1.1f, 1), Complex32.Zero } } } }; TestMatrices = new Dictionary(); foreach (var name in TestData2D.Keys) { TestMatrices.Add(name, CreateMatrix(TestData2D[name])); } } /// /// 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 DiagonalMatrix(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(Complex32[,] data) { return new DiagonalMatrix(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 SparseVector(size); } /// /// Creates a vector from an array. /// /// The array to create this vector from. /// The new vector. protected override Vector CreateVector(Complex32[] data) { return new SparseVector(data); } /// /// Can create a matrix from a diagonal array. /// [Test] public void CanCreateMatrixFromDiagonalArray() { var testData = new Dictionary { { "Singular3x3", new DiagonalMatrix(3, 3, new[] { new Complex32(1.0f, 1), Complex32.Zero, new Complex32(3.0f, 1) }) }, { "Square3x3", new DiagonalMatrix(4, 4, new[] { new Complex32(-1.1f, 1), new Complex32(1.1f, 1), new Complex32(6.6f, 1) }) }, { "Square4x4", new DiagonalMatrix(4, 4, new[] { new Complex32(-1.1f, 1), new Complex32(1.1f, 1), new Complex32(6.2f, 1), new Complex32(-7.7f, 1) }) }, { "Tall3x2", new DiagonalMatrix(3, 2, new[] { new Complex32(-1.1f, 1), new Complex32(1.1f, 1) }) }, { "Wide2x3", new DiagonalMatrix(2, 3, new[] { new Complex32(-1.1f, 1), new Complex32(1.1f, 1) }) }, }; 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[] { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1), new Complex32(4.0f, 1), new Complex32(5.0f, 1) }; var matrix = new DiagonalMatrix(5, 5, data); matrix[0, 0] = new Complex32(10.0f, 1); Assert.AreEqual(new Complex32(10.0f, 1), data[0]); } /// /// Can create a matrix from two-dimensional array. /// /// Matrix name. [Test] public void CanCreateMatrixFrom2DArray([Values("Singular3x3", "Singular4x4", "Square3x3", "Square4x4", "Tall3x2", "Wide2x3")] string name) { var matrix = new DiagonalMatrix(TestData2D[name]); for (var i = 0; i < TestData2D[name].GetLength(0); i++) { for (var j = 0; j < TestData2D[name].GetLength(1); j++) { Assert.AreEqual(TestData2D[name][i, j], matrix[i, j]); } } } /// /// Can create a matrix with uniform values. /// [Test] public void CanCreateMatrixWithUniformValues() { var matrix = new DiagonalMatrix(10, 10, new Complex32(10.0f, 1)); for (var i = 0; i < matrix.RowCount; i++) { Assert.AreEqual(matrix[i, i], new Complex32(10.0f, 1)); } } /// /// Can create an identity matrix. /// [Test] public void CanCreateIdentity() { var matrix = DiagonalMatrix.Identity(5); for (var i = 0; i < matrix.RowCount; i++) { for (var j = 0; j < matrix.ColumnCount; j++) { Assert.AreEqual(i == j ? Complex32.One : Complex32.Zero, matrix[i, j]); } } } /// /// Identity with wrong order throws ArgumentOutOfRangeException. /// /// The size of the square matrix [Test] public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException([Values(0, -1)] int order) { Assert.Throws(() => DiagonalMatrix.Identity(order)); } /// /// Can diagonally stack matrices into a result matrix. /// public override void CanDiagonallyStackMatricesIntoResult() { var top = TestMatrices["Tall3x2"]; var bottom = TestMatrices["Wide2x3"]; var result = new SparseMatrix(top.RowCount + bottom.RowCount, top.ColumnCount + bottom.ColumnCount); top.DiagonalStack(bottom, result); Assert.AreEqual(top.RowCount + bottom.RowCount, result.RowCount); Assert.AreEqual(top.ColumnCount + bottom.ColumnCount, result.ColumnCount); for (var i = 0; i < result.RowCount; i++) { for (var j = 0; j < result.ColumnCount; j++) { if (i < top.RowCount && j < top.ColumnCount) { Assert.AreEqual(top[i, j], result[i, j]); } else if (i >= top.RowCount && j >= top.ColumnCount) { Assert.AreEqual(bottom[i - top.RowCount, j - top.ColumnCount], result[i, j]); } else { Assert.AreEqual(Complex32.Zero, result[i, j]); } } } } /// /// Can multiply a matrix with matrix. /// /// Matrix A name. /// Matrix B name. public override void CanMultiplyMatrixWithMatrixIntoResult(string nameA, string nameB) { var matrixA = TestMatrices[nameA]; var matrixB = TestMatrices[nameB]; var matrixC = new SparseMatrix(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], 15); } } } /// /// Permute matrix rows throws InvalidOperationException. /// [Test] public void PermuteMatrixRowsThrowsInvalidOperationException() { var matrixp = CreateMatrix(TestData2D["Singular3x3"]); var permutation = new Permutation(new[] { 2, 0, 1 }); Assert.Throws(() => matrixp.PermuteRows(permutation)); } /// /// Permute matrix columns throws InvalidOperationException. /// [Test] public void PermuteMatrixColumnsThrowsInvalidOperationException() { var matrixp = CreateMatrix(TestData2D["Singular3x3"]); var permutation = new Permutation(new[] { 2, 0, 1 }); Assert.Throws(() => matrixp.PermuteColumns(permutation)); } /// /// Can permute matrix rows. /// /// Matrix name. public override void CanPermuteMatrixRows(string name) { } /// /// Can permute matrix columns. /// /// Matrix name. public override void CanPermuteMatrixColumns(string name) { } /// /// Can pointwise divide matrices into a result matrix. /// public override void CanPointwiseDivideIntoResult() { foreach (var data in TestMatrices.Values) { var other = data.Clone(); var result = data.Clone(); data.PointwiseDivide(other, result); var min = Math.Min(data.RowCount, data.ColumnCount); for (var i = 0; i < min; i++) { Assert.AreEqual(data[i, i] / other[i, i], result[i, i]); } result = data.PointwiseDivide(other); for (var i = 0; i < min; i++) { Assert.AreEqual(data[i, i] / other[i, i], result[i, i]); } } } /// /// Can set a column with an array. /// /// Matrix name. /// Column array. public override void CanSetColumnWithArray(string name, float[] column) { try { // Pass all invoke to base base.CanSetColumnWithArray(name, column); } catch (AggregateException ex) { // Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) { throw; } } } /// /// Can set a column with a vector. /// /// Matrix name. /// Column values. public override void CanSetColumnWithVector(string name, float[] column) { try { // Pass all invoke to base base.CanSetColumnWithVector(name, column); } catch (AggregateException ex) { // Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) { throw; } } } /// /// Can set a row with an array. /// /// Matrix name. /// Row values. public override void CanSetRowWithArray(string name, float[] row) { try { // Pass all invoke to base base.CanSetRowWithArray(name, row); } catch (AggregateException ex) { // Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) { throw; } } } /// /// Can set a row with a vector. /// /// Matrix name. /// Row index. public override void CanSetRowWithVector(string name, float[] row) { try { // Pass all invoke to base base.CanSetRowWithVector(name, row); } catch (AggregateException ex) { // Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) { throw; } } } /// /// Can set a submatrix. /// /// The row to start copying to. /// The number of rows to copy. /// The column to start copying to. /// The number of columns to copy. public override void CanSetSubMatrix(int rowStart, int rowLength, int colStart, int colLength) { try { // Pass all invoke to base base.CanSetSubMatrix(rowStart, rowLength, colStart, colLength); } catch (AggregateException ex) { // Supress only IndexOutOfRangeException exceptions due to Diagonal matrix nature if (ex.InnerExceptions.Any(innerException => !(innerException is IndexOutOfRangeException))) { throw; } } } /// /// 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); } /// /// Can compute determinant. /// [Test] public void CanComputeDeterminant() { var matrix = TestMatrices["Square3x3"]; var denseMatrix = new DenseMatrix(TestData2D["Square3x3"]); AssertHelpers.AlmostEqual(denseMatrix.Determinant(), matrix.Determinant(), 14); matrix = TestMatrices["Square4x4"]; denseMatrix = new DenseMatrix(TestData2D["Square4x4"]); AssertHelpers.AlmostEqual(denseMatrix.Determinant(), matrix.Determinant(), 14); } /// /// Determinant of non-square matrix throws ArgumentException. /// [Test] public void DeterminantNotSquareMatrixThrowsArgumentException() { var matrix = TestMatrices["Tall3x2"]; Assert.Throws(() => matrix.Determinant()); } /// /// Test whether the index enumerator returns the correct values. /// [Test] public override 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(new Complex32(1.0f, 1.0f), item.Item3); enumerator.MoveNext(); item = enumerator.Current; Assert.AreEqual(0, item.Item1); Assert.AreEqual(1, item.Item2); Assert.AreEqual(Complex32.Zero, item.Item3); enumerator.MoveNext(); item = enumerator.Current; Assert.AreEqual(0, item.Item1); Assert.AreEqual(2, item.Item2); Assert.AreEqual(Complex32.Zero, item.Item3); enumerator.MoveNext(); item = enumerator.Current; Assert.AreEqual(1, item.Item1); Assert.AreEqual(0, item.Item2); Assert.AreEqual(Complex32.Zero, item.Item3); enumerator.MoveNext(); item = enumerator.Current; Assert.AreEqual(1, item.Item1); Assert.AreEqual(1, item.Item2); Assert.AreEqual(Complex32.Zero, item.Item3); enumerator.MoveNext(); item = enumerator.Current; Assert.AreEqual(1, item.Item1); Assert.AreEqual(2, item.Item2); Assert.AreEqual(Complex32.Zero, item.Item3); enumerator.MoveNext(); item = enumerator.Current; Assert.AreEqual(2, item.Item1); Assert.AreEqual(0, item.Item2); Assert.AreEqual(Complex32.Zero, item.Item3); enumerator.MoveNext(); item = enumerator.Current; Assert.AreEqual(2, item.Item1); Assert.AreEqual(1, item.Item2); Assert.AreEqual(Complex32.Zero, item.Item3); enumerator.MoveNext(); item = enumerator.Current; Assert.AreEqual(2, item.Item1); Assert.AreEqual(2, item.Item2); Assert.AreEqual(new Complex32(3.0f, 1.0f), item.Item3); } /// /// Can check if a matrix is symmetric. /// [Test] public override void CanCheckIfMatrixIsSymmetric() { var matrix = TestMatrices["Square3x3"]; Assert.IsTrue(matrix.IsSymmetric); } } }