Browse Source

LA: More consistent range checking in MatrixStorage.Clear and related routines #284

cuda
Christoph Ruegg 12 years ago
parent
commit
94a37cb1c1
  1. 48
      src/Numerics/LinearAlgebra/Matrix.cs
  2. 10
      src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs
  3. 74
      src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs
  4. 150
      src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs
  5. 154
      src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs
  6. 4
      src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs

48
src/Numerics/LinearAlgebra/Matrix.cs

@ -158,7 +158,7 @@ namespace MathNet.Numerics.LinearAlgebra
throw new ArgumentOutOfRangeException("rowIndex"); throw new ArgumentOutOfRangeException("rowIndex");
} }
Storage.Clear(rowIndex, 1, 0, ColumnCount); Storage.ClearUnchecked(rowIndex, 1, 0, ColumnCount);
} }
/// <summary> /// <summary>
@ -171,7 +171,7 @@ namespace MathNet.Numerics.LinearAlgebra
throw new ArgumentOutOfRangeException("columnIndex"); throw new ArgumentOutOfRangeException("columnIndex");
} }
Storage.Clear(0, RowCount, columnIndex, 1); Storage.ClearUnchecked(0, RowCount, columnIndex, 1);
} }
/// <summary> /// <summary>
@ -179,19 +179,6 @@ namespace MathNet.Numerics.LinearAlgebra
/// </summary> /// </summary>
public void ClearRows(params int[] rowIndices) public void ClearRows(params int[] rowIndices)
{ {
if (rowIndices.Length == 0)
{
return;
}
for (int k = 0; k < rowIndices.Length; k++)
{
if (rowIndices[k] < 0 || rowIndices[k] >= RowCount)
{
throw new ArgumentOutOfRangeException("rowIndices");
}
}
Storage.ClearRows(rowIndices); Storage.ClearRows(rowIndices);
} }
@ -200,43 +187,14 @@ namespace MathNet.Numerics.LinearAlgebra
/// </summary> /// </summary>
public void ClearColumns(params int[] columnIndices) public void ClearColumns(params int[] columnIndices)
{ {
if (columnIndices.Length == 0)
{
return;
}
for (int k = 0; k < columnIndices.Length; k++)
{
if (columnIndices[k] < 0 || columnIndices[k] >= ColumnCount)
{
throw new ArgumentOutOfRangeException("columnIndices");
}
}
Storage.ClearColumns(columnIndices); Storage.ClearColumns(columnIndices);
} }
/// <summary> /// <summary>
/// Sets all values of a submatrix to zero. /// Sets all values of a sub-matrix to zero.
/// </summary> /// </summary>
public void ClearSubMatrix(int rowIndex, int rowCount, int columnIndex, int columnCount) public void ClearSubMatrix(int rowIndex, int rowCount, int columnIndex, int columnCount)
{ {
if (rowCount < 1 || columnCount < 1)
{
// nothing to do (but no need to fail either)
return;
}
if (rowIndex + rowCount > RowCount || rowIndex < 0)
{
throw new ArgumentOutOfRangeException("rowIndex");
}
if (columnIndex + columnCount > ColumnCount || columnIndex < 0)
{
throw new ArgumentOutOfRangeException("columnIndex");
}
Storage.Clear(rowIndex, rowCount, columnIndex, columnCount); Storage.Clear(rowIndex, rowCount, columnIndex, columnCount);
} }

10
src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs

@ -108,16 +108,18 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
Data[(column*RowCount) + row] = value; Data[(column*RowCount) + row] = value;
} }
// CLEARING
public override void Clear() public override void Clear()
{ {
Array.Clear(Data, 0, Data.Length); Array.Clear(Data, 0, Data.Length);
} }
public override void Clear(int rowIndex, int rowCount, int columnIndex, int columnCount) internal override void ClearUnchecked(int rowIndex, int rowCount, int columnIndex, int columnCount)
{ {
if (rowIndex == 0 && columnIndex == 0 && rowCount == RowCount && columnCount == ColumnCount) if (rowIndex == 0 && columnIndex == 0 && rowCount == RowCount && columnCount == ColumnCount)
{ {
Clear(); Array.Clear(Data, 0, Data.Length);
return; return;
} }
@ -127,7 +129,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
} }
} }
public override void ClearRows(int[] rowIndices) internal override void ClearRowsUnchecked(int[] rowIndices)
{ {
for (var j = 0; j < ColumnCount; j++) for (var j = 0; j < ColumnCount; j++)
{ {
@ -139,7 +141,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
} }
} }
public override void ClearColumns(int[] columnIndices) internal override void ClearColumnsUnchecked(int[] columnIndices)
{ {
for (int k = 0; k < columnIndices.Length; k++) for (int k = 0; k < columnIndices.Length; k++)
{ {

74
src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs

@ -115,37 +115,6 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
} }
} }
public override void Clear()
{
Array.Clear(Data, 0, Data.Length);
}
public override void Clear(int rowIndex, int rowCount, int columnIndex, int columnCount)
{
var beginInclusive = Math.Max(rowIndex, columnIndex);
var endExclusive = Math.Min(rowIndex + rowCount, columnIndex + columnCount);
if (endExclusive > beginInclusive)
{
Array.Clear(Data, beginInclusive, endExclusive - beginInclusive);
}
}
public override void ClearRows(int[] rowIndices)
{
for (int i = 0; i < rowIndices.Length; i++)
{
Data[rowIndices[i]] = Zero;
}
}
public override void ClearColumns(int[] columnIndices)
{
for (int i = 0; i < columnIndices.Length; i++)
{
Data[columnIndices[i]] = Zero;
}
}
/// <summary> /// <summary>
/// Indicates whether the current object is equal to another object of the same type. /// Indicates whether the current object is equal to another object of the same type.
/// </summary> /// </summary>
@ -204,6 +173,39 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
return hash; return hash;
} }
// CLEARING
public override void Clear()
{
Array.Clear(Data, 0, Data.Length);
}
internal override void ClearUnchecked(int rowIndex, int rowCount, int columnIndex, int columnCount)
{
var beginInclusive = Math.Max(rowIndex, columnIndex);
var endExclusive = Math.Min(rowIndex + rowCount, columnIndex + columnCount);
if (endExclusive > beginInclusive)
{
Array.Clear(Data, beginInclusive, endExclusive - beginInclusive);
}
}
internal override void ClearRowsUnchecked(int[] rowIndices)
{
for (int i = 0; i < rowIndices.Length; i++)
{
Data[rowIndices[i]] = Zero;
}
}
internal override void ClearColumnsUnchecked(int[] columnIndices)
{
for (int i = 0; i < columnIndices.Length; i++)
{
Data[columnIndices[i]] = Zero;
}
}
// INITIALIZATION // INITIALIZATION
public static DiagonalMatrixStorage<T> OfMatrix(MatrixStorage<T> matrix) public static DiagonalMatrixStorage<T> OfMatrix(MatrixStorage<T> matrix)
@ -381,7 +383,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
if (existingData == ExistingData.Clear) if (existingData == ExistingData.Clear)
{ {
target.Clear(targetRowIndex, rowCount, targetColumnIndex, columnCount); target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount);
} }
if (sourceRowIndex == sourceColumnIndex) if (sourceRowIndex == sourceColumnIndex)
@ -422,7 +424,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
throw new NotSupportedException(); throw new NotSupportedException();
} }
target.Clear(targetRowIndex, rowCount, targetColumnIndex, columnCount); target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount);
return; return;
} }
@ -442,7 +444,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
{ {
if (existingData == ExistingData.Clear) if (existingData == ExistingData.Clear)
{ {
target.Clear(targetRowIndex, rowCount, targetColumnIndex, columnCount); target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount);
} }
if (sourceRowIndex > sourceColumnIndex && sourceColumnIndex + columnCount > sourceRowIndex) if (sourceRowIndex > sourceColumnIndex && sourceColumnIndex + columnCount > sourceRowIndex)
@ -790,7 +792,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
if (existingData == ExistingData.Clear) if (existingData == ExistingData.Clear)
{ {
target.Clear(targetRowIndex, rowCount, targetColumnIndex, columnCount); target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount);
} }
if (sourceRowIndex == sourceColumnIndex) if (sourceRowIndex == sourceColumnIndex)
@ -870,7 +872,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
var processZeros = zeros == Zeros.Include || !Zero.Equals(f(0, 1, Zero)); var processZeros = zeros == Zeros.Include || !Zero.Equals(f(0, 1, Zero));
if (existingData == ExistingData.Clear && !processZeros) if (existingData == ExistingData.Clear && !processZeros)
{ {
target.Clear(targetRowIndex, rowCount, targetColumnIndex, columnCount); target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount);
} }
if (processZeros) if (processZeros)

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

@ -128,52 +128,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> /// <remarks>WARNING: This method is not thread safe. Use "lock" with it and be sure to avoid deadlocks.</remarks>
public abstract void At(int row, int column, T value); public abstract void At(int row, int column, T value);
public virtual void Clear()
{
for (var i = 0; i < RowCount; i++)
{
for (var j = 0; j < ColumnCount; j++)
{
At(i, j, Zero);
}
}
}
public virtual void Clear(int rowIndex, int rowCount, int columnIndex, int columnCount)
{
for (var i = rowIndex; i < rowIndex + rowCount; i++)
{
for (var j = columnIndex; j < columnIndex + columnCount; j++)
{
At(i, j, Zero);
}
}
}
public virtual void ClearRows(int[] rowIndices)
{
for (var k = 0; k < rowIndices.Length; k++)
{
int row = rowIndices[k];
for (var j = 0; j < ColumnCount; j++)
{
At(row, j, Zero);
}
}
}
public virtual void ClearColumns(int[] columnIndices)
{
for (var k = 0; k < columnIndices.Length; k++)
{
int column = columnIndices[k];
for (var i = 0; i < RowCount; i++)
{
At(i, column, Zero);
}
}
}
/// <summary> /// <summary>
/// Indicates whether the current object is equal to another object of the same type. /// Indicates whether the current object is equal to another object of the same type.
/// </summary> /// </summary>
@ -250,6 +204,110 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
return hash; return hash;
} }
// CLEARING
public virtual void Clear()
{
for (var i = 0; i < RowCount; i++)
{
for (var j = 0; j < ColumnCount; j++)
{
At(i, j, Zero);
}
}
}
public void Clear(int rowIndex, int rowCount, int columnIndex, int columnCount)
{
if (rowCount < 1 || columnCount < 1)
{
return;
}
if (rowIndex + rowCount > RowCount || rowIndex < 0)
{
throw new ArgumentOutOfRangeException("rowIndex");
}
if (columnIndex + columnCount > ColumnCount || columnIndex < 0)
{
throw new ArgumentOutOfRangeException("columnIndex");
}
ClearUnchecked(rowIndex, rowCount, columnIndex, columnCount);
}
internal virtual void ClearUnchecked(int rowIndex, int rowCount, int columnIndex, int columnCount)
{
for (var i = rowIndex; i < rowIndex + rowCount; i++)
{
for (var j = columnIndex; j < columnIndex + columnCount; j++)
{
At(i, j, Zero);
}
}
}
public void ClearRows(int[] rowIndices)
{
if (rowIndices.Length == 0)
{
return;
}
for (int k = 0; k < rowIndices.Length; k++)
{
if (rowIndices[k] < 0 || rowIndices[k] >= RowCount)
{
throw new ArgumentOutOfRangeException("rowIndices");
}
}
ClearRowsUnchecked(rowIndices);
}
public void ClearColumns(int[] columnIndices)
{
if (columnIndices.Length == 0)
{
return;
}
for (int k = 0; k < columnIndices.Length; k++)
{
if (columnIndices[k] < 0 || columnIndices[k] >= ColumnCount)
{
throw new ArgumentOutOfRangeException("columnIndices");
}
}
ClearColumnsUnchecked(columnIndices);
}
internal virtual void ClearRowsUnchecked(int[] rowIndices)
{
for (var k = 0; k < rowIndices.Length; k++)
{
int row = rowIndices[k];
for (var j = 0; j < ColumnCount; j++)
{
At(row, j, Zero);
}
}
}
internal virtual void ClearColumnsUnchecked(int[] columnIndices)
{
for (var k = 0; k < columnIndices.Length; k++)
{
int column = columnIndices[k];
for (var i = 0; i < RowCount; i++)
{
At(i, column, Zero);
}
}
}
// MATRIX COPY // MATRIX COPY
public void CopyTo(MatrixStorage<T> target, ExistingData existingData = ExistingData.Clear) public void CopyTo(MatrixStorage<T> target, ExistingData existingData = ExistingData.Clear)

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

@ -287,12 +287,83 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
MapInplace(x => x, Zeros.AllowSkip); MapInplace(x => x, Zeros.AllowSkip);
} }
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">
/// An object to compare with this object.
/// </param>
/// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="other"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(MatrixStorage<T> other)
{
// Reject equality when the argument is null or has a different shape.
if (other == null || ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
return false;
}
// Accept if the argument is the same object as this.
if (ReferenceEquals(this, other))
{
return true;
}
var sparse = other as SparseCompressedRowMatrixStorage<T>;
if (sparse == null)
{
return base.Equals(other);
}
if (ValueCount != sparse.ValueCount)
{
// TODO: this is only correct if normalized
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < ValueCount; index++)
{
// TODO: AlmostEquals
if (!Values[index].Equals(sparse.Values[index]) || ColumnIndices[index] != sparse.ColumnIndices[index])
{
return false;
}
}
return true;
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
var values = Values;
var hashNum = Math.Min(ValueCount, 25);
int hash = 17;
unchecked
{
for (var i = 0; i < hashNum; i++)
{
hash = hash*31 + values[i].GetHashCode();
}
}
return hash;
}
// CLEARING
public override void Clear() public override void Clear()
{ {
Array.Clear(RowPointers, 0, RowPointers.Length); Array.Clear(RowPointers, 0, RowPointers.Length);
} }
public override void Clear(int rowIndex, int rowCount, int columnIndex, int columnCount) internal override void ClearUnchecked(int rowIndex, int rowCount, int columnIndex, int columnCount)
{ {
if (rowIndex == 0 && columnIndex == 0 && rowCount == RowCount && columnCount == ColumnCount) if (rowIndex == 0 && columnIndex == 0 && rowCount == RowCount && columnCount == ColumnCount)
{ {
@ -346,7 +417,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
} }
} }
public override void ClearRows(int[] rowIndices) internal override void ClearRowsUnchecked(int[] rowIndices)
{ {
var rows = new bool[RowCount]; var rows = new bool[RowCount];
for (int i = 0; i < rowIndices.Length; i++) for (int i = 0; i < rowIndices.Length; i++)
@ -356,7 +427,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
MapIndexedInplace((i, j, x) => rows[i] ? Zero : x, Zeros.AllowSkip); MapIndexedInplace((i, j, x) => rows[i] ? Zero : x, Zeros.AllowSkip);
} }
public override void ClearColumns(int[] columnIndices) internal override void ClearColumnsUnchecked(int[] columnIndices)
{ {
var columns = new bool[ColumnCount]; var columns = new bool[ColumnCount];
for (int i = 0; i < columnIndices.Length; i++) for (int i = 0; i < columnIndices.Length; i++)
@ -366,75 +437,6 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
MapIndexedInplace((i, j, x) => columns[j] ? Zero : x, Zeros.AllowSkip); MapIndexedInplace((i, j, x) => columns[j] ? Zero : x, Zeros.AllowSkip);
} }
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">
/// An object to compare with this object.
/// </param>
/// <returns>
/// <c>true</c> if the current object is equal to the <paramref name="other"/> parameter; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(MatrixStorage<T> other)
{
// Reject equality when the argument is null or has a different shape.
if (other == null || ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
return false;
}
// Accept if the argument is the same object as this.
if (ReferenceEquals(this, other))
{
return true;
}
var sparse = other as SparseCompressedRowMatrixStorage<T>;
if (sparse == null)
{
return base.Equals(other);
}
if (ValueCount != sparse.ValueCount)
{
// TODO: this is only correct if normalized
return false;
}
// If all else fails, perform element wise comparison.
for (var index = 0; index < ValueCount; index++)
{
// TODO: AlmostEquals
if (!Values[index].Equals(sparse.Values[index]) || ColumnIndices[index] != sparse.ColumnIndices[index])
{
return false;
}
}
return true;
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
var values = Values;
var hashNum = Math.Min(ValueCount, 25);
int hash = 17;
unchecked
{
for (var i = 0; i < hashNum; i++)
{
hash = hash*31 + values[i].GetHashCode();
}
}
return hash;
}
// INITIALIZATION // INITIALIZATION
public static SparseCompressedRowMatrixStorage<T> OfMatrix(MatrixStorage<T> matrix) public static SparseCompressedRowMatrixStorage<T> OfMatrix(MatrixStorage<T> matrix)
@ -959,7 +961,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
if (existingData == ExistingData.Clear) if (existingData == ExistingData.Clear)
{ {
target.Clear(targetRowIndex, rowCount, targetColumnIndex, columnCount); target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount);
} }
for (int i = sourceRowIndex, row = 0; i < sourceRowIndex + rowCount; i++, row++) for (int i = sourceRowIndex, row = 0; i < sourceRowIndex + rowCount; i++, row++)
@ -1029,7 +1031,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
if (existingData == ExistingData.Clear) if (existingData == ExistingData.Clear)
{ {
target.Clear(targetRowIndex, rowCount, targetColumnIndex, columnCount); target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount);
} }
// NOTE: potential for more efficient implementation // NOTE: potential for more efficient implementation
@ -1642,7 +1644,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
var processZeros = zeros == Zeros.Include || !Zero.Equals(f(0, 1, Zero)); var processZeros = zeros == Zeros.Include || !Zero.Equals(f(0, 1, Zero));
if (existingData == ExistingData.Clear && !processZeros) if (existingData == ExistingData.Clear && !processZeros)
{ {
target.Clear(targetRowIndex, rowCount, targetColumnIndex, columnCount); target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount);
} }
if (processZeros) if (processZeros)
@ -1699,7 +1701,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
var processZeros = zeros == Zeros.Include || !Zero.Equals(f(0, 1, Zero)); var processZeros = zeros == Zeros.Include || !Zero.Equals(f(0, 1, Zero));
if (existingData == ExistingData.Clear && !processZeros) if (existingData == ExistingData.Clear && !processZeros)
{ {
target.Clear(targetRowIndex, rowCount, targetColumnIndex, columnCount); target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount);
} }
var rowOffset = targetRowIndex - sourceRowIndex; var rowOffset = targetRowIndex - sourceRowIndex;

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

@ -472,7 +472,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
{ {
if (existingData == ExistingData.Clear) if (existingData == ExistingData.Clear)
{ {
target.Clear(rowIndex, 1, 0, Length); target.ClearUnchecked(rowIndex, 1, 0, Length);
} }
if (ValueCount == 0) if (ValueCount == 0)
@ -492,7 +492,7 @@ namespace MathNet.Numerics.LinearAlgebra.Storage
{ {
if (existingData == ExistingData.Clear) if (existingData == ExistingData.Clear)
{ {
target.Clear(0, Length, columnIndex, 1); target.ClearUnchecked(0, Length, columnIndex, 1);
} }
if (ValueCount == 0) if (ValueCount == 0)

Loading…
Cancel
Save