diff --git a/CSparse/Converter.cs b/CSparse/Converter.cs
index 131cb91..dec3661 100644
--- a/CSparse/Converter.cs
+++ b/CSparse/Converter.cs
@@ -289,5 +289,25 @@ public static CoordinateStorage FromEnumerable(IEnumerable
+ /// Convert a row major array to coordinate storage.
+ ///
+ /// Enumerates the entries of a matrix with value tuples.
+ /// Number of rows.
+ /// Number of columns.
+ /// Coordinate storage.
+ public static CoordinateStorage FromEnumerable(IEnumerable<(int row, int column, T value)> enumerable, int rowCount, int columnCount)
+ where T : struct, IEquatable, IFormattable
+ {
+ var storage = new CoordinateStorage(rowCount, columnCount, Math.Max(rowCount, columnCount));
+
+ foreach (var item in enumerable)
+ {
+ storage.At(item.row, item.column, item.value);
+ }
+
+ return storage;
+ }
}
}
diff --git a/CSparse/Matrix.cs b/CSparse/Matrix.cs
index 907254e..aafcda9 100644
--- a/CSparse/Matrix.cs
+++ b/CSparse/Matrix.cs
@@ -132,9 +132,18 @@ protected Matrix(int rowCount, int columnCount)
///
/// Enumerates all values of the matrix.
///
+ ///
+ /// for a version that returns stack-allocated value tuples to save transient heap allocations (saves performance overhead of allocations + garbage collection) of the class.
+ ///
/// Enumeration of tuples (i, j, a[i, j]).
public abstract IEnumerable> EnumerateIndexed();
+ ///
+ /// Enumerates all values of the matrix, but returns as stack-allocated value tuples instead of heap-allocated tuples.
+ ///
+ /// Enumeration of tuples (i, j, a[i, j]).
+ public abstract IEnumerable<(int row, int column, T value)> EnumerateIndexedAsValueTuples();
+
///
/// Enumerates all values of the matrix.
///
diff --git a/CSparse/Storage/CompressedColumnStorage.cs b/CSparse/Storage/CompressedColumnStorage.cs
index e6a1b70..2329119 100644
--- a/CSparse/Storage/CompressedColumnStorage.cs
+++ b/CSparse/Storage/CompressedColumnStorage.cs
@@ -110,7 +110,7 @@ public CompressedColumnStorage(int rowCount, int columnCount, T[] values, int[]
///
public static CompressedColumnStorage OfMatrix(Matrix matrix)
{
- var c = Converter.FromEnumerable(matrix.EnumerateIndexed(), matrix.RowCount, matrix.ColumnCount);
+ var c = Converter.FromEnumerable(matrix.EnumerateIndexedAsValueTuples(), matrix.RowCount, matrix.ColumnCount);
return Converter.ToCompressedColumnStorage(c);
}
@@ -146,6 +146,9 @@ public static CompressedColumnStorage OfIndexed(CoordinateStorage coordina
///
/// Create a new sparse matrix as a copy of the given indexed enumerable.
///
+ /// The number of rows.
+ /// The number of columns.
+ /// Tuples with the three elements of row, column, and the value that belongs at that position.
public static CompressedColumnStorage OfIndexed(int rows, int columns, IEnumerable> enumerable)
{
var c = Converter.FromEnumerable(enumerable, rows, columns);
@@ -153,6 +156,19 @@ public static CompressedColumnStorage OfIndexed(int rows, int columns, IEnume
return Converter.ToCompressedColumnStorage(c);
}
+ ///
+ /// Create a new sparse matrix as a copy of the given indexed enumerable using a value tuple.
+ ///
+ /// The number of rows.
+ /// The number of columns.
+ /// Value tuples with the three elements of row, column, and the value that belongs at that position.
+ public static CompressedColumnStorage OfIndexed(int rows, int columns, IEnumerable<(int row, int column, T value)> enumerable)
+ {
+ var c = Converter.FromEnumerable(enumerable, rows, columns);
+
+ return Converter.ToCompressedColumnStorage(c);
+ }
+
///
/// Create a new sparse matrix as a copy of the given array (row-major).
///
@@ -564,6 +580,15 @@ public CompressedColumnStorage Clone(bool values = true)
///
public override IEnumerable> EnumerateIndexed()
+ {
+ foreach (var valueTuple in EnumerateIndexedAsValueTuples())
+ {
+ yield return Tuple.Create(valueTuple.row, valueTuple.column, valueTuple.value);
+ }
+ }
+
+ ///
+ public override IEnumerable<(int row, int column, T value)> EnumerateIndexedAsValueTuples()
{
var ax = Values;
var ap = ColumnPointers;
@@ -574,7 +599,7 @@ public override IEnumerable> EnumerateIndexed()
var end = ap[i + 1];
for (var j = ap[i]; j < end; j++)
{
- yield return new Tuple(ai[j], i, ax[j]);
+ yield return (ai[j], i, ax[j]);
}
}
}
diff --git a/CSparse/Storage/DenseColumnMajorStorage.cs b/CSparse/Storage/DenseColumnMajorStorage.cs
index 053a6da..ae7c653 100644
--- a/CSparse/Storage/DenseColumnMajorStorage.cs
+++ b/CSparse/Storage/DenseColumnMajorStorage.cs
@@ -165,8 +165,8 @@ public static DenseColumnMajorStorage OfDiagonalArray(T[] diagonal)
{
int order = diagonal.Length;
- var A = Create(order, order);
-
+ var A = Create(order, order);
+
for (int i = 0; i < order; i++)
{
A.At(i, i, diagonal[i]);
@@ -547,12 +547,21 @@ public override void Clear()
///
public override IEnumerable> EnumerateIndexed()
+ {
+ foreach (var valueTuple in EnumerateIndexedAsValueTuples())
+ {
+ yield return Tuple.Create(valueTuple.row, valueTuple.column, valueTuple.value);
+ }
+ }
+
+ ///
+ public override IEnumerable<(int row, int column, T value)> EnumerateIndexedAsValueTuples()
{
for (int row = 0; row < rows; row++)
{
for (int column = 0; column < columns; column++)
{
- yield return new Tuple(row, column, Values[(column * rows) + row]);
+ yield return (row, column, Values[(column * rows) + row]);
}
}
}