From e70a5977ec91c76497040c5bc91983ca1a8e6090 Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Sat, 28 Sep 2013 12:43:15 +0200 Subject: [PATCH] LA: Builder tweaks #139 --- src/FSharp/LinearAlgebra.Matrix.fs | 40 ++++++++--- src/FSharp/LinearAlgebra.Vector.fs | 12 +++- src/FSharpUnitTests/DenseMatrixTests.fs | 18 +++-- src/FSharpUnitTests/DenseVectorTests.fs | 8 +-- src/FSharpUnitTests/SparseMatrixTests.fs | 18 +++-- src/Numerics/LinearAlgebra/Builder.cs | 92 ++++++++++++++++++------ 6 files changed, 135 insertions(+), 53 deletions(-) diff --git a/src/FSharp/LinearAlgebra.Matrix.fs b/src/FSharp/LinearAlgebra.Matrix.fs index ffa64af3..92a773c3 100644 --- a/src/FSharp/LinearAlgebra.Matrix.fs +++ b/src/FSharp/LinearAlgebra.Matrix.fs @@ -350,20 +350,32 @@ module Matrix = [] module DenseMatrix = + /// Create a matrix that directly binds to a storage object. + let inline ofStorage storage = Matrix<'T>.Build.Dense(storage) + /// Create a matrix that directly binds to a raw storage array in column-major (column by column) format, without copying. let inline raw (rows: int) (cols: int) (columnMajor: 'T[]) = Matrix<'T>.Build.Dense(rows, cols, columnMajor) /// Create an all-zero matrix with the given dimension. - let inline zeroCreate (rows: int) (cols: int) = Matrix<'T>.Build.Dense(rows, cols) + let inline zero (rows: int) (cols: int) = Matrix<'T>.Build.Dense(rows, cols) /// Create a random matrix with the given dimension and value distribution. - let inline randomCreate (rows: int) (cols: int) dist = Matrix<'T>.Build.DenseRandom(rows, cols, dist) + let inline random (rows: int) (cols: int) dist = Matrix<'T>.Build.Random(rows, cols, dist) /// Create a matrix with the given dimension and set all values to x. let inline create (rows: int) (cols: int) (x: 'T) = Matrix<'T>.Build.Dense(rows, cols, x) /// Create a matrix with the given dimension and set all diagonal values to x. All other values are zero. - let inline createDiag (rows: int) (cols: int) (x: 'T) = Matrix<'T>.Build.DenseDiagonal(rows, cols, x) + let inline diag (order: int) (x: 'T) = Matrix<'T>.Build.DenseDiagonal(order, x) + + /// Create a matrix with the given dimension and set all diagonal values to x. All other values are zero. + let inline diag2 (rows: int) (cols: int) (x: 'T) = Matrix<'T>.Build.DenseDiagonal(rows, cols, x) + + /// Create an identity matrix with the given dimension. + let inline identity (order: int) = Matrix<'T>.Build.DenseIdentity(order) + + /// Create an identity matrix with the given dimension. + let inline identity2 (rows: int) (cols: int) = Matrix<'T>.Build.DenseIdentity(rows, cols) /// Initialize a matrix by calling a construction function for every element. let inline init (rows: int) (cols: int) (f: int -> int -> 'T) = Matrix<'T>.Build.Dense(rows, cols, fun i j -> f i j) @@ -377,9 +389,6 @@ module DenseMatrix = /// Initialize a matrix by calling a construction function for every diagonal element. All other values are zero. let inline initDiag (rows: int) (cols: int) (f: int -> 'T) = Matrix<'T>.Build.DenseDiagonal(rows, cols, f) - /// Create an identity matrix with the given dimension. - let inline identity (rows: int) (cols: int) = createDiag rows cols Matrix<'T>.Build.One - /// Create a matrix from a 2D array of floating point numbers. let inline ofArray2 array = Matrix<'T>.Build.DenseOfArray(array) @@ -436,14 +445,26 @@ module DenseMatrix = [] module SparseMatrix = + /// Create a matrix that directly binds to a storage object. + let inline ofStorage storage = Matrix<'T>.Build.Sparse(storage) + /// Create an all-zero matrix with the given dimension. - let inline zeroCreate (rows: int) (cols: int) = Matrix<'T>.Build.Sparse(rows, cols) + let inline zero (rows: int) (cols: int) = Matrix<'T>.Build.Sparse(rows, cols) /// Create a matrix with the given dimension and set all values to x. Note that a dense matrix would likely be more appropriate. let inline create (rows: int) (cols: int) (x: 'T) = Matrix<'T>.Build.Sparse(rows, cols, x) /// Create a matrix with the given dimension and set all diagonal values to x. All other values are zero. - let inline createDiag (rows: int) (cols: int) (x: 'T) = Matrix<'T>.Build.SparseDiagonal(rows, cols, x) + let inline diag (order: int) (x: 'T) = Matrix<'T>.Build.SparseDiagonal(order, x) + + /// Create a matrix with the given dimension and set all diagonal values to x. All other values are zero. + let inline diag2 (rows: int) (cols: int) (x: 'T) = Matrix<'T>.Build.SparseDiagonal(rows, cols, x) + + /// Create an identity matrix with the given dimension. + let inline identity (order: int) = Matrix<'T>.Build.SparseIdentity(order) + + /// Create an identity matrix with the given dimension. + let inline identity2 (rows: int) (cols: int) = Matrix<'T>.Build.SparseIdentity(rows, cols) /// Initialize a matrix by calling a construction function for every element. let inline init (rows: int) (cols: int) (f: int -> int -> 'T) = Matrix<'T>.Build.Sparse(rows, cols, fun n m -> f n m) @@ -457,9 +478,6 @@ module SparseMatrix = /// Initialize a matrix by calling a construction function for every diagonal element. All other values are zero. let inline initDiag (rows: int) (cols: int) (f: int -> 'T) = Matrix<'T>.Build.SparseDiagonal(rows, cols, f) - /// Create an identity matrix with the given dimension. - let inline identity (rows: int) (cols: int) = createDiag rows cols Matrix<'T>.Build.One - /// Create a matrix from a 2D array of floating point numbers. let inline ofArray2 array = Matrix<'T>.Build.SparseOfArray(array) diff --git a/src/FSharp/LinearAlgebra.Vector.fs b/src/FSharp/LinearAlgebra.Vector.fs index 0b06ff77..0c8ca266 100644 --- a/src/FSharp/LinearAlgebra.Vector.fs +++ b/src/FSharp/LinearAlgebra.Vector.fs @@ -221,14 +221,17 @@ module Vector = [] module DenseVector = + /// Create a vector that directly binds to a storage object. + let inline ofStorage (storage: Storage.DenseVectorStorage<'T>) = Vector<'T>.Build.Dense(storage) + /// Create a vector that directly binds to a raw storage array, without copying. let inline raw (raw: 'T[]) = Vector<'T>.Build.Dense(raw) /// Initialize an all-zero vector with the given dimension. - let inline zeroCreate (n: int) = Vector<'T>.Build.Dense(n) + let inline zero (n: int) = Vector<'T>.Build.Dense(n) /// Initialize a random vector with the given dimension and distribution. - let inline randomCreate (n: int) dist = Vector<'T>.Build.DenseRandom(n, dist) + let inline random (n: int) dist = Vector<'T>.Build.Random(n, dist) /// Initialize an x-valued vector with the given dimension. let inline create (n: int) (x: 'T) = Vector<'T>.Build.Dense(n, x) @@ -262,8 +265,11 @@ module DenseVector = [] module SparseVector = + /// Create a vector that directly binds to a storage object. + let inline ofStorage (storage: Storage.SparseVectorStorage<'T>) = Vector<'T>.Build.Sparse(storage) + /// Initialize an all-zero vector with the given dimension. - let inline zeroCreate (n: int) = Vector<'T>.Build.Sparse(n) + let inline zero (n: int) = Vector<'T>.Build.Sparse(n) /// Initialize an x-valued vector with the given dimension. let inline create (n: int) (x: 'T) = Vector<'T>.Build.Sparse(n, x) diff --git a/src/FSharpUnitTests/DenseMatrixTests.fs b/src/FSharpUnitTests/DenseMatrixTests.fs index 82ea64b0..a791bebe 100644 --- a/src/FSharpUnitTests/DenseMatrixTests.fs +++ b/src/FSharpUnitTests/DenseMatrixTests.fs @@ -18,12 +18,12 @@ module DenseMatrixTests = |> DenseMatrix.raw 100 120 [] - let ``DenseMatrix.zeroCreate`` () = - (DenseMatrix.zeroCreate 100 120) + largeM |> should equal largeM + let ``DenseMatrix.zero`` () = + (DenseMatrix.zero 100 120) + largeM |> should equal largeM [] - let ``DenseMatrix.randomCreate`` () = - let m = DenseMatrix.randomCreate 100 120 (Normal.WithMeanStdDev(100.0,0.1)) + let ``DenseMatrix.random`` () = + let m = DenseMatrix.random 100 120 (Normal.WithMeanStdDev(100.0,0.1)) (m :?> Double.DenseMatrix).Values |> ArrayStatistics.Mean |> should (equalWithin 10.0) 100.0 m.RowCount |> should equal 100 m.ColumnCount |> should equal 120 @@ -76,14 +76,18 @@ module DenseMatrixTests = let ``DenseMatrix.ofListi`` () = [ for i in 0 .. 99 do for j in 0 .. 119 -> (i,j, float i * 100.0 + float j) ] |> DenseMatrix.ofListi 100 120 |> should equal largeM + + [] + let ``DenseMatrix.diag`` () = + DenseMatrix.diag 100 2.0 |> should equal (2.0 * (DenseMatrix.identity 100)) [] - let ``DenseMatrix.createDiag`` () = - DenseMatrix.createDiag 100 100 2.0 |> should equal (2.0 * (DenseMatrix.identity 100 100)) + let ``DenseMatrix.diag2`` () = + DenseMatrix.diag2 100 120 2.0 |> should equal (2.0 * (DenseMatrix.identity2 100 120)) [] let ``DenseMatrix.ofDiag`` () = - DenseMatrix.ofDiag (DenseVector.init 100 (fun i -> 2.0)) |> should equal (2.0 * (DenseMatrix.identity 100 100)) + DenseMatrix.ofDiag (DenseVector.init 100 (fun i -> 2.0)) |> should equal (2.0 * (DenseMatrix.identity 100)) [] let ``DenseMatrix.initRow`` () = diff --git a/src/FSharpUnitTests/DenseVectorTests.fs b/src/FSharpUnitTests/DenseVectorTests.fs index 032d1daa..aec073c5 100644 --- a/src/FSharpUnitTests/DenseVectorTests.fs +++ b/src/FSharpUnitTests/DenseVectorTests.fs @@ -16,12 +16,12 @@ module DenseVectorTests = let largev = new Double.DenseVector( Array.init 100 (fun i -> float i / 100.0) ) [] - let ``DenseVector.zeroCreate`` () = - (DenseVector.zeroCreate 100) + largev |> should equal largev + let ``DenseVector.zero`` () = + (DenseVector.zero 100) + largev |> should equal largev [] - let ``DenseVector.randomCreate`` () = - let m = DenseVector.randomCreate 100 (Normal.WithMeanStdDev(100.0,0.1)) + let ``DenseVector.random`` () = + let m = DenseVector.random 100 (Normal.WithMeanStdDev(100.0,0.1)) (m :?> Double.DenseVector).Values |> ArrayStatistics.Mean |> should (equalWithin 10.0) 100.0 m.Count |> should equal 100 diff --git a/src/FSharpUnitTests/SparseMatrixTests.fs b/src/FSharpUnitTests/SparseMatrixTests.fs index c450ed83..046c2ec9 100644 --- a/src/FSharpUnitTests/SparseMatrixTests.fs +++ b/src/FSharpUnitTests/SparseMatrixTests.fs @@ -11,8 +11,8 @@ module SparseMatrixTests = let smallM = DenseMatrix.init 4 6 (fun i j -> if i = 1 && j = 2 then 1.0 else 0.0) [] - let ``SparseMatrix.zeroCreate`` () = - (SparseMatrix.zeroCreate 4 6) + smallM |> should equal smallM + let ``SparseMatrix.zero`` () = + (SparseMatrix.zero 4 6) + smallM |> should equal smallM [] let ``SparseMatrix.init`` () = @@ -46,19 +46,23 @@ module SparseMatrixTests = [] let ``SparseMatrix.ofListi`` () = SparseMatrix.ofListi 4 6 [(1,2,1.0)] |> should equal smallM + + [] + let ``SparseMatrix.diag`` () = + SparseMatrix.diag 100 2.0 |> should equal (2.0 * (SparseMatrix.identity 100)) [] - let ``SparseMatrix.constDiag`` () = - SparseMatrix.createDiag 100 100 2.0 |> should equal (2.0 * (SparseMatrix.identity 100 100)) + let ``SparseMatrix.diag2`` () = + SparseMatrix.diag2 100 120 2.0 |> should equal (2.0 * (SparseMatrix.identity2 100 120)) [] let ``SparseMatrix.ofDiag`` () = - SparseMatrix.ofDiag (DenseVector.init 100 (fun i -> 2.0)) |> should equal (2.0 * (SparseMatrix.identity 100 100)) + SparseMatrix.ofDiag (DenseVector.init 100 (fun i -> 2.0)) |> should equal (2.0 * (SparseMatrix.identity 100)) [] let ``SparseMatrix.init_row`` () = - SparseMatrix.initRows 4 (fun i -> if i=1 then DenseVector.raw [|0.;0.;1.;0.;0.;0.|] else DenseVector.zeroCreate 6) |> should equal smallM + SparseMatrix.initRows 4 (fun i -> if i=1 then DenseVector.raw [|0.;0.;1.;0.;0.;0.|] else DenseVector.zero 6) |> should equal smallM [] let ``SparseMatrix.init_col`` () = - SparseMatrix.initColumns 6 (fun j -> if j=2 then DenseVector.raw [|0.;1.;0.;0.|] else DenseVector.zeroCreate 4) |> should equal smallM + SparseMatrix.initColumns 6 (fun j -> if j=2 then DenseVector.raw [|0.;1.;0.;0.|] else DenseVector.zero 4) |> should equal smallM diff --git a/src/Numerics/LinearAlgebra/Builder.cs b/src/Numerics/LinearAlgebra/Builder.cs index 5d25e07b..6842a3ca 100644 --- a/src/Numerics/LinearAlgebra/Builder.cs +++ b/src/Numerics/LinearAlgebra/Builder.cs @@ -68,7 +68,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double return new DiagonalMatrix(storage); } - public override Matrix DenseRandom(int rows, int columns, IContinuousDistribution distribution) + public override Matrix Random(int rows, int columns, IContinuousDistribution distribution) { return DenseMatrix.CreateRandom(rows, columns, distribution); } @@ -107,7 +107,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double return new SparseVector(storage); } - public override Vector DenseRandom(int length, IContinuousDistribution distribution) + public override Vector Random(int length, IContinuousDistribution distribution) { return new DenseVector(DenseVectorStorage.OfInit(length, i => distribution.Sample())); } @@ -145,7 +145,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single return new DiagonalMatrix(storage); } - public override Matrix DenseRandom(int rows, int columns, IContinuousDistribution distribution) + public override Matrix Random(int rows, int columns, IContinuousDistribution distribution) { return DenseMatrix.CreateRandom(rows, columns, distribution); } @@ -184,7 +184,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single return new SparseVector(storage); } - public override Vector DenseRandom(int length, IContinuousDistribution distribution) + public override Vector Random(int length, IContinuousDistribution distribution) { return new DenseVector(DenseVectorStorage.OfInit(length, i => (float)distribution.Sample())); } @@ -228,7 +228,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex return new DiagonalMatrix(storage); } - public override Matrix DenseRandom(int rows, int columns, IContinuousDistribution distribution) + public override Matrix Random(int rows, int columns, IContinuousDistribution distribution) { return DenseMatrix.CreateRandom(rows, columns, distribution); } @@ -267,7 +267,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex return new SparseVector(storage); } - public override Vector DenseRandom(int length, IContinuousDistribution distribution) + public override Vector Random(int length, IContinuousDistribution distribution) { return new DenseVector(DenseVectorStorage.OfInit(length, i => new Complex(distribution.Sample(), distribution.Sample()))); } @@ -305,7 +305,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 return new DiagonalMatrix(storage); } - public override Matrix DenseRandom(int rows, int columns, IContinuousDistribution distribution) + public override Matrix Random(int rows, int columns, IContinuousDistribution distribution) { return DenseMatrix.CreateRandom(rows, columns, distribution); } @@ -344,7 +344,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 return new SparseVector(storage); } - public override Vector DenseRandom(int length, IContinuousDistribution distribution) + public override Vector Random(int length, IContinuousDistribution distribution) { return new DenseVector(DenseVectorStorage.OfInit(length, i => new Numerics.Complex32((float)distribution.Sample(), (float)distribution.Sample()))); } @@ -382,7 +382,7 @@ namespace MathNet.Numerics.LinearAlgebra /// 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 Storage(MatrixStorage storage) + public Matrix OfStorage(MatrixStorage storage) { var dense = storage as DenseColumnMajorMatrixStorage; if (dense != null) return Dense(dense); @@ -396,6 +396,11 @@ namespace MathNet.Numerics.LinearAlgebra throw new NotSupportedException(); } + /// + /// 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. @@ -451,6 +456,15 @@ namespace MathNet.Numerics.LinearAlgebra 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. /// @@ -460,9 +474,20 @@ namespace MathNet.Numerics.LinearAlgebra } /// - /// Create a new dense matrix with values sampled from the provided random distribution. + /// Create a new diagonal dense identity matrix with a one-diagonal. /// - public abstract Matrix DenseRandom(int rows, int columns, IContinuousDistribution distribution); + 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. @@ -514,7 +539,7 @@ namespace MathNet.Numerics.LinearAlgebra /// public Matrix DenseOfColumns(IEnumerable> data) { - return Dense(DenseColumnMajorMatrixStorage.OfColumnArrays(data.Select(v => v.ToArray()).ToArray())); + return Dense(DenseColumnMajorMatrixStorage.OfColumnArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray())); } /// @@ -581,7 +606,7 @@ namespace MathNet.Numerics.LinearAlgebra /// public Matrix DenseOfRows(IEnumerable> data) { - return Dense(DenseColumnMajorMatrixStorage.OfRowArrays(data.Select(v => v.ToArray()).ToArray())); + return Dense(DenseColumnMajorMatrixStorage.OfRowArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray())); } /// @@ -732,6 +757,15 @@ namespace MathNet.Numerics.LinearAlgebra 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. /// @@ -740,6 +774,22 @@ namespace MathNet.Numerics.LinearAlgebra 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. @@ -803,7 +853,7 @@ namespace MathNet.Numerics.LinearAlgebra /// public Matrix SparseOfColumns(IEnumerable> data) { - return Sparse(SparseCompressedRowMatrixStorage.OfColumnArrays(data.Select(v => v.ToArray()).ToArray())); + return Sparse(SparseCompressedRowMatrixStorage.OfColumnArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray())); } /// @@ -870,7 +920,7 @@ namespace MathNet.Numerics.LinearAlgebra /// public Matrix SparseOfRows(IEnumerable> data) { - return Sparse(SparseCompressedRowMatrixStorage.OfRowArrays(data.Select(v => v.ToArray()).ToArray())); + return Sparse(SparseCompressedRowMatrixStorage.OfRowArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray())); } /// @@ -1009,7 +1059,7 @@ namespace MathNet.Numerics.LinearAlgebra /// 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 Storage(VectorStorage storage) + public Vector OfStorage(VectorStorage storage) { var dense = storage as DenseVectorStorage; if (dense != null) return Dense(dense); @@ -1020,6 +1070,11 @@ namespace MathNet.Numerics.LinearAlgebra throw new NotSupportedException(); } + /// + /// 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. @@ -1062,11 +1117,6 @@ namespace MathNet.Numerics.LinearAlgebra return Dense(DenseVectorStorage.OfInit(length, init)); } - /// - /// Create a new dense vector with values sampled from the provided random distribution. - /// - public abstract Vector DenseRandom(int length, IContinuousDistribution distribution); - /// /// Create a new dense vector as a copy of the given other vector. /// This new vector will be independent from the other vector.