Browse Source

LA: Functional Map/MapIndexed on vectors, with F# support

pull/112/head
Christoph Ruegg 13 years ago
parent
commit
0384038145
  1. 56
      src/FSharp/LinearAlgebra.Double.Vector.fs
  2. 39
      src/FSharpUnitTests/VectorTests.fs
  3. 21
      src/Numerics/LinearAlgebra/Generic/Vector.cs
  4. 18
      src/Numerics/LinearAlgebra/Storage/DenseVectorStorage.cs
  5. 70
      src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs
  6. 18
      src/Numerics/LinearAlgebra/Storage/VectorStorage.cs

56
src/FSharp/LinearAlgebra.Double.Vector.fs

@ -44,29 +44,58 @@ module Vector =
/// In-place mutation by applying a function to every element of the vector.
let inline mapInPlace (f: float -> float) (v: #Vector<float>) =
for i=0 to v.Count-1 do
v.At(i, f (v.At i))
v.MapInplace((fun x -> f x), true)
()
/// In-place mutation by applying a function to every element of the vector.
let inline mapiInPlace (f: int -> float -> float) (v: #Vector<float>) =
for i=0 to v.Count-1 do
v.At(i, f i (v.At i))
v.MapIndexedInplace((fun i x -> f i x), true)
()
/// In-place vector addition.
let inline addInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Add(w, v)
/// In-place mutation by applying a function to every element of the vector.
/// Zero-values may be skipped (relevant mostly for sparse vectors).
let inline mapnzInPlace (f: float -> float) (v: #Vector<float>) =
v.MapInplace((fun x -> f x), false)
()
/// In place vector subtraction.
let inline subInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Subtract(w, v)
/// In-place mutation by applying a function to every element of the vector.
/// Zero-values may be skipped (relevant mostly for sparse vectors).
let inline mapinzInPlace (f: int -> float -> float) (v: #Vector<float>) =
v.MapIndexedInplace((fun i x -> f i x), false)
()
/// Functional map operator for vectors.
/// <include file='../../../../FSharpExamples/DenseVector.xml' path='example'/>
/// Maps a vector to a new vector by applying a function to every element.
let inline map f (v: #Vector<float>) =
let w = v.Clone()
mapInPlace (fun x -> f x) w
w.MapInplace((fun x -> f x), true)
w
/// Maps a vector to a new vector by applying a function to every element.
/// Zero-values may be skipped (relevant mostly for sparse vectors).
let inline mapnz f (v: #Vector<float>) =
let w = v.Clone()
w.MapInplace((fun x -> f x), false)
w
/// Maps a vector to a new vector by applying a function to every element.
let inline mapi (f: int -> float -> float) (v: #Vector<float>) =
let w = v.Clone()
w.MapIndexedInplace((fun i x -> f i x), true)
w
/// Maps a vector to a new vector by applying a function to every element.
/// Zero-values may be skipped (relevant mostly for sparse vectors).
let inline mapinz (f: int -> float -> float) (v: #Vector<float>) =
let w = v.Clone()
w.MapIndexedInplace((fun i x -> f i x), false)
w
/// In-place vector addition.
let inline addInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Add(w, v)
/// In place vector subtraction.
let inline subInPlace (v: #Vector<float>) (w: #Vector<float>) = v.Subtract(w, v)
/// Applies a function to all elements of the vector.
let inline iter (f: float -> unit) (v: #Vector<float>) =
for i=0 to v.Count-1 do
@ -77,11 +106,6 @@ module Vector =
for i=0 to v.Count-1 do
f i (v.At i)
/// Maps a vector to a new vector by applying a function to every element.
let inline mapi (f: int -> float -> float) (v: #Vector<float>) =
let w = v.Clone()
mapiInPlace f w
w
/// Fold all entries of a vector.
let inline fold (f: 'a -> float -> 'a) (acc0: 'a) (v: #Vector<float>) =

39
src/FSharpUnitTests/VectorTests.fs

@ -11,6 +11,9 @@ module VectorTests =
/// A small uniform vector.
let smallv = new DenseVector([|0.3;0.3;0.3;0.3;0.3|]) :> Vector<float>
/// A small uniform vector.
let sparsev = SparseVector.OfIndexedEnumerable(5, [(1,0.3)]) :> Vector<float>
/// A large vector with increasingly large entries
let largev = new DenseVector(Array.init 100 (fun i -> float i / 100.0)) :> Vector<float>
@ -49,16 +52,40 @@ module VectorTests =
Vector.toList smallv |> should equal [0.3;0.3;0.3;0.3;0.3]
[<Test>]
let ``Vector.mapInPlace`` () =
let ``Vector.mapInPlace.Dense`` () =
let w = smallv.Clone()
Vector.mapInPlace (fun x -> 2.0 * x) w
w |> should equal (2.0 * smallv)
[<Test>]
let ``Vector.mapiInPlace`` () =
let ``Vector.mapInPlace.Sparse`` () =
let w = sparsev.Clone()
Vector.mapInPlace (fun x -> 2.0 * x) w
w |> should equal (2.0 * sparsev)
[<Test>]
let ``Vector.mapnzInPlace.Sparse`` () =
let w = sparsev.Clone()
Vector.mapnzInPlace (fun x -> 2.0 * x) w
w |> should equal (2.0 * sparsev)
[<Test>]
let ``Vector.mapiInPlace.Dense`` () =
let w = largev.Clone()
Vector.mapiInPlace (fun i x -> float i / 100.0) w
w |> should equal (largev)
[<Test>]
let ``Vector.mapiInPlace.Sparse`` () =
let w = sparsev.Clone()
Vector.mapiInPlace (fun i x -> 2.0 * float i * x) w
w |> should equal (2.0 * sparsev)
[<Test>]
let ``Vector.mapinzInPlace.Sparse`` () =
let w = sparsev.Clone()
Vector.mapinzInPlace (fun i x -> 2.0 * float i * x) w
w |> should equal (2.0 * sparsev)
[<Test>]
let ``Vector.addInPlace`` () =
@ -76,10 +103,18 @@ module VectorTests =
let ``Vector.map`` () =
Vector.map (fun x -> 2.0 * x) largev |> should equal (2.0 * largev)
[<Test>]
let ``Vector.mapnz`` () =
Vector.mapnz (fun x -> 2.0 * x) largev |> should equal (2.0 * largev)
[<Test>]
let ``Vector.mapi`` () =
Vector.mapi (fun i x -> float i / 100.0) largev |> should equal largev
[<Test>]
let ``Vector.mapinz`` () =
Vector.mapinz (fun i x -> float i / 100.0) largev |> should equal largev
[<Test>]
let ``Vector.fold`` () =
Vector.fold (fun a b -> a - b) 0.0 smallv |> should equal -1.5

21
src/Numerics/LinearAlgebra/Generic/Vector.cs

@ -1291,5 +1291,26 @@ namespace MathNet.Numerics.LinearAlgebra.Generic
{
return Storage.EnumerateNonZero();
}
/// <summary>
/// Applies a function to each value of this vector 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 vectors).
/// </summary>
public void MapInplace(Func<T, T> f, bool forceMapZeros = false)
{
Storage.MapInplace(f, forceMapZeros);
}
/// <summary>
/// Applies a function to each value of this vector and replaces the value with its result.
/// 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 vectors).
/// </summary>
public void MapIndexedInplace(Func<int, T, T> f, bool forceMapZeros = false)
{
Storage.MapIndexedInplace(f, forceMapZeros);
}
}
}

18
src/Numerics/LinearAlgebra/Storage/DenseVectorStorage.cs

@ -291,5 +291,23 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
target.At(ii, columnIndex, Data[i]);
}
}
// FUNCTIONAL COMBINATORS
public override void MapInplace(Func<T, T> f, bool forceMapZeros = false)
{
for (int i = 0; i < Data.Length; i++)
{
Data[i] = f(Data[i]);
}
}
public override void MapIndexedInplace(Func<int, T, T> f, bool forceMapZeros = false)
{
for (int i = 0; i < Data.Length; i++)
{
Data[i] = f(i, Data[i]);
}
}
}
}

70
src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs

@ -590,5 +590,75 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
target.At(Indices[i] + offset, Values[i]);
}
}
// FUNCTIONAL COMBINATORS
public override void MapInplace(Func<T, T> f, bool forceMapZeros = false)
{
var indices = new List<int>();
var values = new List<T>();
if (forceMapZeros || !Zero.Equals(f(Zero)))
{
int k = 0;
for (int i = 0; i < Length; i++)
{
var item = k < ValueCount && (Indices[k]) == i ? f(Values[k++]) : f(Zero);
if (!Zero.Equals(item))
{
values.Add(item);
indices.Add(i);
}
}
}
else
{
for (int i = 0; i < Values.Length; i++)
{
var item = f(Values[i]);
if (!Zero.Equals(item))
{
values.Add(item);
indices.Add(Indices[i]);
}
}
}
Indices = indices.ToArray();
Values = values.ToArray();
ValueCount = values.Count;
}
public override void MapIndexedInplace(Func<int, T, T> f, bool forceMapZeros = false)
{
var indices = new List<int>();
var values = new List<T>();
if (forceMapZeros || !Zero.Equals(f(0, Zero)))
{
int k = 0;
for (int i = 0; i < Length; i++)
{
var item = k < ValueCount && (Indices[k]) == i ? f(i, Values[k++]) : f(i, Zero);
if (!Zero.Equals(item))
{
values.Add(item);
indices.Add(i);
}
}
}
else
{
for (int i = 0; i < Values.Length; i++)
{
var item = f(Indices[i], Values[i]);
if (!Zero.Equals(item))
{
values.Add(item);
indices.Add(Indices[i]);
}
}
}
Indices = indices.ToArray();
Values = values.ToArray();
ValueCount = values.Count;
}
}
}

18
src/Numerics/LinearAlgebra/Storage/VectorStorage.cs

@ -391,5 +391,23 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
target.At(ii, columnIndex, At(i));
}
}
// FUNCTIONAL COMBINATORS
public virtual void MapInplace(Func<T, T> f, bool forceMapZeros = false)
{
for (int i = 0; i < Length; i++)
{
At(i, f(At(i)));
}
}
public virtual void MapIndexedInplace(Func<int, T, T> f, bool forceMapZeros = false)
{
for (int i = 0; i < Length; i++)
{
At(i, f(i, At(i)));
}
}
}
}

Loading…
Cancel
Save