Compare commits

...

34 Commits

Author SHA1 Message Date
Christoph Ruegg 68b34df6bd Merge remote-tracking branch 'Danimoth/symmetric' into la-symmetric 13 years ago
Alexander Karatarakis 148ac01b6f Add Unit tests for Complex32 version of Symmetric matrix and fix bugs 13 years ago
Alexander Karatarakis e55400ef41 Add Unit tests for Comples version of Symmetric matrix and fix bugs 13 years ago
Alexander Karatarakis 38a8b1f01b [SymmetricMatrix] Disable SetRow/Column() for symmetric matrices 13 years ago
Alexander Karatarakis 4cd1c829c5 Add Unit tests for Single version of Symmetric matrix 13 years ago
Alexander Karatarakis a5b9e7eabc Add Complex32 version of Symmetric matrix 13 years ago
Alexander Karatarakis 3654f3b3f0 Remove obsolete remark 13 years ago
Alexander Karatarakis 11ceb277b0 Normalize using statements 13 years ago
Alexander Karatarakis d0b140acce Add Complex version of Symmetric matrix 13 years ago
Alexander Karatarakis 07f563d7e4 [SymmetricDenseMatrix] Trace(): remove redundant check for square matrix since symm matrices are always square 13 years ago
Alexander Karatarakis 938df8b594 Add Single precision version of Symmetric matrix 13 years ago
Alexander Karatarakis ba2665b7bf Add file header 13 years ago
Alexander Karatarakis 3071d77337 [SymmetricMatrix] Override pointwise operations to special case "other" as SymmetricMatrix 13 years ago
Alexander Karatarakis b2aa32c872 [SymmetricMatrix] Throw exception when attempting to point-wise operate symmetric+non-symmetric into symmetric 13 years ago
Alexander Karatarakis 94747be5f6 [MatrixTests.Arithmetic] Fix reversed CanKroneckerProduct() test method names 13 years ago
Alexander Karatarakis 99b710a57d [Matrix.Arithmetic] Matrix-Matrix operations that CreateMatrix() request a fullyMutable matrix 13 years ago
Alexander Karatarakis f55e0b847c [SymmetricMatrix] Change Transpose() to return "this.Clone()" instead of "this" 13 years ago
Alexander Karatarakis 62d7e357f4 [SymmetricMatrix] Override Insert/SetRow/Column 13 years ago
Alexander Karatarakis 12bd8e8827 Fix bug in SymmetricDenseMatrix.CreateMatrix() 13 years ago
Alexander Karatarakis 3a31d49309 Add more tests 13 years ago
Alexander Karatarakis 815c0e795d Add tests 13 years ago
Alexander Karatarakis 02526e814d Fixes from Unit Tests 13 years ago
Alexander Karatarakis 7cebb6ea79 Add SymmetricDenseMatrixTests 13 years ago
Alexander Karatarakis 36fe86a1f5 Add SymmetricMatrixTests 13 years ago
Alexander Karatarakis 1793a674ff Add SymmetricDenseMatrix and tweak the storage 13 years ago
Alexander Karatarakis 58d5b00883 Add new abstract matrix: SymmetricMatrix. Also move Square matrix to Double 13 years ago
Alexander Karatarakis e774bf4be4 Add new abstract class: SquareMatrix 13 years ago
Alexander Karatarakis c606b329b8 Add SymmetricMatrixStorage 13 years ago
Alexander Karatarakis 767f8a8e9b [IStorageIndexer] Rename methods from IndexOf() to Of() 13 years ago
Alexander Karatarakis 708a4d3820 Add new class: DenseColumnMajorSymmetricMatrixStorage 13 years ago
Alexander Karatarakis 3d22fa59fe Add new class: PackedStorageIndexerUpper 13 years ago
Alexander Karatarakis 18b5790a7c Add new abstract class: PackedStorageIndexer 13 years ago
Alexander Karatarakis d1e4fd9a5a Add new abstract class: StaticStorageIndexer 13 years ago
Alexander Karatarakis 363793d9cb Add new interface: IStorageIndexer 13 years ago
  1. 62
      src/Numerics/LinearAlgebra/Complex/SquareMatrix.cs
  2. 767
      src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs
  3. 657
      src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs
  4. 62
      src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs
  5. 767
      src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs
  6. 657
      src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs
  7. 61
      src/Numerics/LinearAlgebra/Double/SquareMatrix.cs
  8. 794
      src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs
  9. 653
      src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs
  10. 6
      src/Numerics/LinearAlgebra/Generic/Matrix.Arithmetic.cs
  11. 61
      src/Numerics/LinearAlgebra/Single/SquareMatrix.cs
  12. 794
      src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs
  13. 653
      src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs
  14. 84
      src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs
  15. 28
      src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs
  16. 50
      src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs
  17. 88
      src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs
  18. 56
      src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs
  19. 64
      src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs
  20. 19
      src/Numerics/Numerics.csproj
  21. 217
      src/UnitTests/LinearAlgebraTests/Complex/SymmetricDenseMatrixTests.cs
  22. 192
      src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.Arithmetic.cs
  23. 124
      src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.cs
  24. 217
      src/UnitTests/LinearAlgebraTests/Complex32/SymmetricDenseMatrixTests.cs
  25. 192
      src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.Arithmetic.cs
  26. 125
      src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.cs
  27. 9
      src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs
  28. 215
      src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs
  29. 191
      src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.Arithmetic.cs
  30. 123
      src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.cs
  31. 215
      src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs
  32. 191
      src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs
  33. 123
      src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs
  34. 12
      src/UnitTests/UnitTests.csproj

62
src/Numerics/LinearAlgebra/Complex/SquareMatrix.cs

@ -0,0 +1,62 @@
// <copyright file="SquareMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Complex
{
using System;
using System.Numerics;
using Properties;
using Storage;
/// <summary>
/// Abstract class for square matrices.
/// </summary>
[Serializable]
public abstract class SquareMatrix : Matrix
{
/// <summary>
/// Number of rows or columns.
/// </summary>
protected readonly int Order;
/// <summary>
/// Initializes a new instance of the <see cref="SquareMatrix"/> class.
/// </summary>
/// <exception cref="ArgumentException">
/// If the matrix is not square.
/// </exception>
protected SquareMatrix(MatrixStorage<Complex> storage)
: base(storage)
{
if (storage.RowCount != storage.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
Order = storage.RowCount;
}
}
}

767
src/Numerics/LinearAlgebra/Complex/SymmetricDenseMatrix.cs

@ -0,0 +1,767 @@
// <copyright file="SymmetricDenseMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Complex
{
using System;
using System.Numerics;
using Generic;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static;
using Properties;
using Storage;
/// <summary>
/// A Symmetric Matrix class with dense storage.
/// </summary>
/// <remarks> The underlying storage is a one dimensional array in column-major order.
/// The Upper Triangle is stored(it is equal to the Lower Triangle) </remarks>
[Serializable]
public class SymmetricDenseMatrix : SymmetricMatrix
{
readonly DenseColumnMajorSymmetricMatrixStorage<Complex> _storage;
/// <summary>
/// Gets the matrix's data.
/// </summary>
/// <value>The matrix's data.</value>
readonly Complex[] _data;
internal SymmetricDenseMatrix(DenseColumnMajorSymmetricMatrixStorage<Complex> storage)
: base(storage)
{
_storage = storage;
_data = _storage.Data;
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class. This matrix is square with a given size.
/// </summary>
/// <param name="order">The order of the matrix.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public SymmetricDenseMatrix(int order)
: this(new DenseColumnMajorSymmetricMatrixStorage<Complex>(order))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class with all entries set to a particular value.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param>
public SymmetricDenseMatrix(int order, Complex value)
: this(order)
{
for (var i = 0; i < _data.Length; i++)
{
_data[i] = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class from a one dimensional array. This constructor
/// will reference the one dimensional array and not copy it.
/// </summary>
/// <param name="order">The size of the square matrix.</param>
/// <param name="array">
/// The one dimensional array to create this matrix from. Column-major and row-major order is identical on a symmetric matrix: http://en.wikipedia.org/wiki/Row-major_order
/// </param>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> does not represent a packed array.
/// </exception>
public SymmetricDenseMatrix(int order, Complex[] array)
: this(new DenseColumnMajorSymmetricMatrixStorage<Complex>(order, array))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class from a 2D array. This constructor
/// will allocate a completely new memory block for storing the symmetric dense matrix.
/// </summary>
/// <param name="array">The 2D array to create this matrix from.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> is not a square array.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> is not a symmetric array.
/// </exception>
public SymmetricDenseMatrix(Complex[,] array)
: this(array.GetLength(0))
{
if (!CheckIfSymmetric(array))
{
throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
}
var indexer = new PackedStorageIndexerUpper(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
_data[indexer.Of(row, column)] = array[row, column];
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class, copying
/// the values from the given matrix. Matrix must be Symmetric.
/// </summary>
/// <param name="matrix">The matrix to copy.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="matrix"/> is not a square matrix.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="matrix"/> is not a symmetric matrix.
/// </exception>
public SymmetricDenseMatrix(Matrix<Complex> matrix)
: this(matrix.RowCount)
{
var symmetricMatrix = matrix as SymmetricDenseMatrix;
if (!matrix.IsSymmetric)
{
throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
}
if (symmetricMatrix == null)
{
var indexer = new PackedStorageIndexerUpper(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
_data[indexer.Of(row, column)] = matrix[row, column];
}
}
}
else
{
matrix.CopyTo(this);
}
}
/// <summary>
/// Gets the matrix's data.
/// </summary>
/// <value>The matrix's data.</value>
public Complex[] Data
{
get { return _data; }
}
/// <summary>
/// Creates a <c>SymmetricDenseMatrix</c> for the given number of rows and columns.
/// If rows and columns are not equal, returns a <c>DenseMatrix</c> instead.
/// </summary>
/// <param name="numberOfRows">
/// The number of rows.
/// </param>
/// <param name="numberOfColumns">
/// The number of columns.
/// </param>
/// <param name="fullyMutable">True if all fields must be mutable (e.g. not a diagonal matrix).</param>
/// <returns>
/// A <c>DenseMatrix</c> or <c>SymmetricDenseMatrix</c> with the given dimensions.
/// </returns>
/// /// <exception cref="ArgumentException">
/// If <paramref name="numberOfRows"/> is not equal to <paramref name="numberOfColumns"/>.
/// Symmetric arrays are always square
/// </exception>
public override Matrix<Complex> CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false)
{
if (numberOfRows != numberOfColumns || fullyMutable)
{
return new DenseMatrix(numberOfRows, numberOfColumns);
}
return new SymmetricDenseMatrix(numberOfRows);
}
/// <summary>
/// Creates a <see cref="Vector{T}"/> with a the given dimension.
/// </summary>
/// <param name="size">The size of the vector.</param>
/// <param name="fullyMutable">True if all fields must be mutable.</param>
/// <returns>
/// A <see cref="Vector{T}"/> with the given dimension.
/// </returns>
public override Vector<Complex> CreateVector(int size, bool fullyMutable = false)
{
return new DenseVector(size);
}
#region Static constructors for special matrices.
/// <summary>
/// Initializes a square <see cref="SymmetricDenseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary>
/// <param name="order">the size of the square matrix.</param>
/// <returns>A symmetric dense identity matrix.</returns>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public static SymmetricDenseMatrix Identity(int order)
{
var m = new SymmetricDenseMatrix(order);
for (var i = 0; i < order; i++)
{
m.At(i, i, Complex.One);
}
return m;
}
#endregion
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of add</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
protected override void DoAdd(Matrix<Complex> other, Matrix<Complex> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoAdd(other, result);
}
else
{
Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
protected override void DoSubtract(Matrix<Complex> other, Matrix<Complex> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoSubtract(other, result);
}
else
{
Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(Complex scalar, Matrix<Complex> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data);
}
}
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<Complex> rightSide, Vector<Complex> result)
{
var denseRight = rightSide as DenseVector;
var denseResult = result as DenseVector;
if (denseRight == null || denseResult == null)
{
base.DoMultiply(rightSide, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoMultiply(rightSide, result);
}
}
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Matrix<Complex> other, Matrix<Complex> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoMultiply(other, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoMultiply(other, result);
}
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoTransposeAndMultiply(Matrix<Complex> other, Matrix<Complex> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoTransposeAndMultiply(other, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoTransposeAndMultiply(other, result);
}
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
protected override void DoNegate(Matrix<Complex> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoNegate(result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data);
}
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
protected override void DoPointwiseMultiply(Matrix<Complex> other, Matrix<Complex> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoPointwiseMultiply(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
protected override void DoPointwiseDivide(Matrix<Complex> other, Matrix<Complex> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoPointwiseDivide(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Returns a new matrix containing the lower triangle of this matrix.
/// </summary>
/// <returns>The lower triangle of this matrix.</returns>
public override Matrix<Complex> LowerTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = 0; column <= row; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the lower triangle of this matrix. The new matrix
/// does not contain the diagonal elements of this matrix.
/// </summary>
/// <returns>The lower triangle of this matrix.</returns>
public override Matrix<Complex> StrictlyLowerTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = 0; column < row; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the upper triangle of this matrix.
/// </summary>
/// <returns>The upper triangle of this matrix.</returns>
public override Matrix<Complex> UpperTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the upper triangle of this matrix. The new matrix
/// does not contain the diagonal elements of this matrix.
/// </summary>
/// <returns>The upper triangle of this matrix.</returns>
public override Matrix<Complex> StrictlyUpperTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row + 1; column < Order; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Computes the trace of this matrix.
/// </summary>
/// <returns>The trace of this matrix</returns>
public override Complex Trace()
{
// Matrix is always square.
var sum = Complex.Zero;
for (var i = 0; i < RowCount; i++)
{
sum += At(i, i);
}
return sum;
}
/// <summary>
/// Populates a symmetric matrix with random elements.
/// </summary>
/// <param name="matrix">The symmetric matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<Complex> matrix, IContinuousDistribution distribution)
{
var denseMatrix = matrix as SymmetricDenseMatrix;
if (denseMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var i = 0; i < denseMatrix._data.Length; i++)
{
denseMatrix._data[i] = distribution.Sample();
}
}
}
/// <summary>
/// Populates a symmetric matrix with random elements.
/// </summary>
/// <param name="matrix">The symmetric matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<Complex> matrix, IDiscreteDistribution distribution)
{
var denseMatrix = matrix as SymmetricDenseMatrix;
if (denseMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var i = 0; i < denseMatrix._data.Length; i++)
{
denseMatrix._data[i] = distribution.Sample();
}
}
}
/// <summary>
/// Adds two matrices together and returns the results.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to add.</param>
/// <param name="rightSide">The right matrix to add.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (leftSide.RowCount != rightSide.RowCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Add(rightSide);
}
/// <summary>
/// Returns a <strong>Matrix</strong> containing the same values of <paramref name="rightSide"/>.
/// </summary>
/// <param name="rightSide">The matrix to get the values from.</param>
/// <returns>A matrix containing a the same values as <paramref name="rightSide"/>.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Clone();
}
/// <summary>
/// Subtracts two matrices together and returns the results.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to subtract.</param>
/// <param name="rightSide">The right matrix to subtract.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (leftSide.RowCount != rightSide.RowCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Subtract(rightSide);
}
/// <summary>
/// Negates each element of the matrix.
/// </summary>
/// <param name="rightSide">The matrix to negate.</param>
/// <returns>A matrix containing the negated values.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Negate();
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, Complex rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (SymmetricDenseMatrix)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator *(Complex leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Multiply(leftSide);
}
/// <summary>
/// Multiplies two matrices.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to multiply.</param>
/// <param name="rightSide">The right matrix to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If the dimensions of <paramref name="leftSide"/> or <paramref name="rightSide"/> don't conform.</exception>
public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide.ColumnCount != rightSide.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> and a Vector.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The vector to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static DenseVector operator *(SymmetricDenseMatrix leftSide, DenseVector rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (DenseVector)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a Vector and a <strong>Matrix</strong>.
/// </summary>
/// <param name="leftSide">The vector to multiply.</param>
/// <param name="rightSide">The matrix to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static DenseVector operator *(DenseVector leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (DenseVector)rightSide.LeftMultiply(leftSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator %(SymmetricDenseMatrix leftSide, Complex rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (SymmetricDenseMatrix)leftSide.Modulus(rightSide);
}
}
}

657
src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs

@ -0,0 +1,657 @@
// <copyright file="SymmetricMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Complex
{
using System;
using System.Numerics;
using Generic;
using Distributions;
using Properties;
using Storage;
/// <summary>
/// Abstract class for symmetric matrices.
/// </summary>
[Serializable]
public abstract class SymmetricMatrix : SquareMatrix
{
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricMatrix"/> class.
/// </summary>
protected SymmetricMatrix(MatrixStorage<Complex> storage)
: base(storage)
{
}
/// <summary>
/// Returns a value indicating whether the array is symmetric.
/// </summary>
/// <param name="array">
/// The array to check for symmetry.
/// </param>
/// <returns>
/// True is array is symmetric, false if not symmetric.
/// </returns>
public static bool CheckIfSymmetric(Complex[,] array)
{
var rows = array.GetLength(0);
var columns = array.GetLength(1);
if (rows != columns)
{
return false;
}
for (var row = 0; row < rows; row++)
{
for (var column = 0; column < columns; column++)
{
if (column >= row)
{
continue;
}
if (!array[row, column].Equals(array[column, row]))
{
return false;
}
}
}
return true;
}
/// <summary>
/// Gets a value indicating whether this matrix is symmetric.
/// </summary>
public override sealed bool IsSymmetric
{
get
{
return true;
}
}
/// <summary>
/// Returns the transpose of this matrix. The transpose is equal and this method returns a reference to this matrix.
/// </summary>
/// <returns>
/// The transpose of this matrix.
/// </returns>
public override sealed Matrix<Complex> Transpose()
{
return this.Clone();
}
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<Complex> ConjugateTranspose()
{
var ret = CreateMatrix(ColumnCount, RowCount);
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
ret.At(row, column, At(column, row).Conjugate());
}
}
return ret;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override Matrix<Complex> Add(Matrix<Complex> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
Matrix<Complex> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
DoAdd(other, result);
return result;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">
/// The matrix to add to this matrix.
/// </param>
/// <param name="result">
/// The matrix to store the result of the addition.
/// </param>
/// <exception cref="ArgumentNullException">
/// If the other matrix is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// If the two matrices don't have the same dimensions.
/// </exception>
protected override void DoAdd(Matrix<Complex> other, Matrix<Complex> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric + non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoAdd(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) + symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <returns>The result of the subtraction.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override Matrix<Complex> Subtract(Matrix<Complex> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
Matrix<Complex> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
DoSubtract(other, result);
return result;
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">
/// The matrix to subtract to this matrix.
/// </param>
/// <param name="result">
/// The matrix to store the result of subtraction.
/// </param>
/// <exception cref="ArgumentNullException">
/// If the other matrix is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// If the two matrices don't have the same dimensions.
/// </exception>
protected override void DoSubtract(Matrix<Complex> other, Matrix<Complex> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric - non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoSubtract(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) - symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">
/// The scalar to multiply the matrix with.
/// </param>
/// <param name="result">
/// The matrix to store the result of the multiplication.
/// </param>
protected override void DoMultiply(Complex scalar, Matrix<Complex> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) * scalar);
}
}
}
}
/// <summary>
/// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to multiply with.
/// </param>
/// <param name="result">
/// The result of the multiplication.
/// </param>
protected override sealed void DoTransposeThisAndMultiply(Matrix<Complex> other, Matrix<Complex> result)
{
DoMultiply(other, result);
}
/// <summary>
/// Multiplies the transpose of this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">
/// The vector to multiply with.
/// </param>
/// <param name="result">
/// The result of the multiplication.
/// </param>
protected override sealed void DoTransposeThisAndMultiply(Vector<Complex> rightSide, Vector<Complex> result)
{
DoMultiply(rightSide, result);
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">
/// The result of the negation.
/// </param>
protected override void DoNegate(Matrix<Complex> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoNegate(result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column != ColumnCount; column++)
{
symmetricResult[row, column] = -At(row, column);
}
}
}
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise multiplication of this matrix and <paramref name="other"/>.</returns>
public override Matrix<Complex> PointwiseMultiply(Matrix<Complex> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other, "other");
}
Matrix<Complex> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
PointwiseMultiply(other, result);
return result;
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to pointwise multiply with this one.
/// </param>
/// <param name="result">
/// The matrix to store the result of the pointwise multiplication.
/// </param>
protected override void DoPointwiseMultiply(Matrix<Complex> other, Matrix<Complex> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric pointwise* non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoPointwiseMultiply(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) * symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Pointwise divide this matrix by another matrix.
/// </summary>
/// <param name="other">The matrix to pointwise subtract this one by.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise division of this matrix and <paramref name="other"/>.</returns>
public override Matrix<Complex> PointwiseDivide(Matrix<Complex> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other);
}
Matrix<Complex> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
PointwiseDivide(other, result);
return result;
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to pointwise divide this one by.
/// </param>
/// <param name="result">
/// The matrix to store the result of the pointwise division.
/// </param>
protected override void DoPointwiseDivide(Matrix<Complex> other, Matrix<Complex> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric pointwise/ non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoPointwiseDivide(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) / symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Computes the modulus for each element of the matrix.
/// </summary>
/// <param name="divisor">
/// The divisor to use.
/// </param>
/// <param name="result">
/// Matrix to store the results in.
/// </param>
protected override void DoModulus(Complex divisor, Matrix<Complex> result)
{
throw new NotImplementedException();
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">
/// The matrix to populate.
/// </param>
/// <param name="distribution">
/// Continuous Random Distribution to generate elements from.
/// </param>
protected override void DoRandom(Matrix<Complex> matrix, IContinuousDistribution distribution)
{
var symmetricMatrix = matrix as SymmetricMatrix;
if (symmetricMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var row = 0; row < matrix.RowCount; row++)
{
for (var column = row; column < matrix.ColumnCount; column++)
{
symmetricMatrix.At(row, column, distribution.Sample());
}
}
}
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">
/// The matrix to populate.
/// </param>
/// <param name="distribution">
/// Continuous Random Distribution to generate elements from.
/// </param>
protected override void DoRandom(Matrix<Complex> matrix, IDiscreteDistribution distribution)
{
var symmetricMatrix = matrix as SymmetricMatrix;
if (symmetricMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var row = 0; row < matrix.RowCount; row++)
{
for (var column = row; column < matrix.ColumnCount; column++)
{
symmetricMatrix.At(row, column, distribution.Sample());
}
}
}
}
/// <summary>
/// Creates a new matrix and inserts the given column at the given index.
/// </summary>
/// <param name="columnIndex">The index of where to insert the column.</param>
/// <param name="column">The column to insert.</param>
/// <returns>A new matrix with the inserted column.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="column "/> is <see langword="null" />. </exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is &lt; zero or &gt; the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> != the number of rows.</exception>
public override Matrix<Complex> InsertColumn(int columnIndex, Vector<Complex> column)
{
throw new InvalidOperationException("Inserting a column is not supported on a symmetric matrix. Symmetric matrices are square");
}
/// <summary>
/// Copies the values of the given array to the specified column. The changes retain the symmetry of the matrix.
/// </summary>
/// <param name="columnIndex">The column to copy the values to.</param>
/// <param name="column">The array to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="column"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is less than zero,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
public override void SetColumn(int columnIndex, Complex[] column)
{
throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Copies the values of the given Vector to the specified column. The changes retain the symmetry of the matrix.
/// </summary>
/// <param name="columnIndex">The column to copy the values to.</param>
/// <param name="column">The vector to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="column"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is less than zero,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
public override void SetColumn(int columnIndex, Vector<Complex> column)
{
throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Creates a new matrix and inserts the given row at the given index.
/// </summary>
/// <param name="rowIndex">The index of where to insert the row.</param>
/// <param name="row">The row to insert.</param>
/// <returns>A new matrix with the inserted column.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />. </exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is &lt; zero or &gt; the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> != the number of columns.</exception>
public override Matrix<Complex> InsertRow(int rowIndex, Vector<Complex> row)
{
throw new InvalidOperationException("Inserting a row is not supported on a symmetric matrix. Symmetric matrices are square");
}
/// <summary>
/// Copies the values of the given Vector to the specified row.
/// </summary>
/// <param name="rowIndex">The row to copy the values to.</param>
/// <param name="row">The vector to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is less than zero,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> does not
/// equal the number of columns of this <strong>Matrix</strong>.</exception>
public override void SetRow(int rowIndex, Vector<Complex> row)
{
throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Copies the values of the given array to the specified row.
/// </summary>
/// <param name="rowIndex">The row to copy the values to.</param>
/// <param name="row">The array to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is less than zero,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> does not
/// equal the number of columns of this <strong>Matrix</strong>.</exception>
public override void SetRow(int rowIndex, Complex[] row)
{
throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry");
}
}
}

62
src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs

@ -0,0 +1,62 @@
// <copyright file="SquareMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Complex32
{
using System;
using Numerics;
using Properties;
using Storage;
/// <summary>
/// Abstract class for square matrices.
/// </summary>
[Serializable]
public abstract class SquareMatrix : Matrix
{
/// <summary>
/// Number of rows or columns.
/// </summary>
protected readonly int Order;
/// <summary>
/// Initializes a new instance of the <see cref="SquareMatrix"/> class.
/// </summary>
/// <exception cref="ArgumentException">
/// If the matrix is not square.
/// </exception>
protected SquareMatrix(MatrixStorage<Complex32> storage)
: base(storage)
{
if (storage.RowCount != storage.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
Order = storage.RowCount;
}
}
}

767
src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs

@ -0,0 +1,767 @@
// <copyright file="SymmetricDenseMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Complex32
{
using System;
using Numerics;
using Generic;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static;
using Properties;
using Storage;
/// <summary>
/// A Symmetric Matrix class with dense storage.
/// </summary>
/// <remarks> The underlying storage is a one dimensional array in column-major order.
/// The Upper Triangle is stored(it is equal to the Lower Triangle) </remarks>
[Serializable]
public class SymmetricDenseMatrix : SymmetricMatrix
{
readonly DenseColumnMajorSymmetricMatrixStorage<Complex32> _storage;
/// <summary>
/// Gets the matrix's data.
/// </summary>
/// <value>The matrix's data.</value>
readonly Complex32[] _data;
internal SymmetricDenseMatrix(DenseColumnMajorSymmetricMatrixStorage<Complex32> storage)
: base(storage)
{
_storage = storage;
_data = _storage.Data;
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class. This matrix is square with a given size.
/// </summary>
/// <param name="order">The order of the matrix.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public SymmetricDenseMatrix(int order)
: this(new DenseColumnMajorSymmetricMatrixStorage<Complex32>(order))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class with all entries set to a particular value.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param>
public SymmetricDenseMatrix(int order, Complex32 value)
: this(order)
{
for (var i = 0; i < _data.Length; i++)
{
_data[i] = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class from a one dimensional array. This constructor
/// will reference the one dimensional array and not copy it.
/// </summary>
/// <param name="order">The size of the square matrix.</param>
/// <param name="array">
/// The one dimensional array to create this matrix from. Column-major and row-major order is identical on a symmetric matrix: http://en.wikipedia.org/wiki/Row-major_order
/// </param>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> does not represent a packed array.
/// </exception>
public SymmetricDenseMatrix(int order, Complex32[] array)
: this(new DenseColumnMajorSymmetricMatrixStorage<Complex32>(order, array))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class from a 2D array. This constructor
/// will allocate a completely new memory block for storing the symmetric dense matrix.
/// </summary>
/// <param name="array">The 2D array to create this matrix from.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> is not a square array.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> is not a symmetric array.
/// </exception>
public SymmetricDenseMatrix(Complex32[,] array)
: this(array.GetLength(0))
{
if (!CheckIfSymmetric(array))
{
throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
}
var indexer = new PackedStorageIndexerUpper(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
_data[indexer.Of(row, column)] = array[row, column];
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class, copying
/// the values from the given matrix. Matrix must be Symmetric.
/// </summary>
/// <param name="matrix">The matrix to copy.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="matrix"/> is not a square matrix.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="matrix"/> is not a symmetric matrix.
/// </exception>
public SymmetricDenseMatrix(Matrix<Complex32> matrix)
: this(matrix.RowCount)
{
var symmetricMatrix = matrix as SymmetricDenseMatrix;
if (!matrix.IsSymmetric)
{
throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
}
if (symmetricMatrix == null)
{
var indexer = new PackedStorageIndexerUpper(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
_data[indexer.Of(row, column)] = matrix[row, column];
}
}
}
else
{
matrix.CopyTo(this);
}
}
/// <summary>
/// Gets the matrix's data.
/// </summary>
/// <value>The matrix's data.</value>
public Complex32[] Data
{
get { return _data; }
}
/// <summary>
/// Creates a <c>SymmetricDenseMatrix</c> for the given number of rows and columns.
/// If rows and columns are not equal, returns a <c>DenseMatrix</c> instead.
/// </summary>
/// <param name="numberOfRows">
/// The number of rows.
/// </param>
/// <param name="numberOfColumns">
/// The number of columns.
/// </param>
/// <param name="fullyMutable">True if all fields must be mutable (e.g. not a diagonal matrix).</param>
/// <returns>
/// A <c>DenseMatrix</c> or <c>SymmetricDenseMatrix</c> with the given dimensions.
/// </returns>
/// /// <exception cref="ArgumentException">
/// If <paramref name="numberOfRows"/> is not equal to <paramref name="numberOfColumns"/>.
/// Symmetric arrays are always square
/// </exception>
public override Matrix<Complex32> CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false)
{
if (numberOfRows != numberOfColumns || fullyMutable)
{
return new DenseMatrix(numberOfRows, numberOfColumns);
}
return new SymmetricDenseMatrix(numberOfRows);
}
/// <summary>
/// Creates a <see cref="Vector{T}"/> with a the given dimension.
/// </summary>
/// <param name="size">The size of the vector.</param>
/// <param name="fullyMutable">True if all fields must be mutable.</param>
/// <returns>
/// A <see cref="Vector{T}"/> with the given dimension.
/// </returns>
public override Vector<Complex32> CreateVector(int size, bool fullyMutable = false)
{
return new DenseVector(size);
}
#region Static constructors for special matrices.
/// <summary>
/// Initializes a square <see cref="SymmetricDenseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary>
/// <param name="order">the size of the square matrix.</param>
/// <returns>A symmetric dense identity matrix.</returns>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public static SymmetricDenseMatrix Identity(int order)
{
var m = new SymmetricDenseMatrix(order);
for (var i = 0; i < order; i++)
{
m.At(i, i, Complex32.One);
}
return m;
}
#endregion
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of add</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
protected override void DoAdd(Matrix<Complex32> other, Matrix<Complex32> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoAdd(other, result);
}
else
{
Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
protected override void DoSubtract(Matrix<Complex32> other, Matrix<Complex32> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoSubtract(other, result);
}
else
{
Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(Complex32 scalar, Matrix<Complex32> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data);
}
}
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<Complex32> rightSide, Vector<Complex32> result)
{
var denseRight = rightSide as DenseVector;
var denseResult = result as DenseVector;
if (denseRight == null || denseResult == null)
{
base.DoMultiply(rightSide, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoMultiply(rightSide, result);
}
}
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoMultiply(other, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoMultiply(other, result);
}
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoTransposeAndMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoTransposeAndMultiply(other, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoTransposeAndMultiply(other, result);
}
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
protected override void DoNegate(Matrix<Complex32> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoNegate(result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data);
}
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
protected override void DoPointwiseMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoPointwiseMultiply(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
protected override void DoPointwiseDivide(Matrix<Complex32> other, Matrix<Complex32> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoPointwiseDivide(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Returns a new matrix containing the lower triangle of this matrix.
/// </summary>
/// <returns>The lower triangle of this matrix.</returns>
public override Matrix<Complex32> LowerTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = 0; column <= row; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the lower triangle of this matrix. The new matrix
/// does not contain the diagonal elements of this matrix.
/// </summary>
/// <returns>The lower triangle of this matrix.</returns>
public override Matrix<Complex32> StrictlyLowerTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = 0; column < row; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the upper triangle of this matrix.
/// </summary>
/// <returns>The upper triangle of this matrix.</returns>
public override Matrix<Complex32> UpperTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the upper triangle of this matrix. The new matrix
/// does not contain the diagonal elements of this matrix.
/// </summary>
/// <returns>The upper triangle of this matrix.</returns>
public override Matrix<Complex32> StrictlyUpperTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row + 1; column < Order; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Computes the trace of this matrix.
/// </summary>
/// <returns>The trace of this matrix</returns>
public override Complex32 Trace()
{
// Matrix is always square.
var sum = Complex32.Zero;
for (var i = 0; i < RowCount; i++)
{
sum += At(i, i);
}
return sum;
}
/// <summary>
/// Populates a symmetric matrix with random elements.
/// </summary>
/// <param name="matrix">The symmetric matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<Complex32> matrix, IContinuousDistribution distribution)
{
var denseMatrix = matrix as SymmetricDenseMatrix;
if (denseMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var i = 0; i < denseMatrix._data.Length; i++)
{
denseMatrix._data[i] = Convert.ToSingle(distribution.Sample());
}
}
}
/// <summary>
/// Populates a symmetric matrix with random elements.
/// </summary>
/// <param name="matrix">The symmetric matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<Complex32> matrix, IDiscreteDistribution distribution)
{
var denseMatrix = matrix as SymmetricDenseMatrix;
if (denseMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var i = 0; i < denseMatrix._data.Length; i++)
{
denseMatrix._data[i] = distribution.Sample();
}
}
}
/// <summary>
/// Adds two matrices together and returns the results.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to add.</param>
/// <param name="rightSide">The right matrix to add.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (leftSide.RowCount != rightSide.RowCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Add(rightSide);
}
/// <summary>
/// Returns a <strong>Matrix</strong> containing the same values of <paramref name="rightSide"/>.
/// </summary>
/// <param name="rightSide">The matrix to get the values from.</param>
/// <returns>A matrix containing a the same values as <paramref name="rightSide"/>.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Clone();
}
/// <summary>
/// Subtracts two matrices together and returns the results.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to subtract.</param>
/// <param name="rightSide">The right matrix to subtract.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (leftSide.RowCount != rightSide.RowCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Subtract(rightSide);
}
/// <summary>
/// Negates each element of the matrix.
/// </summary>
/// <param name="rightSide">The matrix to negate.</param>
/// <returns>A matrix containing the negated values.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Negate();
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, Complex32 rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (SymmetricDenseMatrix)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator *(Complex32 leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Multiply(leftSide);
}
/// <summary>
/// Multiplies two matrices.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to multiply.</param>
/// <param name="rightSide">The right matrix to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If the dimensions of <paramref name="leftSide"/> or <paramref name="rightSide"/> don't conform.</exception>
public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide.ColumnCount != rightSide.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> and a Vector.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The vector to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static DenseVector operator *(SymmetricDenseMatrix leftSide, DenseVector rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (DenseVector)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a Vector and a <strong>Matrix</strong>.
/// </summary>
/// <param name="leftSide">The vector to multiply.</param>
/// <param name="rightSide">The matrix to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static DenseVector operator *(DenseVector leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (DenseVector)rightSide.LeftMultiply(leftSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator %(SymmetricDenseMatrix leftSide, Complex32 rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (SymmetricDenseMatrix)leftSide.Modulus(rightSide);
}
}
}

657
src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs

@ -0,0 +1,657 @@
// <copyright file="SymmetricMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Complex32
{
using System;
using Numerics;
using Generic;
using Distributions;
using Properties;
using Storage;
/// <summary>
/// Abstract class for symmetric matrices.
/// </summary>
[Serializable]
public abstract class SymmetricMatrix : SquareMatrix
{
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricMatrix"/> class.
/// </summary>
protected SymmetricMatrix(MatrixStorage<Complex32> storage)
: base(storage)
{
}
/// <summary>
/// Returns a value indicating whether the array is symmetric.
/// </summary>
/// <param name="array">
/// The array to check for symmetry.
/// </param>
/// <returns>
/// True is array is symmetric, false if not symmetric.
/// </returns>
public static bool CheckIfSymmetric(Complex32[,] array)
{
var rows = array.GetLength(0);
var columns = array.GetLength(1);
if (rows != columns)
{
return false;
}
for (var row = 0; row < rows; row++)
{
for (var column = 0; column < columns; column++)
{
if (column >= row)
{
continue;
}
if (!array[row, column].Equals(array[column, row]))
{
return false;
}
}
}
return true;
}
/// <summary>
/// Gets a value indicating whether this matrix is symmetric.
/// </summary>
public override sealed bool IsSymmetric
{
get
{
return true;
}
}
/// <summary>
/// Returns the transpose of this matrix. The transpose is equal and this method returns a reference to this matrix.
/// </summary>
/// <returns>
/// The transpose of this matrix.
/// </returns>
public override sealed Matrix<Complex32> Transpose()
{
return this.Clone();
}
/// <summary>
/// Returns the conjugate transpose of this matrix.
/// </summary>
/// <returns>The conjugate transpose of this matrix.</returns>
public override Matrix<Complex32> ConjugateTranspose()
{
var ret = CreateMatrix(ColumnCount, RowCount);
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
ret.At(row, column, At(column, row).Conjugate());
}
}
return ret;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override Matrix<Complex32> Add(Matrix<Complex32> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
Matrix<Complex32> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
DoAdd(other, result);
return result;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">
/// The matrix to add to this matrix.
/// </param>
/// <param name="result">
/// The matrix to store the result of the addition.
/// </param>
/// <exception cref="ArgumentNullException">
/// If the other matrix is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// If the two matrices don't have the same dimensions.
/// </exception>
protected override void DoAdd(Matrix<Complex32> other, Matrix<Complex32> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric + non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoAdd(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) + symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <returns>The result of the subtraction.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override Matrix<Complex32> Subtract(Matrix<Complex32> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
Matrix<Complex32> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
DoSubtract(other, result);
return result;
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">
/// The matrix to subtract to this matrix.
/// </param>
/// <param name="result">
/// The matrix to store the result of subtraction.
/// </param>
/// <exception cref="ArgumentNullException">
/// If the other matrix is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// If the two matrices don't have the same dimensions.
/// </exception>
protected override void DoSubtract(Matrix<Complex32> other, Matrix<Complex32> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric - non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoSubtract(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) - symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">
/// The scalar to multiply the matrix with.
/// </param>
/// <param name="result">
/// The matrix to store the result of the multiplication.
/// </param>
protected override void DoMultiply(Complex32 scalar, Matrix<Complex32> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) * scalar);
}
}
}
}
/// <summary>
/// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to multiply with.
/// </param>
/// <param name="result">
/// The result of the multiplication.
/// </param>
protected override sealed void DoTransposeThisAndMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{
DoMultiply(other, result);
}
/// <summary>
/// Multiplies the transpose of this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">
/// The vector to multiply with.
/// </param>
/// <param name="result">
/// The result of the multiplication.
/// </param>
protected override sealed void DoTransposeThisAndMultiply(Vector<Complex32> rightSide, Vector<Complex32> result)
{
DoMultiply(rightSide, result);
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">
/// The result of the negation.
/// </param>
protected override void DoNegate(Matrix<Complex32> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoNegate(result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column != ColumnCount; column++)
{
symmetricResult[row, column] = -At(row, column);
}
}
}
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise multiplication of this matrix and <paramref name="other"/>.</returns>
public override Matrix<Complex32> PointwiseMultiply(Matrix<Complex32> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other, "other");
}
Matrix<Complex32> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
PointwiseMultiply(other, result);
return result;
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to pointwise multiply with this one.
/// </param>
/// <param name="result">
/// The matrix to store the result of the pointwise multiplication.
/// </param>
protected override void DoPointwiseMultiply(Matrix<Complex32> other, Matrix<Complex32> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric pointwise* non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoPointwiseMultiply(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) * symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Pointwise divide this matrix by another matrix.
/// </summary>
/// <param name="other">The matrix to pointwise subtract this one by.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise division of this matrix and <paramref name="other"/>.</returns>
public override Matrix<Complex32> PointwiseDivide(Matrix<Complex32> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other);
}
Matrix<Complex32> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
PointwiseDivide(other, result);
return result;
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to pointwise divide this one by.
/// </param>
/// <param name="result">
/// The matrix to store the result of the pointwise division.
/// </param>
protected override void DoPointwiseDivide(Matrix<Complex32> other, Matrix<Complex32> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric pointwise/ non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoPointwiseDivide(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) / symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Computes the modulus for each element of the matrix.
/// </summary>
/// <param name="divisor">
/// The divisor to use.
/// </param>
/// <param name="result">
/// Matrix to store the results in.
/// </param>
protected override void DoModulus(Complex32 divisor, Matrix<Complex32> result)
{
throw new NotImplementedException();
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">
/// The matrix to populate.
/// </param>
/// <param name="distribution">
/// Continuous Random Distribution to generate elements from.
/// </param>
protected override void DoRandom(Matrix<Complex32> matrix, IContinuousDistribution distribution)
{
var symmetricMatrix = matrix as SymmetricMatrix;
if (symmetricMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var row = 0; row < matrix.RowCount; row++)
{
for (var column = row; column < matrix.ColumnCount; column++)
{
symmetricMatrix.At(row, column, Convert.ToSingle(distribution.Sample()));
}
}
}
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">
/// The matrix to populate.
/// </param>
/// <param name="distribution">
/// Continuous Random Distribution to generate elements from.
/// </param>
protected override void DoRandom(Matrix<Complex32> matrix, IDiscreteDistribution distribution)
{
var symmetricMatrix = matrix as SymmetricMatrix;
if (symmetricMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var row = 0; row < matrix.RowCount; row++)
{
for (var column = row; column < matrix.ColumnCount; column++)
{
symmetricMatrix.At(row, column, distribution.Sample());
}
}
}
}
/// <summary>
/// Creates a new matrix and inserts the given column at the given index.
/// </summary>
/// <param name="columnIndex">The index of where to insert the column.</param>
/// <param name="column">The column to insert.</param>
/// <returns>A new matrix with the inserted column.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="column "/> is <see langword="null" />. </exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is &lt; zero or &gt; the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> != the number of rows.</exception>
public override Matrix<Complex32> InsertColumn(int columnIndex, Vector<Complex32> column)
{
throw new InvalidOperationException("Inserting a column is not supported on a symmetric matrix. Symmetric matrices are square");
}
/// <summary>
/// Copies the values of the given array to the specified column. The changes retain the symmetry of the matrix.
/// </summary>
/// <param name="columnIndex">The column to copy the values to.</param>
/// <param name="column">The array to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="column"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is less than zero,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
public override void SetColumn(int columnIndex, Complex32[] column)
{
throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Copies the values of the given Vector to the specified column. The changes retain the symmetry of the matrix.
/// </summary>
/// <param name="columnIndex">The column to copy the values to.</param>
/// <param name="column">The vector to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="column"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is less than zero,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
public override void SetColumn(int columnIndex, Vector<Complex32> column)
{
throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Creates a new matrix and inserts the given row at the given index.
/// </summary>
/// <param name="rowIndex">The index of where to insert the row.</param>
/// <param name="row">The row to insert.</param>
/// <returns>A new matrix with the inserted column.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />. </exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is &lt; zero or &gt; the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> != the number of columns.</exception>
public override Matrix<Complex32> InsertRow(int rowIndex, Vector<Complex32> row)
{
throw new InvalidOperationException("Inserting a row is not supported on a symmetric matrix. Symmetric matrices are square");
}
/// <summary>
/// Copies the values of the given Vector to the specified row.
/// </summary>
/// <param name="rowIndex">The row to copy the values to.</param>
/// <param name="row">The vector to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is less than zero,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> does not
/// equal the number of columns of this <strong>Matrix</strong>.</exception>
public override void SetRow(int rowIndex, Vector<Complex32> row)
{
throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Copies the values of the given array to the specified row.
/// </summary>
/// <param name="rowIndex">The row to copy the values to.</param>
/// <param name="row">The array to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is less than zero,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> does not
/// equal the number of columns of this <strong>Matrix</strong>.</exception>
public override void SetRow(int rowIndex, Complex32[] row)
{
throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry");
}
}
}

61
src/Numerics/LinearAlgebra/Double/SquareMatrix.cs

@ -0,0 +1,61 @@
// <copyright file="SquareMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Double
{
using System;
using Properties;
using Storage;
/// <summary>
/// Abstract class for square matrices.
/// </summary>
[Serializable]
public abstract class SquareMatrix : Matrix
{
/// <summary>
/// Number of rows or columns.
/// </summary>
protected readonly int Order;
/// <summary>
/// Initializes a new instance of the <see cref="SquareMatrix"/> class.
/// </summary>
/// <exception cref="ArgumentException">
/// If the matrix is not square.
/// </exception>
protected SquareMatrix(MatrixStorage<double> storage)
: base(storage)
{
if (storage.RowCount != storage.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
Order = storage.RowCount;
}
}
}

794
src/Numerics/LinearAlgebra/Double/SymmetricDenseMatrix.cs

@ -0,0 +1,794 @@
// <copyright file="SymmetricDenseMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Double
{
using System;
using Generic;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static;
using MathNet.Numerics.Threading;
using Properties;
using Storage;
/// <summary>
/// A Symmetric Matrix class with dense storage.
/// </summary>
/// <remarks> The underlying storage is a one dimensional array in column-major order.
/// The Upper Triangle is stored(it is equal to the Lower Triangle) </remarks>
[Serializable]
public class SymmetricDenseMatrix : SymmetricMatrix
{
readonly DenseColumnMajorSymmetricMatrixStorage<double> _storage;
/// <summary>
/// Gets the matrix's data.
/// </summary>
/// <value>The matrix's data.</value>
readonly double[] _data;
internal SymmetricDenseMatrix(DenseColumnMajorSymmetricMatrixStorage<double> storage)
: base(storage)
{
_storage = storage;
_data = _storage.Data;
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class. This matrix is square with a given size.
/// </summary>
/// <param name="order">The order of the matrix.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public SymmetricDenseMatrix(int order)
: this(new DenseColumnMajorSymmetricMatrixStorage<double>(order))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class with all entries set to a particular value.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param>
public SymmetricDenseMatrix(int order, double value)
: this(order)
{
for (var i = 0; i < _data.Length; i++)
{
_data[i] = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class from a one dimensional array. This constructor
/// will reference the one dimensional array and not copy it.
/// </summary>
/// <param name="order">The size of the square matrix.</param>
/// <param name="array">
/// The one dimensional array to create this matrix from. Column-major and row-major order is identical on a symmetric matrix: http://en.wikipedia.org/wiki/Row-major_order
/// </param>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> does not represent a packed array.
/// </exception>
public SymmetricDenseMatrix(int order, double[] array)
: this(new DenseColumnMajorSymmetricMatrixStorage<double>(order, array))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class from a 2D array. This constructor
/// will allocate a completely new memory block for storing the symmetric dense matrix.
/// </summary>
/// <param name="array">The 2D array to create this matrix from.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> is not a square array.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> is not a symmetric array.
/// </exception>
public SymmetricDenseMatrix(double[,] array)
: this(array.GetLength(0))
{
if (!CheckIfSymmetric(array))
{
throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
}
var indexer = new PackedStorageIndexerUpper(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
_data[indexer.Of(row, column)] = array[row, column];
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class, copying
/// the values from the given matrix. Matrix must be Symmetric.
/// </summary>
/// <param name="matrix">The matrix to copy.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="matrix"/> is not a square matrix.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="matrix"/> is not a symmetric matrix.
/// </exception>
public SymmetricDenseMatrix(Matrix<double> matrix)
: this(matrix.RowCount)
{
var symmetricMatrix = matrix as SymmetricDenseMatrix;
if (!matrix.IsSymmetric)
{
throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
}
if (symmetricMatrix == null)
{
var indexer = new PackedStorageIndexerUpper(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
_data[indexer.Of(row, column)] = matrix[row, column];
}
}
}
else
{
matrix.CopyTo(this);
}
}
/// <summary>
/// Gets the matrix's data.
/// </summary>
/// <value>The matrix's data.</value>
public double[] Data
{
get { return _data; }
}
/// <summary>
/// Creates a <c>SymmetricDenseMatrix</c> for the given number of rows and columns.
/// If rows and columns are not equal, returns a <c>DenseMatrix</c> instead.
/// </summary>
/// <param name="numberOfRows">
/// The number of rows.
/// </param>
/// <param name="numberOfColumns">
/// The number of columns.
/// </param>
/// <param name="fullyMutable">True if all fields must be mutable (e.g. not a diagonal matrix).</param>
/// <returns>
/// A <c>DenseMatrix</c> or <c>SymmetricDenseMatrix</c> with the given dimensions.
/// </returns>
/// /// <exception cref="ArgumentException">
/// If <paramref name="numberOfRows"/> is not equal to <paramref name="numberOfColumns"/>.
/// Symmetric arrays are always square
/// </exception>
public override Matrix<double> CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false)
{
if (numberOfRows != numberOfColumns || fullyMutable)
{
return new DenseMatrix(numberOfRows, numberOfColumns);
}
return new SymmetricDenseMatrix(numberOfRows);
}
/// <summary>
/// Creates a <see cref="Vector{T}"/> with a the given dimension.
/// </summary>
/// <param name="size">The size of the vector.</param>
/// <param name="fullyMutable">True if all fields must be mutable.</param>
/// <returns>
/// A <see cref="Vector{T}"/> with the given dimension.
/// </returns>
public override Vector<double> CreateVector(int size, bool fullyMutable = false)
{
return new DenseVector(size);
}
#region Static constructors for special matrices.
/// <summary>
/// Initializes a square <see cref="SymmetricDenseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary>
/// <param name="order">the size of the square matrix.</param>
/// <returns>A symmetric dense identity matrix.</returns>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public static SymmetricDenseMatrix Identity(int order)
{
var m = new SymmetricDenseMatrix(order);
for (var i = 0; i < order; i++)
{
m.At(i, i, 1.0);
}
return m;
}
#endregion
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of add</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
protected override void DoAdd(Matrix<double> other, Matrix<double> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoAdd(other, result);
}
else
{
Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
protected override void DoSubtract(Matrix<double> other, Matrix<double> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoSubtract(other, result);
}
else
{
Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(double scalar, Matrix<double> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data);
}
}
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<double> rightSide, Vector<double> result)
{
var denseRight = rightSide as DenseVector;
var denseResult = result as DenseVector;
if (denseRight == null || denseResult == null)
{
base.DoMultiply(rightSide, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoMultiply(rightSide, result);
}
}
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Matrix<double> other, Matrix<double> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoMultiply(other, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoMultiply(other, result);
}
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoTransposeAndMultiply(Matrix<double> other, Matrix<double> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoTransposeAndMultiply(other, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoTransposeAndMultiply(other, result);
}
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
protected override void DoNegate(Matrix<double> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoNegate(result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data);
}
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
protected override void DoPointwiseMultiply(Matrix<double> other, Matrix<double> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoPointwiseMultiply(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
protected override void DoPointwiseDivide(Matrix<double> other, Matrix<double> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoPointwiseDivide(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Returns a new matrix containing the lower triangle of this matrix.
/// </summary>
/// <returns>The lower triangle of this matrix.</returns>
public override Matrix<double> LowerTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = 0; column <= row; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the lower triangle of this matrix. The new matrix
/// does not contain the diagonal elements of this matrix.
/// </summary>
/// <returns>The lower triangle of this matrix.</returns>
public override Matrix<double> StrictlyLowerTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = 0; column < row; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the upper triangle of this matrix.
/// </summary>
/// <returns>The upper triangle of this matrix.</returns>
public override Matrix<double> UpperTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the upper triangle of this matrix. The new matrix
/// does not contain the diagonal elements of this matrix.
/// </summary>
/// <returns>The upper triangle of this matrix.</returns>
public override Matrix<double> StrictlyUpperTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row + 1; column < Order; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Computes the modulus for each element of the matrix.
/// </summary>
/// <param name="divisor">The divisor to use.</param>
/// <param name="result">Matrix to store the results in.</param>
protected override void DoModulus(double divisor, Matrix<double> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoModulus(divisor, result);
}
else
{
if (!ReferenceEquals(this, result))
{
CopyTo(result);
}
CommonParallel.For(
0,
_data.Length,
index => denseResult._data[index] %= divisor);
}
}
/// <summary>
/// Computes the trace of this matrix.
/// </summary>
/// <returns>The trace of this matrix</returns>
public override double Trace()
{
// Matrix is always square.
var sum = 0.0;
for (var i = 0; i < RowCount; i++)
{
sum += At(i, i);
}
return sum;
}
/// <summary>
/// Populates a symmetric matrix with random elements.
/// </summary>
/// <param name="matrix">The symmetric matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<double> matrix, IContinuousDistribution distribution)
{
var denseMatrix = matrix as SymmetricDenseMatrix;
if (denseMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var i = 0; i < denseMatrix._data.Length; i++)
{
denseMatrix._data[i] = distribution.Sample();
}
}
}
/// <summary>
/// Populates a symmetric matrix with random elements.
/// </summary>
/// <param name="matrix">The symmetric matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<double> matrix, IDiscreteDistribution distribution)
{
var denseMatrix = matrix as SymmetricDenseMatrix;
if (denseMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var i = 0; i < denseMatrix._data.Length; i++)
{
denseMatrix._data[i] = distribution.Sample();
}
}
}
/// <summary>
/// Adds two matrices together and returns the results.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to add.</param>
/// <param name="rightSide">The right matrix to add.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (leftSide.RowCount != rightSide.RowCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Add(rightSide);
}
/// <summary>
/// Returns a <strong>Matrix</strong> containing the same values of <paramref name="rightSide"/>.
/// </summary>
/// <param name="rightSide">The matrix to get the values from.</param>
/// <returns>A matrix containing a the same values as <paramref name="rightSide"/>.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Clone();
}
/// <summary>
/// Subtracts two matrices together and returns the results.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to subtract.</param>
/// <param name="rightSide">The right matrix to subtract.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (leftSide.RowCount != rightSide.RowCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Subtract(rightSide);
}
/// <summary>
/// Negates each element of the matrix.
/// </summary>
/// <param name="rightSide">The matrix to negate.</param>
/// <returns>A matrix containing the negated values.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Negate();
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, double rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (SymmetricDenseMatrix)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator *(double leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Multiply(leftSide);
}
/// <summary>
/// Multiplies two matrices.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to multiply.</param>
/// <param name="rightSide">The right matrix to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If the dimensions of <paramref name="leftSide"/> or <paramref name="rightSide"/> don't conform.</exception>
public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide.ColumnCount != rightSide.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> and a Vector.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The vector to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static DenseVector operator *(SymmetricDenseMatrix leftSide, DenseVector rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (DenseVector)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a Vector and a <strong>Matrix</strong>.
/// </summary>
/// <param name="leftSide">The vector to multiply.</param>
/// <param name="rightSide">The matrix to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static DenseVector operator *(DenseVector leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (DenseVector)rightSide.LeftMultiply(leftSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator %(SymmetricDenseMatrix leftSide, double rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (SymmetricDenseMatrix)leftSide.Modulus(rightSide);
}
}
}

653
src/Numerics/LinearAlgebra/Double/SymmetricMatrix.cs

@ -0,0 +1,653 @@
// <copyright file="SymmetricMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Double
{
using System;
using Generic;
using Distributions;
using Properties;
using Storage;
/// <summary>
/// Abstract class for symmetric matrices.
/// </summary>
[Serializable]
public abstract class SymmetricMatrix : SquareMatrix
{
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricMatrix"/> class.
/// </summary>
protected SymmetricMatrix(MatrixStorage<double> storage)
: base(storage)
{
}
/// <summary>
/// Returns a value indicating whether the array is symmetric.
/// </summary>
/// <param name="array">
/// The array to check for symmetry.
/// </param>
/// <returns>
/// True is array is symmetric, false if not symmetric.
/// </returns>
public static bool CheckIfSymmetric(double[,] array)
{
var rows = array.GetLength(0);
var columns = array.GetLength(1);
if (rows != columns)
{
return false;
}
for (var row = 0; row < rows; row++)
{
for (var column = 0; column < columns; column++)
{
if (column >= row)
{
continue;
}
if (!array[row, column].Equals(array[column, row]))
{
return false;
}
}
}
return true;
}
/// <summary>
/// Gets a value indicating whether this matrix is symmetric.
/// </summary>
public override sealed bool IsSymmetric
{
get
{
return true;
}
}
/// <summary>
/// Returns the transpose of this matrix. The transpose is equal and this method returns a reference to this matrix.
/// </summary>
/// <returns>
/// The transpose of this matrix.
/// </returns>
public override sealed Matrix<double> Transpose()
{
return this.Clone();
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override Matrix<double> Add(Matrix<double> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
Matrix<double> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
DoAdd(other, result);
return result;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">
/// The matrix to add to this matrix.
/// </param>
/// <param name="result">
/// The matrix to store the result of the addition.
/// </param>
/// <exception cref="ArgumentNullException">
/// If the other matrix is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// If the two matrices don't have the same dimensions.
/// </exception>
protected override void DoAdd(Matrix<double> other, Matrix<double> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric + non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoAdd(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) + symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <returns>The result of the subtraction.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override Matrix<double> Subtract(Matrix<double> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
Matrix<double> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
DoSubtract(other, result);
return result;
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">
/// The matrix to subtract to this matrix.
/// </param>
/// <param name="result">
/// The matrix to store the result of subtraction.
/// </param>
/// <exception cref="ArgumentNullException">
/// If the other matrix is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// If the two matrices don't have the same dimensions.
/// </exception>
protected override void DoSubtract(Matrix<double> other, Matrix<double> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric - non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoSubtract(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) - symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">
/// The scalar to multiply the matrix with.
/// </param>
/// <param name="result">
/// The matrix to store the result of the multiplication.
/// </param>
protected override void DoMultiply(double scalar, Matrix<double> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) * scalar);
}
}
}
}
/// <summary>
/// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to multiply with.
/// </param>
/// <param name="result">
/// The result of the multiplication.
/// </param>
protected override sealed void DoTransposeThisAndMultiply(Matrix<double> other, Matrix<double> result)
{
DoMultiply(other, result);
}
/// <summary>
/// Multiplies the transpose of this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">
/// The vector to multiply with.
/// </param>
/// <param name="result">
/// The result of the multiplication.
/// </param>
protected override sealed void DoTransposeThisAndMultiply(Vector<double> rightSide, Vector<double> result)
{
DoMultiply(rightSide, result);
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">
/// The result of the negation.
/// </param>
protected override void DoNegate(Matrix<double> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoNegate(result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column != ColumnCount; column++)
{
symmetricResult[row, column] = -At(row, column);
}
}
}
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise multiplication of this matrix and <paramref name="other"/>.</returns>
public override Matrix<double> PointwiseMultiply(Matrix<double> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other, "other");
}
Matrix<double> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
PointwiseMultiply(other, result);
return result;
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to pointwise multiply with this one.
/// </param>
/// <param name="result">
/// The matrix to store the result of the pointwise multiplication.
/// </param>
protected override void DoPointwiseMultiply(Matrix<double> other, Matrix<double> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric pointwise* non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoPointwiseMultiply(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) * symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Pointwise divide this matrix by another matrix.
/// </summary>
/// <param name="other">The matrix to pointwise subtract this one by.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise division of this matrix and <paramref name="other"/>.</returns>
public override Matrix<double> PointwiseDivide(Matrix<double> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other);
}
Matrix<double> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
PointwiseDivide(other, result);
return result;
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to pointwise divide this one by.
/// </param>
/// <param name="result">
/// The matrix to store the result of the pointwise division.
/// </param>
protected override void DoPointwiseDivide(Matrix<double> other, Matrix<double> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric pointwise/ non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoPointwiseDivide(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) / symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Computes the modulus for each element of the matrix.
/// </summary>
/// <param name="divisor">
/// The divisor to use.
/// </param>
/// <param name="result">
/// Matrix to store the results in.
/// </param>
protected override void DoModulus(double divisor, Matrix<double> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoModulus(divisor, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) % divisor);
}
}
}
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">
/// The matrix to populate.
/// </param>
/// <param name="distribution">
/// Continuous Random Distribution to generate elements from.
/// </param>
protected override void DoRandom(Matrix<double> matrix, IContinuousDistribution distribution)
{
var symmetricMatrix = matrix as SymmetricMatrix;
if (symmetricMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var row = 0; row < matrix.RowCount; row++)
{
for (var column = row; column < matrix.ColumnCount; column++)
{
symmetricMatrix.At(row, column, distribution.Sample());
}
}
}
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">
/// The matrix to populate.
/// </param>
/// <param name="distribution">
/// Continuous Random Distribution to generate elements from.
/// </param>
protected override void DoRandom(Matrix<double> matrix, IDiscreteDistribution distribution)
{
var symmetricMatrix = matrix as SymmetricMatrix;
if (symmetricMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var row = 0; row < matrix.RowCount; row++)
{
for (var column = row; column < matrix.ColumnCount; column++)
{
symmetricMatrix.At(row, column, distribution.Sample());
}
}
}
}
/// <summary>
/// Creates a new matrix and inserts the given column at the given index.
/// </summary>
/// <param name="columnIndex">The index of where to insert the column.</param>
/// <param name="column">The column to insert.</param>
/// <returns>A new matrix with the inserted column.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="column "/> is <see langword="null" />. </exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is &lt; zero or &gt; the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> != the number of rows.</exception>
public override Matrix<double> InsertColumn(int columnIndex, Vector<double> column)
{
throw new InvalidOperationException("Inserting a column is not supported on a symmetric matrix. Symmetric matrices are square");
}
/// <summary>
/// Copies the values of the given array to the specified column. The changes retain the symmetry of the matrix.
/// </summary>
/// <param name="columnIndex">The column to copy the values to.</param>
/// <param name="column">The array to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="column"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is less than zero,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
public override void SetColumn(int columnIndex, double[] column)
{
throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Copies the values of the given Vector to the specified column. The changes retain the symmetry of the matrix.
/// </summary>
/// <param name="columnIndex">The column to copy the values to.</param>
/// <param name="column">The vector to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="column"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is less than zero,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
public override void SetColumn(int columnIndex, Vector<double> column)
{
throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Creates a new matrix and inserts the given row at the given index.
/// </summary>
/// <param name="rowIndex">The index of where to insert the row.</param>
/// <param name="row">The row to insert.</param>
/// <returns>A new matrix with the inserted column.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />. </exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is &lt; zero or &gt; the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> != the number of columns.</exception>
public override Matrix<double> InsertRow(int rowIndex, Vector<double> row)
{
throw new InvalidOperationException("Inserting a row is not supported on a symmetric matrix. Symmetric matrices are square");
}
/// <summary>
/// Copies the values of the given Vector to the specified row.
/// </summary>
/// <param name="rowIndex">The row to copy the values to.</param>
/// <param name="row">The vector to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is less than zero,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> does not
/// equal the number of columns of this <strong>Matrix</strong>.</exception>
public override void SetRow(int rowIndex, Vector<double> row)
{
throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Copies the values of the given array to the specified row.
/// </summary>
/// <param name="rowIndex">The row to copy the values to.</param>
/// <param name="row">The array to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is less than zero,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> does not
/// equal the number of columns of this <strong>Matrix</strong>.</exception>
public override void SetRow(int rowIndex, double[] row)
{
throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry");
}
}
}

6
src/Numerics/LinearAlgebra/Generic/Matrix.Arithmetic.cs

@ -481,7 +481,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
throw DimensionsDontMatch<ArgumentException>(this, other);
}
var result = CreateMatrix(RowCount, other.ColumnCount);
var result = CreateMatrix(RowCount, other.ColumnCount, true);
Multiply(other, result);
return result;
}
@ -550,7 +550,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
throw DimensionsDontMatch<ArgumentException>(this, other);
}
var result = CreateMatrix(RowCount, other.RowCount);
var result = CreateMatrix(RowCount, other.RowCount, true);
TransposeAndMultiply(other, result);
return result;
}
@ -683,7 +683,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
throw DimensionsDontMatch<ArgumentException>(this, other);
}
var result = CreateMatrix(ColumnCount, other.ColumnCount);
var result = CreateMatrix(ColumnCount, other.ColumnCount, true);
TransposeThisAndMultiply(other, result);
return result;
}

61
src/Numerics/LinearAlgebra/Single/SquareMatrix.cs

@ -0,0 +1,61 @@
// <copyright file="SquareMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Single
{
using System;
using Properties;
using Storage;
/// <summary>
/// Abstract class for square matrices.
/// </summary>
[Serializable]
public abstract class SquareMatrix : Matrix
{
/// <summary>
/// Number of rows or columns.
/// </summary>
protected readonly int Order;
/// <summary>
/// Initializes a new instance of the <see cref="MathNet.Numerics.LinearAlgebra.Double.SquareMatrix"/> class.
/// </summary>
/// <exception cref="ArgumentException">
/// If the matrix is not square.
/// </exception>
protected SquareMatrix(MatrixStorage<float> storage)
: base(storage)
{
if (storage.RowCount != storage.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
Order = storage.RowCount;
}
}
}

794
src/Numerics/LinearAlgebra/Single/SymmetricDenseMatrix.cs

@ -0,0 +1,794 @@
// <copyright file="SymmetricDenseMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Single
{
using System;
using Generic;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static;
using MathNet.Numerics.Threading;
using Properties;
using Storage;
/// <summary>
/// A Symmetric Matrix class with dense storage.
/// </summary>
/// <remarks> The underlying storage is a one dimensional array in column-major order.
/// The Upper Triangle is stored(it is equal to the Lower Triangle) </remarks>
[Serializable]
public class SymmetricDenseMatrix : SymmetricMatrix
{
readonly DenseColumnMajorSymmetricMatrixStorage<float> _storage;
/// <summary>
/// Gets the matrix's data.
/// </summary>
/// <value>The matrix's data.</value>
readonly float[] _data;
internal SymmetricDenseMatrix(DenseColumnMajorSymmetricMatrixStorage<float> storage)
: base(storage)
{
_storage = storage;
_data = _storage.Data;
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class. This matrix is square with a given size.
/// </summary>
/// <param name="order">The order of the matrix.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public SymmetricDenseMatrix(int order)
: this(new DenseColumnMajorSymmetricMatrixStorage<float>(order))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class with all entries set to a particular value.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
/// <param name="value">The value which we assign to each element of the matrix.</param>
public SymmetricDenseMatrix(int order, float value)
: this(order)
{
for (var i = 0; i < _data.Length; i++)
{
_data[i] = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class from a one dimensional array. This constructor
/// will reference the one dimensional array and not copy it.
/// </summary>
/// <param name="order">The size of the square matrix.</param>
/// <param name="array">
/// The one dimensional array to create this matrix from. Column-major and row-major order is identical on a symmetric matrix: http://en.wikipedia.org/wiki/Row-major_order
/// </param>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> does not represent a packed array.
/// </exception>
public SymmetricDenseMatrix(int order, float[] array)
: this(new DenseColumnMajorSymmetricMatrixStorage<float>(order, array))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class from a 2D array. This constructor
/// will allocate a completely new memory block for storing the symmetric dense matrix.
/// </summary>
/// <param name="array">The 2D array to create this matrix from.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> is not a square array.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="array"/> is not a symmetric array.
/// </exception>
public SymmetricDenseMatrix(float[,] array)
: this(array.GetLength(0))
{
if (!CheckIfSymmetric(array))
{
throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
}
var indexer = new PackedStorageIndexerUpper(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
_data[indexer.Of(row, column)] = array[row, column];
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricDenseMatrix"/> class, copying
/// the values from the given matrix. Matrix must be Symmetric.
/// </summary>
/// <param name="matrix">The matrix to copy.</param>
/// <exception cref="ArgumentException">
/// If <paramref name="matrix"/> is not a square matrix.
/// </exception>
/// <exception cref="ArgumentException">
/// If <paramref name="matrix"/> is not a symmetric matrix.
/// </exception>
public SymmetricDenseMatrix(Matrix<float> matrix)
: this(matrix.RowCount)
{
var symmetricMatrix = matrix as SymmetricDenseMatrix;
if (!matrix.IsSymmetric)
{
throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
}
if (symmetricMatrix == null)
{
var indexer = new PackedStorageIndexerUpper(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
_data[indexer.Of(row, column)] = matrix[row, column];
}
}
}
else
{
matrix.CopyTo(this);
}
}
/// <summary>
/// Gets the matrix's data.
/// </summary>
/// <value>The matrix's data.</value>
public float[] Data
{
get { return _data; }
}
/// <summary>
/// Creates a <c>SymmetricDenseMatrix</c> for the given number of rows and columns.
/// If rows and columns are not equal, returns a <c>DenseMatrix</c> instead.
/// </summary>
/// <param name="numberOfRows">
/// The number of rows.
/// </param>
/// <param name="numberOfColumns">
/// The number of columns.
/// </param>
/// <param name="fullyMutable">True if all fields must be mutable (e.g. not a diagonal matrix).</param>
/// <returns>
/// A <c>DenseMatrix</c> or <c>SymmetricDenseMatrix</c> with the given dimensions.
/// </returns>
/// /// <exception cref="ArgumentException">
/// If <paramref name="numberOfRows"/> is not equal to <paramref name="numberOfColumns"/>.
/// Symmetric arrays are always square
/// </exception>
public override Matrix<float> CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false)
{
if (numberOfRows != numberOfColumns || fullyMutable)
{
return new DenseMatrix(numberOfRows, numberOfColumns);
}
return new SymmetricDenseMatrix(numberOfRows);
}
/// <summary>
/// Creates a <see cref="Vector{T}"/> with a the given dimension.
/// </summary>
/// <param name="size">The size of the vector.</param>
/// <param name="fullyMutable">True if all fields must be mutable.</param>
/// <returns>
/// A <see cref="Vector{T}"/> with the given dimension.
/// </returns>
public override Vector<float> CreateVector(int size, bool fullyMutable = false)
{
return new DenseVector(size);
}
#region Static constructors for special matrices.
/// <summary>
/// Initializes a square <see cref="SymmetricDenseMatrix"/> with all zero's except for ones on the diagonal.
/// </summary>
/// <param name="order">the size of the square matrix.</param>
/// <returns>A symmetric dense identity matrix.</returns>
/// <exception cref="ArgumentException">
/// If <paramref name="order"/> is less than one.
/// </exception>
public static SymmetricDenseMatrix Identity(int order)
{
var m = new SymmetricDenseMatrix(order);
for (var i = 0; i < order; i++)
{
m.At(i, i, 1.0f);
}
return m;
}
#endregion
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of add</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
protected override void DoAdd(Matrix<float> other, Matrix<float> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoAdd(other, result);
}
else
{
Control.LinearAlgebraProvider.AddArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
protected override void DoSubtract(Matrix<float> other, Matrix<float> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoSubtract(other, result);
}
else
{
Control.LinearAlgebraProvider.SubtractArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
protected override void DoMultiply(float scalar, Matrix<float> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data);
}
}
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Vector<float> rightSide, Vector<float> result)
{
var denseRight = rightSide as DenseVector;
var denseResult = result as DenseVector;
if (denseRight == null || denseResult == null)
{
base.DoMultiply(rightSide, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoMultiply(rightSide, result);
}
}
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoMultiply(Matrix<float> other, Matrix<float> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoMultiply(other, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoMultiply(other, result);
}
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected override void DoTransposeAndMultiply(Matrix<float> other, Matrix<float> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoTransposeAndMultiply(other, result);
}
else
{
// TODO: Change this when symmetric methods are implemented in the Linear Algebra Providers.
base.DoTransposeAndMultiply(other, result);
}
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
protected override void DoNegate(Matrix<float> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoNegate(result);
}
else
{
Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data);
}
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
protected override void DoPointwiseMultiply(Matrix<float> other, Matrix<float> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoPointwiseMultiply(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise divide this one by.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
protected override void DoPointwiseDivide(Matrix<float> other, Matrix<float> result)
{
var denseOther = other as SymmetricDenseMatrix;
var denseResult = result as SymmetricDenseMatrix;
if (denseOther == null || denseResult == null)
{
base.DoPointwiseDivide(other, result);
}
else
{
Control.LinearAlgebraProvider.PointWiseDivideArrays(_data, denseOther._data, denseResult._data);
}
}
/// <summary>
/// Returns a new matrix containing the lower triangle of this matrix.
/// </summary>
/// <returns>The lower triangle of this matrix.</returns>
public override Matrix<float> LowerTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = 0; column <= row; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the lower triangle of this matrix. The new matrix
/// does not contain the diagonal elements of this matrix.
/// </summary>
/// <returns>The lower triangle of this matrix.</returns>
public override Matrix<float> StrictlyLowerTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = 0; column < row; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the upper triangle of this matrix.
/// </summary>
/// <returns>The upper triangle of this matrix.</returns>
public override Matrix<float> UpperTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row; column < Order; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Returns a new matrix containing the upper triangle of this matrix. The new matrix
/// does not contain the diagonal elements of this matrix.
/// </summary>
/// <returns>The upper triangle of this matrix.</returns>
public override Matrix<float> StrictlyUpperTriangle()
{
var ret = new DenseMatrix(Order);
for (var row = 0; row < Order; row++)
{
for (var column = row + 1; column < Order; column++)
{
ret[row, column] = At(row, column);
}
}
return ret;
}
/// <summary>
/// Computes the modulus for each element of the matrix.
/// </summary>
/// <param name="divisor">The divisor to use.</param>
/// <param name="result">Matrix to store the results in.</param>
protected override void DoModulus(float divisor, Matrix<float> result)
{
var denseResult = result as SymmetricDenseMatrix;
if (denseResult == null)
{
base.DoModulus(divisor, result);
}
else
{
if (!ReferenceEquals(this, result))
{
CopyTo(result);
}
CommonParallel.For(
0,
_data.Length,
index => denseResult._data[index] %= divisor);
}
}
/// <summary>
/// Computes the trace of this matrix.
/// </summary>
/// <returns>The trace of this matrix</returns>
public override float Trace()
{
// Matrix is always square.
var sum = 0.0f;
for (var i = 0; i < RowCount; i++)
{
sum += At(i, i);
}
return sum;
}
/// <summary>
/// Populates a symmetric matrix with random elements.
/// </summary>
/// <param name="matrix">The symmetric matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<float> matrix, IContinuousDistribution distribution)
{
var denseMatrix = matrix as SymmetricDenseMatrix;
if (denseMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var i = 0; i < denseMatrix._data.Length; i++)
{
denseMatrix._data[i] = Convert.ToSingle(distribution.Sample());
}
}
}
/// <summary>
/// Populates a symmetric matrix with random elements.
/// </summary>
/// <param name="matrix">The symmetric matrix to populate.</param>
/// <param name="distribution">Continuous Random Distribution to generate elements from.</param>
protected override void DoRandom(Matrix<float> matrix, IDiscreteDistribution distribution)
{
var denseMatrix = matrix as SymmetricDenseMatrix;
if (denseMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var i = 0; i < denseMatrix._data.Length; i++)
{
denseMatrix._data[i] = distribution.Sample();
}
}
}
/// <summary>
/// Adds two matrices together and returns the results.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to add.</param>
/// <param name="rightSide">The right matrix to add.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (leftSide.RowCount != rightSide.RowCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Add(rightSide);
}
/// <summary>
/// Returns a <strong>Matrix</strong> containing the same values of <paramref name="rightSide"/>.
/// </summary>
/// <param name="rightSide">The matrix to get the values from.</param>
/// <returns>A matrix containing a the same values as <paramref name="rightSide"/>.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Clone();
}
/// <summary>
/// Subtracts two matrices together and returns the results.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to subtract.</param>
/// <param name="rightSide">The right matrix to subtract.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (leftSide.RowCount != rightSide.RowCount)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Subtract(rightSide);
}
/// <summary>
/// Negates each element of the matrix.
/// </summary>
/// <param name="rightSide">The matrix to negate.</param>
/// <returns>A matrix containing the negated values.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Negate();
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, float rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (SymmetricDenseMatrix)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator *(float leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (SymmetricDenseMatrix)rightSide.Multiply(leftSide);
}
/// <summary>
/// Multiplies two matrices.
/// </summary>
/// <remarks>This operator will allocate new memory for the result. It will
/// choose the representation of either <paramref name="leftSide"/> or <paramref name="rightSide"/> depending on which
/// is denser.</remarks>
/// <param name="leftSide">The left matrix to multiply.</param>
/// <param name="rightSide">The right matrix to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If the dimensions of <paramref name="leftSide"/> or <paramref name="rightSide"/> don't conform.</exception>
public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, SymmetricDenseMatrix rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
if (leftSide.ColumnCount != rightSide.RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixDimensions);
}
return (SymmetricDenseMatrix)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> and a Vector.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The vector to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static DenseVector operator *(SymmetricDenseMatrix leftSide, DenseVector rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (DenseVector)leftSide.Multiply(rightSide);
}
/// <summary>
/// Multiplies a Vector and a <strong>Matrix</strong>.
/// </summary>
/// <param name="leftSide">The vector to multiply.</param>
/// <param name="rightSide">The matrix to multiply.</param>
/// <returns>The result of multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
public static DenseVector operator *(DenseVector leftSide, SymmetricDenseMatrix rightSide)
{
if (rightSide == null)
{
throw new ArgumentNullException("rightSide");
}
return (DenseVector)rightSide.LeftMultiply(leftSide);
}
/// <summary>
/// Multiplies a <strong>Matrix</strong> by a constant and returns the result.
/// </summary>
/// <param name="leftSide">The matrix to multiply.</param>
/// <param name="rightSide">The constant to multiply the matrix by.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
public static SymmetricDenseMatrix operator %(SymmetricDenseMatrix leftSide, float rightSide)
{
if (leftSide == null)
{
throw new ArgumentNullException("leftSide");
}
return (SymmetricDenseMatrix)leftSide.Modulus(rightSide);
}
}
}

653
src/Numerics/LinearAlgebra/Single/SymmetricMatrix.cs

@ -0,0 +1,653 @@
// <copyright file="SymmetricMatrix.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Single
{
using System;
using Generic;
using Distributions;
using Properties;
using Storage;
/// <summary>
/// Abstract class for symmetric matrices.
/// </summary>
[Serializable]
public abstract class SymmetricMatrix : SquareMatrix
{
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricMatrix"/> class.
/// </summary>
protected SymmetricMatrix(MatrixStorage<float> storage)
: base(storage)
{
}
/// <summary>
/// Returns a value indicating whether the array is symmetric.
/// </summary>
/// <param name="array">
/// The array to check for symmetry.
/// </param>
/// <returns>
/// True is array is symmetric, false if not symmetric.
/// </returns>
public static bool CheckIfSymmetric(float[,] array)
{
var rows = array.GetLength(0);
var columns = array.GetLength(1);
if (rows != columns)
{
return false;
}
for (var row = 0; row < rows; row++)
{
for (var column = 0; column < columns; column++)
{
if (column >= row)
{
continue;
}
if (!array[row, column].Equals(array[column, row]))
{
return false;
}
}
}
return true;
}
/// <summary>
/// Gets a value indicating whether this matrix is symmetric.
/// </summary>
public override sealed bool IsSymmetric
{
get
{
return true;
}
}
/// <summary>
/// Returns the transpose of this matrix. The transpose is equal and this method returns a reference to this matrix.
/// </summary>
/// <returns>
/// The transpose of this matrix.
/// </returns>
public override sealed Matrix<float> Transpose()
{
return this.Clone();
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override Matrix<float> Add(Matrix<float> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
Matrix<float> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
DoAdd(other, result);
return result;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">
/// The matrix to add to this matrix.
/// </param>
/// <param name="result">
/// The matrix to store the result of the addition.
/// </param>
/// <exception cref="ArgumentNullException">
/// If the other matrix is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// If the two matrices don't have the same dimensions.
/// </exception>
protected override void DoAdd(Matrix<float> other, Matrix<float> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric + non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoAdd(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) + symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <returns>The result of the subtraction.</returns>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public override Matrix<float> Subtract(Matrix<float> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
Matrix<float> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
DoSubtract(other, result);
return result;
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">
/// The matrix to subtract to this matrix.
/// </param>
/// <param name="result">
/// The matrix to store the result of subtraction.
/// </param>
/// <exception cref="ArgumentNullException">
/// If the other matrix is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// If the two matrices don't have the same dimensions.
/// </exception>
protected override void DoSubtract(Matrix<float> other, Matrix<float> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric - non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoSubtract(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) - symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">
/// The scalar to multiply the matrix with.
/// </param>
/// <param name="result">
/// The matrix to store the result of the multiplication.
/// </param>
protected override void DoMultiply(float scalar, Matrix<float> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoMultiply(scalar, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) * scalar);
}
}
}
}
/// <summary>
/// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to multiply with.
/// </param>
/// <param name="result">
/// The result of the multiplication.
/// </param>
protected override sealed void DoTransposeThisAndMultiply(Matrix<float> other, Matrix<float> result)
{
DoMultiply(other, result);
}
/// <summary>
/// Multiplies the transpose of this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">
/// The vector to multiply with.
/// </param>
/// <param name="result">
/// The result of the multiplication.
/// </param>
protected override sealed void DoTransposeThisAndMultiply(Vector<float> rightSide, Vector<float> result)
{
DoMultiply(rightSide, result);
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">
/// The result of the negation.
/// </param>
protected override void DoNegate(Matrix<float> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoNegate(result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column != ColumnCount; column++)
{
symmetricResult[row, column] = -At(row, column);
}
}
}
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise multiplication of this matrix and <paramref name="other"/>.</returns>
public override Matrix<float> PointwiseMultiply(Matrix<float> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other, "other");
}
Matrix<float> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
PointwiseMultiply(other, result);
return result;
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to pointwise multiply with this one.
/// </param>
/// <param name="result">
/// The matrix to store the result of the pointwise multiplication.
/// </param>
protected override void DoPointwiseMultiply(Matrix<float> other, Matrix<float> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric pointwise* non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoPointwiseMultiply(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) * symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Pointwise divide this matrix by another matrix.
/// </summary>
/// <param name="other">The matrix to pointwise subtract this one by.</param>
/// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise division of this matrix and <paramref name="other"/>.</returns>
public override Matrix<float> PointwiseDivide(Matrix<float> other)
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other);
}
Matrix<float> result;
if (other is SymmetricMatrix)
{
result = CreateMatrix(RowCount, ColumnCount);
}
else
{
result = CreateMatrix(RowCount, ColumnCount, true);
}
PointwiseDivide(other, result);
return result;
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">
/// The matrix to pointwise divide this one by.
/// </param>
/// <param name="result">
/// The matrix to store the result of the pointwise division.
/// </param>
protected override void DoPointwiseDivide(Matrix<float> other, Matrix<float> result)
{
var symmetricOther = other as SymmetricMatrix;
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult != null && !other.IsSymmetric)
{
throw new InvalidOperationException("Symmetric pointwise/ non-symmetric matrix cannot be a symmetric matrix");
}
if (symmetricOther == null || symmetricResult == null)
{
base.DoPointwiseDivide(other, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) / symmetricOther.At(row, column));
}
}
}
}
/// <summary>
/// Computes the modulus for each element of the matrix.
/// </summary>
/// <param name="divisor">
/// The divisor to use.
/// </param>
/// <param name="result">
/// Matrix to store the results in.
/// </param>
protected override void DoModulus(float divisor, Matrix<float> result)
{
var symmetricResult = result as SymmetricMatrix;
if (symmetricResult == null)
{
base.DoModulus(divisor, result);
}
else
{
for (var row = 0; row < RowCount; row++)
{
for (var column = row; column < ColumnCount; column++)
{
symmetricResult.At(row, column, At(row, column) % divisor);
}
}
}
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">
/// The matrix to populate.
/// </param>
/// <param name="distribution">
/// Continuous Random Distribution to generate elements from.
/// </param>
protected override void DoRandom(Matrix<float> matrix, IContinuousDistribution distribution)
{
var symmetricMatrix = matrix as SymmetricMatrix;
if (symmetricMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var row = 0; row < matrix.RowCount; row++)
{
for (var column = row; column < matrix.ColumnCount; column++)
{
symmetricMatrix.At(row, column, Convert.ToSingle(distribution.Sample()));
}
}
}
}
/// <summary>
/// Populates a matrix with random elements.
/// </summary>
/// <param name="matrix">
/// The matrix to populate.
/// </param>
/// <param name="distribution">
/// Continuous Random Distribution to generate elements from.
/// </param>
protected override void DoRandom(Matrix<float> matrix, IDiscreteDistribution distribution)
{
var symmetricMatrix = matrix as SymmetricMatrix;
if (symmetricMatrix == null)
{
base.DoRandom(matrix, distribution);
}
else
{
for (var row = 0; row < matrix.RowCount; row++)
{
for (var column = row; column < matrix.ColumnCount; column++)
{
symmetricMatrix.At(row, column, distribution.Sample());
}
}
}
}
/// <summary>
/// Creates a new matrix and inserts the given column at the given index.
/// </summary>
/// <param name="columnIndex">The index of where to insert the column.</param>
/// <param name="column">The column to insert.</param>
/// <returns>A new matrix with the inserted column.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="column "/> is <see langword="null" />. </exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is &lt; zero or &gt; the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> != the number of rows.</exception>
public override Matrix<float> InsertColumn(int columnIndex, Vector<float> column)
{
throw new InvalidOperationException("Inserting a column is not supported on a symmetric matrix. Symmetric matrices are square");
}
/// <summary>
/// Copies the values of the given array to the specified column. The changes retain the symmetry of the matrix.
/// </summary>
/// <param name="columnIndex">The column to copy the values to.</param>
/// <param name="column">The array to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="column"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is less than zero,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
public override void SetColumn(int columnIndex, float[] column)
{
throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Copies the values of the given Vector to the specified column. The changes retain the symmetry of the matrix.
/// </summary>
/// <param name="columnIndex">The column to copy the values to.</param>
/// <param name="column">The vector to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="column"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="columnIndex"/> is less than zero,
/// or greater than or equal to the number of columns.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="column"/> does not
/// equal the number of rows of this <strong>Matrix</strong>.</exception>
public override void SetColumn(int columnIndex, Vector<float> column)
{
throw new InvalidOperationException("Setting a column is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Creates a new matrix and inserts the given row at the given index.
/// </summary>
/// <param name="rowIndex">The index of where to insert the row.</param>
/// <param name="row">The row to insert.</param>
/// <returns>A new matrix with the inserted column.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />. </exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is &lt; zero or &gt; the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> != the number of columns.</exception>
public override Matrix<float> InsertRow(int rowIndex, Vector<float> row)
{
throw new InvalidOperationException("Inserting a row is not supported on a symmetric matrix. Symmetric matrices are square");
}
/// <summary>
/// Copies the values of the given Vector to the specified row.
/// </summary>
/// <param name="rowIndex">The row to copy the values to.</param>
/// <param name="row">The vector to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is less than zero,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> does not
/// equal the number of columns of this <strong>Matrix</strong>.</exception>
public override void SetRow(int rowIndex, Vector<float> row)
{
throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry");
}
/// <summary>
/// Copies the values of the given array to the specified row.
/// </summary>
/// <param name="rowIndex">The row to copy the values to.</param>
/// <param name="row">The array to copy the values from.</param>
/// <exception cref="ArgumentNullException">If <paramref name="row"/> is <see langword="null" />.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="rowIndex"/> is less than zero,
/// or greater than or equal to the number of rows.</exception>
/// <exception cref="ArgumentException">If the size of <paramref name="row"/> does not
/// equal the number of columns of this <strong>Matrix</strong>.</exception>
public override void SetRow(int rowIndex, float[] row)
{
throw new InvalidOperationException("Setting a row is not supported on a symmetric matrix. It will violate symmetry");
}
}
}

84
src/Numerics/LinearAlgebra/Storage/DenseColumnMajorSymmetricMatrixStorage.cs

@ -0,0 +1,84 @@
using System;
namespace MathNet.Numerics.LinearAlgebra.Storage
{
using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static;
using MathNet.Numerics.Properties;
public class DenseColumnMajorSymmetricMatrixStorage<T> : SymmetricMatrixStorage<T>
where T : struct, IEquatable<T>, IFormattable
{
// [ruegg] public fields are OK here
public readonly T[] Data;
public readonly PackedStorageIndexerUpper Indexer;
internal DenseColumnMajorSymmetricMatrixStorage(int order)
: base(order)
{
Indexer = new PackedStorageIndexerUpper(order);
Data = new T[Indexer.DataLength];
}
internal DenseColumnMajorSymmetricMatrixStorage(int order, T[] data)
: base(order)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
Indexer = new PackedStorageIndexerUpper(order);
if (data.Length != Indexer.DataLength)
{
throw new ArgumentOutOfRangeException("data", string.Format(Resources.ArgumentArrayWrongLength, Indexer.DataLength));
}
Data = data;
}
/// <summary>
/// Retrieves the requested element without range checking.
/// </summary>
/// <param name="row">
/// The row of the element.
/// </param>
/// <param name="column">
/// The column of the element.
/// </param>
/// <returns>
/// The requested element.
/// </returns>
/// <remarks>Not range-checked.</remarks>
public override T At(int row, int column)
{
var r = Math.Min(row, column);
var c = Math.Max(row, column);
return Data[Indexer.Of(r, c)];
}
/// <summary>
/// Sets the element without range checking.
/// </summary>
/// <param name="row"> The row of the element. </param>
/// <param name="column"> The column of the element. </param>
/// <param name="value"> The value to set the element to. </param>
/// <remarks>WARNING: This method is not thread safe. Use "lock" with it and be sure to avoid deadlocks.</remarks>
public override void At(int row, int column, T value)
{
if (row > column)
{
throw new IndexOutOfRangeException("Setting an element in the strictly lower triangle of a symmetric matrix is disabled to avoid errors");
}
Data[Indexer.Of(row, column)] = value;
}
public override void Clear()
{
Array.Clear(Data, 0, Data.Length);
}
}
}

28
src/Numerics/LinearAlgebra/Storage/Indexers/IStorageIndexer.cs

@ -0,0 +1,28 @@
namespace MathNet.Numerics.LinearAlgebra.Storage.Indexers
{
/// <summary>
/// Abstract class that defines common features for all storage schemes.
/// </summary>
public interface IStorageIndexer
{
/// <summary>
/// Retrieves the index of the requested element without parameter checking.
/// </summary><param name="row">
/// The row of the element.
/// </param><param name="column">
/// The column of the element.
/// </param><returns>
/// The requested index.
/// </returns>
int Of(int row, int column);
/// <summary>
/// Retrieves the index of the requested diagonal element without parameter checking.
/// </summary><param name="row">
/// The row=column of the diagonal element.
/// </param><returns>
/// The requested index.
/// </returns>
int OfDiagonal(int row);
}
}

50
src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexer.cs

@ -0,0 +1,50 @@
namespace MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static
{
using System;
using Properties;
/// <summary>
/// A class for managing indexing when using Packed Storage, which is a column-major packing scheme for dense Symmetric, Hermitian or Triangular square matrices.
/// </summary>
public abstract class PackedStorageIndexer : StaticStorageIndexer
{
/// <summary>
/// Number of rows or columns.
/// </summary>
protected readonly int Order;
/// <summary>
/// Length of the stored data.
/// </summary>
private readonly int _dataLength;
/// <summary>
/// Initializes a new instance of the <see cref="PackedStorageIndexer"/> class.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
/// <exception cref="ArgumentOutOfRangeException"><c></c> is out of range.</exception>
protected PackedStorageIndexer(int order)
{
if (order <= 0)
{
throw new ArgumentOutOfRangeException(Resources.MatrixRowsOrColumnsMustBePositive);
}
Order = order;
_dataLength = order * (order + 1) / 2;
}
/// <summary>
/// Gets the length of the stored data.
/// </summary>
public override int DataLength
{
get
{
return _dataLength;
}
}
}
}

88
src/Numerics/LinearAlgebra/Storage/Indexers/Static/PackedStorageIndexerUpper.cs

@ -0,0 +1,88 @@
namespace MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static
{
using System;
/// <summary>
/// A class for managing indexes when using Packed Storage, which is a column-major packing scheme for Symmetric, Hermitian or Triangular square matrices.
/// This variation provides indexes for storing the upper triangle of a matrix (row less than or equal to column).
/// </summary>
public class PackedStorageIndexerUpper : PackedStorageIndexer
{
/// <summary>
/// Initializes a new instance of the <see cref="PackedStorageIndexerUpper"/> class.
/// </summary>
/// <param name="order">
/// The order of the matrix.
/// </param>
internal PackedStorageIndexerUpper(int order)
: base(order)
{
}
/// <summary>
/// Gets the index of the given element.
/// </summary>
/// <param name = "row">
/// The row of the element.
/// </param>
/// <param name = "column">
/// The column of the element.
/// </param>
/// <remarks>
/// This method is parameter checked. <see cref = "Of" /> and <see cref = "OfDiagonal" /> to get values without parameter checking.
/// </remarks>
public override int this[int row, int column]
{
get
{
if (row < 0 || row >= Order)
{
throw new ArgumentOutOfRangeException("row");
}
if (column < 0 || column >= Order)
{
throw new ArgumentOutOfRangeException("column");
}
if (row > column)
{
throw new ArgumentException("Row must be less than or equal to column");
}
return this.Of(row, column);
}
}
/// <summary>
/// Retrieves the index of the requested element without parameter checking. Row must be less than or equal to column.
/// </summary>
/// <param name="row">
/// The row of the element.
/// </param>
/// <param name="column">
/// The column of the element.
/// </param>
/// <returns>
/// The requested index.
/// </returns>
public override int Of(int row, int column)
{
return row + ((column * (column + 1)) / 2);
}
/// <summary>
/// Retrieves the index of the requested diagonal element without parameter checking.
/// </summary>
/// <param name="row">
/// The row=column of the diagonal element.
/// </param>
/// <returns>
/// The requested index.
/// </returns>
public override int OfDiagonal(int row)
{
return (row * (row + 3)) / 2;
}
}
}

56
src/Numerics/LinearAlgebra/Storage/Indexers/Static/StaticStorageIndexer.cs

@ -0,0 +1,56 @@
namespace MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static
{
/// <summary>
/// Classes that contain indexing information of a static storage scheme.
/// </summary>
/// <remarks>
/// A static storage scheme is always the same and only depends on the size of the matrix.
/// </remarks>
public abstract class StaticStorageIndexer : IStorageIndexer
{
/// <summary>
/// Gets the index of the given element.
/// </summary>
/// <param name = "row">
/// The row of the element.
/// </param>
/// <param name = "column">
/// The column of the element.
/// </param>
/// <remarks>
/// This method is parameter checked. <see cref = "IStorageIndexer.Of" /> and <see cref = "IStorageIndexer.OfDiagonal" /> to get values without parameter checking.
/// </remarks>
public abstract int this[int row, int column]
{
get;
}
/// <summary>
/// Gets the length of the stored data.
/// </summary>
public abstract int DataLength
{
get;
}
/// <summary>
/// Retrieves the index of the requested element without parameter checking.
/// </summary><param name="row">
/// The row of the element.
/// </param><param name="column">
/// The column of the element.
/// </param><returns>
/// The requested index.
/// </returns>
public abstract int Of(int row, int column);
/// <summary>
/// Retrieves the index of the requested diagonal element without parameter checking.
/// </summary><param name="row">
/// The row=column of the diagonal element.
/// </param><returns>
/// The requested index.
/// </returns>
public abstract int OfDiagonal(int row);
}
}

64
src/Numerics/LinearAlgebra/Storage/SymmetricMatrixStorage.cs

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MathNet.Numerics.LinearAlgebra.Storage
{
using MathNet.Numerics.Properties;
public abstract class SymmetricMatrixStorage<T> : MatrixStorage<T>
where T : struct, IEquatable<T>, IFormattable
{
// [ruegg] public fields are OK here
protected SymmetricMatrixStorage(int order)
: base(order, order)
{
}
public override bool IsFullyMutable
{
get { return false; }
}
public override bool IsMutable(int row, int column)
{
return row <= column;
}
public override void Clear()
{
for (var i = 0; i < RowCount; i++)
{
for (var j = i; j < ColumnCount; j++)
{
At(i, j, default(T));
}
}
}
public override void Clear(int rowIndex, int rowCount, int columnIndex, int columnCount)
{
for (var i = rowIndex; i < rowIndex + rowCount; i++)
{
for (var j = Math.Max(columnIndex, i); j < columnIndex + columnCount; j++)
{
At(i, j, default(T));
}
}
}
/// <remarks>Parameters assumed to be validated already.</remarks>
public override void CopyTo(MatrixStorage<T> target, bool skipClearing = false)
{
for (int j = 0; j < ColumnCount; j++)
{
for (int i = 0; i <= j; i++)
{
target.At(i, j, At(i, j));
}
}
}
}
}

19
src/Numerics/Numerics.csproj

@ -125,7 +125,24 @@
<Compile Include="Distributions\Multivariate\MatrixNormal.cs" />
<Compile Include="Distributions\Multivariate\Wishart.cs" />
<Compile Include="LinearAlgebra\Storage\SparseVectorStorage.cs" />
<Compile Include="LinearAlgebra\Complex32\SquareMatrix.cs" />
<Compile Include="LinearAlgebra\Complex32\SymmetricDenseMatrix.cs" />
<Compile Include="LinearAlgebra\Complex32\SymmetricMatrix.cs" />
<Compile Include="LinearAlgebra\Complex\SquareMatrix.cs" />
<Compile Include="LinearAlgebra\Complex\SymmetricDenseMatrix.cs" />
<Compile Include="LinearAlgebra\Complex\SymmetricMatrix.cs" />
<Compile Include="LinearAlgebra\Double\SquareMatrix.cs" />
<Compile Include="LinearAlgebra\Double\SymmetricDenseMatrix.cs" />
<Compile Include="LinearAlgebra\Double\SymmetricMatrix.cs" />
<Compile Include="LinearAlgebra\Single\SquareMatrix.cs" />
<Compile Include="LinearAlgebra\Single\SymmetricDenseMatrix.cs" />
<Compile Include="LinearAlgebra\Single\SymmetricMatrix.cs" />
<Compile Include="LinearAlgebra\Storage\DenseColumnMajorSymmetricMatrixStorage.cs" />
<Compile Include="LinearAlgebra\Storage\DenseVectorStorage.cs" />
<Compile Include="LinearAlgebra\Storage\Indexers\IStorageIndexer.cs" />
<Compile Include="LinearAlgebra\Storage\Indexers\Static\PackedStorageIndexer.cs" />
<Compile Include="LinearAlgebra\Storage\Indexers\Static\PackedStorageIndexerUpper.cs" />
<Compile Include="LinearAlgebra\Storage\Indexers\Static\StaticStorageIndexer.cs" />
<Compile Include="LinearAlgebra\Storage\MatrixStorage.Validation.cs" />
<Compile Include="LinearAlgebra\Complex32\ExtensionMethods.cs" />
<Compile Include="LinearAlgebra\Complex32\Factorization\Cholesky.cs" />
@ -339,6 +356,7 @@
<Compile Include="LinearAlgebra\Storage\MatrixStorage.cs" />
<Compile Include="LinearAlgebra\Storage\SparseCompressedRowMatrixStorage.cs" />
<Compile Include="LinearAlgebra\Storage\DiagonalMatrixStorage.cs" />
<Compile Include="LinearAlgebra\Storage\SymmetricMatrixStorage.cs" />
<Compile Include="LinearAlgebra\Storage\VectorStorage.cs" />
<Compile Include="LinearAlgebra\Storage\VectorStorage.Validation.cs" />
<Compile Include="Permutation.cs" />
@ -465,6 +483,7 @@
<ItemGroup>
<None Include="MathNet.Numerics.snk" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>

217
src/UnitTests/LinearAlgebraTests/Complex/SymmetricDenseMatrixTests.cs

@ -0,0 +1,217 @@
// <copyright file="SymmetricDenseMatrixTests.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
{
using System;
using System.Collections.Generic;
using System.Numerics;
using MathNet.Numerics.LinearAlgebra.Complex;
using NUnit.Framework;
/// <summary>
/// Symmetric Dense matrix tests.
/// </summary>
public class SymmetricDenseMatrixTests : SymmetricMatrixTests
{
/// <summary>
/// Creates a matrix for the given number of rows and columns.
/// </summary>
/// <param name="rows">
/// The number of rows.
/// </param>
/// <param name="columns">
/// The number of columns.
/// </param>
/// <returns>
/// A matrix with the given dimensions.
/// </returns>
protected override Matrix CreateMatrix(int rows, int columns)
{
return new DenseMatrix(rows, columns);
}
/// <summary>
/// Creates a matrix from a 2D array.
/// </summary>
/// <param name="data">
/// The 2D array to create this matrix from.
/// </param>
/// <returns>
/// A matrix with the given values.
/// </returns>
protected override Matrix CreateMatrix(Complex[,] data)
{
if (SymmetricMatrix.CheckIfSymmetric(data))
{
return new SymmetricDenseMatrix(data);
}
return new DenseMatrix(data);
}
/// <summary>
/// Creates a vector of the given size.
/// </summary>
/// <param name="size">
/// The size of the vector to create.
/// </param>
/// <returns>
/// The new vector.
/// </returns>
protected override Vector CreateVector(int size)
{
return new DenseVector(size);
}
/// <summary>
/// Creates a vector from an array.
/// </summary>
/// <param name="data">
/// The array to create this vector from.
/// </param>
/// <returns>
/// The new vector.
/// </returns>
protected override Vector CreateVector(Complex[] data)
{
return new DenseVector(data);
}
/// <summary>
/// Can create a matrix form array.
/// </summary>
[Test]
public void CanCreateMatrixFrom1DArray()
{
var testData = new Dictionary<string, Matrix>
{
{ "Singular3x3", new SymmetricDenseMatrix(3, new[] { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(0.0, 1), new Complex(3.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }) },
{ "Square3x3", new SymmetricDenseMatrix(3, new[] { new Complex(-1.1, 1), new Complex(2.0, 1), new Complex(1.1, 1), new Complex(3.0, 1), new Complex(0.0, 1), new Complex(6.6, 1) }) },
{ "Square4x4", new SymmetricDenseMatrix(4, new[] { new Complex(1.1, 1), new Complex(2.0, 1), new Complex(5.0, 1), new Complex(-3.0, 1), new Complex(-6.0, 1), new Complex(8.0, 1), new Complex(4.4, 1), new Complex(7.0, 1), new Complex(9.0, 1), new Complex(10.0, 1) }) },
{ "Singular4x4", new SymmetricDenseMatrix(4, new[] { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(5.0, 1), new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1), new Complex(4.0, 1), new Complex(7.0, 1), new Complex(0.0, 1), new Complex(10.0, 1) }) },
{ "Symmetric3x3", new SymmetricDenseMatrix(3, new[] { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(2.0, 1), new Complex(3.0, 1), new Complex(0.0, 1), new Complex(3.0, 1) }) },
{ "IndexTester4x4", new SymmetricDenseMatrix(4, new [] { new Complex(0, 1), new Complex(1, 1), new Complex(2, 1), new Complex(3, 1), new Complex(4, 1), new Complex(5, 1), new Complex(6, 1), new Complex(7, 1), new Complex(8, 1), new Complex(9, 1) }) }
};
foreach (var name in testData.Keys)
{
Assert.AreEqual(TestMatrices[name], testData[name]);
}
}
/// <summary>
/// Matrix from array is a reference.
/// </summary>
[Test]
public void MatrixFrom1DArrayIsReference()
{
var data = new Complex[] { new Complex(1, 1), new Complex(1, 1), new Complex(1, 1), new Complex(1, 1), new Complex(1, 1), new Complex(1, 1) };
var matrix = new SymmetricDenseMatrix(3, data);
matrix[0, 0] = new Complex(10.0, 2);
Assert.AreEqual(new Complex(10.0, 2), data[0]);
}
/// <summary>
/// Can create a matrix form array.
/// </summary>
[Test]
public void CanCreateMatrixFrom2DArray()
{
var testData = new Dictionary<string, Matrix>
{
{ "Singular3x3", new SymmetricDenseMatrix(new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) } }) },
{ "Square3x3", new SymmetricDenseMatrix(new[,] { { new Complex(-1.1, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(1.1, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(6.6, 1) } }) },
{ "Square4x4", new SymmetricDenseMatrix(new[,] { { new Complex(1.1, 1), new Complex(2.0, 1), new Complex(-3.0, 1), new Complex(4.4, 1) }, { new Complex(2.0, 1), new Complex(5.0, 1), new Complex(-6.0, 1), new Complex(7.0, 1) }, { new Complex(-3.0, 1), new Complex(-6.0, 1), new Complex(8.0, 1), new Complex(9.0, 1) }, { new Complex(4.4, 1), new Complex(7.0, 1), new Complex(9.0, 1), new Complex(10.0, 1) } }) },
{ "Singular4x4", new SymmetricDenseMatrix(new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(0.0, 1), new Complex(4.0, 1) }, { new Complex(2.0, 1), new Complex(5.0, 1), new Complex(0.0, 1), new Complex(7.0, 1) }, { new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }, { new Complex(4.0, 1), new Complex(7.0, 1), new Complex(0.0, 1), new Complex(10.0, 1) } }) },
{ "Symmetric3x3", new SymmetricDenseMatrix(new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(2.0, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(3.0, 1) } }) },
{ "IndexTester4x4", new SymmetricDenseMatrix(new [,] { { new Complex(0, 1), new Complex(1, 1), new Complex(3, 1), new Complex(6, 1) }, { new Complex(1, 1), new Complex(2, 1), new Complex(4, 1), new Complex(7, 1) }, { new Complex(3, 1), new Complex(4, 1), new Complex(5, 1), new Complex(8, 1) }, { new Complex(6, 1), new Complex(7, 1), new Complex(8, 1), new Complex(9, 1) } }) }
};
foreach (var name in testData.Keys)
{
Assert.AreEqual(TestMatrices[name], testData[name]);
}
}
/// <summary>
/// Matrix from two-dimensional array is a copy.
/// </summary>
[Test]
public void MatrixFrom2DArrayIsCopy()
{
var matrix = new DenseMatrix(TestData2D["Singular3x3"]);
matrix[0, 0] = new Complex(10.0, 2);
Assert.AreEqual(new Complex(1.0, 1), TestData2D["Singular3x3"][0, 0]);
}
/// <summary>
/// Can create a matrix with uniform values.
/// </summary>
[Test]
public void CanCreateMatrixWithUniformValues()
{
var matrix = new SymmetricDenseMatrix(10, new Complex(10.0, 2));
var value = new Complex(10.0, 2);
for (var i = 0; i < matrix.RowCount; i++)
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
Assert.AreEqual(matrix[i, j], value);
}
}
}
/// <summary>
/// Can create an identity matrix.
/// </summary>
[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 ? Complex.One : Complex.Zero, matrix[i, j]);
}
}
}
/// <summary>
/// Identity with wrong order throws <c>ArgumentOutOfRangeException</c>.
/// </summary>
/// <param name="order">The size of the square matrix</param>
[TestCase(0)]
[TestCase(-1)]
public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException(int order)
{
Assert.Throws<ArgumentOutOfRangeException>(() => SymmetricDenseMatrix.Identity(order));
}
}
}

192
src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.Arithmetic.cs

@ -0,0 +1,192 @@
// <copyright file="SymmetricMatrixTests.Arithmetic.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
{
using System.Collections.Generic;
using LinearAlgebra.Complex;
using NUnit.Framework;
using System.Numerics;
/// <summary>
/// Abstract class with the common set of matrix tests for symmetric matrices
/// </summary>
public abstract partial class SymmetricMatrixTests
{
/// <summary>
/// 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.
/// </summary>
[SetUp]
public override void SetupMatrices()
{
TestData2D = new Dictionary<string, Complex[,]>
{
{ "Singular3x3", new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) } } },
{ "Square3x3", new[,] { { new Complex(-1.1, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(1.1, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(6.6, 1) } } },
{ "Square4x4", new[,] { { new Complex(1.1, 1), new Complex(2.0, 1), new Complex(-3.0, 1), new Complex(4.4, 1) }, { new Complex(2.0, 1), new Complex(5.0, 1), new Complex(-6.0, 1), new Complex(7.0, 1) }, { new Complex(-3.0, 1), new Complex(-6.0, 1), new Complex(8.0, 1), new Complex(9.0, 1) }, { new Complex(4.4, 1), new Complex(7.0, 1), new Complex(9.0, 1), new Complex(10.0, 1) } } },
{ "Singular4x4", new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(0.0, 1), new Complex(4.0, 1) }, { new Complex(2.0, 1), new Complex(5.0, 1), new Complex(0.0, 1), new Complex(7.0, 1) }, { new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1), new Complex(0.0, 1) }, { new Complex(4.0, 1), new Complex(7.0, 1), new Complex(0.0, 1), new Complex(10.0, 1) } } },
{ "Tall3x2", new[,] { { new Complex(-1.1, 1), new Complex(-2.2, 1) }, { new Complex(0.0, 1), new Complex(1.1, 1) }, { new Complex(-4.4, 1), new Complex(5.5, 1) } } },
{ "Wide2x3", new[,] { { new Complex(-1.1, 1), new Complex(-2.2, 1), new Complex(-3.3, 1) }, { new Complex(0.0, 1), new Complex(1.1, 1), new Complex(2.2, 1) } } },
{ "Symmetric3x3", new[,] { { new Complex(1.0, 1), new Complex(2.0, 1), new Complex(3.0, 1) }, { new Complex(2.0, 1), new Complex(2.0, 1), new Complex(0.0, 1) }, { new Complex(3.0, 1), new Complex(0.0, 1), new Complex(3.0, 1) } } },
{ "NonSymmetric3x3", new[,] { { new Complex(-1.1, 1), new Complex(-2.2, 1), new Complex(-3.3, 1) }, { new Complex(0.0, 1), new Complex(1.1, 1), new Complex(2.2, 1) }, { new Complex(-4.4, 1), new Complex(5.5, 1), new Complex(6.6, 1) } } },
{ "NonSymmetric4x4", new[,] { { new Complex(-1.1, 1), new Complex(-2.2, 1), new Complex(-3.3, 1), new Complex(-4.4, 1) }, { new Complex(0.0, 1), new Complex(1.1, 1), new Complex(2.2, 1), new Complex(3.3, 1) }, { new Complex(1.0, 1), new Complex(2.1, 1), new Complex(6.2, 1), new Complex(4.3, 1) }, { new Complex(-4.4, 1), new Complex(5.5, 1), new Complex(6.6, 1), new Complex(-7.7, 1) } } },
{ "IndexTester4x4", new [,] { { new Complex(0, 1), new Complex(1, 1), new Complex(3, 1), new Complex(6, 1) }, { new Complex(1, 1), new Complex(2, 1), new Complex(4, 1), new Complex(7, 1) }, { new Complex(3, 1), new Complex(4, 1), new Complex(5, 1), new Complex(8, 1) }, { new Complex(6, 1), new Complex(7, 1), new Complex(8, 1), new Complex(9, 1) } } }
};
TestMatrices = new Dictionary<string, Matrix>();
foreach (var name in TestData2D.Keys)
{
TestMatrices.Add(name, CreateMatrix(TestData2D[name]));
}
}
/// <summary>
/// Can add a non-symmetric matrix to this symmetric matrix.
/// </summary>
/// <param name="mtxA">Matrix A name.</param>
/// <param name="mtxB">Matrix B name.</param>
[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]);
}
}
}
/// <summary>
/// Can subtract a non-symmetric matrix from this symmetric matrix.
/// </summary>
/// <param name="mtxA">Matrix A name.</param>
/// <param name="mtxB">Matrix B name.</param>
[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]);
}
}
}
/// <summary>
/// Can compute Frobenius norm.
/// </summary>
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);
}
/// <summary>
/// Can compute Infinity norm.
/// </summary>
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);
}
/// <summary>
/// Can compute L1 norm.
/// </summary>
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);
}
/// <summary>
/// Can compute L2 norm.
/// </summary>
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);
}
}
}

124
src/UnitTests/LinearAlgebraTests/Complex/SymmetricMatrixTests.cs

@ -0,0 +1,124 @@
// <copyright file="SymmetricMatrixTests.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex
{
using System.Numerics;
using MathNet.Numerics.LinearAlgebra.Complex;
using NUnit.Framework;
/// <summary>
/// Abstract class with the common set of matrix tests for symmetric matrices.
/// </summary>
public abstract partial class SymmetricMatrixTests : MatrixTests
{
/// <summary>
/// Can check if a matrix is symmetric.
/// </summary>
[Test]
public override void CanCheckIfMatrixIsSymmetric()
{
var matrix = TestMatrices["Square3x3"];
Assert.IsTrue(matrix.IsSymmetric);
matrix = TestMatrices["NonSymmetric3x3"];
Assert.IsFalse(matrix.IsSymmetric);
}
/// <summary>
/// Can check if a [,] array is symmetric.
/// </summary>
[Test]
public void CanCheckIfArrayIsSymmetric()
{
Assert.IsTrue(SymmetricMatrix.CheckIfSymmetric(TestData2D["Square3x3"]));
Assert.IsFalse(SymmetricMatrix.CheckIfSymmetric(TestData2D["NonSymmetric3x3"]));
}
/// <summary>
/// Test whether the index enumerator returns the correct values.
/// </summary>
[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(new Complex(1.0, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(0, item.Item1);
Assert.AreEqual(1, item.Item2);
Assert.AreEqual(new Complex(2.0, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(0, item.Item1);
Assert.AreEqual(2, item.Item2);
Assert.AreEqual(new Complex(3.0, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(1, item.Item1);
Assert.AreEqual(0, item.Item2);
Assert.AreEqual(new Complex(2.0, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(1, item.Item1);
Assert.AreEqual(1, item.Item2);
Assert.AreEqual(new Complex(0.0, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(1, item.Item1);
Assert.AreEqual(2, item.Item2);
Assert.AreEqual(new Complex(0.0, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(2, item.Item1);
Assert.AreEqual(0, item.Item2);
Assert.AreEqual(new Complex(3.0, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(2, item.Item1);
Assert.AreEqual(1, item.Item2);
Assert.AreEqual(new Complex(0.0, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(2, item.Item1);
Assert.AreEqual(2, item.Item2);
Assert.AreEqual(new Complex(0.0, 1), item.Item3);
}
}
}

217
src/UnitTests/LinearAlgebraTests/Complex32/SymmetricDenseMatrixTests.cs

@ -0,0 +1,217 @@
// <copyright file="SymmetricDenseMatrixTests.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
{
using System;
using System.Collections.Generic;
using Numerics;
using MathNet.Numerics.LinearAlgebra.Complex32;
using NUnit.Framework;
/// <summary>
/// Symmetric Dense matrix tests.
/// </summary>
public class SymmetricDenseMatrixTests : SymmetricMatrixTests
{
/// <summary>
/// Creates a matrix for the given number of rows and columns.
/// </summary>
/// <param name="rows">
/// The number of rows.
/// </param>
/// <param name="columns">
/// The number of columns.
/// </param>
/// <returns>
/// A matrix with the given dimensions.
/// </returns>
protected override Matrix CreateMatrix(int rows, int columns)
{
return new DenseMatrix(rows, columns);
}
/// <summary>
/// Creates a matrix from a 2D array.
/// </summary>
/// <param name="data">
/// The 2D array to create this matrix from.
/// </param>
/// <returns>
/// A matrix with the given values.
/// </returns>
protected override Matrix CreateMatrix(Complex32[,] data)
{
if (SymmetricMatrix.CheckIfSymmetric(data))
{
return new SymmetricDenseMatrix(data);
}
return new DenseMatrix(data);
}
/// <summary>
/// Creates a vector of the given size.
/// </summary>
/// <param name="size">
/// The size of the vector to create.
/// </param>
/// <returns>
/// The new vector.
/// </returns>
protected override Vector CreateVector(int size)
{
return new DenseVector(size);
}
/// <summary>
/// Creates a vector from an array.
/// </summary>
/// <param name="data">
/// The array to create this vector from.
/// </param>
/// <returns>
/// The new vector.
/// </returns>
protected override Vector CreateVector(Complex32[] data)
{
return new DenseVector(data);
}
/// <summary>
/// Can create a matrix form array.
/// </summary>
[Test]
public void CanCreateMatrixFrom1DArray()
{
var testData = new Dictionary<string, Matrix>
{
{ "Singular3x3", new SymmetricDenseMatrix(3, new[] { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }) },
{ "Square3x3", new SymmetricDenseMatrix(3, new[] { new Complex32(-1.1f, 1), new Complex32(2.0f, 1), new Complex32(1.1f, 1), new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(6.6f, 1) }) },
{ "Square4x4", new SymmetricDenseMatrix(4, new[] { new Complex32(1.1f, 1), new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(-3.0f, 1), new Complex32(-6.0f, 1), new Complex32(8.0f, 1), new Complex32(4.4f, 1), new Complex32(7.0f, 1), new Complex32(9.0f, 1), new Complex32(10.0f, 1) }) },
{ "Singular4x4", new SymmetricDenseMatrix(4, new[] { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(4.0f, 1), new Complex32(7.0f, 1), new Complex32(0.0f, 1), new Complex32(10.0f, 1) }) },
{ "Symmetric3x3", new SymmetricDenseMatrix(3, new[] { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(3.0f, 1) }) },
{ "IndexTester4x4", new SymmetricDenseMatrix(4, new [] { new Complex32(0, 1), new Complex32(1, 1), new Complex32(2, 1), new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1), new Complex32(6, 1), new Complex32(7, 1), new Complex32(8, 1), new Complex32(9, 1) }) }
};
foreach (var name in testData.Keys)
{
Assert.AreEqual(TestMatrices[name], testData[name]);
}
}
/// <summary>
/// Matrix from array is a reference.
/// </summary>
[Test]
public void MatrixFrom1DArrayIsReference()
{
var data = new Complex32[] { new Complex32(1, 1), new Complex32(1, 1), new Complex32(1, 1), new Complex32(1, 1), new Complex32(1, 1), new Complex32(1, 1) };
var matrix = new SymmetricDenseMatrix(3, data);
matrix[0, 0] = new Complex32(10.0f, 2);
Assert.AreEqual(new Complex32(10.0f, 2), data[0]);
}
/// <summary>
/// Can create a matrix form array.
/// </summary>
[Test]
public void CanCreateMatrixFrom2DArray()
{
var testData = new Dictionary<string, Matrix>
{
{ "Singular3x3", new SymmetricDenseMatrix(new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) } }) },
{ "Square3x3", new SymmetricDenseMatrix(new[,] { { new Complex32(-1.1f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(1.1f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(6.6f, 1) } }) },
{ "Square4x4", new SymmetricDenseMatrix(new[,] { { new Complex32(1.1f, 1), new Complex32(2.0f, 1), new Complex32(-3.0f, 1), new Complex32(4.4f, 1) }, { new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(-6.0f, 1), new Complex32(7.0f, 1) }, { new Complex32(-3.0f, 1), new Complex32(-6.0f, 1), new Complex32(8.0f, 1), new Complex32(9.0f, 1) }, { new Complex32(4.4f, 1), new Complex32(7.0f, 1), new Complex32(9.0f, 1), new Complex32(10.0f, 1) } }) },
{ "Singular4x4", new SymmetricDenseMatrix(new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(4.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(0.0f, 1), new Complex32(7.0f, 1) }, { new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(4.0f, 1), new Complex32(7.0f, 1), new Complex32(0.0f, 1), new Complex32(10.0f, 1) } }) },
{ "Symmetric3x3", new SymmetricDenseMatrix(new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(3.0f, 1) } }) },
{ "IndexTester4x4", new SymmetricDenseMatrix(new [,] { { new Complex32(0, 1), new Complex32(1, 1), new Complex32(3, 1), new Complex32(6, 1) }, { new Complex32(1, 1), new Complex32(2, 1), new Complex32(4, 1), new Complex32(7, 1) }, { new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1), new Complex32(8, 1) }, { new Complex32(6, 1), new Complex32(7, 1), new Complex32(8, 1), new Complex32(9, 1) } }) }
};
foreach (var name in testData.Keys)
{
Assert.AreEqual(TestMatrices[name], testData[name]);
}
}
/// <summary>
/// Matrix from two-dimensional array is a copy.
/// </summary>
[Test]
public void MatrixFrom2DArrayIsCopy()
{
var matrix = new DenseMatrix(TestData2D["Singular3x3"]);
matrix[0, 0] = new Complex32(10.0f, 2);
Assert.AreEqual(new Complex32(1.0f, 1), TestData2D["Singular3x3"][0, 0]);
}
/// <summary>
/// Can create a matrix with uniform values.
/// </summary>
[Test]
public void CanCreateMatrixWithUniformValues()
{
var matrix = new SymmetricDenseMatrix(10, new Complex32(10.0f, 2));
var value = new Complex32(10.0f, 2);
for (var i = 0; i < matrix.RowCount; i++)
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
Assert.AreEqual(matrix[i, j], value);
}
}
}
/// <summary>
/// Can create an identity matrix.
/// </summary>
[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 ? Complex32.One : Complex32.Zero, matrix[i, j]);
}
}
}
/// <summary>
/// Identity with wrong order throws <c>ArgumentOutOfRangeException</c>.
/// </summary>
/// <param name="order">The size of the square matrix</param>
[TestCase(0)]
[TestCase(-1)]
public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException(int order)
{
Assert.Throws<ArgumentOutOfRangeException>(() => SymmetricDenseMatrix.Identity(order));
}
}
}

192
src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.Arithmetic.cs

@ -0,0 +1,192 @@
// <copyright file="SymmetricMatrixTests.Arithmetic.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
{
using System.Collections.Generic;
using LinearAlgebra.Complex32;
using NUnit.Framework;
using Numerics;
/// <summary>
/// Abstract class with the common set of matrix tests for symmetric matrices
/// </summary>
public abstract partial class SymmetricMatrixTests
{
/// <summary>
/// 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.
/// </summary>
[SetUp]
public override void SetupMatrices()
{
TestData2D = new Dictionary<string, Complex32[,]>
{
{ "Singular3x3", new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) } } },
{ "Square3x3", new[,] { { new Complex32(-1.1f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(1.1f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(6.6f, 1) } } },
{ "Square4x4", new[,] { { new Complex32(1.1f, 1), new Complex32(2.0f, 1), new Complex32(-3.0f, 1), new Complex32(4.4f, 1) }, { new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(-6.0f, 1), new Complex32(7.0f, 1) }, { new Complex32(-3.0f, 1), new Complex32(-6.0f, 1), new Complex32(8.0f, 1), new Complex32(9.0f, 1) }, { new Complex32(4.4f, 1), new Complex32(7.0f, 1), new Complex32(9.0f, 1), new Complex32(10.0f, 1) } } },
{ "Singular4x4", new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1), new Complex32(4.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(5.0f, 1), new Complex32(0.0f, 1), new Complex32(7.0f, 1) }, { new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(4.0f, 1), new Complex32(7.0f, 1), new Complex32(0.0f, 1), new Complex32(10.0f, 1) } } },
{ "Tall3x2", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1) }, { new Complex32(0.0f, 1), new Complex32(1.1f, 1) }, { new Complex32(-4.4f, 1), new Complex32(5.5f, 1) } } },
{ "Wide2x3", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1) }, { new Complex32(0.0f, 1), new Complex32(1.1f, 1), new Complex32(2.2f, 1) } } },
{ "Symmetric3x3", new[,] { { new Complex32(1.0f, 1), new Complex32(2.0f, 1), new Complex32(3.0f, 1) }, { new Complex32(2.0f, 1), new Complex32(2.0f, 1), new Complex32(0.0f, 1) }, { new Complex32(3.0f, 1), new Complex32(0.0f, 1), new Complex32(3.0f, 1) } } },
{ "NonSymmetric3x3", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1) }, { new Complex32(0.0f, 1), new Complex32(1.1f, 1), new Complex32(2.2f, 1) }, { new Complex32(-4.4f, 1), new Complex32(5.5f, 1), new Complex32(6.6f, 1) } } },
{ "NonSymmetric4x4", new[,] { { new Complex32(-1.1f, 1), new Complex32(-2.2f, 1), new Complex32(-3.3f, 1), new Complex32(-4.4f, 1) }, { new Complex32(0.0f, 1), new Complex32(1.1f, 1), new Complex32(2.2f, 1), new Complex32(3.3f, 1) }, { new Complex32(1.0f, 1), new Complex32(2.1f, 1), new Complex32(6.2f, 1), new Complex32(4.3f, 1) }, { new Complex32(-4.4f, 1), new Complex32(5.5f, 1), new Complex32(6.6f, 1), new Complex32(-7.7f, 1) } } },
{ "IndexTester4x4", new [,] { { new Complex32(0, 1), new Complex32(1, 1), new Complex32(3, 1), new Complex32(6, 1) }, { new Complex32(1, 1), new Complex32(2, 1), new Complex32(4, 1), new Complex32(7, 1) }, { new Complex32(3, 1), new Complex32(4, 1), new Complex32(5, 1), new Complex32(8, 1) }, { new Complex32(6, 1), new Complex32(7, 1), new Complex32(8, 1), new Complex32(9, 1) } } }
};
TestMatrices = new Dictionary<string, Matrix>();
foreach (var name in TestData2D.Keys)
{
TestMatrices.Add(name, CreateMatrix(TestData2D[name]));
}
}
/// <summary>
/// Can add a non-symmetric matrix to this symmetric matrix.
/// </summary>
/// <param name="mtxA">Matrix A name.</param>
/// <param name="mtxB">Matrix B name.</param>
[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]);
}
}
}
/// <summary>
/// Can subtract a non-symmetric matrix from this symmetric matrix.
/// </summary>
/// <param name="mtxA">Matrix A name.</param>
/// <param name="mtxB">Matrix B name.</param>
[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]);
}
}
}
/// <summary>
/// Can compute Frobenius norm.
/// </summary>
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);
}
/// <summary>
/// Can compute Infinity norm.
/// </summary>
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);
}
/// <summary>
/// Can compute L1 norm.
/// </summary>
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);
}
/// <summary>
/// Can compute L2 norm.
/// </summary>
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);
}
}
}

125
src/UnitTests/LinearAlgebraTests/Complex32/SymmetricMatrixTests.cs

@ -0,0 +1,125 @@
// <copyright file="SymmetricMatrixTests.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32
{
using MathNet.Numerics.LinearAlgebra.Complex32;
using Numerics;
using NUnit.Framework;
/// <summary>
/// Abstract class with the common set of matrix tests for symmetric matrices.
/// </summary>
public abstract partial class SymmetricMatrixTests : MatrixTests
{
/// <summary>
/// Can check if a matrix is symmetric.
/// </summary>
[Test]
public override void CanCheckIfMatrixIsSymmetric()
{
var matrix = TestMatrices["Square3x3"];
Assert.IsTrue(matrix.IsSymmetric);
matrix = TestMatrices["NonSymmetric3x3"];
Assert.IsFalse(matrix.IsSymmetric);
}
/// <summary>
/// Can check if a [,] array is symmetric.
/// </summary>
[Test]
public void CanCheckIfArrayIsSymmetric()
{
Assert.IsTrue(SymmetricMatrix.CheckIfSymmetric(TestData2D["Square3x3"]));
Assert.IsFalse(SymmetricMatrix.CheckIfSymmetric(TestData2D["NonSymmetric3x3"]));
}
/// <summary>
/// Test whether the index enumerator returns the correct values.
/// </summary>
[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(new Complex32(1.0f, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(0, item.Item1);
Assert.AreEqual(1, item.Item2);
Assert.AreEqual(new Complex32(2.0f, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(0, item.Item1);
Assert.AreEqual(2, item.Item2);
Assert.AreEqual(new Complex32(3.0f, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(1, item.Item1);
Assert.AreEqual(0, item.Item2);
Assert.AreEqual(new Complex32(2.0f, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(1, item.Item1);
Assert.AreEqual(1, item.Item2);
Assert.AreEqual(new Complex32(0.0f, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(1, item.Item1);
Assert.AreEqual(2, item.Item2);
Assert.AreEqual(new Complex32(0.0f, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(2, item.Item1);
Assert.AreEqual(0, item.Item2);
Assert.AreEqual(new Complex32(3.0f, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(2, item.Item1);
Assert.AreEqual(1, item.Item2);
Assert.AreEqual(new Complex32(0.0f, 1), item.Item3);
enumerator.MoveNext();
item = enumerator.Current;
Assert.AreEqual(2, item.Item1);
Assert.AreEqual(2, item.Item2);
Assert.AreEqual(new Complex32(0.0f, 1), item.Item3);
}
}
}

9
src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs

@ -948,10 +948,10 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
}
/// <summary>
/// Can calculate Kronecker product.
/// Can calculate Kronecker product into a result matrix.
/// </summary>
[Test]
public void CanKroneckerProduct()
public void CanKroneckerProductIntoResult()
{
var matrixA = TestMatrices["Wide2x3"];
var matrixB = TestMatrices["Square3x3"];
@ -972,11 +972,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
}
}
/// <summary>
/// Can calculate Kronecker product into a result matrix.
/// Can calculate Kronecker product.
/// </summary>
[Test]
public void CanKroneckerProductIntoResult()
public void CanKroneckerProduct()
{
var matrixA = TestMatrices["Wide2x3"];
var matrixB = TestMatrices["Square3x3"];

215
src/UnitTests/LinearAlgebraTests/Double/SymmetricDenseMatrixTests.cs

@ -0,0 +1,215 @@
// <copyright file="SymmetricDenseMatrixTests.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
{
using System;
using System.Collections.Generic;
using MathNet.Numerics.LinearAlgebra.Double;
using NUnit.Framework;
/// <summary>
/// Symmetric Dense matrix tests.
/// </summary>
public class SymmetricDenseMatrixTests : SymmetricMatrixTests
{
/// <summary>
/// Creates a matrix for the given number of rows and columns.
/// </summary>
/// <param name="rows">
/// The number of rows.
/// </param>
/// <param name="columns">
/// The number of columns.
/// </param>
/// <returns>
/// A matrix with the given dimensions.
/// </returns>
protected override Matrix CreateMatrix(int rows, int columns)
{
return new DenseMatrix(rows, columns);
}
/// <summary>
/// Creates a matrix from a 2D array.
/// </summary>
/// <param name="data">
/// The 2D array to create this matrix from.
/// </param>
/// <returns>
/// A matrix with the given values.
/// </returns>
protected override Matrix CreateMatrix(double[,] data)
{
if (SymmetricMatrix.CheckIfSymmetric(data))
{
return new SymmetricDenseMatrix(data);
}
return new DenseMatrix(data);
}
/// <summary>
/// Creates a vector of the given size.
/// </summary>
/// <param name="size">
/// The size of the vector to create.
/// </param>
/// <returns>
/// The new vector.
/// </returns>
protected override Vector CreateVector(int size)
{
return new DenseVector(size);
}
/// <summary>
/// Creates a vector from an array.
/// </summary>
/// <param name="data">
/// The array to create this vector from.
/// </param>
/// <returns>
/// The new vector.
/// </returns>
protected override Vector CreateVector(double[] data)
{
return new DenseVector(data);
}
/// <summary>
/// Can create a matrix form array.
/// </summary>
[Test]
public void CanCreateMatrixFrom1DArray()
{
var testData = new Dictionary<string, Matrix>
{
{ "Singular3x3", new SymmetricDenseMatrix(3, new[] { 1.0, 2.0, 0.0, 3.0, 0.0, 0.0 }) },
{ "Square3x3", new SymmetricDenseMatrix(3, new[] { -1.1, 2.0, 1.1, 3.0, 0.0, 6.6 }) },
{ "Square4x4", new SymmetricDenseMatrix(4, new[] { 1.1, 2.0, 5.0, -3.0, -6.0, 8.0, 4.4, 7.0, 9.0, 10.0 }) },
{ "Singular4x4", new SymmetricDenseMatrix(4, new[] { 1.0, 2.0, 5.0, 0.0, 0.0, 0.0, 4.0, 7.0, 0.0, 10.0 }) },
{ "Symmetric3x3", new SymmetricDenseMatrix(3, new[] { 1.0, 2.0, 2.0, 3.0, 0.0, 3.0 }) },
{ "IndexTester4x4", new SymmetricDenseMatrix(4, new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }) }
};
foreach (var name in testData.Keys)
{
Assert.AreEqual(TestMatrices[name], testData[name]);
}
}
/// <summary>
/// Matrix from array is a reference.
/// </summary>
[Test]
public void MatrixFrom1DArrayIsReference()
{
var data = new double[] { 1, 1, 1, 1, 1, 1 };
var matrix = new SymmetricDenseMatrix(3, data);
matrix[0, 0] = 10.0;
Assert.AreEqual(10.0, data[0]);
}
/// <summary>
/// Can create a matrix form array.
/// </summary>
[Test]
public void CanCreateMatrixFrom2DArray()
{
var testData = new Dictionary<string, Matrix>
{
{ "Singular3x3", new SymmetricDenseMatrix(new[,] { { 1.0, 2.0, 3.0 }, { 2.0, 0.0, 0.0 }, { 3.0, 0.0, 0.0 } }) },
{ "Square3x3", new SymmetricDenseMatrix(new[,] { { -1.1, 2.0, 3.0 }, { 2.0, 1.1, 0.0 }, { 3.0, 0.0, 6.6 } }) },
{ "Square4x4", new SymmetricDenseMatrix(new[,] { { 1.1, 2.0, -3.0, 4.4 }, { 2.0, 5.0, -6.0, 7.0 }, { -3.0, -6.0, 8.0, 9.0 }, { 4.4, 7.0, 9.0, 10.0 } }) },
{ "Singular4x4", new SymmetricDenseMatrix(new[,] { { 1.0, 2.0, 0.0, 4.0 }, { 2.0, 5.0, 0.0, 7.0 }, { 0.0, 0.0, 0.0, 0.0 }, { 4.0, 7.0, 0.0, 10.0 } }) },
{ "Symmetric3x3", new SymmetricDenseMatrix(new[,] { { 1.0, 2.0, 3.0 }, { 2.0, 2.0, 0.0 }, { 3.0, 0.0, 3.0 } }) },
{ "IndexTester4x4", new SymmetricDenseMatrix(new double[,] { { 0, 1, 3, 6 }, { 1, 2, 4, 7 }, { 3, 4, 5, 8 }, { 6, 7, 8, 9 } }) }
};
foreach (var name in testData.Keys)
{
Assert.AreEqual(TestMatrices[name], testData[name]);
}
}
/// <summary>
/// Matrix from two-dimensional array is a copy.
/// </summary>
[Test]
public void MatrixFrom2DArrayIsCopy()
{
var matrix = new DenseMatrix(TestData2D["Singular3x3"]);
matrix[0, 0] = 10.0;
Assert.AreEqual(1.0, TestData2D["Singular3x3"][0, 0]);
}
/// <summary>
/// Can create a matrix with uniform values.
/// </summary>
[Test]
public void CanCreateMatrixWithUniformValues()
{
var matrix = new SymmetricDenseMatrix(10, 10.0);
for (var i = 0; i < matrix.RowCount; i++)
{
for (var j = 0; j < matrix.ColumnCount; j++)
{
Assert.AreEqual(matrix[i, j], 10.0);
}
}
}
/// <summary>
/// Can create an identity matrix.
/// </summary>
[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.0 : 0.0, matrix[i, j]);
}
}
}
/// <summary>
/// Identity with wrong order throws <c>ArgumentOutOfRangeException</c>.
/// </summary>
/// <param name="order">The size of the square matrix</param>
[TestCase(0)]
[TestCase(-1)]
public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException(int order)
{
Assert.Throws<ArgumentOutOfRangeException>(() => SymmetricDenseMatrix.Identity(order));
}
}
}

191
src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.Arithmetic.cs

@ -0,0 +1,191 @@
// <copyright file="SymmetricMatrixTests.Arithmetic.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
{
using System.Collections.Generic;
using LinearAlgebra.Double;
using NUnit.Framework;
/// <summary>
/// Abstract class with the common set of matrix tests for symmetric matrices
/// </summary>
public abstract partial class SymmetricMatrixTests
{
/// <summary>
/// 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.
/// </summary>
[SetUp]
public override void SetupMatrices()
{
TestData2D = new Dictionary<string, double[,]>
{
{ "Singular3x3", new[,] { { 1.0, 2.0, 3.0 }, { 2.0, 0.0, 0.0 }, { 3.0, 0.0, 0.0 } } },
{ "Square3x3", new[,] { { -1.1, 2.0, 3.0 }, { 2.0, 1.1, 0.0 }, { 3.0, 0.0, 6.6 } } },
{ "Square4x4", new[,] { { 1.1, 2.0, -3.0, 4.4 }, { 2.0, 5.0, -6.0, 7.0 }, { -3.0, -6.0, 8.0, 9.0 }, { 4.4, 7.0, 9.0, 10.0 } } },
{ "Singular4x4", new[,] { { 1.0, 2.0, 0.0, 4.0 }, { 2.0, 5.0, 0.0, 7.0 }, { 0.0, 0.0, 0.0, 0.0 }, { 4.0, 7.0, 0.0, 10.0 } } },
{ "Tall3x2", new[,] { { -1.1, -2.2 }, { 0.0, 1.1 }, { -4.4, 5.5 } } },
{ "Wide2x3", new[,] { { -1.1, -2.2, -3.3 }, { 0.0, 1.1, 2.2 } } },
{ "Symmetric3x3", new[,] { { 1.0, 2.0, 3.0 }, { 2.0, 2.0, 0.0 }, { 3.0, 0.0, 3.0 } } },
{ "NonSymmetric3x3", new[,] { { -1.1, -2.2, -3.3 }, { 0.0, 1.1, 2.2 }, { -4.4, 5.5, 6.6 } } },
{ "NonSymmetric4x4", new[,] { { -1.1, -2.2, -3.3, -4.4 }, { 0.0, 1.1, 2.2, 3.3 }, { 1.0, 2.1, 6.2, 4.3 }, { -4.4, 5.5, 6.6, -7.7 } } },
{ "IndexTester4x4", new double[,] { { 0, 1, 3, 6 }, { 1, 2, 4, 7 }, { 3, 4, 5, 8 }, { 6, 7, 8, 9 } } }
};
TestMatrices = new Dictionary<string, Matrix>();
foreach (var name in TestData2D.Keys)
{
TestMatrices.Add(name, CreateMatrix(TestData2D[name]));
}
}
/// <summary>
/// Can add a non-symmetric matrix to this symmetric matrix.
/// </summary>
/// <param name="mtxA">Matrix A name.</param>
/// <param name="mtxB">Matrix B name.</param>
[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]);
}
}
}
/// <summary>
/// Can subtract a non-symmetric matrix from this symmetric matrix.
/// </summary>
/// <param name="mtxA">Matrix A name.</param>
/// <param name="mtxB">Matrix B name.</param>
[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]);
}
}
}
/// <summary>
/// Can compute Frobenius norm.
/// </summary>
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);
}
/// <summary>
/// Can compute Infinity norm.
/// </summary>
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);
}
/// <summary>
/// Can compute L1 norm.
/// </summary>
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);
}
/// <summary>
/// Can compute L2 norm.
/// </summary>
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);
}
}
}

123
src/UnitTests/LinearAlgebraTests/Double/SymmetricMatrixTests.cs

@ -0,0 +1,123 @@
// <copyright file="SymmetricMatrixTests.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double
{
using MathNet.Numerics.LinearAlgebra.Double;
using NUnit.Framework;
/// <summary>
/// Abstract class with the common set of matrix tests for symmetric matrices.
/// </summary>
public abstract partial class SymmetricMatrixTests : MatrixTests
{
/// <summary>
/// Can check if a matrix is symmetric.
/// </summary>
[Test]
public override void CanCheckIfMatrixIsSymmetric()
{
var matrix = TestMatrices["Square3x3"];
Assert.IsTrue(matrix.IsSymmetric);
matrix = TestMatrices["NonSymmetric3x3"];
Assert.IsFalse(matrix.IsSymmetric);
}
/// <summary>
/// Can check if a [,] array is symmetric.
/// </summary>
[Test]
public void CanCheckIfArrayIsSymmetric()
{
Assert.IsTrue(SymmetricMatrix.CheckIfSymmetric(TestData2D["Square3x3"]));
Assert.IsFalse(SymmetricMatrix.CheckIfSymmetric(TestData2D["NonSymmetric3x3"]));
}
/// <summary>
/// Test whether the index enumerator returns the correct values.
/// </summary>
[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);
}
}
}

215
src/UnitTests/LinearAlgebraTests/Single/SymmetricDenseMatrixTests.cs

@ -0,0 +1,215 @@
// <copyright file="SymmetricDenseMatrixTests.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
{
using System;
using System.Collections.Generic;
using MathNet.Numerics.LinearAlgebra.Single;
using NUnit.Framework;
/// <summary>
/// Symmetric Dense matrix tests.
/// </summary>
public class SymmetricDenseMatrixTests : SymmetricMatrixTests
{
/// <summary>
/// Creates a matrix for the given number of rows and columns.
/// </summary>
/// <param name="rows">
/// The number of rows.
/// </param>
/// <param name="columns">
/// The number of columns.
/// </param>
/// <returns>
/// A matrix with the given dimensions.
/// </returns>
protected override Matrix CreateMatrix(int rows, int columns)
{
return new DenseMatrix(rows, columns);
}
/// <summary>
/// Creates a matrix from a 2D array.
/// </summary>
/// <param name="data">
/// The 2D array to create this matrix from.
/// </param>
/// <returns>
/// A matrix with the given values.
/// </returns>
protected override Matrix CreateMatrix(float[,] data)
{
if (SymmetricMatrix.CheckIfSymmetric(data))
{
return new SymmetricDenseMatrix(data);
}
return new DenseMatrix(data);
}
/// <summary>
/// Creates a vector of the given size.
/// </summary>
/// <param name="size">
/// The size of the vector to create.
/// </param>
/// <returns>
/// The new vector.
/// </returns>
protected override Vector CreateVector(int size)
{
return new DenseVector(size);
}
/// <summary>
/// Creates a vector from an array.
/// </summary>
/// <param name="data">
/// The array to create this vector from.
/// </param>
/// <returns>
/// The new vector.
/// </returns>
protected override Vector CreateVector(float[] data)
{
return new DenseVector(data);
}
/// <summary>
/// Can create a matrix form array.
/// </summary>
[Test]
public void CanCreateMatrixFrom1DArray()
{
var testData = new Dictionary<string, Matrix>
{
{ "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]);
}
}
/// <summary>
/// Matrix from array is a reference.
/// </summary>
[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]);
}
/// <summary>
/// Can create a matrix form array.
/// </summary>
[Test]
public void CanCreateMatrixFrom2DArray()
{
var testData = new Dictionary<string, Matrix>
{
{ "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]);
}
}
/// <summary>
/// Matrix from two-dimensional array is a copy.
/// </summary>
[Test]
public void MatrixFrom2DArrayIsCopy()
{
var matrix = new DenseMatrix(TestData2D["Singular3x3"]);
matrix[0, 0] = 10.0f;
Assert.AreEqual(1.0f, TestData2D["Singular3x3"][0, 0]);
}
/// <summary>
/// Can create a matrix with uniform values.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can create an identity matrix.
/// </summary>
[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]);
}
}
}
/// <summary>
/// Identity with wrong order throws <c>ArgumentOutOfRangeException</c>.
/// </summary>
/// <param name="order">The size of the square matrix</param>
[TestCase(0)]
[TestCase(-1)]
public void IdentityWithWrongOrderThrowsArgumentOutOfRangeException(int order)
{
Assert.Throws<ArgumentOutOfRangeException>(() => SymmetricDenseMatrix.Identity(order));
}
}
}

191
src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.Arithmetic.cs

@ -0,0 +1,191 @@
// <copyright file="SymmetricMatrixTests.Arithmetic.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
{
using System.Collections.Generic;
using LinearAlgebra.Single;
using NUnit.Framework;
/// <summary>
/// Abstract class with the common set of matrix tests for symmetric matrices
/// </summary>
public abstract partial class SymmetricMatrixTests
{
/// <summary>
/// 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.
/// </summary>
[SetUp]
public override void SetupMatrices()
{
TestData2D = new Dictionary<string, float[,]>
{
{ "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<string, Matrix>();
foreach (var name in TestData2D.Keys)
{
TestMatrices.Add(name, CreateMatrix(TestData2D[name]));
}
}
/// <summary>
/// Can add a non-symmetric matrix to this symmetric matrix.
/// </summary>
/// <param name="mtxA">Matrix A name.</param>
/// <param name="mtxB">Matrix B name.</param>
[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]);
}
}
}
/// <summary>
/// Can subtract a non-symmetric matrix from this symmetric matrix.
/// </summary>
/// <param name="mtxA">Matrix A name.</param>
/// <param name="mtxB">Matrix B name.</param>
[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]);
}
}
}
/// <summary>
/// Can compute Frobenius norm.
/// </summary>
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);
}
/// <summary>
/// Can compute Infinity norm.
/// </summary>
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);
}
/// <summary>
/// Can compute L1 norm.
/// </summary>
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);
}
/// <summary>
/// Can compute L2 norm.
/// </summary>
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);
}
}
}

123
src/UnitTests/LinearAlgebraTests/Single/SymmetricMatrixTests.cs

@ -0,0 +1,123 @@
// <copyright file="SymmetricMatrixTests.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single
{
using MathNet.Numerics.LinearAlgebra.Single;
using NUnit.Framework;
/// <summary>
/// Abstract class with the common set of matrix tests for symmetric matrices.
/// </summary>
public abstract partial class SymmetricMatrixTests : MatrixTests
{
/// <summary>
/// Can check if a matrix is symmetric.
/// </summary>
[Test]
public override void CanCheckIfMatrixIsSymmetric()
{
var matrix = TestMatrices["Square3x3"];
Assert.IsTrue(matrix.IsSymmetric);
matrix = TestMatrices["NonSymmetric3x3"];
Assert.IsFalse(matrix.IsSymmetric);
}
/// <summary>
/// Can check if a [,] array is symmetric.
/// </summary>
[Test]
public void CanCheckIfArrayIsSymmetric()
{
Assert.IsTrue(SymmetricMatrix.CheckIfSymmetric(TestData2D["Square3x3"]));
Assert.IsFalse(SymmetricMatrix.CheckIfSymmetric(TestData2D["NonSymmetric3x3"]));
}
/// <summary>
/// Test whether the index enumerator returns the correct values.
/// </summary>
[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);
}
}
}

12
src/UnitTests/UnitTests.csproj

@ -272,6 +272,9 @@
<Compile Include="LinearAlgebraTests\Complex32\SparseVectorTest.TextHandling.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="LinearAlgebraTests\Complex32\SymmetricDenseMatrixTests.cs" />
<Compile Include="LinearAlgebraTests\Complex32\SymmetricMatrixTests.Arithmetic.cs" />
<Compile Include="LinearAlgebraTests\Complex32\SymmetricMatrixTests.cs" />
<Compile Include="LinearAlgebraTests\Complex32\UserDefinedMatrix.cs">
<SubType>Code</SubType>
</Compile>
@ -420,6 +423,9 @@
<Compile Include="LinearAlgebraTests\Complex\SparseVectorTest.TextHandling.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="LinearAlgebraTests\Complex\SymmetricDenseMatrixTests.cs" />
<Compile Include="LinearAlgebraTests\Complex\SymmetricMatrixTests.Arithmetic.cs" />
<Compile Include="LinearAlgebraTests\Complex\SymmetricMatrixTests.cs" />
<Compile Include="LinearAlgebraTests\Complex\UserDefinedMatrix.cs">
<SubType>Code</SubType>
</Compile>
@ -568,6 +574,9 @@
<Compile Include="LinearAlgebraTests\Double\SparseVectorTest.TextHandling.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="LinearAlgebraTests\Double\SymmetricDenseMatrixTests.cs" />
<Compile Include="LinearAlgebraTests\Double\SymmetricMatrixTests.Arithmetic.cs" />
<Compile Include="LinearAlgebraTests\Double\SymmetricMatrixTests.cs" />
<Compile Include="LinearAlgebraTests\Double\UserDefinedMatrix.cs">
<SubType>Code</SubType>
</Compile>
@ -718,6 +727,9 @@
<Compile Include="LinearAlgebraTests\Single\SparseVectorTest.TextHandling.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="LinearAlgebraTests\Single\SymmetricDenseMatrixTests.cs" />
<Compile Include="LinearAlgebraTests\Single\SymmetricMatrixTests.Arithmetic.cs" />
<Compile Include="LinearAlgebraTests\Single\SymmetricMatrixTests.cs" />
<Compile Include="LinearAlgebraTests\Single\UserDefinedMatrix.cs">
<SubType>Code</SubType>
</Compile>

Loading…
Cancel
Save