// // 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.Complex { using System; using System.Linq; using System.Numerics; using Distributions; using Generic; using Properties; using Threading; /// /// A matrix type for diagonal matrices. /// /// /// Diagonal matrices can be non-square matrices but the diagonal always starts /// at element 0,0. A diagonal matrix will throw an exception if non diagonal /// entries are set. The exception to this is when the off diagonal elements are /// 0.0 or NaN; these settings will cause no change to the diagonal matrix. /// public class DiagonalMatrix : Matrix { /// /// Initializes a new instance of the class. This matrix is square with a given size. /// /// the size of the square matrix. /// /// If is less than one. /// public DiagonalMatrix(int order) : base(order) { Data = new Complex[order * order]; } /// /// Initializes a new instance of the class. /// /// /// The number of rows. /// /// /// The number of columns. /// public DiagonalMatrix(int rows, int columns) : base(rows, columns) { Data = new Complex[Math.Min(rows, columns)]; } /// /// Initializes a new instance of the class with all entries set to a particular value. /// /// /// The number of rows. /// /// /// The number of columns. /// /// The value which we assign to each element of the matrix. public DiagonalMatrix(int rows, int columns, Complex value) : base(rows, columns) { Data = new Complex[Math.Min(rows, columns)]; for (var i = 0; i < Data.Length; i++) { Data[i] = value; } } /// /// Initializes a new instance of the class from a one dimensional array with diagonal elements. This constructor /// will reference the one dimensional array and not copy it. /// /// The number of rows. /// The number of columns. /// The one dimensional array which contain diagonal elements. public DiagonalMatrix(int rows, int columns, Complex[] diagonalArray) : base(rows, columns) { Data = diagonalArray; } /// /// Initializes a new instance of the class from a 2D array. /// /// The 2D array to create this matrix from. /// When contains an off-diagonal element. /// Depending on the implementation, an /// may be thrown if one of the indices is outside the dimensions of the matrix. public DiagonalMatrix(Complex[,] array) : this(array.GetLength(0), array.GetLength(1)) { var rows = array.GetLength(0); var columns = array.GetLength(1); for (var i = 0; i < rows; i++) { for (var j = 0; j < columns; j++) { if (i == j) { Data[i] = array[i, j]; } else if (((array[i, j].Real != 0.0) && !double.IsNaN(array[i, j].Real)) || ((array[i, j].Imaginary != 0.0) && !double.IsNaN(array[i, j].Imaginary))) { throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix."); } } } } /// /// Gets the matrix's data. /// /// The matrix's data. internal Complex[] Data { get; private set; } /// /// Retrieves the requested element without range checking. /// /// /// The row of the element. /// /// /// The column of the element. /// /// /// The requested element. /// /// Depending on the implementation, an /// may be thrown if one of the indices is outside the dimensions of the matrix. public override Complex At(int row, int column) { return row == column ? Data[row] : 0.0; } /// /// Sets the value of the given element. /// /// /// The row of the element. /// /// /// The column of the element. /// /// /// The value to set the element to. /// /// When trying to set an off diagonal element. /// Depending on the implementation, an /// may be thrown if one of the indices is outside the dimensions of the matrix. public override void At(int row, int column, Complex value) { if (row == column) { Data[row] = value; } else if (((value.Real != 0.0) && !double.IsNaN(value.Real)) || ((value.Imaginary != 0.0) && !double.IsNaN(value.Imaginary))) { throw new IndexOutOfRangeException("Cannot set an off-diagonal element in a diagonal matrix."); } } /// /// Creates a DiagonalMatrix for the given number of rows and columns. /// /// /// The number of rows. /// /// /// The number of columns. /// /// /// A DiagonalMatrix with the given dimensions. /// public override Matrix CreateMatrix(int numberOfRows, int numberOfColumns) { return new DiagonalMatrix(numberOfRows, numberOfColumns); } /// /// Creates a with a the given dimension. /// /// The size of the vector. /// /// A with the given dimension. /// public override Vector CreateVector(int size) { return new SparseVector(size); } /// /// Sets all values to zero. /// public override void Clear() { Array.Clear(Data, 0, Data.Length); } /// /// Indicates whether the current object is equal to another object of the same type. /// /// /// An object to compare with this object. /// /// /// true if the current object is equal to the parameter; otherwise, false. /// public override bool Equals(object obj) { var diagonalMatrix = obj as DiagonalMatrix; if (diagonalMatrix == null) { return base.Equals(obj); } // Accept if the argument is the same object as this if (ReferenceEquals(this, diagonalMatrix)) { return true; } if (diagonalMatrix.Data.Length != Data.Length) { return false; } // If all else fails, perform element wise comparison. return !Data.Where((t, i) => t != diagonalMatrix.Data[i]).Any(); } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { var hashNum = Math.Min(Data.Length, 25); long hash = 0; for (var i = 0; i < hashNum; i++) { #if SILVERLIGHT hash ^= Precision.DoubleToInt64Bits(Data[i].GetHashCode()); #else hash ^= BitConverter.DoubleToInt64Bits(Data[i].GetHashCode()); #endif } return BitConverter.ToInt32(BitConverter.GetBytes(hash), 4); } #region Elementary operations /// /// Adds another matrix to this matrix. The result will be written into this matrix. /// /// The matrix to add to this matrix. /// If the other matrix is . /// If the two matrices don't have the same dimensions. /// If is not . public override void Add(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } var m = other as DiagonalMatrix; if (m == null) { throw new ArgumentException(Resources.ArgumentTypeMismatch); } Add(m); } /// /// Adds another to this matrix. The result will be written into this matrix. /// /// The to add to this matrix. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public void Add(DiagonalMatrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); } Control.LinearAlgebraProvider.AddArrays(Data, other.Data, Data); } /// /// Subtracts another matrix from this matrix. The result will be written into this matrix. /// /// The matrix to subtract. /// If the other matrix is . /// If the two matrices don't have the same dimensions. /// If is not . public override void Subtract(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } var m = other as DiagonalMatrix; if (m == null) { throw new ArgumentException(Resources.ArgumentTypeMismatch); } Subtract(m); } /// /// Subtracts another from this matrix. The result will be written into this matrix. /// /// The to subtract. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public void Subtract(DiagonalMatrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw new ArgumentOutOfRangeException(Resources.ArgumentMatrixDimensions); } Control.LinearAlgebraProvider.SubtractArrays(Data, other.Data, Data); } /// /// Copies the values of the given array to the diagonal. /// /// The array to copy the values from. The length of the vector should be /// Min(Rows, Columns). /// If is . /// If the length of does not /// equal Min(Rows, Columns). /// For non-square matrices, the elements of are copied to /// this[i,i]. public override void SetDiagonal(Complex[] source) { if (source == null) { throw new ArgumentNullException("source"); } if (source.Length != Data.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "source"); } CommonParallel.For(0, source.Length, index => Data[index] = source[index]); } /// /// Copies the values of the given to the diagonal. /// /// The vector to copy the values from. The length of the vector should be /// Min(Rows, Columns). /// If is . /// If the length of does not /// equal Min(Rows, Columns). /// For non-square matrices, the elements of are copied to /// this[i,i]. public override void SetDiagonal(Vector source) { var denseSource = source as DenseVector; if (denseSource == null) { base.SetDiagonal(source); return; } if (Data.Length != denseSource.Data.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source"); } CommonParallel.For(0, denseSource.Data.Length, index => Data[index] = denseSource.Data[index]); } /// /// Multiplies each element of this matrix with a scalar. /// /// The scalar to multiply with. public override void Multiply(Complex scalar) { if (scalar == 0.0) { Clear(); return; } if (scalar == 1.0) { return; } Control.LinearAlgebraProvider.ScaleArray(scalar, Data); } /// /// Multiplies this diagonal matrix with another diagonal matrix and places the results into the result diagonal matrix. /// /// The matrix to multiply with. /// The result of the multiplication. /// If the other matrix is . /// If the result matrix is . /// If this.Columns != other.Rows. /// If the result matrix's dimensions are not the this.Rows x other.Columns. public override void Multiply(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != other.RowCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions); } if (result.RowCount != RowCount || result.ColumnCount != other.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions); } var m = other as DiagonalMatrix; var r = result as DiagonalMatrix; if (m == null || r == null) { base.Multiply(other, result); } else { var thisDataCopy = new Complex[r.Data.Length]; var otherDataCopy = new Complex[r.Data.Length]; CommonParallel.For(0, (r.Data.Length > Data.Length) ? Data.Length : r.Data.Length, index => thisDataCopy[index] = Data[index]); CommonParallel.For(0, (r.Data.Length > m.Data.Length) ? m.Data.Length : r.Data.Length, index => otherDataCopy[index] = m.Data[index]); Control.LinearAlgebraProvider.PointWiseMultiplyArrays(thisDataCopy, otherDataCopy, r.Data); } } /// /// Multiplies this matrix with another matrix and returns the result. /// /// The matrix to multiply with. /// If this.Columns != other.Rows. /// If the other matrix is . /// The result of multiplication. public override Matrix Multiply(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (ColumnCount != other.RowCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions); } var m = other as DiagonalMatrix; if (m == null) { return base.Multiply(other); } var result = (DiagonalMatrix)CreateMatrix(RowCount, other.ColumnCount); Multiply(other, result); return result; } /// /// Multiplies this matrix with a vector and places the results into the result matrix. /// /// The vector to multiply with. /// The result of the multiplication. /// If is . /// If is . /// If result.Count != this.RowCount. /// If this.ColumnCount != .Count. public override void Multiply(Vector rightSide, Vector result) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } if (ColumnCount != rightSide.Count) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "rightSide"); } if (result == null) { throw new ArgumentNullException("result"); } if (RowCount != result.Count) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } if (ReferenceEquals(rightSide, result)) { var tmp = result.CreateVector(result.Count); Multiply(rightSide, tmp); tmp.CopyTo(result); } else { // Clear the result vector result.Clear(); // Multiply the elements in the vector with the corresponding diagonal element in this. for (var r = 0; r < Data.Length; r++) { result[r] = Data[r] * rightSide[r]; } } } /// /// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector. /// /// The vector to multiply with. /// The result of the multiplication. /// If is . /// If the result matrix is . /// If result.Count != this.ColumnCount. /// If this.RowCount != .Count. public override void LeftMultiply(Vector leftSide, Vector result) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } if (RowCount != leftSide.Count) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "leftSide"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != result.Count) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } if (ReferenceEquals(leftSide, result)) { var tmp = result.CreateVector(result.Count); LeftMultiply(leftSide, tmp); tmp.CopyTo(result); } else { // Clear the result vector result.Clear(); // Multiply the elements in the vector with the corresponding diagonal element in this. for (var r = 0; r < Data.Length; r++) { result[r] = Data[r] * leftSide[r]; } } } /// /// Computes the determinant of this matrix. /// /// The determinant of this matrix. public override Complex Determinant() { if (RowCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare); } return Data.Aggregate(Complex.One, (current, t) => current * t); } /// /// Returns the elements of the diagonal in a . /// /// The elements of the diagonal. /// For non-square matrices, the method returns Min(Rows, Columns) elements where /// i == j (i is the row index, and j is the column index). public override Vector Diagonal() { // TODO: Should we return reference to array? In current implementation we return copy of array, so changes in DenseVector will // not influence onto diagonal elements return new DenseVector((Complex[])Data.Clone()); } /// /// Multiplies this diagonal matrix with transpose of another diagonal matrix and places the results into the result diagonal matrix. /// /// The matrix to multiply with. /// The result of the multiplication. /// If the other matrix is . /// If the result matrix is . /// If this.Columns != other.Rows. /// If the result matrix's dimensions are not the this.Rows x other.Columns. public override void TransposeAndMultiply(Matrix other, Matrix result) { var otherDiagonal = other as DiagonalMatrix; var resultDiagonal = result as DiagonalMatrix; if (otherDiagonal == null || resultDiagonal == null) { base.TransposeAndMultiply(other, result); return; } Multiply(otherDiagonal.Transpose(), result); } /// /// Multiplies this matrix with transpose of another matrix and returns the result. /// /// The matrix to multiply with. /// If this.Columns != other.Rows. /// If the other matrix is . /// The result of multiplication. public override Matrix TransposeAndMultiply(Matrix other) { var otherDiagonal = other as DiagonalMatrix; if (otherDiagonal == null) { return base.TransposeAndMultiply(other); } if (ColumnCount != otherDiagonal.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions); } var result = (DiagonalMatrix)CreateMatrix(RowCount, other.RowCount); TransposeAndMultiply(other, result); return result; } /// /// Multiplies two diagonal matrices. /// /// 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 DiagonalMatrix operator *(DiagonalMatrix leftSide, DiagonalMatrix 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 (DiagonalMatrix)leftSide.Multiply(rightSide); } #endregion /// /// Copies the elements of this matrix to the given matrix. /// /// /// The matrix to copy values into. /// /// /// If target is . /// /// /// If this and the target matrix do not have the same dimensions.. /// public override void CopyTo(Matrix target) { var diagonalTarget = target as DiagonalMatrix; if (diagonalTarget == null) { base.CopyTo(target); return; } if (ReferenceEquals(this, target)) { return; } if (RowCount != target.RowCount || ColumnCount != target.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "target"); } CommonParallel.For(0, Data.Length, index => diagonalTarget.Data[index] = Data[index]); } /// /// Returns the transpose of this matrix. /// /// The transpose of this matrix. public override Matrix Transpose() { var ret = new DiagonalMatrix(ColumnCount, RowCount); CommonParallel.For(0, Data.Length, index => ret.Data[index] = Data[index]); return ret; } /// /// Returns the conjugate transpose of this matrix. /// /// The conjugate transpose of this matrix. public override Matrix ConjugateTranspose() { var ret = new DiagonalMatrix(ColumnCount, RowCount); CommonParallel.For(0, Data.Length, index => ret.Data[index] = Data[index].Conjugate()); return ret; } /// /// Copies the requested column elements into the given vector. /// /// The column to copy elements from. /// The row to start copying from. /// The number of elements to copy. /// The to copy the column into. /// If the result is . /// If is negative, /// or greater than or equal to the number of columns. /// If is negative, /// or greater than or equal to the number of rows. /// If + /// is greater than or equal to the number of rows. /// If is not positive. /// If result.Count < length. public override void Column(int columnIndex, int rowIndex, int length, Vector result) { if (result == null) { throw new ArgumentNullException("result"); } if (columnIndex >= ColumnCount || columnIndex < 0) { throw new ArgumentOutOfRangeException("columnIndex"); } if (rowIndex >= RowCount || rowIndex < 0) { throw new ArgumentOutOfRangeException("rowIndex"); } if (rowIndex + length > RowCount) { throw new ArgumentOutOfRangeException("length"); } if (length < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); } if (result.Count < length) { throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); } // Clear the result and copy the diagonal entry. result.Clear(); if (columnIndex >= rowIndex && columnIndex < rowIndex + length && columnIndex < Data.Length) { result[columnIndex - rowIndex] = Data[columnIndex]; } } /// /// Copies the requested row elements into a new . /// /// The row to copy elements from. /// The column to start copying from. /// The number of elements to copy. /// The to copy the column into. /// If the result is . /// If is negative, /// or greater than or equal to the number of columns. /// If is negative, /// or greater than or equal to the number of rows. /// If + /// is greater than or equal to the number of rows. /// If is not positive. /// If result.Count < length. public override void Row(int rowIndex, int columnIndex, int length, Vector result) { if (result == null) { throw new ArgumentNullException("result"); } if (rowIndex >= RowCount || rowIndex < 0) { throw new ArgumentOutOfRangeException("rowIndex"); } if (columnIndex >= ColumnCount || columnIndex < 0) { throw new ArgumentOutOfRangeException("columnIndex"); } if (columnIndex + length > ColumnCount) { throw new ArgumentOutOfRangeException("length"); } if (length < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); } if (result.Count < length) { throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); } // Clear the result and copy the diagonal entry. result.Clear(); if (rowIndex >= columnIndex && rowIndex < columnIndex + length && rowIndex < Data.Length) { result[rowIndex - columnIndex] = Data[rowIndex]; } } /// Calculates the L1 norm. /// The L1 norm of the matrix. public override double L1Norm() { return Data.Aggregate(double.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude)); } /// Calculates the L2 norm. /// The L2 norm of the matrix. public override double L2Norm() { return Data.Aggregate(double.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude)); } /// Calculates the Frobenius norm of this matrix. /// The Frobenius norm of this matrix. public override double FrobeniusNorm() { var norm = Data.Sum(t => t.Magnitude * t.Magnitude); return Math.Sqrt(norm); } /// Calculates the infinity norm of this matrix. /// The infinity norm of this matrix. public override double InfinityNorm() { return L1Norm(); } /// Calculates the condition number of this matrix. /// The condition number of the matrix. public override double ConditionNumber() { var maxSv = double.NegativeInfinity; var minSv = double.PositiveInfinity; for (var i = 0; i < Data.Length; i++) { maxSv = Math.Max(maxSv, Data[i].Magnitude); minSv = Math.Min(minSv, Data[i].Magnitude); } return maxSv / minSv; } /// Computes the inverse of this matrix. /// If is not a square matrix. /// If is singular. /// The inverse of this matrix. public override Matrix Inverse() { if (RowCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare); } var inverse = (DiagonalMatrix)Clone(); for (var i = 0; i < Data.Length; i++) { if (Data[i] != 0.0) { inverse.Data[i] = 1.0 / Data[i]; } else { throw new ArgumentException(Resources.ArgumentMatrixNotSingular); } } return inverse; } /// /// Returns a new matrix containing the lower triangle of this matrix. /// /// The lower triangle of this matrix. public override Matrix LowerTriangle() { return Clone(); } /// /// Puts the lower triangle of this matrix into the result matrix. /// /// Where to store the lower triangle. /// If is . /// If the result matrix's dimensions are not the same as this matrix. public override void LowerTriangle(Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } if (ReferenceEquals(this, result)) { return; } result.Clear(); for (var i = 0; i < Data.Length; i++) { result[i, i] = Data[i]; } } /// /// 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() { return new DiagonalMatrix(RowCount, ColumnCount); } /// /// Puts the strictly lower triangle of this matrix into the result matrix. /// /// Where to store the lower triangle. /// If is . /// If the result matrix's dimensions are not the same as this matrix. public override void StrictlyLowerTriangle(Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } result.Clear(); } /// /// Returns a new matrix containing the upper triangle of this matrix. /// /// The upper triangle of this matrix. public override Matrix UpperTriangle() { return Clone(); } /// /// Puts the upper triangle of this matrix into the result matrix. /// /// Where to store the lower triangle. /// If is . /// If the result matrix's dimensions are not the same as this matrix. public override void UpperTriangle(Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } result.Clear(); for (var i = 0; i < Data.Length; i++) { result[i, i] = Data[i]; } } /// /// 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() { return new DiagonalMatrix(RowCount, ColumnCount); } /// /// Puts the strictly upper triangle of this matrix into the result matrix. /// /// Where to store the lower triangle. /// If is . /// If the result matrix's dimensions are not the same as this matrix. public override void StrictlyUpperTriangle(Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } result.Clear(); } /// /// Creates a matrix that contains the values from the requested sub-matrix. /// /// The row to start copying from. /// The number of rows to copy. Must be positive. /// The column to start copying from. /// The number of columns to copy. Must be positive. /// The requested sub-matrix. /// If: is /// negative, or greater than or equal to the number of rows. /// is negative, or greater than or equal to the number /// of columns. /// (columnIndex + columnLength) >= Columns /// (rowIndex + rowLength) >= Rows /// If or /// is not positive. public override Matrix SubMatrix(int rowIndex, int rowLength, int columnIndex, int columnLength) { if (rowIndex >= RowCount || rowIndex < 0) { throw new ArgumentOutOfRangeException("rowIndex"); } if (columnIndex >= ColumnCount || columnIndex < 0) { throw new ArgumentOutOfRangeException("columnIndex"); } if (rowLength < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "rowLength"); } if (columnLength < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "columnLength"); } var colMax = columnIndex + columnLength; var rowMax = rowIndex + rowLength; if (rowMax > RowCount) { throw new ArgumentOutOfRangeException("rowLength"); } if (colMax > ColumnCount) { throw new ArgumentOutOfRangeException("columnLength"); } var result = new SparseMatrix(rowLength, columnLength); if (rowIndex > columnIndex && columnIndex + columnLength > rowIndex) { for (var i = 0; rowIndex - columnIndex + i < Math.Min(columnLength, rowLength); i++) { result[i, rowIndex - columnIndex + i] = Data[rowIndex + i]; } } else if (rowIndex < columnIndex && rowIndex + rowLength > columnIndex) { for (var i = 0; rowIndex - columnIndex + i < Math.Min(columnLength, rowLength); i++) { result[columnIndex - rowIndex + i, i] = Data[columnIndex + i]; } } else { for (var i = 0; i < Math.Min(columnLength, rowLength); i++) { result[i, i] = Data[rowIndex + i]; } } return result; } /// /// Returns this matrix as a multidimensional array. /// /// A multidimensional containing the values of this matrix. public override Complex[,] ToArray() { var result = new Complex[RowCount, ColumnCount]; for (var i = 0; i < Data.Length; i++) { result[i, i] = Data[i]; } return result; } /// /// Creates a new and inserts the given column at the given index. /// /// The index of where to insert the column. /// The column to insert. /// A new 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) { if (column == null) { throw new ArgumentNullException("column"); } if (columnIndex < 0 || columnIndex > ColumnCount) { throw new ArgumentOutOfRangeException("columnIndex"); } if (column.Count != RowCount) { throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "column"); } var result = new SparseMatrix(RowCount, ColumnCount + 1); for (var i = 0; i < columnIndex; i++) { result.SetColumn(i, Column(i)); } result.SetColumn(columnIndex, column); for (var i = columnIndex + 1; i < ColumnCount + 1; i++) { result.SetColumn(i, Column(i - 1)); } return result; } /// /// Creates a new and inserts the given row at the given index. /// /// The index of where to insert the row. /// The row to insert. /// A new 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) { if (row == null) { throw new ArgumentNullException("row"); } if (rowIndex < 0 || rowIndex > RowCount) { throw new ArgumentOutOfRangeException("rowIndex"); } if (row.Count != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "row"); } var result = new SparseMatrix(RowCount + 1, ColumnCount); for (var i = 0; i < rowIndex; i++) { result.SetRow(i, Row(i)); } result.SetRow(rowIndex, row); for (var i = rowIndex + 1; i < RowCount; i++) { result.SetRow(i, Row(i - 1)); } return result; } /// /// Stacks this matrix on top of the given matrix and places the result into the result . /// /// The matrix to stack this matrix upon. /// The combined . /// If lower is . /// If upper.Columns != lower.Columns. public override Matrix Stack(Matrix lower) { if (lower == null) { throw new ArgumentNullException("lower"); } if (lower.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension, "lower"); } var result = new SparseMatrix(RowCount + lower.RowCount, ColumnCount); Stack(lower, result); return result; } /// /// Stacks this matrix on top of the given matrix and places the result into the result . /// /// The matrix to stack this matrix upon. /// The combined . /// If lower is . /// If upper.Columns != lower.Columns. public override void Stack(Matrix lower, Matrix result) { if (lower == null) { throw new ArgumentNullException("lower"); } if (lower.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension, "lower"); } if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != (RowCount + lower.RowCount) || result.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } // Clear the result matrix result.Clear(); // Copy the diagonal part into the result matrix. for (var i = 0; i < Data.Length; i++) { result[i, i] = Data[i]; } // Copy the lower matrix into the result matrix. for (var i = 0; i < lower.RowCount; i++) { for (var j = 0; j < lower.ColumnCount; j++) { result[i + RowCount, j] = lower[i, j]; } } } /// /// Concatenates this matrix with the given matrix. /// /// The matrix to concatenate. /// The combined . public override Matrix Append(Matrix right) { if (right == null) { throw new ArgumentNullException("right"); } if (right.RowCount != RowCount) { throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); } var result = new SparseMatrix(RowCount, ColumnCount + right.ColumnCount); Append(right, result); return result; } /// /// Concatenates this matrix with the given matrix and places the result into the result . /// /// The matrix to concatenate. /// The combined . public override void Append(Matrix right, Matrix result) { if (right == null) { throw new ArgumentNullException("right"); } if (right.RowCount != RowCount) { throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); } if (result == null) { throw new ArgumentNullException("result"); } if (result.ColumnCount != (ColumnCount + right.ColumnCount) || result.RowCount != RowCount) { throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension); } // Clear the result matrix result.Clear(); // Copy the diagonal part into the result matrix. for (var i = 0; i < Data.Length; i++) { result[i, i] = Data[i]; } // Copy the lower matrix into the result matrix. for (var i = 0; i < right.RowCount; i++) { for (var j = 0; j < right.ColumnCount; j++) { result[i, j + RowCount] = right[i, j]; } } } /// /// Diagonally stacks his matrix on top of the given matrix. The new matrix is a M-by-N matrix, /// where M = this.Rows + lower.Rows and N = this.Columns + lower.Columns. /// The values of off the off diagonal matrices/blocks are set to zero. /// /// The lower, right matrix. /// If lower is . /// the combined matrix public override Matrix DiagonalStack(Matrix lower) { if (lower == null) { throw new ArgumentNullException("lower"); } var result = new SparseMatrix(RowCount + lower.RowCount, ColumnCount + lower.ColumnCount); DiagonalStack(lower, result); return result; } /// /// Diagonally stacks his matrix on top of the given matrix and places the combined matrix into the result matrix. /// /// The lower, right matrix. /// The combined matrix /// If lower is . /// If the result matrix is . /// If the result matrix's dimensions are not (this.Rows + lower.rows) x (this.Columns + lower.Columns). public override void DiagonalStack(Matrix lower, Matrix result) { if (lower == null) { throw new ArgumentNullException("lower"); } if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount + lower.RowCount || result.ColumnCount != ColumnCount + lower.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } // Clear the result matrix result.Clear(); // Copy the diagonal part into the result matrix. for (var i = 0; i < Data.Length; i++) { result[i, i] = Data[i]; } // Copy the lower matrix into the result matrix. CommonParallel.For(0, lower.RowCount, i => CommonParallel.For(0, lower.ColumnCount, j => result.At(i + RowCount, j + ColumnCount, lower.At(i, j)))); } /// /// 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. /// If the other matrix is . /// If the result matrix is . /// If this matrix and are not the same size. /// If this matrix and are not the same size. public override void PointwiseMultiply(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions, "result"); } var m = other as DiagonalMatrix; var r = result as DiagonalMatrix; if (m == null || r == null) { base.PointwiseMultiply(other, result); } else { Control.LinearAlgebraProvider.PointWiseMultiplyArrays(Data, m.Data, r.Data); } } /// /// Permute the columns of a matrix according to a permutation. /// /// The column permutation to apply to this matrix. /// Always thrown /// Permutation in diagonal matrix are senseless, because of matrix nature public override void PermuteColumns(Permutation p) { throw new InvalidOperationException("Permutations in diagonal matrix are not allowed"); } /// /// Permute the rows of a matrix according to a permutation. /// /// The row permutation to apply to this matrix. /// Always thrown /// Permutation in diagonal matrix are senseless, because of matrix nature public override void PermuteRows(Permutation p) { throw new InvalidOperationException("Permutations in diagonal matrix are not allowed"); } #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 diagonal identity matrix. /// /// If is less than one. /// public static DiagonalMatrix Identity(int order) { var m = new DiagonalMatrix(order); for (var i = 0; i < order; i++) { m.Data[i] = 1.0; } return m; } #endregion /// /// Negates each element of this matrix. /// public override void Negate() { Multiply(-1); } /// /// Generates matrix with random elements. /// /// Number of rows. /// Number of columns. /// Continuous Random Distribution or Source /// /// An numberOfRows-by-numberOfColumns matrix with elements distributed according to the provided distribution. /// /// If the parameter is not positive. /// If the parameter is not positive. public override Matrix Random(int numberOfRows, int numberOfColumns, IContinuousDistribution distribution) { if (numberOfRows < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows"); } if (numberOfColumns < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); } var matrix = CreateMatrix(numberOfRows, numberOfColumns); var mn = Math.Min(numberOfRows, numberOfColumns); CommonParallel.For(0, mn, i => matrix[i, i] = new Complex(distribution.Sample(), distribution.Sample())); return matrix; } /// /// Generates matrix with random elements. /// /// Number of rows. /// Number of columns. /// Continuous Random Distribution or Source /// /// An numberOfRows-by-numberOfColumns matrix with elements distributed according to the provided distribution. /// /// If the parameter is not positive. /// If the parameter is not positive. public override Matrix Random(int numberOfRows, int numberOfColumns, IDiscreteDistribution distribution) { if (numberOfRows < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfRows"); } if (numberOfColumns < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "numberOfColumns"); } var matrix = CreateMatrix(numberOfRows, numberOfColumns); var mn = Math.Min(numberOfRows, numberOfColumns); CommonParallel.For(0, mn, i => matrix[i, i] = new Complex(distribution.Sample(), distribution.Sample())); return matrix; } #region Simple arithmetic of type T /// /// Add two values T+T /// /// Left operand value /// Right operand value /// Result of addition protected sealed override Complex AddT(Complex val1, Complex val2) { return val1 + val2; } /// /// Subtract two values T-T /// /// Left operand value /// Right operand value /// Result of subtract protected sealed override Complex SubtractT(Complex val1, Complex val2) { return val1 - val2; } /// /// Multiply two values T*T /// /// Left operand value /// Right operand value /// Result of multiplication protected sealed override Complex MultiplyT(Complex val1, Complex val2) { return val1 * val2; } /// /// Divide two values T/T /// /// Left operand value /// Right operand value /// Result of divide protected sealed override Complex DivideT(Complex val1, Complex val2) { return val1 / val2; } /// /// Take absolute value /// /// Source alue /// True if one; otherwise false protected sealed override double AbsoluteT(Complex val1) { return val1.Magnitude; } #endregion } }