// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // // Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // namespace MathNet.Numerics.LinearAlgebra.Generic { using Factorization; using Numerics; using Properties; using Storage; using System; using System.Collections.Generic; using System.Numerics; using System.Runtime; /// /// 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; } /// /// 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; } /// /// Constructs matrix from a list of column vectors. /// /// The vectors to construct the matrix from. /// The matrix constructed from the list of column vectors. /// Creates a matrix of size Max([i].Count) x .Count public static Matrix CreateFromColumns(IList> columnVectors) { if (columnVectors == null) { throw new ArgumentNullException("columnVectors"); } if (columnVectors.Count == 0) { throw new ArgumentOutOfRangeException("columnVectors"); } var rows = columnVectors[0].Count; var columns = columnVectors.Count; for (var column = 1; column < columns; column++) { rows = Math.Max(rows, columnVectors[column].Count); } var matrix = columnVectors[0].CreateMatrix(rows, columns); for (var j = 0; j < columns; j++) { for (var i = 0; i < columnVectors[j].Count; i++) { matrix.At(i, j, columnVectors[j][i]); } } return matrix; } /// /// Constructs matrix from a list of row vectors. /// /// The vectors to construct the matrix from. /// The matrix constructed from the list of row vectors. /// Creates a matrix of size Max(.Count) x [i].Count public static Matrix CreateFromRows(IList> rowVectors) { if (rowVectors == null) { throw new ArgumentNullException("rowVectors"); } if (rowVectors.Count == 0) { throw new ArgumentOutOfRangeException("rowVectors"); } var rows = rowVectors.Count; var columns = rowVectors[0].Count; for (var row = 1; row < rows; row++) { columns = Math.Max(columns, rowVectors[row].Count); } var matrix = rowVectors[0].CreateMatrix(rows, columns); for (var i = 0; i < rows; i++) { for (var j = 0; j < rowVectors[i].Count; j++) { matrix.At(i, j, rowVectors[i][j]); } } return matrix; } /// /// 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 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 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 submatrix to zero. /// public void ClearSubMatrix(int rowIndex, int rowCount, int columnIndex, int columnCount) { if (rowCount < 1) { throw new ArgumentOutOfRangeException("rowCount", Resources.ArgumentMustBePositive); } if (columnCount < 1) { throw new ArgumentOutOfRangeException("columnCount", Resources.ArgumentMustBePositive); } 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); } /// /// Creates a clone of this instance. /// /// /// A clone of the instance. /// public Matrix Clone() { var result = CreateMatrix(RowCount, ColumnCount); Storage.CopyToUnchecked(result.Storage, skipClearing: true); 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); } /// /// Creates a Matrix for the given number of rows and columns. /// /// The number of rows. /// The number of columns. /// True if all fields must be mutable (e.g. not a diagonal matrix). /// /// A Matrix with the given dimensions. /// /// /// Creates a matrix of the same matrix type as the current matrix. /// public abstract Matrix CreateMatrix(int numberOfRows, int numberOfColumns, bool fullyMutable = false); /// /// Creates a Vector with a the given dimension. /// /// The size of the vector. /// True if all fields must be mutable. /// /// A Vector with the given dimension. /// /// /// Creates a vector of the same type as the current matrix. /// public abstract Vector CreateVector(int size, bool fullyMutable = false); /// /// 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 = CreateVector(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 = CreateVector(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 = CreateVector(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 = CreateVector(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 ret = CreateMatrix(RowCount, ColumnCount); for (var row = 0; row < RowCount; row++) { for (var column = row; column < ColumnCount; column++) { ret.At(row, column, At(row, column)); } } return ret; } /// /// Returns a new matrix containing the lower triangle of this matrix. /// /// The lower triangle of this matrix. public virtual Matrix LowerTriangle() { var ret = CreateMatrix(RowCount, ColumnCount); for (var row = 0; row < RowCount; row++) { for (var column = 0; column <= row && column < ColumnCount; column++) { ret.At(row, column, At(row, column)); } } return ret; } /// /// 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 target = CreateMatrix(rowCount, columnCount); Storage.CopySubMatrixTo(target.Storage, rowIndex, 0, rowCount, columnIndex, 0, columnCount, skipClearing: true); return target; } /// /// 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 = CreateVector(min); for (var i = 0; i < min; i++) { diagonal[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 = CreateMatrix(RowCount, ColumnCount); for (var row = 0; row < RowCount; row++) { for (var column = 0; column < row; 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 = CreateMatrix(RowCount, ColumnCount); 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 virtual 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 = CreateMatrix(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; } /// /// 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 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 virtual 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 = CreateMatrix(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 + 1; i++) { result.SetRow(i, Row(i - 1)); } 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 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 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 /// If is /// 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) { if (subMatrix == null) { throw new ArgumentNullException("subMatrix"); } subMatrix.Storage.CopySubMatrixTo(Storage, 0, rowIndex, rowCount, 0, 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[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 virtual Matrix Transpose() { var ret = CreateMatrix(ColumnCount, RowCount); for (var j = 0; j < ColumnCount; j++) { for (var i = 0; i < RowCount; i++) { ret.At(j, i, At(i, j)); } } return ret; } /// /// 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 = CreateMatrix(RowCount, ColumnCount + right.ColumnCount, fullyMutable: true); Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, RowCount, 0, 0, ColumnCount, skipClearing: true); right.Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, right.RowCount, 0, ColumnCount, right.ColumnCount, skipClearing: true); 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 = CreateMatrix(RowCount + lower.RowCount, ColumnCount, fullyMutable: true); Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, RowCount, 0, 0, ColumnCount, skipClearing: true); lower.Storage.CopySubMatrixToUnchecked(result.Storage, 0, RowCount, lower.RowCount, 0, 0, lower.ColumnCount, skipClearing: true); 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 = CreateMatrix(RowCount + lower.RowCount, ColumnCount + lower.ColumnCount, fullyMutable: true); 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); } /// Calculates the L1 norm. /// The L1 norm of the matrix. public abstract T L1Norm(); /// Calculates the L2 norm. /// The L2 norm of the matrix. /// For sparse matrices, the L2 norm is computed using a dense implementation of singular value decomposition. /// In a later release, it will be replaced with a sparse implementation. public virtual T L2Norm() { return Svd.Create(this, false).Norm2; } /// Calculates the Frobenius norm of this matrix. /// The Frobenius norm of this matrix. public abstract T FrobeniusNorm(); /// Calculates the infinity norm of this matrix. /// The infinity norm of this matrix. public abstract T InfinityNorm(); /// /// Gets a value indicating whether this matrix is symmetric. /// public virtual bool IsSymmetric { get { 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; } } /// /// Returns an that enumerates over the matrix columns. /// /// An that enumerates over the matrix columns /// public virtual IEnumerable>> ColumnEnumerator() { for (var i = 0; i < ColumnCount; i++) { yield return new Tuple>(i, Column(i)); } } /// /// Returns an that enumerates the requested matrix columns. /// /// The column to start enumerating over. /// The number of columns to enumerating over. /// An that enumerates over requested matrix columns. /// /// If: /// is negative, /// or greater than or equal to the number of columns. /// (index + length) >= Columns. /// /// If is not positive. public virtual IEnumerable>> ColumnEnumerator(int index, int length) { if (index >= ColumnCount || index < 0) { throw new ArgumentOutOfRangeException("index"); } if (index + length > ColumnCount) { throw new ArgumentOutOfRangeException("length"); } if (length < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); } var maxIndex = index + length; for (var i = index; i < maxIndex; i++) { yield return new Tuple>(i, Column(i)); } } /// /// Returns an that enumerates the requested matrix rows. /// /// The row to start enumerating over. /// The number of rows to enumerating over. /// An that enumerates over requested matrix rows. /// /// If: /// is negative, /// or greater than or equal to the number of rows. /// (index + length) >= Rows. /// If is not positive. public virtual IEnumerable>> RowEnumerator(int index, int length) { if (index >= RowCount || index < 0) { throw new ArgumentOutOfRangeException("index"); } if (index + length > RowCount) { throw new ArgumentOutOfRangeException("length"); } if (length < 1) { throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); } var maxi = index + length; for (var i = index; i < maxi; i++) { yield return new Tuple>(i, Row(i)); } } /// /// Returns an that enumerates over the matrix rows. /// /// An that enumerates over the matrix rows /// public virtual IEnumerable>> RowEnumerator() { for (var i = 0; i < RowCount; i++) { yield return new Tuple>(i, Row(i)); } } /// /// Iterates throw each element in the matrix (row-wise). /// /// The value at the current iteration along with its position (row, column, value). public virtual IEnumerable> IndexedEnumerator() { for (var row = 0; row < RowCount; row++) { for (var column = 0; column < ColumnCount; column++) { yield return new Tuple(row, column, At(row, column)); } } } /// /// 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(); } } }