//
// 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);
}
}
}