// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // Copyright (c) 2009-2010 Math.NET // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // namespace MathNet.Numerics.LinearAlgebra.Complex32 { using System; using System.Linq; using Generic; using Numerics; 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. /// [Serializable] 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 Complex32[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 Complex32[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, Complex32 value) : base(rows, columns) { Data = new Complex32[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, Complex32[] 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(Complex32[,] 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 Complex32[] 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 Complex32 At(int row, int column) { return row == column ? Data[row] : 0.0f; } /// /// 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, Complex32 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 PORTABLE 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 matrix to add to this matrix. /// The result of the addition. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public override Matrix Add(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other, "other"); } Matrix result; if (other is DiagonalMatrix) { result = new DiagonalMatrix(RowCount, ColumnCount); } else { result = new DenseMatrix(RowCount, ColumnCount); } Add(other, result); return result; } /// /// Adds another matrix to this matrix. /// /// The matrix to add to this matrix. /// The matrix to store the result of the addition. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public override void Add(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other, "other"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other, "other"); } var diagOther = other as DiagonalMatrix; var diagResult = result as DiagonalMatrix; if (diagOther == null || diagResult == null) { base.Add(other, result); } else { Control.LinearAlgebraProvider.AddArrays(Data, diagOther.Data, diagResult.Data); } } /// /// Subtracts another matrix from this matrix. /// /// The matrix to subtract. /// The result of the subtraction. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public override Matrix Subtract(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other, "other"); } Matrix result; if (other is DiagonalMatrix) { result = new DiagonalMatrix(RowCount, ColumnCount); } else { result = new DenseMatrix(RowCount, ColumnCount); } Subtract(other, result); return result; } /// /// Subtracts another matrix from this matrix. /// /// The matrix to subtract. /// The matrix to store the result of the subtraction. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public override void Subtract(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other, "other"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other, "result"); } var diagOther = other as DiagonalMatrix; var diagResult = result as DiagonalMatrix; if (diagOther == null || diagResult == null) { base.Subtract(other, result); } else { Control.LinearAlgebraProvider.SubtractArrays(Data, diagOther.Data, diagResult.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(Complex32[] source) { if (source == null) { throw new ArgumentNullException("source"); } if (source.Length != Data.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "source"); } Array.Copy(source, Data, source.Length); } /// /// 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"); } Array.Copy(denseSource.Data, Data, denseSource.Data.Length); } /// /// 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. /// If the result matrix is . /// If the result matrix's dimensions are not the same as this matrix. protected override void DoMultiply(Complex32 scalar, Matrix result) { if (scalar.IsZero()) { result.Clear(); return; } if (scalar.IsOne()) { CopyTo(result); return; } var diagResult = result as DiagonalMatrix; if (diagResult == null) { base.Multiply(scalar, result); } else { if (!ReferenceEquals(this, result)) { CopyTo(diagResult); } Control.LinearAlgebraProvider.ScaleArray(scalar, Data, diagResult.Data); } } /// /// Multiplies this matrix with another matrix and places the results into the result 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 DimensionsDontMatch(this, other); } if (result.RowCount != RowCount || result.ColumnCount != other.ColumnCount) { throw DimensionsDontMatch(this, other); } var m = other as DiagonalMatrix; var r = result as DiagonalMatrix; if (m == null || r == null) { base.Multiply(other, result); } else { var thisDataCopy = new Complex32[r.Data.Length]; var otherDataCopy = new Complex32[r.Data.Length]; Array.Copy(Data, thisDataCopy, (r.Data.Length > Data.Length) ? Data.Length : r.Data.Length); Array.Copy(m.Data, otherDataCopy, (r.Data.Length > m.Data.Length) ? m.Data.Length : r.Data.Length); 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 DimensionsDontMatch(this, other); } 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 DimensionsDontMatch(this, rightSide, "rightSide"); } if (result == null) { throw new ArgumentNullException("result"); } if (RowCount != result.Count) { throw DimensionsDontMatch(this, result, "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 DimensionsDontMatch(this, leftSide, "leftSide"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != result.Count) { throw DimensionsDontMatch(this, result, "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 Complex32 Determinant() { if (RowCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare); } return Data.Aggregate(Complex32.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((Complex32[])Data.Clone()); } /// /// 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. /// 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 DimensionsDontMatch(this, otherDiagonal); } var result = (DiagonalMatrix)CreateMatrix(RowCount, other.RowCount); TransposeAndMultiply(other, result); return result; } #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 DimensionsDontMatch(this, target, "target"); } Array.Copy(Data, diagonalTarget.Data, Data.Length); } /// /// Returns the transpose of this matrix. /// /// The transpose of this matrix. public override Matrix Transpose() { var ret = new DiagonalMatrix(ColumnCount, RowCount); Array.Copy(Data, ret.Data, Data.Length); 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 Complex32 L1Norm() { return Data.Aggregate(float.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude)); } /// Calculates the L2 norm. /// The L2 norm of the matrix. public override Complex32 L2Norm() { return Data.Aggregate(float.NegativeInfinity, (current, t) => Math.Max(current, t.Magnitude)); } /// Calculates the Frobenius norm of this matrix. /// The Frobenius norm of this matrix. public override Complex32 FrobeniusNorm() { var norm = Data.Sum(t => t.Magnitude * t.Magnitude); return Convert.ToSingle(Math.Sqrt(norm)); } /// Calculates the infinity norm of this matrix. /// The infinity norm of this matrix. public override Complex32 InfinityNorm() { return L1Norm(); } /// Calculates the condition number of this matrix. /// The condition number of the matrix. public override Complex32 ConditionNumber() { var maxSv = float.NegativeInfinity; var minSv = float.PositiveInfinity; foreach (var t in Data) { maxSv = Math.Max(maxSv, t.Magnitude); minSv = Math.Min(minSv, t.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.0f) { inverse.Data[i] = 1.0f / 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 DimensionsDontMatch(this, result, "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 DimensionsDontMatch(this, result, "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 DimensionsDontMatch(this, result, "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 DimensionsDontMatch(this, result, "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 rowCount, int columnIndex, int columnCount) { if (rowIndex >= RowCount || rowIndex < 0) { throw new ArgumentOutOfRangeException("rowIndex"); } if (columnIndex >= ColumnCount || columnIndex < 0) { throw new ArgumentOutOfRangeException("columnIndex"); } if (rowCount < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "rowCount"); } if (columnCount < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "columnCount"); } var colMax = columnIndex + columnCount; var rowMax = rowIndex + rowCount; if (rowMax > RowCount) { throw new ArgumentOutOfRangeException("rowCount"); } if (colMax > ColumnCount) { throw new ArgumentOutOfRangeException("columnCount"); } var result = new SparseMatrix(rowCount, columnCount); if (rowIndex > columnIndex && columnIndex + columnCount > rowIndex) { for (var i = 0; rowIndex - columnIndex + i < Math.Min(columnCount, rowCount); i++) { result[i, rowIndex - columnIndex + i] = Data[rowIndex + i]; } } else if (rowIndex < columnIndex && rowIndex + rowCount > columnIndex) { for (var i = 0; rowIndex - columnIndex + i < Math.Min(columnCount, rowCount); i++) { result[columnIndex - rowIndex + i, i] = Data[columnIndex + i]; } } else { for (var i = 0; i < Math.Min(columnCount, rowCount); 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 Complex32[,] ToArray() { var result = new Complex32[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 DimensionsDontMatch(this, lower, 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 DimensionsDontMatch(this, lower, 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)))); } /// /// 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"); } /// /// Gets a value indicating whether this matrix is symmetric. /// public override bool IsSymmetric { get { return true; } } #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.0f; } return m; } #endregion } }