// // 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-2013 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.Complex { using Algorithms.LinearAlgebra; using Distributions; using Generic; using Properties; using Storage; using System; using System.Diagnostics; using System.Numerics; /// /// A Matrix class with dense storage. The underlying storage is a one dimensional array in column-major order. /// [Serializable] [DebuggerDisplay("DenseMatrix {RowCount}x{ColumnCount}-Complex")] public class DenseMatrix : Matrix { /// /// Number of rows. /// /// Using this instead of the RowCount property to speed up calculating /// a matrix index in the data array. readonly int _rowCount; /// /// Number of columns. /// /// Using this instead of the ColumnCount property to speed up calculating /// a matrix index in the data array. readonly int _columnCount; /// /// Gets the matrix's data. /// /// The matrix's data. readonly Complex[] _values; /// /// Create a new dense matrix straight from an initialized matrix storage instance. /// The storage is used directly without copying. /// Intended for advanced scenarios where you're working directly with /// storage for performance or interop reasons. /// public DenseMatrix(DenseColumnMajorMatrixStorage storage) : base(storage) { _rowCount = storage.RowCount; _columnCount = storage.ColumnCount; _values = storage.Data; } /// /// Create a new square dense matrix with the given number of rows and columns. /// All cells of the matrix will be initialized to zero. /// Zero-length matrices are not supported. /// /// If the order is less than one. public DenseMatrix(int order) : this(new DenseColumnMajorMatrixStorage(order, order)) { } /// /// Create a new dense matrix with the given number of rows and columns. /// All cells of the matrix will be initialized to zero. /// Zero-length matrices are not supported. /// /// If the row or column count is less than one. public DenseMatrix(int rows, int columns) : this(new DenseColumnMajorMatrixStorage(rows, columns)) { } /// /// Create a new dense matrix with the given number of rows and columns. /// All cells of the matrix will be initialized to the provided value. /// Zero-length matrices are not supported. /// /// If the row or column count is less than one. public DenseMatrix(int rows, int columns, Complex value) : this(rows, columns) { for (var i = 0; i < _values.Length; i++) { _values[i] = value; } } /// /// Create a new dense matrix with the given number of rows and columns directly binding to a raw array. /// The array is assumed to be in column-major order and is used directly without copying. /// Very efficient, but changes to the array and the matrix will affect each other. /// /// public DenseMatrix(int rows, int columns, Complex[] storage) : this(new DenseColumnMajorMatrixStorage(rows, columns, storage)) { } /// /// Create a new dense matrix as a copy of the given two-dimensional array. /// This new matrix will be independent from the provided array. /// A new memory block will be allocated for storing the matrix. /// public DenseMatrix(Complex[,] array) : this(array.GetLength(0), array.GetLength(1)) { for (var i = 0; i < _rowCount; i++) { for (var j = 0; j < _columnCount; j++) { _values[(j * _rowCount) + i] = array[i, j]; } } } /// /// Create a new dense matrix as a copy of the given other matrix. /// This new matrix will be independent from the other matrix. /// A new memory block will be allocated for storing the matrix. /// public DenseMatrix(Matrix matrix) : this(matrix.RowCount, matrix.ColumnCount) { matrix.Storage.CopyToUnchecked(Storage, skipClearing: true); } /// /// Create a new dense matrix with values sampled from the provided random distribution. /// public static DenseMatrix CreateRandom(int rows, int columns, IContinuousDistribution distribution) { var storage = new DenseColumnMajorMatrixStorage(rows, columns); for (var i = 0; i < storage.Data.Length; i++) { storage.Data[i] = new Complex(distribution.Sample(), distribution.Sample()); } return new DenseMatrix(storage); } /// /// Gets the matrix's data. /// /// The matrix's data. [Obsolete("Use Values instead. Scheduled for removal in v3.0.")] public Complex[] Data { get { return _values; } } /// /// Gets the matrix's data. /// /// The matrix's data. public Complex[] Values { get { return _values; } } /// /// Creates a DenseMatrix for the given number of rows and columns. /// /// The number of rows. /// The number of columns. /// True if all fields must be mutable (e.g. not a diagonal matrix). /// /// A DenseMatrix with the given dimensions. /// public override Matrix CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false) { return new DenseMatrix(numberOfRows, numberOfColumns); } /// /// 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); } /// /// Returns the transpose of this matrix. /// /// The transpose of this matrix. public override Matrix Transpose() { var ret = new DenseMatrix(_columnCount, _rowCount); for (var j = 0; j < _columnCount; j++) { var index = j * _rowCount; for (var i = 0; i < _rowCount; i++) { ret._values[(i * _columnCount) + j] = _values[index + i]; } } return ret; } /// Calculates the L1 norm. /// The L1 norm of the matrix. public override Complex L1Norm() { return Control.LinearAlgebraProvider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _values); } /// Calculates the Frobenius norm of this matrix. /// The Frobenius norm of this matrix. public override Complex FrobeniusNorm() { return Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _values); } /// Calculates the infinity norm of this matrix. /// The infinity norm of this matrix. public override Complex InfinityNorm() { return Control.LinearAlgebraProvider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _values); } #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 dense identity matrix. /// /// If is less than one. /// public static DenseMatrix Identity(int order) { var m = new DenseMatrix(order); for (var i = 0; i < order; i++) { m._values[(i * order) + i] = 1.0; } return m; } #endregion /// /// 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(Complex scalar, Matrix result) { var denseResult = result as DenseMatrix; if (denseResult == null) { base.DoMultiply(scalar, result); } else { Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult._values); } } /// /// 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 { Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate( Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose, 1.0, _values, _rowCount, _columnCount, denseRight.Values, denseRight.Count, 1, 0.0, denseResult.Values); } } /// /// 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 DenseMatrix; var denseResult = result as DenseMatrix; if (denseOther == null || denseResult == null) { base.DoMultiply(other, result); } else { Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate( Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.DontTranspose, 1.0, _values, _rowCount, _columnCount, denseOther._values, denseOther._rowCount, denseOther._columnCount, 0.0, denseResult._values); } } /// /// 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 DenseMatrix; var denseResult = result as DenseMatrix; if (denseOther == null || denseResult == null) { base.DoTransposeAndMultiply(other, result); } else { Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate( Algorithms.LinearAlgebra.Transpose.DontTranspose, Algorithms.LinearAlgebra.Transpose.Transpose, 1.0, _values, _rowCount, _columnCount, denseOther._values, denseOther._rowCount, denseOther._columnCount, 0.0, denseResult._values); } } /// /// 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 void DoTransposeThisAndMultiply(Vector rightSide, Vector result) { var denseRight = rightSide as DenseVector; var denseResult = result as DenseVector; if (denseRight == null || denseResult == null) { base.DoTransposeThisAndMultiply(rightSide, result); } else { Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate( Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.DontTranspose, 1.0, _values, _rowCount, _columnCount, denseRight.Values, denseRight.Count, 1, 0.0, denseResult.Values); } } /// /// 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 void DoTransposeThisAndMultiply(Matrix other, Matrix result) { var denseOther = other as DenseMatrix; var denseResult = result as DenseMatrix; if (denseOther == null || denseResult == null) { base.DoTransposeThisAndMultiply(other, result); } else { Control.LinearAlgebraProvider.MatrixMultiplyWithUpdate( Algorithms.LinearAlgebra.Transpose.Transpose, Algorithms.LinearAlgebra.Transpose.DontTranspose, 1.0, _values, _rowCount, _columnCount, denseOther._values, denseOther._rowCount, denseOther._columnCount, 0.0, denseResult._values); } } /// /// 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 DenseMatrix; if (denseResult == null) { base.DoNegate(result); } else { Control.LinearAlgebraProvider.ScaleArray(-1, _values, denseResult._values); } } /// /// 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 DenseMatrix; var denseResult = result as DenseMatrix; if (denseOther == null || denseResult == null) { base.DoPointwiseMultiply(other, result); } else { Control.LinearAlgebraProvider.PointWiseMultiplyArrays(_values, denseOther._values, denseResult._values); } } /// /// 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 DenseMatrix; var denseResult = result as DenseMatrix; if (denseOther == null || denseResult == null) { base.DoPointwiseDivide(other, result); } else { Control.LinearAlgebraProvider.PointWiseDivideArrays(_values, denseOther._values, denseResult._values); } } /// /// 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 DenseMatrix; var denseResult = result as DenseMatrix; if (denseOther == null || denseResult == null) { base.DoAdd(other, result); } else { Control.LinearAlgebraProvider.AddArrays(_values, denseOther._values, denseResult._values); } } /// /// 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 DenseMatrix; var denseResult = result as DenseMatrix; if (denseOther == null || denseResult == null) { base.DoSubtract(other, result); } else { Control.LinearAlgebraProvider.SubtractArrays(_values, denseOther._values, denseResult._values); } } /// /// Returns the conjugate transpose of this matrix. /// /// The conjugate transpose of this matrix. public override Matrix ConjugateTranspose() { var ret = new DenseMatrix(_columnCount, _rowCount); for (var j = 0; j < _columnCount; j++) { var index = j * _rowCount; for (var i = 0; i < _rowCount; i++) { ret._values[(i * _columnCount) + j] = _values[index + i].Conjugate(); } } return ret; } /// /// Computes the trace of this matrix. /// /// The trace of this matrix /// If the matrix is not square public override Complex Trace() { if (_rowCount != _columnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare); } var sum = Complex.Zero; for (var i = 0; i < _rowCount; i++) { sum += _values[(i * _rowCount) + i]; } return sum; } /// /// 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 DenseMatrix operator +(DenseMatrix leftSide, DenseMatrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } if (leftSide == null) { throw new ArgumentNullException("leftSide"); } if (leftSide._rowCount != rightSide._rowCount || leftSide._columnCount != rightSide._columnCount) { throw DimensionsDontMatch(leftSide, rightSide); } return (DenseMatrix)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 DenseMatrix operator +(DenseMatrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } return (DenseMatrix)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 DenseMatrix operator -(DenseMatrix leftSide, DenseMatrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } if (leftSide == null) { throw new ArgumentNullException("leftSide"); } if (leftSide._rowCount != rightSide._rowCount || leftSide._columnCount != rightSide._columnCount) { throw DimensionsDontMatch(leftSide, rightSide); } return (DenseMatrix)leftSide.Subtract(rightSide); } /// /// Negates each element of the matrix. /// /// The matrix to negate. /// A matrix containing the negated values. /// If is . public static DenseMatrix operator -(DenseMatrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } return (DenseMatrix)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 DenseMatrix operator *(DenseMatrix leftSide, Complex rightSide) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } return (DenseMatrix)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 DenseMatrix operator *(Complex leftSide, DenseMatrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } return (DenseMatrix)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 DenseMatrix operator *(DenseMatrix leftSide, DenseMatrix rightSide) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } if (rightSide == null) { throw new ArgumentNullException("rightSide"); } if (leftSide._columnCount != rightSide._rowCount) { throw DimensionsDontMatch(leftSide, rightSide); } return (DenseMatrix)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 *(DenseMatrix 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, DenseMatrix 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 DenseMatrix operator %(DenseMatrix leftSide, Complex rightSide) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } return (DenseMatrix)leftSide.Modulus(rightSide); } } }