// // 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 MathNet.Numerics.Distributions; using MathNet.Numerics.LinearAlgebra.Solvers; using MathNet.Numerics.LinearAlgebra.Storage; // TODO: split up and move to proper folders namespace MathNet.Numerics.LinearAlgebra.Double { internal class MatrixBuilder : MatrixBuilder { public override double Zero { get { return 0d; } } public override double One { get { return 1d; } } public override Matrix Dense(DenseColumnMajorMatrixStorage storage) { return new DenseMatrix(storage); } public override Matrix Sparse(SparseCompressedRowMatrixStorage storage) { return new SparseMatrix(storage); } public override Matrix Diagonal(DiagonalMatrixStorage storage) { return new DiagonalMatrix(storage); } public override Matrix Random(int rows, int columns, IContinuousDistribution distribution) { return Dense(rows, columns, (i, j) => distribution.Sample()); } public override IIterationStopCriterium[] IterativeSolverStopCriteria(int maxIterations = 1000) { return new IIterationStopCriterium[] { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium(maxIterations), new ResidualStopCriterium(1e-12) }; } } internal class VectorBuilder : VectorBuilder { public override double Zero { get { return 0d; } } public override double One { get { return 1d; } } public override Vector Dense(DenseVectorStorage storage) { return new DenseVector(storage); } public override Vector Sparse(SparseVectorStorage storage) { return new SparseVector(storage); } public override Vector Random(int length, IContinuousDistribution distribution) { return Dense(length, i => distribution.Sample()); } } } namespace MathNet.Numerics.LinearAlgebra.Single { internal class MatrixBuilder : MatrixBuilder { public override float Zero { get { return 0f; } } public override float One { get { return 1f; } } public override Matrix Dense(DenseColumnMajorMatrixStorage storage) { return new DenseMatrix(storage); } public override Matrix Sparse(SparseCompressedRowMatrixStorage storage) { return new SparseMatrix(storage); } public override Matrix Diagonal(DiagonalMatrixStorage storage) { return new DiagonalMatrix(storage); } public override Matrix Random(int rows, int columns, IContinuousDistribution distribution) { return Dense(rows, columns, (i, j) => (float) distribution.Sample()); } public override IIterationStopCriterium[] IterativeSolverStopCriteria(int maxIterations = 1000) { return new IIterationStopCriterium[] { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium(maxIterations), new ResidualStopCriterium(1e-6) }; } } internal class VectorBuilder : VectorBuilder { public override float Zero { get { return 0f; } } public override float One { get { return 1f; } } public override Vector Dense(DenseVectorStorage storage) { return new DenseVector(storage); } public override Vector Sparse(SparseVectorStorage storage) { return new SparseVector(storage); } public override Vector Random(int length, IContinuousDistribution distribution) { return Dense(length, i => (float) distribution.Sample()); } } } namespace MathNet.Numerics.LinearAlgebra.Complex { #if NOSYSNUMERICS using Complex = Numerics.Complex; #else using Complex = System.Numerics.Complex; #endif internal class MatrixBuilder : MatrixBuilder { public override Complex Zero { get { return Complex.Zero; } } public override Complex One { get { return Complex.One; } } public override Matrix Dense(DenseColumnMajorMatrixStorage storage) { return new DenseMatrix(storage); } public override Matrix Sparse(SparseCompressedRowMatrixStorage storage) { return new SparseMatrix(storage); } public override Matrix Diagonal(DiagonalMatrixStorage storage) { return new DiagonalMatrix(storage); } public override Matrix Random(int rows, int columns, IContinuousDistribution distribution) { return Dense(rows, columns, (i, j) => new Complex(distribution.Sample(), distribution.Sample())); } public override IIterationStopCriterium[] IterativeSolverStopCriteria(int maxIterations = 1000) { return new IIterationStopCriterium[] { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium(maxIterations), new ResidualStopCriterium(1e-12) }; } } internal class VectorBuilder : VectorBuilder { public override Complex Zero { get { return Complex.Zero; } } public override Complex One { get { return Complex.One; } } public override Vector Dense(DenseVectorStorage storage) { return new DenseVector(storage); } public override Vector Sparse(SparseVectorStorage storage) { return new SparseVector(storage); } public override Vector Random(int length, IContinuousDistribution distribution) { return Dense(length, i => new Complex(distribution.Sample(), distribution.Sample())); } } } namespace MathNet.Numerics.LinearAlgebra.Complex32 { internal class MatrixBuilder : MatrixBuilder { public override Numerics.Complex32 Zero { get { return Numerics.Complex32.Zero; } } public override Numerics.Complex32 One { get { return Numerics.Complex32.One; } } public override Matrix Dense(DenseColumnMajorMatrixStorage storage) { return new DenseMatrix(storage); } public override Matrix Sparse(SparseCompressedRowMatrixStorage storage) { return new SparseMatrix(storage); } public override Matrix Diagonal(DiagonalMatrixStorage storage) { return new DiagonalMatrix(storage); } public override Matrix Random(int rows, int columns, IContinuousDistribution distribution) { return Dense(rows, columns, (i, j) => new Numerics.Complex32((float) distribution.Sample(), (float) distribution.Sample())); } public override IIterationStopCriterium[] IterativeSolverStopCriteria(int maxIterations = 1000) { return new IIterationStopCriterium[] { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium(maxIterations), new ResidualStopCriterium(1e-6) }; } } internal class VectorBuilder : VectorBuilder { public override Numerics.Complex32 Zero { get { return Numerics.Complex32.Zero; } } public override Numerics.Complex32 One { get { return Numerics.Complex32.One; } } public override Vector Dense(DenseVectorStorage storage) { return new DenseVector(storage); } public override Vector Sparse(SparseVectorStorage storage) { return new SparseVector(storage); } public override Vector Random(int length, IContinuousDistribution distribution) { return Dense(length, i => new Numerics.Complex32((float) distribution.Sample(), (float) distribution.Sample())); } } } namespace MathNet.Numerics.LinearAlgebra { #if NOSYSNUMERICS using Complex64 = Numerics.Complex; #else using Complex64 = System.Numerics.Complex; #endif /// /// Generic linear algebra type builder, for situations where a matrix or vector /// must be created in a generic way. Usage of generic builders should not be /// required in normal user code. /// public abstract class MatrixBuilder where T : struct, IEquatable, IFormattable { /// /// Gets the value of 0.0 for type T. /// public abstract T Zero { get; } /// /// Gets the value of 1.0 for type T. /// public abstract T One { get; } /// /// Create a new matrix straight from an initialized matrix storage instance. /// If you have an instance of a discrete storage type instead, use their direct methods instead. /// public Matrix OfStorage(MatrixStorage storage) { var dense = storage as DenseColumnMajorMatrixStorage; if (dense != null) return Dense(dense); var sparse = storage as SparseCompressedRowMatrixStorage; if (sparse != null) return Sparse(sparse); var diagonal = storage as DiagonalMatrixStorage; if (diagonal != null) return Diagonal(diagonal); throw new NotSupportedException(); } /// /// Create a new matrix with the same kind of the provided example. /// public Matrix SameAs(Matrix example, int rows, int columns, bool fullyMutable = false) { var storage = example.Storage; if (storage is DenseColumnMajorMatrixStorage) return Dense(rows, columns); if (!fullyMutable && storage is DiagonalMatrixStorage) return Diagonal(rows, columns); if (storage is SparseCompressedRowMatrixStorage) return Sparse(rows, columns); return Dense(rows, columns); } /// /// Create a new matrix with the same kind and dimensions of the provided example. /// public Matrix SameAs(Matrix example) { return SameAs(example, example.RowCount, example.ColumnCount); } /// /// Create a new matrix with the same kind of the provided example. /// public Matrix SameAs(Vector example, int rows, int columns) { return example.Storage.IsDense ? Dense(rows, columns) : Sparse(rows, columns); } /// /// Create a new matrix with a type that can represent and is closest to both provided samples. /// public Matrix SameAs(Matrix example, Matrix otherExample, int rows, int columns, bool fullyMutable = false) { var storage1 = example.Storage; var storage2 = otherExample.Storage; if (storage1 is DenseColumnMajorMatrixStorage || storage2 is DenseColumnMajorMatrixStorage) return Dense(rows, columns); if (!fullyMutable && storage1 is DiagonalMatrixStorage && storage2 is DiagonalMatrixStorage) return Diagonal(rows, columns); if (storage1 is SparseCompressedRowMatrixStorage || storage2 is SparseCompressedRowMatrixStorage) return Sparse(rows, columns); return Dense(rows, columns); } /// /// Create a new matrix with a type that can represent and is closest to both provided samples and the dimensions of example. /// public Matrix SameAs(Matrix example, Matrix otherExample) { return SameAs(example, otherExample, example.RowCount, example.ColumnCount); } /// /// Create a new dense matrix with values sampled from the provided random distribution. /// public abstract Matrix Random(int rows, int columns, IContinuousDistribution distribution); /// /// Create a new dense matrix straight from an initialized matrix storage instance. /// The storage is used directly without copying. /// Intended for advanced scenarios where you're working directly with /// storage for performance or interop reasons. /// public abstract Matrix Dense(DenseColumnMajorMatrixStorage storage); /// /// Create a new dense matrix with the given number of rows and columns. /// All cells of the matrix will be initialized to zero. /// Zero-length matrices are not supported. /// public Matrix Dense(int rows, int columns) { return Dense(new DenseColumnMajorMatrixStorage(rows, columns)); } /// /// Create a new dense matrix with the given number of rows and columns directly binding to a raw array. /// The array is assumed to be in column-major order (column by column) and is used directly without copying. /// Very efficient, but changes to the array and the matrix will affect each other. /// /// public Matrix Dense(int rows, int columns, T[] storage) { return Dense(new DenseColumnMajorMatrixStorage(rows, columns, storage)); } /// /// Create a new dense matrix and initialize each value to the same provided value. /// public Matrix Dense(int rows, int columns, T value) { if (Zero.Equals(value)) return Dense(rows, columns); return Dense(DenseColumnMajorMatrixStorage.OfInit(rows, columns, (i, j) => value)); } /// /// Create a new dense matrix and initialize each value using the provided init function. /// public Matrix Dense(int rows, int columns, Func init) { return Dense(DenseColumnMajorMatrixStorage.OfInit(rows, columns, init)); } /// /// Create a new diagonal dense matrix and initialize each diagonal value to the same provided value. /// public Matrix DenseDiagonal(int rows, int columns, T value) { if (Zero.Equals(value)) return Dense(rows, columns); return Dense(DenseColumnMajorMatrixStorage.OfDiagonalInit(rows, columns, i => value)); } /// /// Create a new diagonal dense matrix and initialize each diagonal value to the same provided value. /// public Matrix DenseDiagonal(int order, T value) { if (Zero.Equals(value)) return Dense(order, order); return Dense(DenseColumnMajorMatrixStorage.OfDiagonalInit(order, order, i => value)); } /// /// Create a new diagonal dense matrix and initialize each diagonal value using the provided init function. /// public Matrix DenseDiagonal(int rows, int columns, Func init) { return Dense(DenseColumnMajorMatrixStorage.OfDiagonalInit(rows, columns, init)); } /// /// Create a new diagonal dense identity matrix with a one-diagonal. /// public Matrix DenseIdentity(int rows, int columns) { return Dense(DenseColumnMajorMatrixStorage.OfDiagonalInit(rows, columns, i => One)); } /// /// Create a new diagonal dense identity matrix with a one-diagonal. /// public Matrix DenseIdentity(int order) { return Dense(DenseColumnMajorMatrixStorage.OfDiagonalInit(order, order, i => One)); } /// /// Create a new dense matrix as a copy of the given other matrix. /// This new matrix will be independent from the other matrix. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfMatrix(Matrix matrix) { return Dense(DenseColumnMajorMatrixStorage.OfMatrix(matrix.Storage)); } /// /// Create a new dense matrix as a copy of the given two-dimensional array. /// This new matrix will be independent from the provided array. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfArray(T[,] array) { return Dense(DenseColumnMajorMatrixStorage.OfArray(array)); } /// /// Create a new dense matrix as a copy of the given indexed enumerable. /// Keys must be provided at most once, zero is assumed if a key is omitted. /// This new matrix will be independent from the enumerable. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfIndexed(int rows, int columns, IEnumerable> enumerable) { return Dense(DenseColumnMajorMatrixStorage.OfIndexedEnumerable(rows, columns, enumerable)); } /// /// Create a new dense matrix as a copy of the given enumerable. /// The enumerable is assumed to be in column-major order (column by column). /// This new matrix will be independent from the enumerable. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfColumnMajor(int rows, int columns, IEnumerable columnMajor) { return Dense(DenseColumnMajorMatrixStorage.OfColumnMajorEnumerable(rows, columns, columnMajor)); } /// /// Create a new dense matrix as a copy of the given enumerable of enumerable columns. /// Each enumerable in the master enumerable specifies a column. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfColumns(IEnumerable> data) { return Dense(DenseColumnMajorMatrixStorage.OfColumnArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray())); } /// /// Create a new dense matrix as a copy of the given enumerable of enumerable columns. /// Each enumerable in the master enumerable specifies a column. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfColumns(int rows, int columns, IEnumerable> data) { return Dense(DenseColumnMajorMatrixStorage.OfColumnEnumerables(rows, columns, data)); } /// /// Create a new dense matrix of T as a copy of the given column arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfColumnArrays(params T[][] columns) { return Dense(DenseColumnMajorMatrixStorage.OfColumnArrays(columns)); } /// /// Create a new dense matrix of T as a copy of the given column arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfColumnArrays(IEnumerable columns) { return Dense(DenseColumnMajorMatrixStorage.OfColumnArrays((columns as T[][]) ?? columns.ToArray())); } /// /// Create a new dense matrix as a copy of the given column vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfColumnVectors(params Vector[] columns) { var storage = new VectorStorage[columns.Length]; for (int i = 0; i < columns.Length; i++) { storage[i] = columns[i].Storage; } return Dense(DenseColumnMajorMatrixStorage.OfColumnVectors(storage)); } /// /// Create a new dense matrix as a copy of the given column vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfColumnVectors(IEnumerable> columns) { return Dense(DenseColumnMajorMatrixStorage.OfColumnVectors(columns.Select(c => c.Storage).ToArray())); } /// /// Create a new dense matrix as a copy of the given enumerable of enumerable rows. /// Each enumerable in the master enumerable specifies a row. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfRows(IEnumerable> data) { return Dense(DenseColumnMajorMatrixStorage.OfRowArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray())); } /// /// Create a new dense matrix as a copy of the given enumerable of enumerable rows. /// Each enumerable in the master enumerable specifies a row. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfRows(int rows, int columns, IEnumerable> data) { return Dense(DenseColumnMajorMatrixStorage.OfRowEnumerables(rows, columns, data)); } /// /// Create a new dense matrix of T as a copy of the given row arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfRowArrays(params T[][] rows) { return Dense(DenseColumnMajorMatrixStorage.OfRowArrays(rows)); } /// /// Create a new dense matrix of T as a copy of the given row arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfRowArrays(IEnumerable rows) { return Dense(DenseColumnMajorMatrixStorage.OfRowArrays((rows as T[][]) ?? rows.ToArray())); } /// /// Create a new dense matrix as a copy of the given row vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfRowVectors(params Vector[] rows) { var storage = new VectorStorage[rows.Length]; for (int i = 0; i < rows.Length; i++) { storage[i] = rows[i].Storage; } return Dense(DenseColumnMajorMatrixStorage.OfRowVectors(storage)); } /// /// Create a new dense matrix as a copy of the given row vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfRowVectors(IEnumerable> rows) { return Dense(DenseColumnMajorMatrixStorage.OfRowVectors(rows.Select(r => r.Storage).ToArray())); } /// /// Create a new dense matrix with the diagonal as a copy of the given vector. /// This new matrix will be independent from the vector. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfDiagonalVector(Vector diagonal) { var m = Dense(diagonal.Count, diagonal.Count); m.SetDiagonal(diagonal); return m; } /// /// Create a new dense matrix with the diagonal as a copy of the given vector. /// This new matrix will be independent from the vector. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfDiagonalVector(int rows, int columns, Vector diagonal) { var m = Dense(rows, columns); m.SetDiagonal(diagonal); return m; } /// /// Create a new dense matrix with the diagonal as a copy of the given array. /// This new matrix will be independent from the array. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfDiagonalArray(T[] diagonal) { var m = Dense(diagonal.Length, diagonal.Length); m.SetDiagonal(diagonal); return m; } /// /// Create a new dense matrix with the diagonal as a copy of the given array. /// This new matrix will be independent from the array. /// A new memory block will be allocated for storing the matrix. /// public Matrix DenseOfDiagonalArray(int rows, int columns, T[] diagonal) { var m = Dense(rows, columns); m.SetDiagonal(diagonal); return m; } /// /// Create a new dense matrix from a 2D array of existing matrices. /// The matrices in the array are not required to be dense already. /// If the matrices do not align properly, they are placed on the top left /// corner of their cell with the remaining fields left zero. /// public Matrix DenseOfMatrixArray(Matrix[,] matrices) { var rowspans = new int[matrices.GetLength(0)]; var colspans = new int[matrices.GetLength(1)]; for (int i = 0; i < rowspans.Length; i++) { for (int j = 0; j < colspans.Length; j++) { rowspans[i] = Math.Max(rowspans[i], matrices[i, j].RowCount); colspans[j] = Math.Max(colspans[j], matrices[i, j].ColumnCount); } } var m = Dense(rowspans.Sum(), colspans.Sum()); int rowoffset = 0; for (int i = 0; i < rowspans.Length; i++) { int coloffset = 0; for (int j = 0; j < colspans.Length; j++) { m.SetSubMatrix(rowoffset, coloffset, matrices[i,j]); coloffset += colspans[j]; } rowoffset += rowspans[i]; } return m; } /// /// Create a new sparse matrix straight from an initialized matrix storage instance. /// The storage is used directly without copying. /// Intended for advanced scenarios where you're working directly with /// storage for performance or interop reasons. /// public abstract Matrix Sparse(SparseCompressedRowMatrixStorage storage); /// /// Create a sparse matrix of T with the given number of rows and columns. /// /// The number of rows. /// The number of columns. public Matrix Sparse(int rows, int columns) { return Sparse(new SparseCompressedRowMatrixStorage(rows, columns)); } /// /// Create a new sparse matrix and initialize each value to the same provided value. /// public Matrix Sparse(int rows, int columns, T value) { if (Zero.Equals(value)) return Sparse(rows, columns); return Sparse(SparseCompressedRowMatrixStorage.OfInit(rows, columns, (i, j) => value)); } /// /// Create a new sparse matrix and initialize each value using the provided init function. /// public Matrix Sparse(int rows, int columns, Func init) { return Sparse(SparseCompressedRowMatrixStorage.OfInit(rows, columns, init)); } /// /// Create a new diagonal sparse matrix and initialize each diagonal value to the same provided value. /// public Matrix SparseDiagonal(int rows, int columns, T value) { if (Zero.Equals(value)) return Sparse(rows, columns); return Sparse(SparseCompressedRowMatrixStorage.OfDiagonalInit(rows, columns, i => value)); } /// /// Create a new diagonal sparse matrix and initialize each diagonal value to the same provided value. /// public Matrix SparseDiagonal(int order, T value) { if (Zero.Equals(value)) return Sparse(order, order); return Sparse(SparseCompressedRowMatrixStorage.OfDiagonalInit(order, order, i => value)); } /// /// Create a new diagonal sparse matrix and initialize each diagonal value using the provided init function. /// public Matrix SparseDiagonal(int rows, int columns, Func init) { return Sparse(SparseCompressedRowMatrixStorage.OfDiagonalInit(rows, columns, init)); } /// /// Create a new diagonal dense identity matrix with a one-diagonal. /// public Matrix SparseIdentity(int rows, int columns) { return Sparse(SparseCompressedRowMatrixStorage.OfDiagonalInit(rows, columns, i => One)); } /// /// Create a new diagonal dense identity matrix with a one-diagonal. /// public Matrix SparseIdentity(int order) { return Sparse(SparseCompressedRowMatrixStorage.OfDiagonalInit(order, order, i => One)); } /// /// Create a new sparse matrix as a copy of the given other matrix. /// This new matrix will be independent from the other matrix. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfMatrix(Matrix matrix) { return Sparse(SparseCompressedRowMatrixStorage.OfMatrix(matrix.Storage)); } /// /// Create a new sparse matrix as a copy of the given two-dimensional array. /// This new matrix will be independent from the provided array. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfArray(T[,] array) { return Sparse(SparseCompressedRowMatrixStorage.OfArray(array)); } /// /// Create a new sparse matrix as a copy of the given indexed enumerable. /// Keys must be provided at most once, zero is assumed if a key is omitted. /// This new matrix will be independent from the enumerable. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfIndexed(int rows, int columns, IEnumerable> enumerable) { return Sparse(SparseCompressedRowMatrixStorage.OfIndexedEnumerable(rows, columns, enumerable)); } /// /// Create a new sparse matrix as a copy of the given enumerable. /// The enumerable is assumed to be in row-major order (row by row). /// This new matrix will be independent from the enumerable. /// A new memory block will be allocated for storing the vector. /// /// public Matrix SparseOfRowMajor(int rows, int columns, IEnumerable rowMajor) { return Sparse(SparseCompressedRowMatrixStorage.OfRowMajorEnumerable(rows, columns, rowMajor)); } /// /// Create a new sparse matrix with the given number of rows and columns as a copy of the given array. /// The array is assumed to be in column-major order (column by column). /// This new matrix will be independent from the provided array. /// A new memory block will be allocated for storing the matrix. /// /// public Matrix SparseOfColumnMajor(int rows, int columns, IList columnMajor) { return Sparse(SparseCompressedRowMatrixStorage.OfColumnMajorList(rows, columns, columnMajor)); } /// /// Create a new sparse matrix as a copy of the given enumerable of enumerable columns. /// Each enumerable in the master enumerable specifies a column. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfColumns(IEnumerable> data) { return Sparse(SparseCompressedRowMatrixStorage.OfColumnArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray())); } /// /// Create a new sparse matrix as a copy of the given enumerable of enumerable columns. /// Each enumerable in the master enumerable specifies a column. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfColumns(int rows, int columns, IEnumerable> data) { return Sparse(SparseCompressedRowMatrixStorage.OfColumnEnumerables(rows, columns, data)); } /// /// Create a new sparse matrix as a copy of the given column arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfColumnArrays(params T[][] columns) { return Sparse(SparseCompressedRowMatrixStorage.OfColumnArrays(columns)); } /// /// Create a new sparse matrix as a copy of the given column arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfColumnArrays(IEnumerable columns) { return Sparse(SparseCompressedRowMatrixStorage.OfColumnArrays((columns as T[][]) ?? columns.ToArray())); } /// /// Create a new sparse matrix as a copy of the given column vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfColumnVectors(params Vector[] columns) { var storage = new VectorStorage[columns.Length]; for (int i = 0; i < columns.Length; i++) { storage[i] = columns[i].Storage; } return Sparse(SparseCompressedRowMatrixStorage.OfColumnVectors(storage)); } /// /// Create a new sparse matrix as a copy of the given column vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfColumnVectors(IEnumerable> columns) { return Sparse(SparseCompressedRowMatrixStorage.OfColumnVectors(columns.Select(c => c.Storage).ToArray())); } /// /// Create a new sparse matrix as a copy of the given enumerable of enumerable rows. /// Each enumerable in the master enumerable specifies a row. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfRows(IEnumerable> data) { return Sparse(SparseCompressedRowMatrixStorage.OfRowArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray())); } /// /// Create a new sparse matrix as a copy of the given enumerable of enumerable rows. /// Each enumerable in the master enumerable specifies a row. /// This new matrix will be independent from the enumerables. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfRows(int rows, int columns, IEnumerable> data) { return Sparse(SparseCompressedRowMatrixStorage.OfRowEnumerables(rows, columns, data)); } /// /// Create a new sparse matrix as a copy of the given row arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfRowArrays(params T[][] rows) { return Sparse(SparseCompressedRowMatrixStorage.OfRowArrays(rows)); } /// /// Create a new sparse matrix as a copy of the given row arrays. /// This new matrix will be independent from the arrays. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfRowArrays(IEnumerable rows) { return Sparse(SparseCompressedRowMatrixStorage.OfRowArrays((rows as T[][]) ?? rows.ToArray())); } /// /// Create a new sparse matrix as a copy of the given row vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfRowVectors(params Vector[] rows) { var storage = new VectorStorage[rows.Length]; for (int i = 0; i < rows.Length; i++) { storage[i] = rows[i].Storage; } return Sparse(SparseCompressedRowMatrixStorage.OfRowVectors(storage)); } /// /// Create a new sparse matrix as a copy of the given row vectors. /// This new matrix will be independent from the vectors. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfRowVectors(IEnumerable> rows) { return Sparse(SparseCompressedRowMatrixStorage.OfRowVectors(rows.Select(r => r.Storage).ToArray())); } /// /// Create a new sparse matrix with the diagonal as a copy of the given vector. /// This new matrix will be independent from the vector. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfDiagonalVector(Vector diagonal) { var m = Sparse(diagonal.Count, diagonal.Count); m.SetDiagonal(diagonal); return m; } /// /// Create a new sparse matrix with the diagonal as a copy of the given vector. /// This new matrix will be independent from the vector. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfDiagonalVector(int rows, int columns, Vector diagonal) { var m = Sparse(rows, columns); m.SetDiagonal(diagonal); return m; } /// /// Create a new sparse matrix with the diagonal as a copy of the given array. /// This new matrix will be independent from the array. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfDiagonalArray(T[] diagonal) { var m = Sparse(diagonal.Length, diagonal.Length); m.SetDiagonal(diagonal); return m; } /// /// Create a new sparse matrix with the diagonal as a copy of the given array. /// This new matrix will be independent from the array. /// A new memory block will be allocated for storing the matrix. /// public Matrix SparseOfDiagonalArray(int rows, int columns, T[] diagonal) { var m = Sparse(rows, columns); m.SetDiagonal(diagonal); return m; } /// /// Create a new sparse matrix from a 2D array of existing matrices. /// The matrices in the array are not required to be sparse already. /// If the matrices do not align properly, they are placed on the top left /// corner of their cell with the remaining fields left zero. /// public Matrix SparseOfMatrixArray(Matrix[,] matrices) { var rowspans = new int[matrices.GetLength(0)]; var colspans = new int[matrices.GetLength(1)]; for (int i = 0; i < rowspans.Length; i++) { for (int j = 0; j < colspans.Length; j++) { rowspans[i] = Math.Max(rowspans[i], matrices[i, j].RowCount); colspans[j] = Math.Max(colspans[j], matrices[i, j].ColumnCount); } } var m = Sparse(rowspans.Sum(), colspans.Sum()); int rowoffset = 0; for (int i = 0; i < rowspans.Length; i++) { int coloffset = 0; for (int j = 0; j < colspans.Length; j++) { m.SetSubMatrix(rowoffset, coloffset, matrices[i, j]); coloffset += colspans[j]; } rowoffset += rowspans[i]; } return m; } /// /// Create a new diagonal matrix straight from an initialized matrix storage instance. /// The storage is used directly without copying. /// Intended for advanced scenarios where you're working directly with /// storage for performance or interop reasons. /// public abstract Matrix Diagonal(DiagonalMatrixStorage storage); /// /// Create a new diagonal matrix with the given number of rows and columns. /// All cells of the matrix will be initialized to zero. /// Zero-length matrices are not supported. /// public Matrix Diagonal(int rows, int columns) { return Diagonal(new DiagonalMatrixStorage(rows, columns)); } /// /// Create a new diagonal matrix with the given number of rows and columns directly binding to a raw array. /// The array is assumed to represent the diagonal values and is used directly without copying. /// Very efficient, but changes to the array and the matrix will affect each other. /// /// public Matrix Diagonal(int rows, int columns, T[] storage) { return Diagonal(new DiagonalMatrixStorage(rows, columns, storage)); } /// /// Create a new square diagonal matrix directly binding to a raw array. /// The array is assumed to represent the diagonal values and is used directly without copying. /// Very efficient, but changes to the array and the matrix will affect each other. /// /// public Matrix Diagonal(T[] storage) { return Diagonal(new DiagonalMatrixStorage(storage.Length, storage.Length, storage)); } /// /// Create a new diagonal matrix and initialize each diagonal value to the same provided value. /// public Matrix Diagonal(int rows, int columns, T value) { if (Zero.Equals(value)) return Diagonal(rows, columns); return Diagonal(DiagonalMatrixStorage.OfInit(rows, columns, i => value)); } /// /// Create a new diagonal matrix and initialize each diagonal value using the provided init function. /// public Matrix Diagonal(int rows, int columns, Func init) { return Diagonal(DiagonalMatrixStorage.OfInit(rows, columns, init)); } /// /// Create a new diagonal identity matrix with a one-diagonal. /// public Matrix DiagonalIdentity(int rows, int columns) { return Diagonal(DiagonalMatrixStorage.OfInit(rows, columns, i => One)); } /// /// Create a new diagonal identity matrix with a one-diagonal. /// public Matrix DiagonalIdentity(int order) { return Diagonal(DiagonalMatrixStorage.OfInit(order, order, i => One)); } /// /// Create a new diagonal matrix with the diagonal as a copy of the given vector. /// This new matrix will be independent from the vector. /// A new memory block will be allocated for storing the matrix. /// public Matrix DiagonalOfDiagonalVector(Vector diagonal) { var m = Diagonal(diagonal.Count, diagonal.Count); m.SetDiagonal(diagonal); return m; } /// /// Create a new diagonal matrix with the diagonal as a copy of the given vector. /// This new matrix will be independent from the vector. /// A new memory block will be allocated for storing the matrix. /// public Matrix DiagonalOfDiagonalVector(int rows, int columns, Vector diagonal) { var m = Diagonal(rows, columns); m.SetDiagonal(diagonal); return m; } /// /// Create a new diagonal matrix with the diagonal as a copy of the given array. /// This new matrix will be independent from the array. /// A new memory block will be allocated for storing the matrix. /// public Matrix DiagonalOfDiagonalArray(T[] diagonal) { var m = Diagonal(diagonal.Length, diagonal.Length); m.SetDiagonal(diagonal); return m; } /// /// Create a new diagonal matrix with the diagonal as a copy of the given array. /// This new matrix will be independent from the array. /// A new memory block will be allocated for storing the matrix. /// public Matrix DiagonalOfDiagonalArray(int rows, int columns, T[] diagonal) { var m = Diagonal(rows, columns); m.SetDiagonal(diagonal); return m; } public abstract IIterationStopCriterium[] IterativeSolverStopCriteria(int maxIterations = 1000); } /// /// Generic linear algebra type builder, for situations where a matrix or vector /// must be created in a generic way. Usage of generic builders should not be /// required in normal user code. /// public abstract class VectorBuilder where T : struct, IEquatable, IFormattable { /// /// Gets the value of 0.0 for type T. /// public abstract T Zero { get; } /// /// Gets the value of 1.0 for type T. /// public abstract T One { get; } /// /// Create a new vector straight from an initialized matrix storage instance. /// If you have an instance of a discrete storage type instead, use their direct methods instead. /// public Vector OfStorage(VectorStorage storage) { var dense = storage as DenseVectorStorage; if (dense != null) return Dense(dense); var sparse = storage as SparseVectorStorage; if (sparse != null) return Sparse(sparse); throw new NotSupportedException(); } /// /// Create a new vector with the same kind of the provided example. /// public Vector SameAs(Vector example, int length) { return example.Storage.IsDense ? Dense(length) : Sparse(length); } /// /// Create a new vector with the same kind and dimension of the provided example. /// public Vector SameAs(Vector example) { return example.Storage.IsDense ? Dense(example.Count) : Sparse(example.Count); } /// /// Create a new vector with the same kind of the provided example. /// public Vector SameAs(Matrix example, int length) { return example.Storage.IsDense ? Dense(length) : Sparse(length); } /// /// Create a new vector with a type that can represent and is closest to both provided samples. /// public Vector SameAs(Vector example, Vector otherExample, int length) { return example.Storage.IsDense || otherExample.Storage.IsDense ? Dense(length) : Sparse(length); } /// /// Create a new vector with a type that can represent and is closest to both provided samples and the dimensions of example. /// public Vector SameAs(Vector example, Vector otherExample) { return example.Storage.IsDense || otherExample.Storage.IsDense ? Dense(example.Count) : Sparse(example.Count); } /// /// Create a new dense vector with values sampled from the provided random distribution. /// public abstract Vector Random(int length, IContinuousDistribution distribution); /// /// Create a new dense vector straight from an initialized vector storage instance. /// The storage is used directly without copying. /// Intended for advanced scenarios where you're working directly with /// storage for performance or interop reasons. /// public abstract Vector Dense(DenseVectorStorage storage); /// /// Create a dense vector of T with the given size. /// /// The size of the vector. public Vector Dense(int size) { return Dense(new DenseVectorStorage(size)); } /// /// Create a dense vector of T that is directly bound to the specified array. /// public Vector Dense(T[] array) { return Dense(new DenseVectorStorage(array.Length, array)); } /// /// Create a new dense vector and initialize each value using the provided value. /// public Vector Dense(int length, T value) { if (Zero.Equals(value)) return Dense(length); return Dense(DenseVectorStorage.OfInit(length, i => value)); } /// /// Create a new dense vector and initialize each value using the provided init function. /// public Vector Dense(int length, Func init) { return Dense(DenseVectorStorage.OfInit(length, init)); } /// /// Create a new dense vector as a copy of the given other vector. /// This new vector will be independent from the other vector. /// A new memory block will be allocated for storing the vector. /// public Vector DenseOfVector(Vector vector) { return Dense(DenseVectorStorage.OfVector(vector.Storage)); } /// /// Create a new dense vector as a copy of the given array. /// This new vector will be independent from the array. /// A new memory block will be allocated for storing the vector. /// public Vector DenseOfArray(T[] array) { return Dense(DenseVectorStorage.OfVector(new DenseVectorStorage(array.Length, array))); } /// /// Create a new dense vector as a copy of the given enumerable. /// This new vector will be independent from the enumerable. /// A new memory block will be allocated for storing the vector. /// public Vector DenseOfEnumerable(IEnumerable enumerable) { return Dense(DenseVectorStorage.OfEnumerable(enumerable)); } /// /// Create a new dense vector as a copy of the given indexed enumerable. /// Keys must be provided at most once, zero is assumed if a key is omitted. /// This new vector will be independent from the enumerable. /// A new memory block will be allocated for storing the vector. /// public Vector DenseOfIndexed(int length, IEnumerable> enumerable) { return Dense(DenseVectorStorage.OfIndexedEnumerable(length, enumerable)); } /// /// Create a new sparse vector straight from an initialized vector storage instance. /// The storage is used directly without copying. /// Intended for advanced scenarios where you're working directly with /// storage for performance or interop reasons. /// public abstract Vector Sparse(SparseVectorStorage storage); /// /// Create a sparse vector of T with the given size. /// /// The size of the vector. public Vector Sparse(int size) { return Sparse(new SparseVectorStorage(size)); } /// /// Create a new sparse vector and initialize each value using the provided value. /// public Vector Sparse(int length, T value) { if (Zero.Equals(value)) return Sparse(length); return Sparse(SparseVectorStorage.OfInit(length, i => value)); } /// /// Create a new sparse vector and initialize each value using the provided init function. /// public Vector Sparse(int length, Func init) { return Sparse(SparseVectorStorage.OfInit(length, init)); } /// /// Create a new sparse vector as a copy of the given other vector. /// This new vector will be independent from the other vector. /// A new memory block will be allocated for storing the vector. /// public Vector SparseOfVector(Vector vector) { return Sparse(SparseVectorStorage.OfVector(vector.Storage)); } /// /// Create a new sparse vector as a copy of the given array. /// This new vector will be independent from the array. /// A new memory block will be allocated for storing the vector. /// public Vector SparseOfArray(T[] array) { return Sparse(SparseVectorStorage.OfEnumerable(array)); } /// /// Create a new sparse vector as a copy of the given enumerable. /// This new vector will be independent from the enumerable. /// A new memory block will be allocated for storing the vector. /// public Vector SparseOfEnumerable(IEnumerable enumerable) { return Sparse(SparseVectorStorage.OfEnumerable(enumerable)); } /// /// Create a new sparse vector as a copy of the given indexed enumerable. /// Keys must be provided at most once, zero is assumed if a key is omitted. /// This new vector will be independent from the enumerable. /// A new memory block will be allocated for storing the vector. /// public Vector SparseOfIndexed(int length, IEnumerable> enumerable) { return Sparse(SparseVectorStorage.OfIndexedEnumerable(length, enumerable)); } } internal static class BuilderInstance where T : struct, IEquatable, IFormattable { static Lazy, VectorBuilder>> _singleton = new Lazy, VectorBuilder>>(Create); static Tuple, VectorBuilder> Create() { if (typeof (T) == typeof (Complex64)) { return new Tuple, VectorBuilder>( (MatrixBuilder) (object) new Complex.MatrixBuilder(), (VectorBuilder) (object) new Complex.VectorBuilder()); } if (typeof (T) == typeof (Numerics.Complex32)) { return new Tuple, VectorBuilder>( (MatrixBuilder) (object) new Complex32.MatrixBuilder(), (VectorBuilder) (object) new Complex32.VectorBuilder()); } if (typeof (T) == typeof (double)) { return new Tuple, VectorBuilder>( (MatrixBuilder) (object) new Double.MatrixBuilder(), (VectorBuilder) (object) new Double.VectorBuilder()); } if (typeof (T) == typeof (float)) { return new Tuple, VectorBuilder>( (MatrixBuilder) (object) new Single.MatrixBuilder(), (VectorBuilder) (object) new Single.VectorBuilder()); } throw new NotSupportedException(); } public static void Register(MatrixBuilder matrixBuilder, VectorBuilder vectorBuilder) { _singleton = new Lazy, VectorBuilder>>(() => new Tuple, VectorBuilder>(matrixBuilder, vectorBuilder)); } public static MatrixBuilder Matrix { get { return _singleton.Value.Item1; } } public static VectorBuilder Vector { get { return _singleton.Value.Item2; } } } }