From d53c1cda0dfdc664a88df315d1b1c87fe9d161e9 Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Wed, 28 Aug 2013 00:54:27 +0200 Subject: [PATCH] LA: Clean up and extend matrix enumeration --- .../LinearAlgebra/MatrixDataAccessor.cs | 4 +- src/Examples/LinearAlgebra/MatrixNorms.cs | 8 +- src/FSharp/LinearAlgebra.Double.Matrix.fs | 14 -- src/FSharp/LinearAlgebra.Matrix.fs | 11 ++ .../LinearAlgebra/Complex/SparseMatrix.cs | 38 ---- .../LinearAlgebra/Complex32/SparseMatrix.cs | 38 ---- .../LinearAlgebra/Double/SparseMatrix.cs | 38 ---- src/Numerics/LinearAlgebra/Matrix.cs | 166 +++++++++++------- .../LinearAlgebra/Single/SparseMatrix.cs | 38 ---- .../Storage/DenseColumnMajorMatrixStorage.cs | 38 ++++ .../Storage/DiagonalMatrixStorage.cs | 39 ++++ .../LinearAlgebra/Storage/MatrixStorage.cs | 40 +++++ .../SparseCompressedRowMatrixStorage.cs | 46 +++++ src/Numerics/LinearAlgebra/Vector.cs | 4 +- .../MatrixStructureTheory.cs | 20 +-- 15 files changed, 294 insertions(+), 248 deletions(-) diff --git a/src/Examples/LinearAlgebra/MatrixDataAccessor.cs b/src/Examples/LinearAlgebra/MatrixDataAccessor.cs index f4bf55f4..b43a22ba 100644 --- a/src/Examples/LinearAlgebra/MatrixDataAccessor.cs +++ b/src/Examples/LinearAlgebra/MatrixDataAccessor.cs @@ -137,7 +137,7 @@ namespace Examples.LinearAlgebraExamples // 9. Get columns using column enumerator. If you need all columns you may use ColumnEnumerator without parameters Console.WriteLine(@"9. Get columns using column enumerator"); - foreach (var keyValuePair in matrix.ColumnEnumerator(2, 4)) + foreach (var keyValuePair in matrix.EnumerateColumnsIndexed(2, 4)) { Console.WriteLine(@"Column {0}: {1}", keyValuePair.Item1, keyValuePair.Item2.ToString("#0.00\t", formatProvider)); } @@ -146,7 +146,7 @@ namespace Examples.LinearAlgebraExamples // 10. Get rows using row enumerator. If you need all rows you may use RowEnumerator without parameters Console.WriteLine(@"10. Get rows using row enumerator"); - foreach (var keyValuePair in matrix.RowEnumerator(4, 3)) + foreach (var keyValuePair in matrix.EnumerateRowsIndexed(4, 3)) { Console.WriteLine(@"Row {0}: {1}", keyValuePair.Item1, keyValuePair.Item2.ToString("#0.00\t", formatProvider)); } diff --git a/src/Examples/LinearAlgebra/MatrixNorms.cs b/src/Examples/LinearAlgebra/MatrixNorms.cs index 54a837e1..03f744bc 100644 --- a/src/Examples/LinearAlgebra/MatrixNorms.cs +++ b/src/Examples/LinearAlgebra/MatrixNorms.cs @@ -95,7 +95,7 @@ namespace Examples.LinearAlgebraExamples // 5. Normalize matrix columns Console.WriteLine(@"5. Normalize matrix columns: before normalize"); - foreach (var keyValuePair in matrix.ColumnEnumerator()) + foreach (var keyValuePair in matrix.EnumerateColumnsIndexed()) { Console.WriteLine(@"Column {0} 2-nd norm is: {1}", keyValuePair.Item1, keyValuePair.Item2.L2Norm()); } @@ -103,7 +103,7 @@ namespace Examples.LinearAlgebraExamples Console.WriteLine(); var normalized = matrix.NormalizeColumns(2); Console.WriteLine(@"5. Normalize matrix columns: after normalize"); - foreach (var keyValuePair in normalized.ColumnEnumerator()) + foreach (var keyValuePair in normalized.EnumerateColumnsIndexed()) { Console.WriteLine(@"Column {0} 2-nd norm is: {1}", keyValuePair.Item1, keyValuePair.Item2.L2Norm()); } @@ -112,7 +112,7 @@ namespace Examples.LinearAlgebraExamples // 6. Normalize matrix columns Console.WriteLine(@"6. Normalize matrix rows: before normalize"); - foreach (var keyValuePair in matrix.RowEnumerator()) + foreach (var keyValuePair in matrix.EnumerateRowsIndexed()) { Console.WriteLine(@"Row {0} 2-nd norm is: {1}", keyValuePair.Item1, keyValuePair.Item2.L2Norm()); } @@ -120,7 +120,7 @@ namespace Examples.LinearAlgebraExamples Console.WriteLine(); normalized = matrix.NormalizeRows(2); Console.WriteLine(@"6. Normalize matrix rows: after normalize"); - foreach (var keyValuePair in normalized.RowEnumerator()) + foreach (var keyValuePair in normalized.EnumerateRowsIndexed()) { Console.WriteLine(@"Row {0} 2-nd norm is: {1}", keyValuePair.Item1, keyValuePair.Item2.L2Norm()); } diff --git a/src/FSharp/LinearAlgebra.Double.Matrix.fs b/src/FSharp/LinearAlgebra.Double.Matrix.fs index ee4fdd9a..966e0bf2 100644 --- a/src/FSharp/LinearAlgebra.Double.Matrix.fs +++ b/src/FSharp/LinearAlgebra.Double.Matrix.fs @@ -36,12 +36,6 @@ open MathNet.Numerics.LinearAlgebra [] module Matrix = - /// Creates a sequence that iterates the non-zero entries in the matrix. - let inline nonZeroEntries (A: #Matrix<_>) = - seq { for i in 0 .. A.RowCount-1 do - for j in 0 .. A.ColumnCount-1 do - if A.At(i,j) <> 0.0 then yield (i, j, A.At(i,j)) } - /// Returns the sum of all elements of a matrix. let inline sum (A: #Matrix<_>) = let mutable f = 0.0 @@ -50,14 +44,6 @@ module Matrix = f <- f + A.At(i,j) f - /// Returns the sum of the results generated by applying a position dependent function to each column of the matrix. - let inline sumColsBy (f: int -> Vector -> 'a) (A: #Matrix<_>) = - A.ColumnEnumerator() |> Seq.map (fun (j,col) -> f j col) |> Seq.reduce (+) - - /// Returns the sum of the results generated by applying a position dependent function to each row of the matrix. - let inline sumRowsBy (f: int -> Vector -> 'a) (A: #Matrix<_>) = - A.RowEnumerator() |> Seq.map (fun (i,row) -> f i row) |> Seq.reduce (+) - /// Fold all columns into one row vector. let inline foldByCol (f: float -> float -> float) acc (A: #Matrix) = let v = new DenseVector(A.ColumnCount) diff --git a/src/FSharp/LinearAlgebra.Matrix.fs b/src/FSharp/LinearAlgebra.Matrix.fs index d2846fd5..1639c0dd 100644 --- a/src/FSharp/LinearAlgebra.Matrix.fs +++ b/src/FSharp/LinearAlgebra.Matrix.fs @@ -266,3 +266,14 @@ module Matrix = for i=0 to A.ColumnCount-1 do macc <- f macc (A.Item(k,i)) macc + + /// Returns the sum of the results generated by applying a position dependent function to each column of the matrix. + let inline sumColsBy f (A: #Matrix<_>) = + A.EnumerateColumnsIndexed() |> Seq.map (fun (j,col) -> f j col) |> Seq.reduce (+) + + /// Returns the sum of the results generated by applying a position dependent function to each row of the matrix. + let inline sumRowsBy f (A: #Matrix<_>) = + A.EnumerateRowsIndexed() |> Seq.map (fun (i,row) -> f i row) |> Seq.reduce (+) + + /// Creates a sequence that iterates the non-zero entries in the matrix. + let nonZeroEntries (A: #Matrix<_>) = A.EnumerateNonZero() diff --git a/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs index f96df054..a2c2eab3 100644 --- a/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs @@ -1070,44 +1070,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex } } - /// - /// Iterates throw each element in the matrix (row-wise). - /// - /// The value at the current iteration along with its position (row, column, value). - public override IEnumerable> IndexedEnumerator() - { - var rowPointers = _storage.RowPointers; - var columnIndices = _storage.ColumnIndices; - var values = _storage.Values; - var valueCount = _storage.ValueCount; - - for (var row = 0; row < RowCount - 1; row++) - { - var start = rowPointers[row]; - var end = rowPointers[row + 1]; - - if (start == end) - { - continue; - } - - for (var index = start; index < end; index++) - { - yield return new Tuple(row, columnIndices[index], values[index]); - } - } - - var lastRow = rowPointers.Length - 1; - - if (rowPointers[lastRow] < valueCount) - { - for (var index = rowPointers[lastRow]; index < valueCount; index++) - { - yield return new Tuple(lastRow, columnIndices[index], values[index]); - } - } - } - /// /// Gets a value indicating whether this matrix is symmetric. /// diff --git a/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs index 5e7d0e86..836a780a 100644 --- a/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs @@ -1064,44 +1064,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 } } - /// - /// Iterates throw each element in the matrix (row-wise). - /// - /// The value at the current iteration along with its position (row, column, value). - public override IEnumerable> IndexedEnumerator() - { - var rowPointers = _storage.RowPointers; - var columnIndices = _storage.ColumnIndices; - var values = _storage.Values; - var valueCount = _storage.ValueCount; - - for (var row = 0; row < RowCount - 1; row++) - { - var start = rowPointers[row]; - var end = rowPointers[row + 1]; - - if (start == end) - { - continue; - } - - for (var index = start; index < end; index++) - { - yield return new Tuple(row, columnIndices[index], values[index]); - } - } - - var lastRow = rowPointers.Length - 1; - - if (rowPointers[lastRow] < valueCount) - { - for (var index = rowPointers[lastRow]; index < valueCount; index++) - { - yield return new Tuple(lastRow, columnIndices[index], values[index]); - } - } - } - /// /// Gets a value indicating whether this matrix is symmetric. /// diff --git a/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs index 12ea8bb2..4de87a06 100644 --- a/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs @@ -1088,44 +1088,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double } } - /// - /// Iterates throw each element in the matrix (row-wise). - /// - /// The value at the current iteration along with its position (row, column, value). - public override IEnumerable> IndexedEnumerator() - { - var rowPointers = _storage.RowPointers; - var columnIndices = _storage.ColumnIndices; - var values = _storage.Values; - var valueCount = _storage.ValueCount; - - for (var row = 0; row < RowCount - 1; row++) - { - var start = rowPointers[row]; - var end = rowPointers[row + 1]; - - if (start == end) - { - continue; - } - - for (var index = start; index < end; index++) - { - yield return new Tuple(row, columnIndices[index], values[index]); - } - } - - var lastRow = rowPointers.Length - 1; - - if (rowPointers[lastRow] < valueCount) - { - for (var index = rowPointers[lastRow]; index < valueCount; index++) - { - yield return new Tuple(lastRow, columnIndices[index], values[index]); - } - } - } - /// /// Gets a value indicating whether this matrix is symmetric. /// diff --git a/src/Numerics/LinearAlgebra/Matrix.cs b/src/Numerics/LinearAlgebra/Matrix.cs index f6d75965..a41d661e 100644 --- a/src/Numerics/LinearAlgebra/Matrix.cs +++ b/src/Numerics/LinearAlgebra/Matrix.cs @@ -1254,97 +1254,134 @@ namespace MathNet.Numerics.LinearAlgebra } /// - /// Returns an that enumerates over the matrix columns. + /// Returns an IEnumerable that can be used to iterate through all values of the matrix. /// - /// An that enumerates over the matrix columns - /// - public virtual IEnumerable>> ColumnEnumerator() + /// + /// The enumerator will include all values, even if they are zero. + /// The ordering of the values is unspecified (not necessarily column by column or row by row). + /// + public IEnumerable Enumerate() + { + return Storage.Enumerate(); + } + + /// + /// Returns an IEnumerable that can be used to iterate through all values of the matrix and their index. + /// + /// + /// The enumerator returns a Tuple with the first two values being the row and column index + /// and the third value being the value of the element at that index. + /// The enumerator will include all values, even if they are zero. + /// + public IEnumerable> EnumerateIndexed() + { + return Storage.EnumerateIndexed(); + } + + /// + /// Returns an IEnumerable that can be used to iterate through all non-zero values of the matrix and their index. + /// + /// + /// The enumerator returns a Tuple with the first two values being the row and column index + /// and the third value being the value of the element at that index. + /// The enumerator will skip all elements with a zero value. + /// + public IEnumerable> EnumerateNonZero() + { + return Storage.EnumerateNonZero(); + } + + /// + /// Returns an IEnumerable that can be used to iterate through all columns of the matrix. + /// + public IEnumerable> EnumerateColumns() { for (var i = 0; i < ColumnCount; i++) { - yield return new Tuple>(i, Column(i)); + yield return Column(i); } } /// - /// Returns an that enumerates the requested matrix columns. + /// Returns an IEnumerable that can be used to iterate through a subset of all columns of the matrix. /// /// The column to start enumerating over. /// The number of columns to enumerating over. - /// An that enumerates over requested matrix columns. - /// - /// If: - /// is negative, - /// or greater than or equal to the number of columns. - /// (index + length) >= Columns. - /// - /// If is not positive. - public virtual IEnumerable>> ColumnEnumerator(int index, int length) + public IEnumerable> EnumerateColumns(int index, int length) { - if (index >= ColumnCount || index < 0) + var maxIndex = Math.Min(index + length, ColumnCount); + for (var i = Math.Max(index, 0); i < maxIndex; i++) { - throw new ArgumentOutOfRangeException("index"); + yield return Column(i); } + } - if (index + length > ColumnCount) + /// + /// Returns an IEnumerable that can be used to iterate through all columns of the matrix and their index. + /// + /// + /// The enumerator returns a Tuple with the first value being the column index + /// and the second value being the value of the column at that index. + /// + public IEnumerable>> EnumerateColumnsIndexed() + { + for (var i = 0; i < ColumnCount; i++) { - throw new ArgumentOutOfRangeException("length"); + yield return new Tuple>(i, Column(i)); } + } - if (length < 1) + /// + /// Returns an IEnumerable that can be used to iterate through a subset of all columns of the matrix and their index. + /// + /// The column to start enumerating over. + /// The number of columns to enumerating over. + /// + /// The enumerator returns a Tuple with the first value being the column index + /// and the second value being the value of the column at that index. + /// + public IEnumerable>> EnumerateColumnsIndexed(int index, int length) + { + var maxIndex = Math.Min(index + length, ColumnCount); + for (var i = Math.Max(index, 0); i < maxIndex; i++) { - throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); + yield return new Tuple>(i, Column(i)); } + } - var maxIndex = index + length; - for (var i = index; i < maxIndex; i++) + /// + /// Returns an IEnumerable that can be used to iterate through all rows of the matrix. + /// + public IEnumerable> EnumerateRows() + { + for (var i = 0; i < RowCount; i++) { - yield return new Tuple>(i, Column(i)); + yield return Row(i); } } /// - /// Returns an that enumerates the requested matrix rows. + /// Returns an IEnumerable that can be used to iterate through a subset of all rows of the matrix. /// /// The row to start enumerating over. /// The number of rows to enumerating over. - /// An that enumerates over requested matrix rows. - /// - /// If: - /// is negative, - /// or greater than or equal to the number of rows. - /// (index + length) >= Rows. - /// If is not positive. - public virtual IEnumerable>> RowEnumerator(int index, int length) + public IEnumerable> EnumerateRows(int index, int length) { - if (index >= RowCount || index < 0) - { - throw new ArgumentOutOfRangeException("index"); - } - - if (index + length > RowCount) + var maxIndex = Math.Min(index + length, RowCount); + for (var i = Math.Max(index, 0); i < maxIndex; i++) { - throw new ArgumentOutOfRangeException("length"); - } - - if (length < 1) - { - throw new ArgumentException(Resources.ArgumentMustBePositive, "length"); - } - - var maxi = index + length; - for (var i = index; i < maxi; i++) - { - yield return new Tuple>(i, Row(i)); + yield return Row(i); } } /// - /// Returns an that enumerates over the matrix rows. + /// Returns an IEnumerable that can be used to iterate through all rows of the matrix and their index. /// - /// An that enumerates over the matrix rows - /// - public virtual IEnumerable>> RowEnumerator() + /// + /// The enumerator returns a Tuple with the first value being the row index + /// and the second value being the value of the row at that index. + /// + public IEnumerable>> EnumerateRowsIndexed() { for (var i = 0; i < RowCount; i++) { @@ -1353,17 +1390,20 @@ namespace MathNet.Numerics.LinearAlgebra } /// - /// Iterates through each element in the matrix (row-wise). + /// Returns an IEnumerable that can be used to iterate through a subset of all rows of the matrix and their index. /// - /// The value at the current iteration along with its position (row, column, value). - public virtual IEnumerable> IndexedEnumerator() + /// The row to start enumerating over. + /// The number of rows to enumerating over. + /// + /// The enumerator returns a Tuple with the first value being the row index + /// and the second value being the value of the row at that index. + /// + public IEnumerable>> EnumerateRowsIndexed(int index, int length) { - for (var row = 0; row < RowCount; row++) + var maxIndex = Math.Min(index + length, RowCount); + for (var i = Math.Max(index, 0); i < maxIndex; i++) { - for (var column = 0; column < ColumnCount; column++) - { - yield return new Tuple(row, column, At(row, column)); - } + yield return new Tuple>(i, Row(i)); } } diff --git a/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs index c4213988..7c1546e1 100644 --- a/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs @@ -1087,44 +1087,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single } } - /// - /// Iterates throw each element in the matrix (row-wise). - /// - /// The value at the current iteration along with its position (row, column, value). - public override IEnumerable> IndexedEnumerator() - { - var rowPointers = _storage.RowPointers; - var columnIndices = _storage.ColumnIndices; - var values = _storage.Values; - var valueCount = _storage.ValueCount; - - for (var row = 0; row < RowCount - 1; row++) - { - var start = rowPointers[row]; - var end = rowPointers[row + 1]; - - if (start == end) - { - continue; - } - - for (var index = start; index < end; index++) - { - yield return new Tuple(row, columnIndices[index], values[index]); - } - } - - var lastRow = rowPointers.Length - 1; - - if (rowPointers[lastRow] < valueCount) - { - for (var index = rowPointers[lastRow]; index < valueCount; index++) - { - yield return new Tuple(lastRow, columnIndices[index], values[index]); - } - } - } - /// /// Gets a value indicating whether this matrix is symmetric. /// diff --git a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs index 4a1b1b01..fd819131 100644 --- a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs @@ -30,6 +30,7 @@ using System; using System.Collections.Generic; +using System.Linq; using MathNet.Numerics.Properties; using MathNet.Numerics.Threading; @@ -276,6 +277,43 @@ namespace MathNet.Numerics.LinearAlgebra.Storage return new DenseColumnMajorMatrixStorage(rows, columns, array); } + // ENUMERATION + + public override IEnumerable Enumerate() + { + return Data; + } + + public override IEnumerable> EnumerateIndexed() + { + int index = 0; + for (int j = 0; j < ColumnCount; j++) + { + for (int i = 0; i < RowCount; i++) + { + yield return new Tuple(i, j, Data[index]); + index++; + } + } + } + + public override IEnumerable> EnumerateNonZero() + { + int index = 0; + for (int j = 0; j < ColumnCount; j++) + { + for (int i = 0; i < RowCount; i++) + { + var x = Data[index]; + if (!Zero.Equals(x)) + { + yield return new Tuple(i, j, x); + } + index++; + } + } + } + // MATRIX COPY internal override void CopyToUnchecked(MatrixStorage target, bool skipClearing = false) diff --git a/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs index 7abdae67..2648aec0 100644 --- a/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs @@ -244,6 +244,45 @@ namespace MathNet.Numerics.LinearAlgebra.Storage return storage; } + // ENUMERATION + + public override IEnumerable Enumerate() + { + for (int j = 0; j < ColumnCount; j++) + { + for (int i = 0; i < RowCount; i++) + { + // PERF: consider to break up loop to avoid branching + yield return i == j ? Data[i] : Zero; + } + } + } + + public override IEnumerable> EnumerateIndexed() + { + for (int j = 0; j < ColumnCount; j++) + { + for (int i = 0; i < RowCount; i++) + { + // PERF: consider to break up loop to avoid branching + yield return i == j + ? new Tuple(i, i, Data[i]) + : new Tuple(i, j, Zero); + } + } + } + + public override IEnumerable> EnumerateNonZero() + { + for (int i = 0; i < Data.Length; i++) + { + if (!Zero.Equals(Data[i])) + { + yield return new Tuple(i, i, Data[i]); + } + } + } + // MATRIX COPY internal override void CopyToUnchecked(MatrixStorage target, bool skipClearing = false) diff --git a/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs index ec01602e..5efc1888 100644 --- a/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs @@ -29,6 +29,7 @@ // using System; +using System.Collections.Generic; using MathNet.Numerics.Properties; namespace MathNet.Numerics.LinearAlgebra.Storage @@ -226,6 +227,45 @@ namespace MathNet.Numerics.LinearAlgebra.Storage return hash; } + // ENUMERATION + + public virtual IEnumerable Enumerate() + { + for (int i = 0; i < RowCount; i++) + { + for (int j = 0; j < ColumnCount; j++) + { + yield return At(i, j); + } + } + } + + public virtual IEnumerable> EnumerateIndexed() + { + for (int i = 0; i < RowCount; i++) + { + for (int j = 0; j < ColumnCount; j++) + { + yield return new Tuple(i, j, At(i, j)); + } + } + } + + public virtual IEnumerable> EnumerateNonZero() + { + for (int i = 0; i < RowCount; i++) + { + for (int j = 0; j < ColumnCount; j++) + { + var x = At(i, j); + if (!Zero.Equals(x)) + { + yield return new Tuple(i, j, x); + } + } + } + } + // MATRIX COPY public void CopyTo(MatrixStorage target, bool skipClearing = false) diff --git a/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs index 8797bdb4..24486539 100644 --- a/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs @@ -638,6 +638,52 @@ namespace MathNet.Numerics.LinearAlgebra.Storage return storage; } + // ENUMERATION + + public override IEnumerable Enumerate() + { + int k = 0; + for (int row = 0; row < RowCount; row++) + { + for (int col = 0; col < ColumnCount; col++) + { + yield return k < (row < RowPointers.Length - 1 ? RowPointers[row + 1] : ValueCount) && (ColumnIndices[k]) == col + ? Values[k++] + : Zero; + } + } + } + + public override IEnumerable> EnumerateIndexed() + { + int k = 0; + for (int row = 0; row < RowCount; row++) + { + for (int col = 0; col < ColumnCount; col++) + { + yield return k < (row < RowPointers.Length - 1 ? RowPointers[row + 1] : ValueCount) && (ColumnIndices[k]) == col + ? new Tuple(row, col, Values[k++]) + : new Tuple(row, col, Zero); + } + } + } + + public override IEnumerable> EnumerateNonZero() + { + for (int row = 0; row < RowCount; row++) + { + var startIndex = RowPointers[row]; + var endIndex = row < RowPointers.Length - 1 ? RowPointers[row + 1] : ValueCount; + for (var j = startIndex; j < endIndex; j++) + { + if (!Zero.Equals(Values[j])) + { + yield return new Tuple(row, ColumnIndices[j], Values[j]); + } + } + } + } + // MATRIX COPY internal override void CopyToUnchecked(MatrixStorage target, bool skipClearing = false) diff --git a/src/Numerics/LinearAlgebra/Vector.cs b/src/Numerics/LinearAlgebra/Vector.cs index 258b2e13..4c607fc2 100644 --- a/src/Numerics/LinearAlgebra/Vector.cs +++ b/src/Numerics/LinearAlgebra/Vector.cs @@ -303,7 +303,7 @@ namespace MathNet.Numerics.LinearAlgebra /// Returns an IEnumerable that can be used to iterate through all values of the vector and their index. /// /// - /// The enumerator returns a with the first value being the element index + /// The enumerator returns a Tuple with the first value being the element index /// and the second value being the value of the element at that index. /// The enumerator will include all values, even if they are zero. /// @@ -316,7 +316,7 @@ namespace MathNet.Numerics.LinearAlgebra /// Returns an IEnumerable that can be used to iterate through all non-zero values of the vector and their index. /// /// - /// The enumerator returns a with the first value being the element index + /// The enumerator returns a Tuple with the first value being the element index /// and the second value being the value of the element at that index. /// The enumerator will skip all elements with a zero value. /// diff --git a/src/UnitTests/LinearAlgebraTests/MatrixStructureTheory.cs b/src/UnitTests/LinearAlgebraTests/MatrixStructureTheory.cs index 2dc611c3..5592ef8d 100644 --- a/src/UnitTests/LinearAlgebraTests/MatrixStructureTheory.cs +++ b/src/UnitTests/LinearAlgebraTests/MatrixStructureTheory.cs @@ -365,17 +365,15 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests public void CanEnumerateWithIndex() { var dense = CreateDenseRandom(2, 3, 0); - using (var enumerator = dense.IndexedEnumerator().GetEnumerator()) - for (int i = 0; i < 2; i++) - { - for (int j = 0; j < 3; j++) - { - enumerator.MoveNext(); - Assert.AreEqual(i, enumerator.Current.Item1); - Assert.AreEqual(j, enumerator.Current.Item2); - Assert.AreEqual(dense[i, j], enumerator.Current.Item3); - } - } + int rowIdxSum = 0, colIdxSum = 0; + foreach (var value in dense.EnumerateIndexed()) + { + rowIdxSum += value.Item1; + colIdxSum += value.Item2; + Assert.AreEqual(dense[value.Item1, value.Item2], value.Item3); + } + Assert.AreEqual(dense.RowCount*(dense.RowCount - 1)/2*dense.ColumnCount, rowIdxSum); + Assert.AreEqual(dense.ColumnCount*(dense.ColumnCount - 1)/2*dense.RowCount, colIdxSum); } } }