// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // 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. // using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using IStation.Numerics.Distributions; using IStation.Numerics.LinearAlgebra.Complex32.Factorization; using IStation.Numerics.LinearAlgebra.Factorization; using IStation.Numerics.LinearAlgebra.Storage; using IStation.Numerics.Providers.LinearAlgebra; using IStation.Numerics.Threading; namespace IStation.Numerics.LinearAlgebra.Complex32 { using Numerics; /// /// A Matrix class with dense storage. The underlying storage is a one dimensional array in column-major order (column by column). /// [Serializable] [DebuggerDisplay("DenseMatrix {RowCount}x{ColumnCount}-Complex32")] 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. private readonly int _rowCount; /// /// Number of columns. /// /// Using this instead of the ColumnCount property to speed up calculating /// a matrix index in the data array. private readonly int _columnCount; /// /// Gets the matrix's data. /// /// The matrix's data. readonly Complex32[] _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. /// /// 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. /// /// 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 directly binding to a raw array. /// The array is assumed to be in column-major order (column by column) 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, Complex32[] storage) : this(new DenseColumnMajorMatrixStorage(rows, columns, storage)) { } /// /// 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 static DenseMatrix OfMatrix(Matrix matrix) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfMatrix(matrix.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 static DenseMatrix OfArray(Complex32[,] array) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfArray(array)); } /// /// Create a new dense matrix as a copy of the given indexed enumerable. /// Keys must be provided at most once, zero is assumed if a key is omitted. /// This new matrix will be independent from the enumerable. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfIndexed(int rows, int columns, IEnumerable> enumerable) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfIndexedEnumerable(rows, columns, enumerable)); } /// /// Create a new dense matrix as a copy of the given enumerable. /// The enumerable is assumed to be in column-major order (column by column). /// This new matrix will be independent from the enumerable. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfColumnMajor(int rows, int columns, IEnumerable columnMajor) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfColumnMajorEnumerable(rows, columns, columnMajor)); } /// /// Create a new dense matrix as a copy of the given enumerable of enumerable columns. /// Each enumerable in the master enumerable specifies a column. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfColumns(IEnumerable> data) { return OfColumnArrays(data.Select(v => v.ToArray()).ToArray()); } /// /// Create a new dense matrix as a copy of the given enumerable of enumerable columns. /// Each enumerable in the master enumerable specifies a column. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfColumns(int rows, int columns, IEnumerable> data) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfColumnEnumerables(rows, columns, data)); } /// /// Create a new dense matrix as a copy of the given column arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfColumnArrays(params Complex32[][] columns) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfColumnArrays(columns)); } /// /// Create a new dense matrix as a copy of the given column arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfColumnArrays(IEnumerable columns) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfColumnArrays((columns as Complex32[][]) ?? columns.ToArray())); } /// /// Create a new dense matrix as a copy of the given column vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfColumnVectors(params Vector[] columns) { var storage = new VectorStorage[columns.Length]; for (int i = 0; i < columns.Length; i++) { storage[i] = columns[i].Storage; } return new DenseMatrix(DenseColumnMajorMatrixStorage.OfColumnVectors(storage)); } /// /// Create a new dense matrix as a copy of the given column vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfColumnVectors(IEnumerable> columns) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfColumnVectors(columns.Select(c => c.Storage).ToArray())); } /// /// Create a new dense matrix as a copy of the given enumerable of enumerable rows. /// Each enumerable in the master enumerable specifies a row. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfRows(IEnumerable> data) { return OfRowArrays(data.Select(v => v.ToArray()).ToArray()); } /// /// Create a new dense matrix as a copy of the given enumerable of enumerable rows. /// Each enumerable in the master enumerable specifies a row. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfRows(int rows, int columns, IEnumerable> data) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfRowEnumerables(rows, columns, data)); } /// /// Create a new dense matrix as a copy of the given row arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfRowArrays(params Complex32[][] rows) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfRowArrays(rows)); } /// /// Create a new dense matrix as a copy of the given row arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfRowArrays(IEnumerable rows) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfRowArrays((rows as Complex32[][]) ?? rows.ToArray())); } /// /// Create a new dense matrix as a copy of the given row vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfRowVectors(params Vector[] rows) { var storage = new VectorStorage[rows.Length]; for (int i = 0; i < rows.Length; i++) { storage[i] = rows[i].Storage; } return new DenseMatrix(DenseColumnMajorMatrixStorage.OfRowVectors(storage)); } /// /// Create a new dense matrix as a copy of the given row vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfRowVectors(IEnumerable> rows) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfRowVectors(rows.Select(r => r.Storage).ToArray())); } /// /// Create a new dense matrix with the diagonal as a copy of the given vector. /// This new matrix will be independent from the vector. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfDiagonalVector(Vector diagonal) { var m = new DenseMatrix(diagonal.Count, diagonal.Count); m.SetDiagonal(diagonal); return m; } /// /// Create a new dense matrix with the diagonal as a copy of the given vector. /// This new matrix will be independent from the vector. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfDiagonalVector(int rows, int columns, Vector diagonal) { var m = new DenseMatrix(rows, columns); m.SetDiagonal(diagonal); return m; } /// /// Create a new dense matrix with the diagonal as a copy of the given array. /// This new matrix will be independent from the array. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfDiagonalArray(Complex32[] diagonal) { var m = new DenseMatrix(diagonal.Length, diagonal.Length); m.SetDiagonal(diagonal); return m; } /// /// Create a new dense matrix with the diagonal as a copy of the given array. /// This new matrix will be independent from the array. /// A new memory block will be allocated for storing the matrix. /// public static DenseMatrix OfDiagonalArray(int rows, int columns, Complex32[] diagonal) { var m = new DenseMatrix(rows, columns); m.SetDiagonal(diagonal); return m; } /// /// Create a new dense matrix and initialize each value to the same provided value. /// public static DenseMatrix Create(int rows, int columns, Complex32 value) { if (value == Complex32.Zero) return new DenseMatrix(rows, columns); return new DenseMatrix(DenseColumnMajorMatrixStorage.OfValue(rows, columns, value)); } /// /// Create a new dense matrix and initialize each value using the provided init function. /// public static DenseMatrix Create(int rows, int columns, Func init) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfInit(rows, columns, init)); } /// /// Create a new diagonal dense matrix and initialize each diagonal value to the same provided value. /// public static DenseMatrix CreateDiagonal(int rows, int columns, Complex32 value) { if (value == Complex32.Zero) return new DenseMatrix(rows, columns); return new DenseMatrix(DenseColumnMajorMatrixStorage.OfDiagonalInit(rows, columns, i => value)); } /// /// Create a new diagonal dense matrix and initialize each diagonal value using the provided init function. /// public static DenseMatrix CreateDiagonal(int rows, int columns, Func init) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfDiagonalInit(rows, columns, init)); } /// /// Create a new square sparse identity matrix where each diagonal value is set to One. /// public static DenseMatrix CreateIdentity(int order) { return new DenseMatrix(DenseColumnMajorMatrixStorage.OfDiagonalInit(order, order, i => One)); } /// /// Create a new dense matrix with values sampled from the provided random distribution. /// public static DenseMatrix CreateRandom(int rows, int columns, IContinuousDistribution distribution) { return new DenseMatrix(new DenseColumnMajorMatrixStorage(rows, columns, Generate.RandomComplex32(rows*columns, distribution))); } /// /// Gets the matrix's data. /// /// The matrix's data. public Complex32[] Values => _values; /// Calculates the induced L1 norm of this matrix. /// The maximum absolute column sum of the matrix. public override double L1Norm() { return LinearAlgebraControl.Provider.MatrixNorm(Norm.OneNorm, _rowCount, _columnCount, _values); } /// Calculates the induced infinity norm of this matrix. /// The maximum absolute row sum of the matrix. public override double InfinityNorm() { return LinearAlgebraControl.Provider.MatrixNorm(Norm.InfinityNorm, _rowCount, _columnCount, _values); } /// Calculates the entry-wise Frobenius norm of this matrix. /// The square root of the sum of the squared values. public override double FrobeniusNorm() { return LinearAlgebraControl.Provider.MatrixNorm(Norm.FrobeniusNorm, _rowCount, _columnCount, _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) { if (result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.ScaleArray(-1, _values, denseResult._values); return; } base.DoNegate(result); } /// /// Complex conjugates each element of this matrix and place the results into the result matrix. /// /// The result of the conjugation. protected override void DoConjugate(Matrix result) { if (result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.ConjugateArray(_values, denseResult._values); return; } base.DoConjugate(result); } /// /// Add a scalar to each element of the matrix and stores the result in the result vector. /// /// The scalar to add. /// The matrix to store the result of the addition. protected override void DoAdd(Complex32 scalar, Matrix result) { if (result is DenseMatrix denseResult) { CommonParallel.For(0, _values.Length, 4096, (a, b) => { var v = denseResult._values; for (int i = a; i < b; i++) { v[i] = _values[i] + scalar; } }); } else { base.DoAdd(scalar, result); } } /// /// 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) { // dense + dense = dense if (other.Storage is DenseColumnMajorMatrixStorage denseOther && result.Storage is DenseColumnMajorMatrixStorage denseResult) { LinearAlgebraControl.Provider.AddArrays(_values, denseOther.Data, denseResult.Data); return; } // dense + diagonal = any if (other.Storage is DiagonalMatrixStorage diagonalOther) { Storage.CopyToUnchecked(result.Storage, ExistingData.Clear); var diagonal = diagonalOther.Data; for (int i = 0; i < diagonal.Length; i++) { result.At(i, i, result.At(i, i) + diagonal[i]); } return; } base.DoAdd(other, result); } /// /// Subtracts a scalar from each element of the matrix and stores the result in the result vector. /// /// The scalar to subtract. /// The matrix to store the result of the subtraction. protected override void DoSubtract(Complex32 scalar, Matrix result) { if (result is DenseMatrix denseResult) { CommonParallel.For(0, _values.Length, 4096, (a, b) => { var v = denseResult._values; for (int i = a; i < b; i++) { v[i] = _values[i] - scalar; } }); } else { base.DoSubtract(scalar, result); } } /// /// 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) { // dense + dense = dense if (other.Storage is DenseColumnMajorMatrixStorage denseOther && result.Storage is DenseColumnMajorMatrixStorage denseResult) { LinearAlgebraControl.Provider.SubtractArrays(_values, denseOther.Data, denseResult.Data); return; } // dense + diagonal = matrix if (other.Storage is DiagonalMatrixStorage diagonalOther) { CopyTo(result); var diagonal = diagonalOther.Data; for (int i = 0; i < diagonal.Length; i++) { result.At(i, i, result.At(i, i) - diagonal[i]); } return; } base.DoSubtract(other, result); } /// /// 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) { if (result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.ScaleArray(scalar, _values, denseResult._values); } else { base.DoMultiply(scalar, result); } } /// /// 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) { if (rightSide is DenseVector denseRight && result is DenseVector denseResult) { LinearAlgebraControl.Provider.MatrixMultiply( _values, _rowCount, _columnCount, denseRight.Values, denseRight.Count, 1, denseResult.Values); } else { 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) { if (other is DenseMatrix denseOther && result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.MatrixMultiply( _values, _rowCount, _columnCount, denseOther._values, denseOther._rowCount, denseOther._columnCount, denseResult._values); return; } if (other.Storage is DiagonalMatrixStorage diagonalOther) { var diagonal = diagonalOther.Data; var d = Math.Min(ColumnCount, other.ColumnCount); if (d < other.ColumnCount) { result.ClearSubMatrix(0, RowCount, ColumnCount, other.ColumnCount - ColumnCount); } int index = 0; for (int j = 0; j < d; j++) { for (int i = 0; i < RowCount; i++) { result.At(i, j, _values[index]*diagonal[j]); index++; } } return; } 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) { if (other is DenseMatrix denseOther && result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.MatrixMultiplyWithUpdate( Providers.LinearAlgebra.Transpose.DontTranspose, Providers.LinearAlgebra.Transpose.Transpose, 1.0f, _values, _rowCount, _columnCount, denseOther._values, denseOther._rowCount, denseOther._columnCount, 0.0f, denseResult._values); return; } if (other.Storage is DiagonalMatrixStorage diagonalOther) { var diagonal = diagonalOther.Data; var d = Math.Min(ColumnCount, other.RowCount); if (d < other.RowCount) { result.ClearSubMatrix(0, RowCount, ColumnCount, other.RowCount - ColumnCount); } int index = 0; for (int j = 0; j < d; j++) { for (int i = 0; i < RowCount; i++) { result.At(i, j, _values[index]*diagonal[j]); index++; } } return; } base.DoTransposeAndMultiply(other, result); } /// /// Multiplies this matrix with the conjugate 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 DoConjugateTransposeAndMultiply(Matrix other, Matrix result) { if (other is DenseMatrix denseOther && result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.MatrixMultiplyWithUpdate( Providers.LinearAlgebra.Transpose.DontTranspose, Providers.LinearAlgebra.Transpose.ConjugateTranspose, 1.0f, _values, _rowCount, _columnCount, denseOther._values, denseOther._rowCount, denseOther._columnCount, 0.0f, denseResult._values); return; } if (other.Storage is DiagonalMatrixStorage diagonalOther) { var diagonal = diagonalOther.Data; var conjugateDiagonal = new Complex32[diagonal.Length]; for (int i = 0; i < diagonal.Length; i++) { conjugateDiagonal[i] = diagonal[i].Conjugate(); } var d = Math.Min(ColumnCount, other.RowCount); if (d < other.RowCount) { result.ClearSubMatrix(0, RowCount, ColumnCount, other.RowCount - ColumnCount); } int index = 0; for (int j = 0; j < d; j++) { for (int i = 0; i < RowCount; i++) { result.At(i, j, _values[index]*conjugateDiagonal[j]); index++; } } return; } base.DoConjugateTransposeAndMultiply(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 void DoTransposeThisAndMultiply(Vector rightSide, Vector result) { if (rightSide is DenseVector denseRight && result is DenseVector denseResult) { LinearAlgebraControl.Provider.MatrixMultiplyWithUpdate( Providers.LinearAlgebra.Transpose.Transpose, Providers.LinearAlgebra.Transpose.DontTranspose, 1.0f, _values, _rowCount, _columnCount, denseRight.Values, denseRight.Count, 1, 0.0f, denseResult.Values); } else { base.DoTransposeThisAndMultiply(rightSide, result); } } /// /// Multiplies the conjugate 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 DoConjugateTransposeThisAndMultiply(Vector rightSide, Vector result) { if (rightSide is DenseVector denseRight && result is DenseVector denseResult) { LinearAlgebraControl.Provider.MatrixMultiplyWithUpdate( Providers.LinearAlgebra.Transpose.ConjugateTranspose, Providers.LinearAlgebra.Transpose.DontTranspose, 1.0f, _values, _rowCount, _columnCount, denseRight.Values, denseRight.Count, 1, 0.0f, denseResult.Values); return; } base.DoConjugateTransposeThisAndMultiply(rightSide, result); } /// /// 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) { if (other is DenseMatrix denseOther && result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.MatrixMultiplyWithUpdate( Providers.LinearAlgebra.Transpose.Transpose, Providers.LinearAlgebra.Transpose.DontTranspose, 1.0f, _values, _rowCount, _columnCount, denseOther._values, denseOther._rowCount, denseOther._columnCount, 0.0f, denseResult._values); return; } if (other.Storage is DiagonalMatrixStorage diagonalOther) { var diagonal = diagonalOther.Data; var d = Math.Min(RowCount, other.ColumnCount); if (d < other.ColumnCount) { result.ClearSubMatrix(0, ColumnCount, RowCount, other.ColumnCount - RowCount); } int index = 0; for (int i = 0; i < ColumnCount; i++) { for (int j = 0; j < d; j++) { result.At(i, j, _values[index]*diagonal[j]); index++; } index += (RowCount - d); } return; } base.DoTransposeThisAndMultiply(other, result); } /// /// 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 DoConjugateTransposeThisAndMultiply(Matrix other, Matrix result) { if (other is DenseMatrix denseOther && result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.MatrixMultiplyWithUpdate( Providers.LinearAlgebra.Transpose.ConjugateTranspose, Providers.LinearAlgebra.Transpose.DontTranspose, 1.0f, _values, _rowCount, _columnCount, denseOther._values, denseOther._rowCount, denseOther._columnCount, 0.0f, denseResult._values); return; } if (other.Storage is DiagonalMatrixStorage diagonalOther) { var diagonal = diagonalOther.Data; var d = Math.Min(RowCount, other.ColumnCount); if (d < other.ColumnCount) { result.ClearSubMatrix(0, ColumnCount, RowCount, other.ColumnCount - RowCount); } int index = 0; for (int i = 0; i < ColumnCount; i++) { for (int j = 0; j < d; j++) { result.At(i, j, _values[index].Conjugate()*diagonal[j]); index++; } index += (RowCount - d); } return; } base.DoConjugateTransposeThisAndMultiply(other, result); } /// /// Divides each element of the matrix by a scalar and places results into the result matrix. /// /// The scalar to divide the matrix with. /// The matrix to store the result of the division. protected override void DoDivide(Complex32 divisor, Matrix result) { if (result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.ScaleArray(1.0f / divisor, _values, denseResult._values); } else { base.DoDivide(divisor, 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) { if (other is DenseMatrix denseOther && result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.PointWiseMultiplyArrays(_values, denseOther._values, denseResult._values); } else { base.DoPointwiseMultiply(other, 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 divisor, Matrix result) { if (divisor is DenseMatrix denseDivisor && result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.PointWiseDivideArrays(_values, denseDivisor._values, denseResult._values); } else { base.DoPointwiseDivide(divisor, result); } } /// /// Pointwise raise this matrix to an exponent and store the result into the result matrix. /// /// The exponent to raise this matrix values to. /// The vector to store the result of the pointwise power. protected override void DoPointwisePower(Matrix exponent, Matrix result) { if (exponent is DenseMatrix denseExponent && result is DenseMatrix denseResult) { LinearAlgebraControl.Provider.PointWisePowerArrays(_values, denseExponent._values, denseResult._values); } else { base.DoPointwisePower(exponent, result); } } /// /// Computes the trace of this matrix. /// /// The trace of this matrix /// If the matrix is not square public override Complex32 Trace() { if (_rowCount != _columnCount) { throw new ArgumentException("Matrix must be square."); } var sum = Complex32.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(nameof(rightSide)); } if (leftSide == null) { throw new ArgumentNullException(nameof(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(nameof(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(nameof(rightSide)); } if (leftSide == null) { throw new ArgumentNullException(nameof(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(nameof(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, Complex32 rightSide) { if (leftSide == null) { throw new ArgumentNullException(nameof(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 *(Complex32 leftSide, DenseMatrix rightSide) { if (rightSide == null) { throw new ArgumentNullException(nameof(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(nameof(leftSide)); } if (rightSide == null) { throw new ArgumentNullException(nameof(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(nameof(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(nameof(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, Complex32 rightSide) { if (leftSide == null) { throw new ArgumentNullException(nameof(leftSide)); } return (DenseMatrix)leftSide.Remainder(rightSide); } /// /// Evaluates whether this matrix is symmetric. /// public override bool IsSymmetric() { if (RowCount != ColumnCount) { return false; } for (var j = 0; j < ColumnCount; j++) { var index = j * RowCount; for (var i = j + 1; i < RowCount; i++) { if (_values[(i*ColumnCount) + j] != _values[index + i]) { return false; } } } return true; } /// /// Evaluates whether this matrix is Hermitian (conjugate symmetric). /// public override bool IsHermitian() { if (RowCount != ColumnCount) { return false; } int stride = RowCount + 1; for (var k = 0; k < _values.Length; k += stride) { if (!_values[k].IsReal()) { return false; } } for (var j = 0; j < ColumnCount; j++) { var index = j * RowCount; for (var i = j + 1; i < RowCount; i++) { if (_values[(i*ColumnCount) + j] != _values[index + i].Conjugate()) { return false; } } } return true; } public override Cholesky Cholesky() { return DenseCholesky.Create(this); } public override LU LU() { return DenseLU.Create(this); } public override QR QR(QRMethod method = QRMethod.Thin) { return DenseQR.Create(this, method); } public override GramSchmidt GramSchmidt() { return DenseGramSchmidt.Create(this); } public override Svd Svd(bool computeVectors = true) { return DenseSvd.Create(this, computeVectors); } public override Evd Evd(Symmetricity symmetricity = Symmetricity.Unknown) { return DenseEvd.Create(this, symmetricity); } } }