// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // // Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; using System.Linq; using System.Runtime; using MathNet.Numerics.LinearAlgebra.Storage; using MathNet.Numerics.Properties; using MathNet.Numerics.Threading; namespace MathNet.Numerics.LinearAlgebra { /// /// Defines the base class for Matrix classes. /// /// Supported data types are double, single, , and . [Serializable] public abstract partial class Matrix : IFormattable, IEquatable> #if !PORTABLE , ICloneable #endif where T : struct, IEquatable, IFormattable { /// /// Initializes a new instance of the Matrix class. /// protected Matrix(MatrixStorage storage) { Storage = storage; RowCount = storage.RowCount; ColumnCount = storage.ColumnCount; } public static readonly MatrixBuilder Build = BuilderInstance.Matrix; /// /// Gets the raw matrix data storage. /// public MatrixStorage Storage { get; private set; } /// /// Gets the number of columns. /// /// The number of columns. public int ColumnCount { get; private set; } /// /// Gets the number of rows. /// /// The number of rows. public int RowCount { get; private set; } /// /// Gets or sets the value at the given row and column, with range checking. /// /// /// The row of the element. /// /// /// The column of the element. /// /// The value to get or set. /// This method is ranged checked. and /// to get and set values without range checking. public T this[int row, int column] { [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] //[MethodImpl(MethodImplOptions.AggressiveInlining)] .Net 4.5 only get { return Storage[row, column]; } [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] //[MethodImpl(MethodImplOptions.AggressiveInlining)] .Net 4.5 only set { Storage[row, column] = value; } } /// /// Retrieves the requested element without range checking. /// /// /// The row of the element. /// /// /// The column of the element. /// /// /// The requested element. /// [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] //[MethodImpl(MethodImplOptions.AggressiveInlining)] .Net 4.5 only public T At(int row, int column) { return Storage.At(row, column); } /// /// Sets the value of the given element without range checking. /// /// /// The row of the element. /// /// /// The column of the element. /// /// /// The value to set the element to. /// [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] //[MethodImpl(MethodImplOptions.AggressiveInlining)] .Net 4.5 only public void At(int row, int column, T value) { Storage.At(row, column, value); } /// /// Sets all values to zero. /// public void Clear() { Storage.Clear(); } /// /// Sets all values of a row to zero. /// public void ClearRow(int rowIndex) { if (rowIndex < 0 || rowIndex >= RowCount) { throw new ArgumentOutOfRangeException("rowIndex"); } Storage.Clear(rowIndex, 1, 0, ColumnCount); } /// /// Sets all values of a column to zero. /// public void ClearColumn(int columnIndex) { if (columnIndex < 0 || columnIndex >= ColumnCount) { throw new ArgumentOutOfRangeException("columnIndex"); } Storage.Clear(0, RowCount, columnIndex, 1); } /// /// Sets all values for all of the chosen rows to zero. /// public void ClearRows(params int[] rowIndices) { if (rowIndices.Length == 0) { return; } for (int k = 0; k < rowIndices.Length; k++) { if (rowIndices[k] < 0 || rowIndices[k] >= RowCount) { throw new ArgumentOutOfRangeException("rowIndices"); } } Storage.ClearRows(rowIndices); } /// /// Sets all values for all of the chosen columns to zero. /// public void ClearColumns(params int[] columnIndices) { if (columnIndices.Length == 0) { return; } for (int k = 0; k < columnIndices.Length; k++) { if (columnIndices[k] < 0 || columnIndices[k] >= ColumnCount) { throw new ArgumentOutOfRangeException("columnIndices"); } } Storage.ClearColumns(columnIndices); } /// /// Sets all values of a submatrix to zero. /// public void ClearSubMatrix(int rowIndex, int rowCount, int columnIndex, int columnCount) { if (rowCount < 1 || columnCount < 1) { // nothing to do (but no need to fail either) return; } if (rowIndex + rowCount > RowCount || rowIndex < 0) { throw new ArgumentOutOfRangeException("rowIndex"); } if (columnIndex + columnCount > ColumnCount || columnIndex < 0) { throw new ArgumentOutOfRangeException("columnIndex"); } Storage.Clear(rowIndex, rowCount, columnIndex, columnCount); } /// /// Set all values whose absolute value is smaller than the threshold to zero, in-place. /// public abstract void CoerceZero(double threshold); /// /// Set all values that meet the predicate to zero, in-place. /// public void CoerceZero(Func zeroPredicate) { MapInplace(x => zeroPredicate(x) ? Zero : x, Zeros.AllowSkip); } /// /// Creates a clone of this instance. /// /// /// A clone of the instance. /// public Matrix Clone() { var result = Build.SameAs(this); Storage.CopyToUnchecked(result.Storage, ExistingData.AssumeZeros); return result; } /// /// 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 void CopyTo(Matrix target) { if (target == null) { throw new ArgumentNullException("target"); } Storage.CopyTo(target.Storage); } /// /// Copies a row into an Vector. /// /// The row to copy. /// A Vector containing the copied elements. /// If is negative, /// or greater than or equal to the number of rows. public Vector Row(int index) { if (index >= RowCount || index < 0) { throw new ArgumentOutOfRangeException("index"); } var ret = Vector.Build.SameAs(this, ColumnCount); Storage.CopySubRowToUnchecked(ret.Storage, index, 0, 0, ColumnCount); return ret; } /// /// Copies a row into to the given Vector. /// /// The row to copy. /// The Vector to copy the row into. /// If the result vector is . /// If is negative, /// or greater than or equal to the number of rows. /// If this.Columns != result.Count. public void Row(int index, Vector result) { if (result == null) { throw new ArgumentNullException("result"); } Storage.CopyRowTo(result.Storage, index); } /// /// Copies the requested row elements into a new Vector. /// /// The row to copy elements from. /// The column to start copying from. /// The number of elements to copy. /// A Vector containing the requested elements. /// 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 + length) >= Columns. /// If is not positive. public Vector Row(int rowIndex, int columnIndex, int length) { var ret = Vector.Build.SameAs(this, length); Storage.CopySubRowTo(ret.Storage, rowIndex, columnIndex, 0, length); return ret; } /// /// Copies the requested row elements into a new Vector. /// /// The row to copy elements from. /// The column to start copying from. /// The number of elements to copy. /// The Vector to copy the column into. /// If the result Vector 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 void Row(int rowIndex, int columnIndex, int length, Vector result) { if (result == null) { throw new ArgumentNullException("result"); } Storage.CopySubRowTo(result.Storage, rowIndex, columnIndex, 0, length); } /// /// Copies a column into a new Vector>. /// /// The column to copy. /// A Vector containing the copied elements. /// If is negative, /// or greater than or equal to the number of columns. public Vector Column(int index) { if (index >= ColumnCount || index < 0) { throw new ArgumentOutOfRangeException("index"); } var ret = Vector.Build.SameAs(this, RowCount); Storage.CopySubColumnToUnchecked(ret.Storage, index, 0, 0, RowCount); return ret; } /// /// Copies a column into to the given Vector. /// /// The column to copy. /// The Vector to copy the column into. /// If the result Vector is . /// If is negative, /// or greater than or equal to the number of columns. /// If this.Rows != result.Count. public void Column(int index, Vector result) { if (result == null) { throw new ArgumentNullException("result"); } Storage.CopyColumnTo(result.Storage, index); } /// /// Copies the requested column elements into a new Vector. /// /// The column to copy elements from. /// The row to start copying from. /// The number of elements to copy. /// A Vector containing the requested elements. /// If: /// is negative, /// or greater than or equal to the number of columns. /// is negative, /// or greater than or equal to the number of rows. /// (rowIndex + length) >= Rows. /// /// If is not positive. public Vector Column(int columnIndex, int rowIndex, int length) { var ret = Vector.Build.SameAs(this, length); Storage.CopySubColumnTo(ret.Storage, columnIndex, rowIndex, 0, 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 Vector to copy the column into. /// If the result Vector 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 void Column(int columnIndex, int rowIndex, int length, Vector result) { if (result == null) { throw new ArgumentNullException("result"); } Storage.CopySubColumnTo(result.Storage, columnIndex, rowIndex, 0, length); } /// /// Returns a new matrix containing the upper triangle of this matrix. /// /// The upper triangle of this matrix. public virtual Matrix UpperTriangle() { var result = Build.SameAs(this); for (var row = 0; row < RowCount; row++) { for (var column = row; column < ColumnCount; column++) { result.At(row, column, At(row, column)); } } return result; } /// /// Returns a new matrix containing the lower triangle of this matrix. /// /// The lower triangle of this matrix. public virtual Matrix LowerTriangle() { var result = Build.SameAs(this); for (var row = 0; row < RowCount; row++) { for (var column = 0; column <= row && column < ColumnCount; column++) { result.At(row, column, At(row, column)); } } return result; } /// /// 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 virtual void LowerTriangle(Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result, "result"); } for (var row = 0; row < RowCount; row++) { for (var column = 0; column < ColumnCount; column++) { result.At(row, column, row >= column ? At(row, column) : Zero); } } } /// /// 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 virtual void UpperTriangle(Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result, "result"); } for (var row = 0; row < RowCount; row++) { for (var column = 0; column < ColumnCount; column++) { result.At(row, column, row <= column ? At(row, column) : Zero); } } } /// /// 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 virtual Matrix SubMatrix(int rowIndex, int rowCount, int columnIndex, int columnCount) { var result = Build.SameAs(this, rowCount, columnCount); Storage.CopySubMatrixTo(result.Storage, rowIndex, 0, rowCount, columnIndex, 0, columnCount, ExistingData.AssumeZeros); return result; } /// /// Returns the elements of the diagonal in a Vector. /// /// 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 virtual Vector Diagonal() { var min = Math.Min(RowCount, ColumnCount); var diagonal = Vector.Build.SameAs(this, min); for (var i = 0; i < min; i++) { diagonal.At(i, At(i, i)); } return diagonal; } /// /// 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 virtual Matrix StrictlyLowerTriangle() { var result = Build.SameAs(this); for (var row = 0; row < RowCount; row++) { var columns = Math.Min(row, ColumnCount); for (var column = 0; column < columns; column++) { result.At(row, column, At(row, column)); } } return result; } /// /// 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 virtual void StrictlyLowerTriangle(Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result, "result"); } for (var row = 0; row < RowCount; row++) { for (var column = 0; column < ColumnCount; column++) { result.At(row, column, row > column ? At(row, column) : Zero); } } } /// /// 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 virtual Matrix StrictlyUpperTriangle() { var result = Build.SameAs(this); for (var row = 0; row < RowCount; row++) { for (var column = row + 1; column < ColumnCount; column++) { result.At(row, column, At(row, column)); } } return result; } /// /// 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 virtual void StrictlyUpperTriangle(Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result, "result"); } for (var row = 0; row < RowCount; row++) { for (var column = 0; column < ColumnCount; column++) { result.At(row, column, row < column ? At(row, column) : Zero); } } } /// /// Creates a new matrix and inserts the given column at the given index. /// /// The index of where to insert the column. /// The column to insert. /// A new matrix with the inserted column. /// If is . /// If is < zero or > the number of columns. /// If the size of != the number of rows. public 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 = Build.SameAs(this, RowCount, ColumnCount + 1, fullyMutable: true); Storage.CopySubMatrixTo(result.Storage, 0, 0, RowCount, 0, 0, columnIndex, ExistingData.AssumeZeros); result.SetColumn(columnIndex, column); Storage.CopySubMatrixTo(result.Storage, 0, 0, RowCount, columnIndex, columnIndex + 1, ColumnCount - columnIndex, ExistingData.AssumeZeros); return result; } /// /// Creates a new matrix with the given column removed. /// /// The index of the column to remove. /// A new matrix without the chosen column. /// If is < zero or > the number of columns. public Matrix RemoveColumn(int columnIndex) { if (columnIndex < 0 || columnIndex > ColumnCount) { throw new ArgumentOutOfRangeException("columnIndex"); } var result = Build.SameAs(this, RowCount, ColumnCount - 1, fullyMutable: true); Storage.CopySubMatrixTo(result.Storage, 0, 0, RowCount, 0, 0, columnIndex, ExistingData.AssumeZeros); Storage.CopySubMatrixTo(result.Storage, 0, 0, RowCount, columnIndex + 1, columnIndex, ColumnCount - columnIndex - 1, ExistingData.AssumeZeros); return result; } /// /// Copies the values of the given Vector to the specified column. /// /// The column to copy the values to. /// The vector to copy the values from. /// If is . /// If is less than zero, /// or greater than or equal to the number of columns. /// If the size of does not /// equal the number of rows of this Matrix. public void SetColumn(int columnIndex, Vector column) { if (column == null) { throw new ArgumentNullException("column"); } column.Storage.CopyToColumn(Storage, columnIndex); } /// /// Copies the values of the given Vector to the specified sub-column. /// /// The column to copy the values to. /// The row to start copying to. /// The number of elements to copy. /// The vector to copy the values from. /// If is . /// If is less than zero, /// or greater than or equal to the number of columns. /// If the size of does not /// equal the number of rows of this Matrix. public void SetColumn(int columnIndex, int rowIndex, int length, Vector column) { if (column == null) { throw new ArgumentNullException("column"); } column.Storage.CopyToSubColumn(Storage, columnIndex, 0, rowIndex, length); } /// /// Copies the values of the given array to the specified column. /// /// The column to copy the values to. /// The array to copy the values from. /// If is . /// If is less than zero, /// or greater than or equal to the number of columns. /// If the size of does not /// equal the number of rows of this Matrix. /// If the size of does not /// equal the number of rows of this Matrix. public void SetColumn(int columnIndex, T[] column) { if (column == null) { throw new ArgumentNullException("column"); } new DenseVectorStorage(column.Length, column).CopyToColumn(Storage, columnIndex); } /// /// Creates a new matrix and inserts the given row at the given index. /// /// The index of where to insert the row. /// The row to insert. /// A new matrix with the inserted column. /// If is . /// If is < zero or > the number of rows. /// If the size of != the number of columns. public 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 = Build.SameAs(this, RowCount + 1, ColumnCount, fullyMutable: true); Storage.CopySubMatrixTo(result.Storage, 0, 0, rowIndex, 0, 0, ColumnCount, ExistingData.AssumeZeros); result.SetRow(rowIndex, row); Storage.CopySubMatrixTo(result.Storage, rowIndex, rowIndex+1, RowCount - rowIndex, 0, 0, ColumnCount, ExistingData.AssumeZeros); return result; } /// /// Creates a new matrix with the given row removed. /// /// The index of the row to remove. /// A new matrix without the chosen row. /// If is < zero or > the number of rows. public Matrix RemoveRow(int rowIndex) { if (rowIndex < 0 || rowIndex > RowCount) { throw new ArgumentOutOfRangeException("rowIndex"); } var result = Build.SameAs(this, RowCount - 1, ColumnCount, fullyMutable: true); Storage.CopySubMatrixTo(result.Storage, 0, 0, rowIndex, 0, 0, ColumnCount, ExistingData.AssumeZeros); Storage.CopySubMatrixTo(result.Storage, rowIndex + 1, rowIndex, RowCount - rowIndex - 1, 0, 0, ColumnCount, ExistingData.AssumeZeros); return result; } /// /// Copies the values of the given Vector to the specified row. /// /// The row to copy the values to. /// The vector to copy the values from. /// If is . /// If is less than zero, /// or greater than or equal to the number of rows. /// If the size of does not /// equal the number of columns of this Matrix. public void SetRow(int rowIndex, Vector row) { if (row == null) { throw new ArgumentNullException("row"); } row.Storage.CopyToRow(Storage, rowIndex); } /// /// Copies the values of the given Vector to the specified sub-row. /// /// The row to copy the values to. /// The column to start copying to. /// The number of elements to copy. /// The vector to copy the values from. /// If is . /// If is less than zero, /// or greater than or equal to the number of rows. /// If the size of does not /// equal the number of columns of this Matrix. public void SetRow(int rowIndex, int columnIndex, int length, Vector row) { if (row == null) { throw new ArgumentNullException("row"); } row.Storage.CopyToSubRow(Storage, rowIndex, 0, columnIndex, length); } /// /// Copies the values of the given array to the specified row. /// /// The row to copy the values to. /// The array to copy the values from. /// If is . /// If is less than zero, /// or greater than or equal to the number of rows. /// If the size of does not /// equal the number of columns of this Matrix. public void SetRow(int rowIndex, T[] row) { if (row == null) { throw new ArgumentNullException("row"); } new DenseVectorStorage(row.Length, row).CopyToRow(Storage, rowIndex); } /// /// Copies the values of a given matrix into a region in this matrix. /// /// The row to start copying to. /// The column to start copying to. /// The sub-matrix to copy from. /// 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 public void SetSubMatrix(int rowIndex, int columnIndex, Matrix subMatrix) { subMatrix.Storage.CopySubMatrixTo(Storage, 0, rowIndex, subMatrix.RowCount, 0, columnIndex, subMatrix.ColumnCount); } /// /// Copies the values of a given matrix into a region in this matrix. /// /// The row to start copying to. /// The number of rows to copy. Must be positive. /// The column to start copying to. /// The number of columns to copy. Must be positive. /// The sub-matrix to copy from. /// 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 /// the size of is not at least x . /// If or /// is not positive. public void SetSubMatrix(int rowIndex, int rowCount, int columnIndex, int columnCount, Matrix subMatrix) { subMatrix.Storage.CopySubMatrixTo(Storage, 0, rowIndex, rowCount, 0, columnIndex, columnCount); } /// /// Copies the values of a given matrix into a region in this matrix. /// /// The row to start copying to. /// The row of the sub-matrix to start copying from. /// The number of rows to copy. Must be positive. /// The column to start copying to. /// The column of the sub-matrix to start copying from. /// The number of columns to copy. Must be positive. /// The sub-matrix to copy from. /// 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 /// the size of is not at least x . /// If or /// is not positive. public void SetSubMatrix(int rowIndex, int sorceRowIndex, int rowCount, int columnIndex, int sourceColumnIndex, int columnCount, Matrix subMatrix) { subMatrix.Storage.CopySubMatrixTo(Storage, sorceRowIndex, rowIndex, rowCount, sourceColumnIndex, columnIndex, columnCount); } /// /// Copies the values of the given Vector 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 virtual void SetDiagonal(Vector source) { if (source == null) { throw new ArgumentNullException("source"); } var min = Math.Min(RowCount, ColumnCount); if (source.Count != min) { throw new ArgumentException(Resources.ArgumentVectorsSameLength, "source"); } for (var i = 0; i < min; i++) { At(i, i, source.At(i)); } } /// /// 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 virtual void SetDiagonal(T[] source) { if (source == null) { throw new ArgumentNullException("source"); } var min = Math.Min(RowCount, ColumnCount); if (source.Length != min) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "source"); } for (var i = 0; i < min; i++) { At(i, i, source[i]); } } /// /// Returns the transpose of this matrix. /// /// The transpose of this matrix. public Matrix Transpose() { var result = Build.SameAs(this, ColumnCount, RowCount); Storage.TransposeToUnchecked(result.Storage, ExistingData.AssumeZeros); return result; } /// /// Returns the conjugate transpose of this matrix. /// /// The conjugate transpose of this matrix. public abstract Matrix ConjugateTranspose(); /// /// Permute the rows of a matrix according to a permutation. /// /// The row permutation to apply to this matrix. public virtual void PermuteRows(Permutation p) { if (p.Dimension != RowCount) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "p"); } // Get a sequence of inversions from the permutation. var inv = p.ToInversions(); for (var i = 0; i < inv.Length; i++) { if (inv[i] != i) { var q = inv[i]; for (var j = 0; j < ColumnCount; j++) { var temp = At(q, j); At(q, j, At(i, j)); At(i, j, temp); } } } } /// /// Permute the columns of a matrix according to a permutation. /// /// The column permutation to apply to this matrix. public virtual void PermuteColumns(Permutation p) { if (p.Dimension != ColumnCount) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "p"); } // Get a sequence of inversions from the permutation. var inv = p.ToInversions(); for (var i = 0; i < inv.Length; i++) { if (inv[i] != i) { var q = inv[i]; for (var j = 0; j < RowCount; j++) { var temp = At(j, q); At(j, q, At(j, i)); At(j, i, temp); } } } } /// /// Concatenates this matrix with the given matrix. /// /// The matrix to concatenate. /// The combined matrix. /// /// public Matrix Append(Matrix right) { if (right == null) { throw new ArgumentNullException("right"); } if (right.RowCount != RowCount) { throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension); } var result = Build.SameAs(this, right, RowCount, ColumnCount + right.ColumnCount, fullyMutable: true); Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, RowCount, 0, 0, ColumnCount, ExistingData.AssumeZeros); right.Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, right.RowCount, 0, ColumnCount, right.ColumnCount, ExistingData.AssumeZeros); return result; } /// /// Concatenates this matrix with the given matrix and places the result into the result matrix. /// /// The matrix to concatenate. /// The combined matrix. /// /// public 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); } Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, RowCount, 0, 0, ColumnCount); right.Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, right.RowCount, 0, ColumnCount, right.ColumnCount); } /// /// Stacks this matrix on top of the given matrix and places the result into the result matrix. /// /// The matrix to stack this matrix upon. /// The combined matrix. /// If lower is . /// If upper.Columns != lower.Columns. /// /// public Matrix Stack(Matrix lower) { if (lower == null) { throw new ArgumentNullException("lower"); } if (lower.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension, "lower"); } var result = Build.SameAs(this, lower, RowCount + lower.RowCount, ColumnCount, fullyMutable: true); Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, RowCount, 0, 0, ColumnCount, ExistingData.AssumeZeros); lower.Storage.CopySubMatrixToUnchecked(result.Storage, 0, RowCount, lower.RowCount, 0, 0, lower.ColumnCount, ExistingData.AssumeZeros); return result; } /// /// Stacks this matrix on top of the given matrix and places the result into the result matrix. /// /// The matrix to stack this matrix upon. /// The combined matrix. /// If lower is . /// If upper.Columns != lower.Columns. /// /// public 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, result, "result"); } Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, RowCount, 0, 0, ColumnCount); lower.Storage.CopySubMatrixToUnchecked(result.Storage, 0, RowCount, lower.RowCount, 0, 0, lower.ColumnCount); } /// /// 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 Matrix DiagonalStack(Matrix lower) { if (lower == null) { throw new ArgumentNullException("lower"); } var result = Build.SameAs(this, lower, RowCount + lower.RowCount, ColumnCount + lower.ColumnCount, RowCount != ColumnCount); Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, RowCount, 0, 0, ColumnCount); lower.Storage.CopySubMatrixToUnchecked(result.Storage, 0, RowCount, lower.RowCount, 0, ColumnCount, lower.ColumnCount); 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 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, result, "result"); } Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, RowCount, 0, 0, ColumnCount); lower.Storage.CopySubMatrixToUnchecked(result.Storage, 0, RowCount, lower.RowCount, 0, ColumnCount, lower.ColumnCount); } /// /// Evaluates whether this matrix is symmetric. /// public virtual bool IsSymmetric() { if (RowCount != ColumnCount) { return false; } for (var row = 0; row < RowCount; row++) { for (var column = row + 1; column < ColumnCount; column++) { if (!At(row, column).Equals(At(column, row))) { return false; } } } return true; } /// /// Evaluates whether this matrix is hermitian (conjugate symmetric). /// public abstract bool IsHermitian(); /// /// Evaluates whether this matrix is conjugate symmetric. /// [Obsolete("Use IsHermitian instead. Will be removed in v4.")] public bool IsConjugateSymmetric() { return IsHermitian(); } /// /// Returns this matrix as a multidimensional array. /// /// A multidimensional containing the values of this matrix. public T[,] ToArray() { return Storage.ToArray(); } /// /// Returns the matrix's elements as an array with the data laid out column-wise. /// ///
        /// 1, 2, 3
        /// 4, 5, 6  will be returned as  1, 4, 7, 2, 5, 8, 3, 6, 9
        /// 7, 8, 9
        /// 
/// An array containing the matrix's elements. /// /// public T[] ToColumnWiseArray() { return Storage.ToColumnMajorArray(); } /// /// Returns the matrix's elements as an array with the data laid row-wise. /// ///
        /// 1, 2, 3
        /// 4, 5, 6  will be returned as  1, 2, 3, 4, 5, 6, 7, 8, 9
        /// 7, 8, 9
        /// 
/// An array containing the matrix's elements. /// /// public T[] ToRowWiseArray() { return Storage.ToRowMajorArray(); } /// /// Returns an IEnumerable that can be used to iterate through all values of the matrix. /// /// /// The enumerator will include all values, even if they are zero. /// The ordering of the values is unspecified (not necessarily column-wise or row-wise). /// /// /// public IEnumerable Enumerate() { return Storage.Enumerate(); } /// /// Returns an IEnumerable that can be used to iterate through all values of the matrix. /// /// /// The enumerator will include all values, even if they are zero. /// The ordering of the values is unspecified (not necessarily column-wise or row-wise). /// /// /// public IEnumerable Enumerate(Zeros zeros = Zeros.Include) { switch (zeros) { case Zeros.AllowSkip: return Storage.EnumerateNonZero(); default: return Storage.Enumerate(); } } /// /// Returns an IEnumerable that can be used to iterate through all values of the matrix and their index. /// /// /// The enumerator returns a Tuple with the first two values being the row and column index /// and the third value being the value of the element at that index. /// The enumerator will include all values, even if they are zero. /// public IEnumerable> EnumerateIndexed() { return Storage.EnumerateIndexed(); } /// /// Returns an IEnumerable that can be used to iterate through all values of the matrix and their index. /// /// /// The enumerator returns a Tuple with the first two values being the row and column index /// and the third value being the value of the element at that index. /// The enumerator will include all values, even if they are zero. /// public IEnumerable> EnumerateIndexed(Zeros zeros = Zeros.Include) { switch (zeros) { case Zeros.AllowSkip: return Storage.EnumerateNonZeroIndexed(); default: return Storage.EnumerateIndexed(); } } /// /// Returns an IEnumerable that can be used to iterate through all non-zero values of the matrix. /// /// /// The enumerator will skip all elements with a zero value. /// [Obsolete("Use Enumerate(Zeros.AllowSkip) instead. Will be removed in v4.")] public IEnumerable EnumerateNonZero() { return Storage.EnumerateNonZero(); } /// /// Returns an IEnumerable that can be used to iterate through all non-zero values of the matrix and their index. /// /// /// The enumerator returns a Tuple with the first two values being the row and column index /// and the third value being the value of the element at that index. /// The enumerator will skip all elements with a zero value. /// [Obsolete("Use EnumerateIndexed(Zeros.AllowSkip) instead. Will be removed in v4.")] public IEnumerable> EnumerateNonZeroIndexed() { return Storage.EnumerateNonZeroIndexed(); } /// /// Returns an IEnumerable that can be used to iterate through all columns of the matrix. /// public IEnumerable> EnumerateColumns() { for (var i = 0; i < ColumnCount; i++) { yield return Column(i); } } /// /// Returns an IEnumerable that can be used to iterate through a subset of all columns of the matrix. /// /// The column to start enumerating over. /// The number of columns to enumerating over. public IEnumerable> EnumerateColumns(int index, int length) { var maxIndex = Math.Min(index + length, ColumnCount); for (var i = Math.Max(index, 0); i < maxIndex; i++) { yield return Column(i); } } /// /// Returns an IEnumerable that can be used to iterate through all columns of the matrix and their index. /// /// /// The enumerator returns a Tuple with the first value being the column index /// and the second value being the value of the column at that index. /// public IEnumerable>> EnumerateColumnsIndexed() { for (var i = 0; i < ColumnCount; i++) { yield return new Tuple>(i, Column(i)); } } /// /// Returns an IEnumerable that can be used to iterate through a subset of all columns of the matrix and their index. /// /// The column to start enumerating over. /// The number of columns to enumerating over. /// /// The enumerator returns a Tuple with the first value being the column index /// and the second value being the value of the column at that index. /// public IEnumerable>> EnumerateColumnsIndexed(int index, int length) { var maxIndex = Math.Min(index + length, ColumnCount); for (var i = Math.Max(index, 0); i < maxIndex; i++) { yield return new Tuple>(i, Column(i)); } } /// /// Returns an IEnumerable that can be used to iterate through all rows of the matrix. /// public IEnumerable> EnumerateRows() { for (var i = 0; i < RowCount; i++) { yield return Row(i); } } /// /// Returns an IEnumerable that can be used to iterate through a subset of all rows of the matrix. /// /// The row to start enumerating over. /// The number of rows to enumerating over. public IEnumerable> EnumerateRows(int index, int length) { var maxIndex = Math.Min(index + length, RowCount); for (var i = Math.Max(index, 0); i < maxIndex; i++) { yield return Row(i); } } /// /// Returns an IEnumerable that can be used to iterate through all rows of the matrix and their index. /// /// /// The enumerator returns a Tuple with the first value being the row index /// and the second value being the value of the row at that index. /// public IEnumerable>> EnumerateRowsIndexed() { for (var i = 0; i < RowCount; i++) { yield return new Tuple>(i, Row(i)); } } /// /// Returns an IEnumerable that can be used to iterate through a subset of all rows of the matrix and their index. /// /// The row to start enumerating over. /// The number of rows to enumerating over. /// /// The enumerator returns a Tuple with the first value being the row index /// and the second value being the value of the row at that index. /// public IEnumerable>> EnumerateRowsIndexed(int index, int length) { var maxIndex = Math.Min(index + length, RowCount); for (var i = Math.Max(index, 0); i < maxIndex; i++) { yield return new Tuple>(i, Row(i)); } } /// /// Applies a function to each value of this matrix and replaces the value with its result. /// If forceMapZero is not set to true, zero values may or may not be skipped depending /// on the actual data storage implementation (relevant mostly for sparse matrices). /// public void MapInplace(Func f, Zeros zeros = Zeros.AllowSkip) { Storage.MapInplace(f, zeros); } /// /// Applies a function to each value of this matrix and replaces the value with its result. /// The row and column indices of each value (zero-based) are passed as first arguments to the function. /// If forceMapZero is not set to true, zero values may or may not be skipped depending /// on the actual data storage implementation (relevant mostly for sparse matrices). /// public void MapIndexedInplace(Func f, Zeros zeros = Zeros.AllowSkip) { Storage.MapIndexedInplace(f, zeros); } /// /// Applies a function to each value of this matrix and replaces the value in the result matrix. /// If forceMapZero is not set to true, zero values may or may not be skipped depending /// on the actual data storage implementation (relevant mostly for sparse matrices). /// public void Map(Func f, Matrix result, Zeros zeros = Zeros.AllowSkip) { if (ReferenceEquals(this, result)) { Storage.MapInplace(f, zeros); } else { Storage.MapTo(result.Storage, f, zeros, zeros == Zeros.Include ? ExistingData.AssumeZeros : ExistingData.Clear); } } /// /// Applies a function to each value of this matrix and replaces the value in the result matrix. /// The index of each value (zero-based) is passed as first argument to the function. /// If forceMapZero is not set to true, zero values may or may not be skipped depending /// on the actual data storage implementation (relevant mostly for sparse matrices). /// public void MapIndexed(Func f, Matrix result, Zeros zeros = Zeros.AllowSkip) { if (ReferenceEquals(this, result)) { Storage.MapIndexedInplace(f, zeros); } else { Storage.MapIndexedTo(result.Storage, f, zeros, zeros == Zeros.Include ? ExistingData.AssumeZeros : ExistingData.Clear); } } /// /// Applies a function to each value of this matrix and replaces the value in the result matrix. /// If forceMapZero is not set to true, zero values may or may not be skipped depending /// on the actual data storage implementation (relevant mostly for sparse matrices). /// public void MapConvert(Func f, Matrix result, Zeros zeros = Zeros.AllowSkip) where TU : struct, IEquatable, IFormattable { Storage.MapTo(result.Storage, f, zeros, zeros == Zeros.Include ? ExistingData.AssumeZeros : ExistingData.Clear); } /// /// Applies a function to each value of this matrix and replaces the value in the result matrix. /// The index of each value (zero-based) is passed as first argument to the function. /// If forceMapZero is not set to true, zero values may or may not be skipped depending /// on the actual data storage implementation (relevant mostly for sparse matrices). /// public void MapIndexedConvert(Func f, Matrix result, Zeros zeros = Zeros.AllowSkip) where TU : struct, IEquatable, IFormattable { Storage.MapIndexedTo(result.Storage, f, zeros, zeros == Zeros.Include ? ExistingData.AssumeZeros : ExistingData.Clear); } /// /// Applies a function to each value of this matrix and returns the results as a new matrix. /// If forceMapZero is not set to true, zero values may or may not be skipped depending /// on the actual data storage implementation (relevant mostly for sparse matrices). /// public Matrix Map(Func f, Zeros zeros = Zeros.AllowSkip) where TU : struct, IEquatable, IFormattable { var result = Matrix.Build.SameAs(this, RowCount, ColumnCount, fullyMutable: zeros == Zeros.Include); Storage.MapToUnchecked(result.Storage, f, zeros, ExistingData.AssumeZeros); return result; } /// /// Applies a function to each value of this matrix and returns the results as a new matrix. /// The index of each value (zero-based) is passed as first argument to the function. /// If forceMapZero is not set to true, zero values may or may not be skipped depending /// on the actual data storage implementation (relevant mostly for sparse matrices). /// public Matrix MapIndexed(Func f, Zeros zeros = Zeros.AllowSkip) where TU : struct, IEquatable, IFormattable { var result = Matrix.Build.SameAs(this, RowCount, ColumnCount, fullyMutable: zeros == Zeros.Include); Storage.MapIndexedToUnchecked(result.Storage, f, zeros, ExistingData.AssumeZeros); return result; } /// /// For each row, applies a function f to each element of the row, threading an accumulator argument through the computation. /// Returns an array with the resulting accumulator states for each row. /// public TU[] FoldByRow(Func f, TU state, Zeros zeros = Zeros.AllowSkip) { var result = new TU[RowCount]; if (!EqualityComparer.Default.Equals(state, default(TU))) { CommonParallel.For(0, result.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { result[i] = state; } }); } Storage.FoldByRowUnchecked(result, f, (x, c) => x, result, zeros); return result; } /// /// For each column, applies a function f to each element of the column, threading an accumulator argument through the computation. /// Returns an array with the resulting accumulator states for each column. /// public TU[] FoldByColumn(Func f, TU state, Zeros zeros = Zeros.AllowSkip) { var result = new TU[ColumnCount]; if (!EqualityComparer.Default.Equals(state, default(TU))) { CommonParallel.For(0, result.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { result[i] = state; } }); } Storage.FoldByColumnUnchecked(result, f, (x, c) => x, result, zeros); return result; } /// /// Applies a function f to each row vector, threading an accumulator vector argument through the computation. /// Returns the resulting accumulator vector. /// public Vector FoldRows(Func, Vector, Vector> f, Vector state) where TU : struct, IEquatable, IFormattable { foreach (var vector in EnumerateRows()) { state = f(state, vector); } return state; } /// /// Applies a function f to each column vector, threading an accumulator vector argument through the computation. /// Returns the resulting accumulator vector. /// public Vector FoldColumns(Func, Vector, Vector> f, Vector state) where TU : struct, IEquatable, IFormattable { foreach (var vector in EnumerateColumns()) { state = f(state, vector); } return state; } /// /// Reduces all row vectors by applying a function between two of them, until only a single vector is left. /// public Vector ReduceRows(Func, Vector, Vector> f) { return EnumerateRows().Aggregate(f); } /// /// Reduces all column vectors by applying a function between two of them, until only a single vector is left. /// public Vector ReduceColumns(Func, Vector, Vector> f) { return EnumerateColumns().Aggregate(f); } } }