Browse Source

LA: Vector.Find/2, Exists/2, ForAll/2

pull/297/head
Christoph Ruegg 11 years ago
parent
commit
e591f86e2f
  1. 24
      src/Numerics/LinearAlgebra/Matrix.cs
  2. 67
      src/Numerics/LinearAlgebra/Storage/DenseVectorStorage.cs
  3. 38
      src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs
  4. 30
      src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs
  5. 185
      src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs
  6. 80
      src/Numerics/LinearAlgebra/Storage/VectorStorage.cs
  7. 57
      src/Numerics/LinearAlgebra/Vector.cs

24
src/Numerics/LinearAlgebra/Matrix.cs

@ -1745,33 +1745,57 @@ namespace MathNet.Numerics.LinearAlgebra
return Storage.Fold2(other.Storage, f, state, zeros);
}
/// <summary>
/// Returns a tuple with the index and value of the first element satisfying a predicate, or null if none is found.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public Tuple<int, int, T> Find(Func<T, bool> predicate, Zeros zeros = Zeros.AllowSkip)
{
return Storage.Find(predicate, zeros);
}
/// <summary>
/// Returns a tuple with the index and values of the first element pair of two matrices of the same size satisfying a predicate, or null if none is found.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public Tuple<int, int, T, TOther> Find2<TOther>(Func<T, TOther, bool> predicate, Matrix<TOther> other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable<TOther>, IFormattable
{
return Storage.Find2(other.Storage, predicate, zeros);
}
/// <summary>
/// Returns true if at least one element satisfies a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public bool Exists(Func<T, bool> predicate, Zeros zeros = Zeros.AllowSkip)
{
return Storage.Find(predicate, zeros) != null;
}
/// <summary>
/// Returns true if at least one element pairs of two matrices of the same size satisfies a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public bool Exists2<TOther>(Func<T, TOther, bool> predicate, Matrix<TOther> other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable<TOther>, IFormattable
{
return Storage.Find2(other.Storage, predicate, zeros) != null;
}
/// <summary>
/// Returns true if all elements satisfy a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public bool ForAll(Func<T, bool> predicate, Zeros zeros = Zeros.AllowSkip)
{
return Storage.Find(x => !predicate(x), zeros) == null;
}
/// <summary>
/// Returns true if all element pairs of two matrices of the same size satisfy a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public bool ForAll2<TOther>(Func<T, TOther, bool> predicate, Matrix<TOther> other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable<TOther>, IFormattable
{

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

@ -90,6 +90,8 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
Data[index] = value;
}
// CLEARING
public override void Clear()
{
Array.Clear(Data, 0, Data.Length);
@ -353,6 +355,71 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
}
}
// FIND
public override Tuple<int, T> Find(Func<T, bool> predicate, Zeros zeros)
{
for (int i = 0; i < Data.Length; i++)
{
if (predicate(Data[i]))
{
return new Tuple<int, T>(i, Data[i]);
}
}
return null;
}
internal override Tuple<int, T, TOther> Find2Unchecked<TOther>(VectorStorage<TOther> other, Func<T, TOther, bool> predicate, Zeros zeros)
{
var denseOther = other as DenseVectorStorage<TOther>;
if (denseOther != null)
{
TOther[] otherData = denseOther.Data;
for (int i = 0; i < Data.Length; i++)
{
if (predicate(Data[i], otherData[i]))
{
return new Tuple<int, T, TOther>(i, Data[i], otherData[i]);
}
}
return null;
}
var sparseOther = other as SparseVectorStorage<TOther>;
if (sparseOther != null)
{
int[] otherIndices = sparseOther.Indices;
TOther[] otherValues = sparseOther.Values;
int otherValueCount = sparseOther.ValueCount;
TOther otherZero = BuilderInstance<TOther>.Matrix.Zero;
int k = 0;
for (int i = 0; i < Data.Length; i++)
{
if (k < otherValueCount && otherIndices[k] == i)
{
if (predicate(Data[i], otherValues[k]))
{
return new Tuple<int, T, TOther>(i, Data[i], otherValues[k]);
}
k++;
}
else
{
if (predicate(Data[i], otherZero))
{
return new Tuple<int, T, TOther>(i, Data[i], otherZero);
}
}
}
return null;
}
// FALLBACK
return base.Find2Unchecked(other, predicate, zeros);
}
// FUNCTIONAL COMBINATORS
internal override void MapToUnchecked<TU>(VectorStorage<TU> target, Func<T, TU> f, Zeros zeros, ExistingData existingData)

38
src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs

@ -794,6 +794,44 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
}
}
public void Map2To(MatrixStorage<T> target, MatrixStorage<T> other, Func<T, T, T> f, Zeros zeros, ExistingData existingData)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (other == null)
{
throw new ArgumentNullException("other");
}
if (RowCount != target.RowCount || ColumnCount != target.ColumnCount)
{
var message = string.Format(Resources.ArgumentMatrixDimensions2, RowCount + "x" + ColumnCount, target.RowCount + "x" + target.ColumnCount);
throw new ArgumentException(message, "target");
}
if (RowCount != other.RowCount || ColumnCount != other.ColumnCount)
{
var message = string.Format(Resources.ArgumentMatrixDimensions2, RowCount + "x" + ColumnCount, other.RowCount + "x" + other.ColumnCount);
throw new ArgumentException(message, "other");
}
Map2ToUnchecked(target, other, f, zeros, existingData);
}
internal virtual void Map2ToUnchecked(MatrixStorage<T> target, MatrixStorage<T> other, Func<T, T, T> f, Zeros zeros, ExistingData existingData)
{
for (int i = 0; i < RowCount; i++)
{
for (int j = 0; j < ColumnCount; j++)
{
target.At(i, j, f(At(i, j), other.At(i, j)));
}
}
}
// FUNCTIONAL COMBINATORS: FOLD
/// <remarks>The state array will not be modified, unless it is the same instance as the target array (which is allowed).</remarks>

30
src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs

@ -1367,7 +1367,8 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
TOther[] otherData = diagonalOther.Data;
TOther otherZero = BuilderInstance<TOther>.Matrix.Zero;
if (zeros == Zeros.Include)
// Full Scan
if (zeros == Zeros.Include && predicate(Zero, otherZero))
{
int k = 0;
for (int row = 0; row < RowCount; row++)
@ -1384,6 +1385,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
return null;
}
// Sparse Scan
for (int row = 0; row < RowCount; row++)
{
bool diagonal = false;
@ -1446,35 +1448,31 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
for (int row = 0; row < RowCount; row++)
{
var startIndex = RowPointers[row];
var endIndex = RowPointers[row + 1];
var otherStartIndex = otherRowPointers[row];
var otherEndIndex = otherRowPointers[row + 1];
var j1 = startIndex;
var j2 = otherStartIndex;
while (j1 < endIndex || j2 < otherEndIndex)
var k = RowPointers[row];
var otherk = otherRowPointers[row];
while (k < endIndex || otherk < otherEndIndex)
{
if (j1 == endIndex || j2 < otherEndIndex && ColumnIndices[j1] > otherColumnIndices[j2])
if (k == endIndex || otherk < otherEndIndex && ColumnIndices[k] > otherColumnIndices[otherk])
{
if (predicate(Zero, otherValues[j2++]))
if (predicate(Zero, otherValues[otherk++]))
{
return new Tuple<int, int, T, TOther>(row, otherColumnIndices[j2 - 1], Zero, otherValues[j2 - 1]);
return new Tuple<int, int, T, TOther>(row, otherColumnIndices[otherk - 1], Zero, otherValues[otherk - 1]);
}
}
else if (j2 == otherEndIndex || ColumnIndices[j1] < otherColumnIndices[j2])
else if (otherk == otherEndIndex || ColumnIndices[k] < otherColumnIndices[otherk])
{
if (predicate(Values[j1++], otherZero))
if (predicate(Values[k++], otherZero))
{
return new Tuple<int, int, T, TOther>(row, ColumnIndices[j1 - 1], Values[j1 - 1], otherZero);
return new Tuple<int, int, T, TOther>(row, ColumnIndices[k - 1], Values[k - 1], otherZero);
}
}
else
{
if (predicate(Values[j1++], otherValues[j2++]))
if (predicate(Values[k++], otherValues[otherk++]))
{
return new Tuple<int, int, T, TOther>(row, ColumnIndices[j1 - 1], Values[j1 - 1], otherValues[j2 - 1]);
return new Tuple<int, int, T, TOther>(row, ColumnIndices[k - 1], Values[k - 1], otherValues[otherk - 1]);
}
}
}

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

@ -183,42 +183,6 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
return delta;
}
public override void Clear()
{
ValueCount = 0;
}
public override void Clear(int index, int count)
{
if (index == 0 && count == Length)
{
Clear();
return;
}
var first = Array.BinarySearch(Indices, 0, ValueCount, index);
var last = Array.BinarySearch(Indices, 0, ValueCount, index + count - 1);
if (first < 0) first = ~first;
if (last < 0) last = ~last - 1;
int itemCount = last - first + 1;
if (itemCount > 0)
{
Array.Copy(Values, first + count, Values, first, ValueCount - first - count);
Array.Copy(Indices, first + count, Indices, first, ValueCount - first - count);
ValueCount -= count;
}
// Check whether we need to shrink the arrays. This is reasonable to do if
// there are a lot of non-zero elements and storage is two times bigger
if ((ValueCount > 1024) && (ValueCount < Indices.Length / 2))
{
Array.Resize(ref Values, ValueCount);
Array.Resize(ref Indices, ValueCount);
}
}
public override bool Equals(VectorStorage<T> other)
{
// Reject equality when the argument is null or has a different shape.
@ -293,6 +257,44 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
return hash;
}
// CLEARING
public override void Clear()
{
ValueCount = 0;
}
public override void Clear(int index, int count)
{
if (index == 0 && count == Length)
{
Clear();
return;
}
var first = Array.BinarySearch(Indices, 0, ValueCount, index);
var last = Array.BinarySearch(Indices, 0, ValueCount, index + count - 1);
if (first < 0) first = ~first;
if (last < 0) last = ~last - 1;
int itemCount = last - first + 1;
if (itemCount > 0)
{
Array.Copy(Values, first + count, Values, first, ValueCount - first - count);
Array.Copy(Indices, first + count, Indices, first, ValueCount - first - count);
ValueCount -= count;
}
// Check whether we need to shrink the arrays. This is reasonable to do if
// there are a lot of non-zero elements and storage is two times bigger
if ((ValueCount > 1024) && (ValueCount < Indices.Length / 2))
{
Array.Resize(ref Values, ValueCount);
Array.Resize(ref Indices, ValueCount);
}
}
// INITIALIZATION
public static SparseVectorStorage<T> OfVector(VectorStorage<T> vector)
@ -645,6 +647,117 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
}
}
// FIND
public override Tuple<int, T> Find(Func<T, bool> predicate, Zeros zeros)
{
for (int i = 0; i < ValueCount; i++)
{
if (predicate(Values[i]))
{
return new Tuple<int, T>(Indices[i], Values[i]);
}
}
if (zeros == Zeros.Include && ValueCount < Length && predicate(Zero))
{
for (int i = 0; i < Length; i++)
{
if (i >= ValueCount || Indices[i] != i)
{
return new Tuple<int, T>(i, Zero);
}
}
}
return null;
}
internal override Tuple<int, T, TOther> Find2Unchecked<TOther>(VectorStorage<TOther> other, Func<T, TOther, bool> predicate, Zeros zeros)
{
var denseOther = other as DenseVectorStorage<TOther>;
if (denseOther != null)
{
TOther[] otherData = denseOther.Data;
int k = 0;
for (int i = 0; i < otherData.Length; i++)
{
if (k < ValueCount && Indices[k] == i)
{
if (predicate(Values[k], otherData[i]))
{
return new Tuple<int, T, TOther>(i, Values[k], otherData[i]);
}
k++;
}
else
{
if (predicate(Zero, otherData[i]))
{
return new Tuple<int, T, TOther>(i, Zero, otherData[i]);
}
}
}
return null;
}
var sparseOther = other as SparseVectorStorage<TOther>;
if (sparseOther != null)
{
int[] otherIndices = sparseOther.Indices;
TOther[] otherValues = sparseOther.Values;
int otherValueCount = sparseOther.ValueCount;
TOther otherZero = BuilderInstance<TOther>.Matrix.Zero;
// Full Scan
int k = 0, otherk = 0;
if (zeros == Zeros.Include && ValueCount < Length && sparseOther.ValueCount < Length && predicate(Zero, otherZero))
{
for (int i = 0; i < Length; i++)
{
var left = k < ValueCount && Indices[k] == i ? Values[k++] : Zero;
var right = otherk < otherValueCount && otherIndices[otherk] == i ? otherValues[otherk++] : otherZero;
if (predicate(left, right))
{
return new Tuple<int, T, TOther>(i, left, right);
}
}
return null;
}
// Sparse Scan
k = 0;
otherk = 0;
while (k < ValueCount || otherk < otherValueCount)
{
if (k == ValueCount || otherk < otherValueCount && Indices[k] > otherIndices[otherk])
{
if (predicate(Zero, otherValues[otherk++]))
{
return new Tuple<int, T, TOther>(otherIndices[otherk - 1], Zero, otherValues[otherk - 1]);
}
}
else if (otherk == otherValueCount || Indices[k] < otherIndices[otherk])
{
if (predicate(Values[k++], otherZero))
{
return new Tuple<int, T, TOther>(Indices[k - 1], Values[k - 1], otherZero);
}
}
else
{
if (predicate(Values[k++], otherValues[otherk++]))
{
return new Tuple<int, T, TOther>(Indices[k - 1], Values[k - 1], otherValues[otherk - 1]);
}
}
}
return null;
}
// FALL BACK
return base.Find2Unchecked(other, predicate, zeros);
}
// FUNCTIONAL COMBINATORS
internal override void MapToUnchecked<TU>(VectorStorage<TU> target, Func<T, TU> f, Zeros zeros, ExistingData existingData)

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

@ -98,22 +98,6 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
/// <remarks>WARNING: This method is not thread safe. Use "lock" with it and be sure to avoid deadlocks.</remarks>
public abstract void At(int index, T value);
public virtual void Clear()
{
for (var i = 0; i < Length; i++)
{
At(i, Zero);
}
}
public virtual void Clear(int index, int count)
{
for (var i = index; i < index + count; i++)
{
At(i, Zero);
}
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
@ -185,6 +169,24 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
return hash;
}
// CLEARING
public virtual void Clear()
{
for (var i = 0; i < Length; i++)
{
At(i, Zero);
}
}
public virtual void Clear(int index, int count)
{
for (var i = index; i < index + count; i++)
{
At(i, Zero);
}
}
// VECTOR COPY
public void CopyTo(VectorStorage<T> target, ExistingData existingData = ExistingData.Clear)
@ -411,6 +413,52 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
}
}
// FIND
public virtual Tuple<int, T> Find(Func<T, bool> predicate, Zeros zeros)
{
for (int i = 0; i < Length; i++)
{
var item = At(i);
if (predicate(item))
{
return new Tuple<int, T>(i, item);
}
}
return null;
}
public Tuple<int, T, TOther> Find2<TOther>(VectorStorage<TOther> other, Func<T, TOther, bool> predicate, Zeros zeros)
where TOther : struct, IEquatable<TOther>, IFormattable
{
if (other == null)
{
throw new ArgumentNullException("other");
}
if (Length != other.Length)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other");
}
return Find2Unchecked(other, predicate, zeros);
}
internal virtual Tuple<int, T, TOther> Find2Unchecked<TOther>(VectorStorage<TOther> other, Func<T, TOther, bool> predicate, Zeros zeros)
where TOther : struct, IEquatable<TOther>, IFormattable
{
for (int i = 0; i < Length; i++)
{
var item = At(i);
var otherItem = other.At(i);
if (predicate(item, otherItem))
{
return new Tuple<int, T, TOther>(i, item, otherItem);
}
}
return null;
}
// FUNCTIONAL COMBINATORS
public void MapTo<TU>(VectorStorage<TU> target, Func<T, TU> f,

57
src/Numerics/LinearAlgebra/Vector.cs

@ -484,5 +484,62 @@ namespace MathNet.Numerics.LinearAlgebra
{
return Storage.Fold2(other.Storage, f, state, zeros);
}
/// <summary>
/// Returns a tuple with the index and value of the first element satisfying a predicate, or null if none is found.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public Tuple<int, T> Find(Func<T, bool> predicate, Zeros zeros = Zeros.AllowSkip)
{
return Storage.Find(predicate, zeros);
}
/// <summary>
/// Returns a tuple with the index and values of the first element pair of two vectors of the same size satisfying a predicate, or null if none is found.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public Tuple<int, T, TOther> Find2<TOther>(Func<T, TOther, bool> predicate, Vector<TOther> other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable<TOther>, IFormattable
{
return Storage.Find2(other.Storage, predicate, zeros);
}
/// <summary>
/// Returns true if at least one element satisfies a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public bool Exists(Func<T, bool> predicate, Zeros zeros = Zeros.AllowSkip)
{
return Storage.Find(predicate, zeros) != null;
}
/// <summary>
/// Returns true if at least one element pairs of two vectors of the same size satisfies a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public bool Exists2<TOther>(Func<T, TOther, bool> predicate, Vector<TOther> other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable<TOther>, IFormattable
{
return Storage.Find2(other.Storage, predicate, zeros) != null;
}
/// <summary>
/// Returns true if all elements satisfy a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public bool ForAll(Func<T, bool> predicate, Zeros zeros = Zeros.AllowSkip)
{
return Storage.Find(x => !predicate(x), zeros) == null;
}
/// <summary>
/// Returns true if all element pairs of two vectors of the same size satisfy a predicate.
/// Zero elements may be skipped on sparse data structures if allowed (default).
/// </summary>
public bool ForAll2<TOther>(Func<T, TOther, bool> predicate, Vector<TOther> other, Zeros zeros = Zeros.AllowSkip)
where TOther : struct, IEquatable<TOther>, IFormattable
{
return Storage.Find2(other.Storage, (x, y) => !predicate(x, y), zeros) == null;
}
}
}

Loading…
Cancel
Save