From a5b9e7eabc3865feb4eae1bb38cf467cf3c7d34b Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 26 Nov 2012 15:11:10 +0200 Subject: [PATCH] Add Complex32 version of Symmetric matrix Signed-off-by: Alexander Karatarakis --- .../LinearAlgebra/Complex/SymmetricMatrix.cs | 1 - .../LinearAlgebra/Complex32/SquareMatrix.cs | 62 ++ .../Complex32/SymmetricDenseMatrix.cs | 767 ++++++++++++++++++ .../Complex32/SymmetricMatrix.cs | 711 ++++++++++++++++ src/Numerics/Numerics.csproj | 3 + 5 files changed, 1543 insertions(+), 1 deletion(-) create mode 100644 src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs create mode 100644 src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs create mode 100644 src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs diff --git a/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs index 2b29f837..ba6d712f 100644 --- a/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex/SymmetricMatrix.cs @@ -33,7 +33,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex using Properties; using Storage; - /// /// Abstract class for symmetric matrices. /// diff --git a/src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs new file mode 100644 index 00000000..337a5118 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex32/SquareMatrix.cs @@ -0,0 +1,62 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// http://mathnetnumerics.codeplex.com +// Copyright (c) 2009-2010 Math.NET +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex32 +{ + using System; + using Numerics; + using Properties; + using Storage; + + /// + /// Abstract class for square matrices. + /// + [Serializable] + public abstract class SquareMatrix : Matrix + { + /// + /// Number of rows or columns. + /// + protected readonly int Order; + + /// + /// Initializes a new instance of the class. + /// + /// + /// If the matrix is not square. + /// + protected SquareMatrix(MatrixStorage storage) + : base(storage) + { + if (storage.RowCount != storage.ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSquare); + } + + Order = storage.RowCount; + } + } +} diff --git a/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs new file mode 100644 index 00000000..7e62c4d7 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex32/SymmetricDenseMatrix.cs @@ -0,0 +1,767 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// http://mathnetnumerics.codeplex.com +// Copyright (c) 2009-2010 Math.NET +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex32 +{ + using System; + using Numerics; + using Generic; + using MathNet.Numerics.Distributions; + using MathNet.Numerics.LinearAlgebra.Storage.Indexers.Static; + using Properties; + using Storage; + + /// + /// A Symmetric Matrix class with dense storage. + /// + /// The underlying storage is a one dimensional array in column-major order. + /// The Upper Triangle is stored(it is equal to the Lower Triangle) + [Serializable] + public class SymmetricDenseMatrix : SymmetricMatrix + { + readonly DenseColumnMajorSymmetricMatrixStorage _storage; + + /// + /// Gets the matrix's data. + /// + /// The matrix's data. + readonly Complex32[] _data; + + internal SymmetricDenseMatrix(DenseColumnMajorSymmetricMatrixStorage storage) + : base(storage) + { + _storage = storage; + _data = _storage.Data; + } + + /// + /// Initializes a new instance of the class. This matrix is square with a given size. + /// + /// The order of the matrix. + /// + /// If is less than one. + /// + public SymmetricDenseMatrix(int order) + : this(new DenseColumnMajorSymmetricMatrixStorage(order)) + { + } + + /// + /// Initializes a new instance of the class with all entries set to a particular value. + /// + /// + /// The order of the matrix. + /// + /// The value which we assign to each element of the matrix. + public SymmetricDenseMatrix(int order, Complex32 value) + : this(order) + { + for (var i = 0; i < _data.Length; i++) + { + _data[i] = value; + } + } + + /// + /// Initializes a new instance of the class from a one dimensional array. This constructor + /// will reference the one dimensional array and not copy it. + /// + /// The size of the square matrix. + /// + /// 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 + /// + /// + /// If does not represent a packed array. + /// + public SymmetricDenseMatrix(int order, Complex32[] array) + : this(new DenseColumnMajorSymmetricMatrixStorage(order, array)) + { + } + + /// + /// Initializes a new instance of the class from a 2D array. This constructor + /// will allocate a completely new memory block for storing the symmetric dense matrix. + /// + /// The 2D array to create this matrix from. + /// + /// If is not a square array. + /// + /// + /// If is not a symmetric array. + /// + 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]; + } + } + } + + /// + /// Initializes a new instance of the class, copying + /// the values from the given matrix. Matrix must be Symmetric. + /// + /// The matrix to copy. + /// + /// If is not a square matrix. + /// + /// + /// If is not a symmetric matrix. + /// + public SymmetricDenseMatrix(Matrix 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); + } + } + + /// + /// Gets the matrix's data. + /// + /// The matrix's data. + public Complex32[] Data + { + get { return _data; } + } + + /// + /// Creates a SymmetricDenseMatrix for the given number of rows and columns. + /// If rows and columns are not equal, returns a DenseMatrix instead. + /// + /// + /// The number of rows. + /// + /// + /// The number of columns. + /// + /// True if all fields must be mutable (e.g. not a diagonal matrix). + /// + /// A DenseMatrix or SymmetricDenseMatrix with the given dimensions. + /// + /// /// + /// If is not equal to . + /// Symmetric arrays are always square + /// + public override Matrix CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false) + { + if (numberOfRows != numberOfColumns || fullyMutable) + { + return new DenseMatrix(numberOfRows, numberOfColumns); + } + + return new SymmetricDenseMatrix(numberOfRows); + } + + /// + /// Creates a with a the given dimension. + /// + /// The size of the vector. + /// True if all fields must be mutable. + /// + /// A with the given dimension. + /// + public override Vector CreateVector(int size, bool fullyMutable = false) + { + return new DenseVector(size); + } + + #region Static constructors for special matrices. + + /// + /// Initializes a square with all zero's except for ones on the diagonal. + /// + /// the size of the square matrix. + /// A symmetric dense identity matrix. + /// + /// If is less than one. + /// + 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 + + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The matrix to store the result of add + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + protected override void DoAdd(Matrix other, Matrix 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); + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The matrix to store the result of the subtraction. + protected override void DoSubtract(Matrix other, Matrix 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); + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// The scalar to multiply the matrix with. + /// The matrix to store the result of the multiplication. + protected override void DoMultiply(Complex32 scalar, Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + if (denseResult == null) + { + base.DoMultiply(scalar, result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(scalar, _data, denseResult._data); + } + } + + /// + /// Multiplies this matrix with a vector and places the results into the result vector. + /// + /// The vector to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Vector rightSide, Vector 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); + } + } + + /// + /// Multiplies this matrix with another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoMultiply(Matrix other, Matrix 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); + } + } + + /// + /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix. + /// + /// The matrix to multiply with. + /// The result of the multiplication. + protected override void DoTransposeAndMultiply(Matrix other, Matrix 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); + } + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// The result of the negation. + protected override void DoNegate(Matrix result) + { + var denseResult = result as SymmetricDenseMatrix; + + if (denseResult == null) + { + base.DoNegate(result); + } + else + { + Control.LinearAlgebraProvider.ScaleArray(-1, _data, denseResult._data); + } + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise multiply with this one. + /// The matrix to store the result of the pointwise multiplication. + protected override void DoPointwiseMultiply(Matrix other, Matrix 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); + } + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// The matrix to pointwise divide this one by. + /// The matrix to store the result of the pointwise division. + protected override void DoPointwiseDivide(Matrix other, Matrix 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); + } + } + + /// + /// Returns a new matrix containing the lower triangle of this matrix. + /// + /// The lower triangle of this matrix. + public override Matrix 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; + } + + /// + /// Returns a new matrix containing the lower triangle of this matrix. The new matrix + /// does not contain the diagonal elements of this matrix. + /// + /// The lower triangle of this matrix. + public override Matrix 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; + } + + /// + /// Returns a new matrix containing the upper triangle of this matrix. + /// + /// The upper triangle of this matrix. + public override Matrix 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; + } + + /// + /// Returns a new matrix containing the upper triangle of this matrix. The new matrix + /// does not contain the diagonal elements of this matrix. + /// + /// The upper triangle of this matrix. + public override Matrix 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; + } + + /// + /// Computes the trace of this matrix. + /// + /// The trace of this matrix + 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; + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix 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()); + } + } + } + + /// + /// Populates a symmetric matrix with random elements. + /// + /// The symmetric matrix to populate. + /// Continuous Random Distribution to generate elements from. + protected override void DoRandom(Matrix 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(); + } + } + } + + /// + /// Adds two matrices together and returns the results. + /// + /// This operator will allocate new memory for the result. It will + /// choose the representation of either or depending on which + /// is denser. + /// The left matrix to add. + /// The right matrix to add. + /// The result of the addition. + /// If and don't have the same dimensions. + /// If or is . + 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); + } + + /// + /// Returns a Matrix containing the same values of . + /// + /// The matrix to get the values from. + /// A matrix containing a the same values as . + /// If is . + public static SymmetricDenseMatrix operator +(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Clone(); + } + + /// + /// Subtracts two matrices together and returns the results. + /// + /// This operator will allocate new memory for the result. It will + /// choose the representation of either or depending on which + /// is denser. + /// The left matrix to subtract. + /// The right matrix to subtract. + /// The result of the addition. + /// If and don't have the same dimensions. + /// If or is . + 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); + } + + /// + /// Negates each element of the matrix. + /// + /// The matrix to negate. + /// A matrix containing the negated values. + /// If is . + public static SymmetricDenseMatrix operator -(SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Negate(); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(SymmetricDenseMatrix leftSide, Complex32 rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator *(Complex32 leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (SymmetricDenseMatrix)rightSide.Multiply(leftSide); + } + + /// + /// Multiplies two matrices. + /// + /// This operator will allocate new memory for the result. It will + /// choose the representation of either or depending on which + /// is denser. + /// The left matrix to multiply. + /// The right matrix to multiply. + /// The result of multiplication. + /// If or is . + /// If the dimensions of or don't conform. + 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); + } + + /// + /// Multiplies a Matrix and a Vector. + /// + /// The matrix to multiply. + /// The vector to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(SymmetricDenseMatrix leftSide, DenseVector rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (DenseVector)leftSide.Multiply(rightSide); + } + + /// + /// Multiplies a Vector and a Matrix. + /// + /// The vector to multiply. + /// The matrix to multiply. + /// The result of multiplication. + /// If or is . + public static DenseVector operator *(DenseVector leftSide, SymmetricDenseMatrix rightSide) + { + if (rightSide == null) + { + throw new ArgumentNullException("rightSide"); + } + + return (DenseVector)rightSide.LeftMultiply(leftSide); + } + + /// + /// Multiplies a Matrix by a constant and returns the result. + /// + /// The matrix to multiply. + /// The constant to multiply the matrix by. + /// The result of the multiplication. + /// If is . + public static SymmetricDenseMatrix operator %(SymmetricDenseMatrix leftSide, Complex32 rightSide) + { + if (leftSide == null) + { + throw new ArgumentNullException("leftSide"); + } + + return (SymmetricDenseMatrix)leftSide.Modulus(rightSide); + } + } +} \ No newline at end of file diff --git a/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs new file mode 100644 index 00000000..099df458 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex32/SymmetricMatrix.cs @@ -0,0 +1,711 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// http://mathnetnumerics.codeplex.com +// Copyright (c) 2009-2010 Math.NET +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex32 +{ + using System; + using Numerics; + using Generic; + using Distributions; + using Properties; + using Storage; + + /// + /// Abstract class for symmetric matrices. + /// + [Serializable] + public abstract class SymmetricMatrix : SquareMatrix + { + /// + /// Initializes a new instance of the class. + /// + protected SymmetricMatrix(MatrixStorage storage) + : base(storage) + { + } + + /// + /// Returns a value indicating whether the array is symmetric. + /// + /// + /// The array to check for symmetry. + /// + /// + /// True is array is symmetric, false if not symmetric. + /// + 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; + } + + /// + /// Gets a value indicating whether this matrix is symmetric. + /// + public override sealed bool IsSymmetric + { + get + { + return true; + } + } + + /// + /// Returns the transpose of this matrix. The transpose is equal and this method returns a reference to this matrix. + /// + /// + /// The transpose of this matrix. + /// + public override sealed Matrix Transpose() + { + return this.Clone(); + } + + /// + /// Adds another matrix to this matrix. + /// + /// The matrix to add to this matrix. + /// The result of the addition. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Add(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoAdd(other, result); + return result; + } + + /// + /// Adds another matrix to this matrix. + /// + /// + /// The matrix to add to this matrix. + /// + /// + /// The matrix to store the result of the addition. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoAdd(Matrix other, Matrix 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)); + } + } + } + } + + /// + /// Subtracts another matrix from this matrix. + /// + /// The matrix to subtract. + /// The result of the subtraction. + /// If the other matrix is . + /// If the two matrices don't have the same dimensions. + public override Matrix Subtract(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + DoSubtract(other, result); + return result; + } + + + /// + /// Subtracts another matrix from this matrix. + /// + /// + /// The matrix to subtract to this matrix. + /// + /// + /// The matrix to store the result of subtraction. + /// + /// + /// If the other matrix is . + /// + /// + /// If the two matrices don't have the same dimensions. + /// + protected override void DoSubtract(Matrix other, Matrix 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)); + } + } + } + } + + /// + /// Multiplies each element of the matrix by a scalar and places results into the result matrix. + /// + /// + /// The scalar to multiply the matrix with. + /// + /// + /// The matrix to store the result of the multiplication. + /// + protected override void DoMultiply(Complex32 scalar, Matrix 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); + } + } + } + } + + /// + /// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix. + /// + /// + /// The matrix to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Matrix other, Matrix result) + { + DoMultiply(other, result); + } + + /// + /// Multiplies the transpose of this matrix with a vector and places the results into the result vector. + /// + /// + /// The vector to multiply with. + /// + /// + /// The result of the multiplication. + /// + protected override sealed void DoTransposeThisAndMultiply(Vector rightSide, Vector result) + { + DoMultiply(rightSide, result); + } + + /// + /// Negate each element of this matrix and place the results into the result matrix. + /// + /// + /// The result of the negation. + /// + protected override void DoNegate(Matrix 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); + } + } + } + } + + /// + /// Pointwise multiplies this matrix with another matrix. + /// + /// The matrix to pointwise multiply with this one. + /// If the other matrix is . + /// If this matrix and are not the same size. + /// A new matrix that is the pointwise multiplication of this matrix and . + public override Matrix PointwiseMultiply(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other, "other"); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseMultiply(other, result); + return result; + } + + /// + /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise multiply with this one. + /// + /// + /// The matrix to store the result of the pointwise multiplication. + /// + protected override void DoPointwiseMultiply(Matrix other, Matrix 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)); + } + } + } + } + + /// + /// Pointwise divide this matrix by another matrix. + /// + /// The matrix to pointwise subtract this one by. + /// If the other matrix is . + /// If this matrix and are not the same size. + /// A new matrix that is the pointwise division of this matrix and . + public override Matrix PointwiseDivide(Matrix other) + { + if (other == null) + { + throw new ArgumentNullException("other"); + } + + if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) + { + throw DimensionsDontMatch(this, other); + } + + Matrix result; + if (other is SymmetricMatrix) + { + result = CreateMatrix(RowCount, ColumnCount); + } + else + { + result = CreateMatrix(RowCount, ColumnCount, true); + } + + PointwiseDivide(other, result); + return result; + } + + /// + /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. + /// + /// + /// The matrix to pointwise divide this one by. + /// + /// + /// The matrix to store the result of the pointwise division. + /// + protected override void DoPointwiseDivide(Matrix other, Matrix 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)); + } + } + } + } + + /// + /// Computes the modulus for each element of the matrix. + /// + /// + /// The divisor to use. + /// + /// + /// Matrix to store the results in. + /// + protected override void DoModulus(Complex32 divisor, Matrix result) + { + throw new NotImplementedException(); + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix 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())); + } + } + } + } + + /// + /// Populates a matrix with random elements. + /// + /// + /// The matrix to populate. + /// + /// + /// Continuous Random Distribution to generate elements from. + /// + protected override void DoRandom(Matrix 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()); + } + } + } + } + + /// + /// Creates a new matrix and inserts the given column at the given index. + /// + /// The index of where to insert the column. + /// The column to insert. + /// A new matrix with the inserted column. + /// If is . + /// If is < zero or > the number of columns. + /// If the size of != the number of rows. + public override Matrix InsertColumn(int columnIndex, Vector column) + { + throw new InvalidOperationException("Inserting a column is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given array to the specified column. The changes retain the symmetry of the matrix. + /// + /// The column to copy the values to. + /// The array to copy the values from. + /// If is . + /// If is less than zero, + /// or greater than or equal to the number of columns. + /// If the size of does not + /// equal the number of rows of this Matrix. + /// If the size of does not + /// equal the number of rows of this Matrix. + public override void SetColumn(int columnIndex, Complex32[] column) + { + if (columnIndex < 0 || columnIndex >= ColumnCount) + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + + if (column == null) + { + throw new ArgumentNullException("column"); + } + + if (column.Length != RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "column"); + } + + for (var i = 0; i < columnIndex; i++) + { + At(i, columnIndex, column[i]); + } + } + + /// + /// Copies the values of the given Vector to the specified column. The changes retain the symmetry of the matrix. + /// + /// The column to copy the values to. + /// The vector to copy the values from. + /// If is . + /// If is less than zero, + /// or greater than or equal to the number of columns. + /// If the size of does not + /// equal the number of rows of this Matrix. + public override void SetColumn(int columnIndex, Vector column) + { + if (columnIndex < 0 || columnIndex >= ColumnCount) + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + + if (column == null) + { + throw new ArgumentNullException("column"); + } + + if (column.Count != RowCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "column"); + } + + for (var i = 0; i < columnIndex; i++) + { + At(i, columnIndex, column[i]); + } + } + + /// + /// Creates a new matrix and inserts the given row at the given index. + /// + /// The index of where to insert the row. + /// The row to insert. + /// A new matrix with the inserted column. + /// If is . + /// If is < zero or > the number of rows. + /// If the size of != the number of columns. + public override Matrix InsertRow(int rowIndex, Vector row) + { + throw new InvalidOperationException("Inserting a row is not supported on a symmetric matrix. Symmetric matrices are square"); + } + + /// + /// Copies the values of the given Vector to the specified row. + /// + /// The row to copy the values to. + /// The vector to copy the values from. + /// If is . + /// If is less than zero, + /// or greater than or equal to the number of rows. + /// If the size of does not + /// equal the number of columns of this Matrix. + public override void SetRow(int rowIndex, Vector row) + { + if (rowIndex < 0 || rowIndex >= RowCount) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (row == null) + { + throw new ArgumentNullException("row"); + } + + if (row.Count != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } + + /// + /// Copies the values of the given array to the specified row. + /// + /// The row to copy the values to. + /// The array to copy the values from. + /// If is . + /// If is less than zero, + /// or greater than or equal to the number of rows. + /// If the size of does not + /// equal the number of columns of this Matrix. + public override void SetRow(int rowIndex, Complex32[] row) + { + if (rowIndex < 0 || rowIndex >= RowCount) + { + throw new ArgumentOutOfRangeException("rowIndex"); + } + + if (row == null) + { + throw new ArgumentNullException("row"); + } + + if (row.Length != ColumnCount) + { + throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); + } + + for (var i = rowIndex; i < ColumnCount; i++) + { + At(rowIndex, i, row[i]); + } + } + } +} diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index b0666824..6ea108fb 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -140,6 +140,9 @@ + + +