(this, result, "result");
}
Storage.CopySubMatrixToUnchecked(result.Storage, 0, 0, RowCount, 0, 0, ColumnCount, ExistingData.Clear);
lower.Storage.CopySubMatrixToUnchecked(result.Storage, 0, RowCount, lower.RowCount, 0, ColumnCount, lower.ColumnCount, ExistingData.Clear);
}
///
/// 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();
///
/// Returns this matrix as a multidimensional array.
/// The returned array will be independent from this matrix.
/// A new memory block will be allocated for the 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 by column (column major).
/// The returned array will be independent from this matrix.
/// A new memory block will be allocated for the array.
///
///
/// 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[] ToColumnMajorArray()
{
return Storage.ToColumnMajorArray();
}
///
/// Returns the matrix's elements as an array with the data laid row by row (row major).
/// The returned array will be independent from this matrix.
/// A new memory block will be allocated for the array.
///
///
/// 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[] ToRowMajorArray()
{
return Storage.ToRowMajorArray();
}
///
/// Returns this matrix as array of row arrays.
/// The returned arrays will be independent from this matrix.
/// A new memory block will be allocated for the arrays.
///
public T[][] ToRowArrays()
{
return Storage.ToRowArrays();
}
///
/// Returns this matrix as array of column arrays.
/// The returned arrays will be independent from this matrix.
/// A new memory block will be allocated for the arrays.
///
public T[][] ToColumnArrays()
{
return Storage.ToColumnArrays();
}
///
/// Returns the internal multidimensional array of this matrix if, and only if, this matrix is stored by such an array internally.
/// Otherwise returns null. Changes to the returned array and the matrix will affect each other.
/// Use ToArray instead if you always need an independent array.
///
public T[,] AsArray()
{
return Storage.AsArray();
}
///
/// Returns the internal column by column (column major) array of this matrix if, and only if, this matrix is stored by such arrays internally.
/// Otherwise returns null. Changes to the returned arrays and the matrix will affect each other.
/// Use ToColumnMajorArray instead if you always need an independent array.
///
///
/// 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[] AsColumnMajorArray()
{
return Storage.AsColumnMajorArray();
}
///
/// Returns the internal row by row (row major) array of this matrix if, and only if, this matrix is stored by such arrays internally.
/// Otherwise returns null. Changes to the returned arrays and the matrix will affect each other.
/// Use ToRowMajorArray instead if you always need an independent array.
///
///
/// 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[] AsRowMajorArray()
{
return Storage.AsRowMajorArray();
}
///
/// Returns the internal row arrays of this matrix if, and only if, this matrix is stored by such arrays internally.
/// Otherwise returns null. Changes to the returned arrays and the matrix will affect each other.
/// Use ToRowArrays instead if you always need an independent array.
///
public T[][] AsRowArrays()
{
return Storage.AsRowArrays();
}
///
/// Returns the internal column arrays of this matrix if, and only if, this matrix is stored by such arrays internally.
/// Otherwise returns null. Changes to the returned arrays and the matrix will affect each other.
/// Use ToColumnArrays instead if you always need an independent array.
///
public T[][] AsColumnArrays()
{
return Storage.AsColumnArrays();
}
///
/// 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 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);
}
///
/// Applies a function to each value pair of two matrices and replaces the value in the result vector.
///
public void Map2(Func f, Matrix other, Matrix result, Zeros zeros = Zeros.AllowSkip)
{
Storage.Map2To(result.Storage, other.Storage, f, zeros, ExistingData.Clear);
}
///
/// Applies a function to each value pair of two matrices and returns the results as a new vector.
///
public Matrix Map2(Func f, Matrix other, Zeros zeros = Zeros.AllowSkip)
{
var result = Build.SameAs(this);
Storage.Map2To(result.Storage, other.Storage, f, zeros, ExistingData.AssumeZeros);
return result;
}
///
/// Applies a function to update the status with each value pair of two matrices and returns the resulting status.
///
public TState Fold2(Func f, TState state, Matrix other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable, IFormattable
{
return Storage.Fold2(other.Storage, f, state, zeros);
}
///
/// Returns a tuple with the index and value of the first element satisfying a predicate, or null if none is found.
/// Zero elements may be skipped on sparse data structures if allowed (default).
///
public Tuple Find(Func predicate, Zeros zeros = Zeros.AllowSkip)
{
return Storage.Find(predicate, zeros);
}
///
/// Returns a tuple with the index and values of the first element pair of two matrices of the same size satisfying a predicate, or null if none is found.
/// Zero elements may be skipped on sparse data structures if allowed (default).
///
public Tuple Find2(Func predicate, Matrix other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable, IFormattable
{
return Storage.Find2(other.Storage, predicate, zeros);
}
///
/// Returns true if at least one element satisfies a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
///
public bool Exists(Func predicate, Zeros zeros = Zeros.AllowSkip)
{
return Storage.Find(predicate, zeros) != null;
}
///
/// Returns true if at least one element pairs of two matrices of the same size satisfies a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
///
public bool Exists2(Func predicate, Matrix other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable, IFormattable
{
return Storage.Find2(other.Storage, predicate, zeros) != null;
}
///
/// Returns true if all elements satisfy a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
///
public bool ForAll(Func predicate, Zeros zeros = Zeros.AllowSkip)
{
return Storage.Find(x => !predicate(x), zeros) == null;
}
///
/// Returns true if all element pairs of two matrices of the same size satisfy a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
///
public bool ForAll2(Func predicate, Matrix other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable, IFormattable
{
return Storage.Find2(other.Storage, (x, y) => !predicate(x, y), zeros) == null;
}
}
}