Browse Source

LA: Builder tweaks #139

optimization-1
Christoph Ruegg 13 years ago
parent
commit
e70a5977ec
  1. 40
      src/FSharp/LinearAlgebra.Matrix.fs
  2. 12
      src/FSharp/LinearAlgebra.Vector.fs
  3. 18
      src/FSharpUnitTests/DenseMatrixTests.fs
  4. 8
      src/FSharpUnitTests/DenseVectorTests.fs
  5. 18
      src/FSharpUnitTests/SparseMatrixTests.fs
  6. 92
      src/Numerics/LinearAlgebra/Builder.cs

40
src/FSharp/LinearAlgebra.Matrix.fs

@ -350,20 +350,32 @@ module Matrix =
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
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 =
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
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)

12
src/FSharp/LinearAlgebra.Vector.fs

@ -221,14 +221,17 @@ module Vector =
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
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 =
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
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)

18
src/FSharpUnitTests/DenseMatrixTests.fs

@ -18,12 +18,12 @@ module DenseMatrixTests =
|> DenseMatrix.raw 100 120
[<Test>]
let ``DenseMatrix.zeroCreate`` () =
(DenseMatrix.zeroCreate 100 120) + largeM |> should equal largeM
let ``DenseMatrix.zero`` () =
(DenseMatrix.zero 100 120) + largeM |> should equal largeM
[<Test>]
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
[<Test>]
let ``DenseMatrix.diag`` () =
DenseMatrix.diag 100 2.0 |> should equal (2.0 * (DenseMatrix.identity 100))
[<Test>]
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))
[<Test>]
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))
[<Test>]
let ``DenseMatrix.initRow`` () =

8
src/FSharpUnitTests/DenseVectorTests.fs

@ -16,12 +16,12 @@ module DenseVectorTests =
let largev = new Double.DenseVector( Array.init 100 (fun i -> float i / 100.0) )
[<Test>]
let ``DenseVector.zeroCreate`` () =
(DenseVector.zeroCreate 100) + largev |> should equal largev
let ``DenseVector.zero`` () =
(DenseVector.zero 100) + largev |> should equal largev
[<Test>]
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

18
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)
[<Test>]
let ``SparseMatrix.zeroCreate`` () =
(SparseMatrix.zeroCreate 4 6) + smallM |> should equal smallM
let ``SparseMatrix.zero`` () =
(SparseMatrix.zero 4 6) + smallM |> should equal smallM
[<Test>]
let ``SparseMatrix.init`` () =
@ -46,19 +46,23 @@ module SparseMatrixTests =
[<Test>]
let ``SparseMatrix.ofListi`` () =
SparseMatrix.ofListi 4 6 [(1,2,1.0)] |> should equal smallM
[<Test>]
let ``SparseMatrix.diag`` () =
SparseMatrix.diag 100 2.0 |> should equal (2.0 * (SparseMatrix.identity 100))
[<Test>]
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))
[<Test>]
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))
[<Test>]
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
[<Test>]
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

92
src/Numerics/LinearAlgebra/Builder.cs

@ -68,7 +68,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double
return new DiagonalMatrix(storage);
}
public override Matrix<double> DenseRandom(int rows, int columns, IContinuousDistribution distribution)
public override Matrix<double> 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<double> DenseRandom(int length, IContinuousDistribution distribution)
public override Vector<double> Random(int length, IContinuousDistribution distribution)
{
return new DenseVector(DenseVectorStorage<double>.OfInit(length, i => distribution.Sample()));
}
@ -145,7 +145,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single
return new DiagonalMatrix(storage);
}
public override Matrix<float> DenseRandom(int rows, int columns, IContinuousDistribution distribution)
public override Matrix<float> 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<float> DenseRandom(int length, IContinuousDistribution distribution)
public override Vector<float> Random(int length, IContinuousDistribution distribution)
{
return new DenseVector(DenseVectorStorage<float>.OfInit(length, i => (float)distribution.Sample()));
}
@ -228,7 +228,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
return new DiagonalMatrix(storage);
}
public override Matrix<Complex> DenseRandom(int rows, int columns, IContinuousDistribution distribution)
public override Matrix<Complex> 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<Complex> DenseRandom(int length, IContinuousDistribution distribution)
public override Vector<Complex> Random(int length, IContinuousDistribution distribution)
{
return new DenseVector(DenseVectorStorage<Complex>.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<Numerics.Complex32> DenseRandom(int rows, int columns, IContinuousDistribution distribution)
public override Matrix<Numerics.Complex32> 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<Numerics.Complex32> DenseRandom(int length, IContinuousDistribution distribution)
public override Vector<Numerics.Complex32> Random(int length, IContinuousDistribution distribution)
{
return new DenseVector(DenseVectorStorage<Numerics.Complex32>.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.
/// </summary>
public Matrix<T> Storage(MatrixStorage<T> storage)
public Matrix<T> OfStorage(MatrixStorage<T> storage)
{
var dense = storage as DenseColumnMajorMatrixStorage<T>;
if (dense != null) return Dense(dense);
@ -396,6 +396,11 @@ namespace MathNet.Numerics.LinearAlgebra
throw new NotSupportedException();
}
/// <summary>
/// Create a new dense matrix with values sampled from the provided random distribution.
/// </summary>
public abstract Matrix<T> Random(int rows, int columns, IContinuousDistribution distribution);
/// <summary>
/// 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<T>.OfDiagonalInit(rows, columns, i => value));
}
/// <summary>
/// Create a new diagonal dense matrix and initialize each diagonal value to the same provided value.
/// </summary>
public Matrix<T> DenseDiagonal(int order, T value)
{
if (Zero.Equals(value)) return Dense(order, order);
return Dense(DenseColumnMajorMatrixStorage<T>.OfDiagonalInit(order, order, i => value));
}
/// <summary>
/// Create a new diagonal dense matrix and initialize each diagonal value using the provided init function.
/// </summary>
@ -460,9 +474,20 @@ namespace MathNet.Numerics.LinearAlgebra
}
/// <summary>
/// Create a new dense matrix with values sampled from the provided random distribution.
/// Create a new diagonal dense identity matrix with a one-diagonal.
/// </summary>
public abstract Matrix<T> DenseRandom(int rows, int columns, IContinuousDistribution distribution);
public Matrix<T> DenseIdentity(int rows, int columns)
{
return Dense(DenseColumnMajorMatrixStorage<T>.OfDiagonalInit(rows, columns, i => One));
}
/// <summary>
/// Create a new diagonal dense identity matrix with a one-diagonal.
/// </summary>
public Matrix<T> DenseIdentity(int order)
{
return Dense(DenseColumnMajorMatrixStorage<T>.OfDiagonalInit(order, order, i => One));
}
/// <summary>
/// Create a new dense matrix as a copy of the given other matrix.
@ -514,7 +539,7 @@ namespace MathNet.Numerics.LinearAlgebra
/// </summary>
public Matrix<T> DenseOfColumns(IEnumerable<IEnumerable<T>> data)
{
return Dense(DenseColumnMajorMatrixStorage<T>.OfColumnArrays(data.Select(v => v.ToArray()).ToArray()));
return Dense(DenseColumnMajorMatrixStorage<T>.OfColumnArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray()));
}
/// <summary>
@ -581,7 +606,7 @@ namespace MathNet.Numerics.LinearAlgebra
/// </summary>
public Matrix<T> DenseOfRows(IEnumerable<IEnumerable<T>> data)
{
return Dense(DenseColumnMajorMatrixStorage<T>.OfRowArrays(data.Select(v => v.ToArray()).ToArray()));
return Dense(DenseColumnMajorMatrixStorage<T>.OfRowArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray()));
}
/// <summary>
@ -732,6 +757,15 @@ namespace MathNet.Numerics.LinearAlgebra
return Sparse(SparseCompressedRowMatrixStorage<T>.OfDiagonalInit(rows, columns, i => value));
}
/// <summary>
/// Create a new diagonal sparse matrix and initialize each diagonal value to the same provided value.
/// </summary>
public Matrix<T> SparseDiagonal(int order, T value)
{
if (Zero.Equals(value)) return Sparse(order, order);
return Sparse(SparseCompressedRowMatrixStorage<T>.OfDiagonalInit(order, order, i => value));
}
/// <summary>
/// Create a new diagonal sparse matrix and initialize each diagonal value using the provided init function.
/// </summary>
@ -740,6 +774,22 @@ namespace MathNet.Numerics.LinearAlgebra
return Sparse(SparseCompressedRowMatrixStorage<T>.OfDiagonalInit(rows, columns, init));
}
/// <summary>
/// Create a new diagonal dense identity matrix with a one-diagonal.
/// </summary>
public Matrix<T> SparseIdentity(int rows, int columns)
{
return Sparse(SparseCompressedRowMatrixStorage<T>.OfDiagonalInit(rows, columns, i => One));
}
/// <summary>
/// Create a new diagonal dense identity matrix with a one-diagonal.
/// </summary>
public Matrix<T> SparseIdentity(int order)
{
return Sparse(SparseCompressedRowMatrixStorage<T>.OfDiagonalInit(order, order, i => One));
}
/// <summary>
/// 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
/// </summary>
public Matrix<T> SparseOfColumns(IEnumerable<IEnumerable<T>> data)
{
return Sparse(SparseCompressedRowMatrixStorage<T>.OfColumnArrays(data.Select(v => v.ToArray()).ToArray()));
return Sparse(SparseCompressedRowMatrixStorage<T>.OfColumnArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray()));
}
/// <summary>
@ -870,7 +920,7 @@ namespace MathNet.Numerics.LinearAlgebra
/// </summary>
public Matrix<T> SparseOfRows(IEnumerable<IEnumerable<T>> data)
{
return Sparse(SparseCompressedRowMatrixStorage<T>.OfRowArrays(data.Select(v => v.ToArray()).ToArray()));
return Sparse(SparseCompressedRowMatrixStorage<T>.OfRowArrays(data.Select(v => (v as T[]) ?? v.ToArray()).ToArray()));
}
/// <summary>
@ -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.
/// </summary>
public Vector<T> Storage(VectorStorage<T> storage)
public Vector<T> OfStorage(VectorStorage<T> storage)
{
var dense = storage as DenseVectorStorage<T>;
if (dense != null) return Dense(dense);
@ -1020,6 +1070,11 @@ namespace MathNet.Numerics.LinearAlgebra
throw new NotSupportedException();
}
/// <summary>
/// Create a new dense vector with values sampled from the provided random distribution.
/// </summary>
public abstract Vector<T> Random(int length, IContinuousDistribution distribution);
/// <summary>
/// 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<T>.OfInit(length, init));
}
/// <summary>
/// Create a new dense vector with values sampled from the provided random distribution.
/// </summary>
public abstract Vector<T> DenseRandom(int length, IContinuousDistribution distribution);
/// <summary>
/// Create a new dense vector as a copy of the given other vector.
/// This new vector will be independent from the other vector.

Loading…
Cancel
Save