diff --git a/CHANGELOG.md b/CHANGELOG.md index 045a391..bc3bab2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### Version 4.4.0 - 2026-06-10 + +* Add Refactorize methods to SparseCholesky, SparseLDL and SparseLU + ### Version 4.3.0 - 2025-11-11 * Add net10.0 and remove net6.0 target framework. diff --git a/CSparse.Tests/CSparse.Tests.csproj b/CSparse.Tests/CSparse.Tests.csproj index a795c2b..e4cb7b0 100644 --- a/CSparse.Tests/CSparse.Tests.csproj +++ b/CSparse.Tests/CSparse.Tests.csproj @@ -41,9 +41,9 @@ - - - + + + diff --git a/CSparse.Tests/Complex/ComplexNumberComparer.cs b/CSparse.Tests/Complex/ComplexNumberComparer.cs index 0a98cdd..ab2adce 100644 --- a/CSparse.Tests/Complex/ComplexNumberComparer.cs +++ b/CSparse.Tests/Complex/ComplexNumberComparer.cs @@ -11,7 +11,7 @@ namespace CSparse.Tests.Complex public class ComplexNumberComparer : IComparer, IComparer { - public static ComplexNumberComparer Default = new ComplexNumberComparer(); + public static ComplexNumberComparer Default = new(); // Floating point tolerance const double TOL = 1e-8; diff --git a/CSparse.Tests/Complex/MatrixHelper.cs b/CSparse.Tests/Complex/MatrixHelper.cs index db1081d..b5dfdc6 100644 --- a/CSparse.Tests/Complex/MatrixHelper.cs +++ b/CSparse.Tests/Complex/MatrixHelper.cs @@ -4,22 +4,18 @@ namespace CSparse.Tests.Complex using CSparse.Storage; using System.Collections.Generic; using System.IO; - using System.Linq; using System.Numerics; class MatrixHelper { - private static Dictionary> dense = new Dictionary>(); - - private static Dictionary> sparse = new Dictionary>(); + private static readonly Dictionary> dense = []; + private static readonly Dictionary> sparse = []; public static SparseTestData LoadSparse(int rows, int columns) { string resource = string.Format("test-data-dense-{0}x{1}.txt", rows, columns); - SparseTestData data; - - if (!sparse.TryGetValue(resource, out data)) + if (!sparse.TryGetValue(resource, out SparseTestData data)) { var dense = LoadDense(rows, columns); @@ -35,9 +31,7 @@ public static DenseTestData LoadDense(int rows, int columns) { string resource = string.Format("test-data-dense-{0}x{1}.txt", rows, columns); - DenseTestData data; - - if (!dense.TryGetValue(resource, out data)) + if (!dense.TryGetValue(resource, out DenseTestData data)) { var stream = ResourceLoader.GetStream(resource, "Double"); @@ -53,22 +47,21 @@ private static DenseTestData ReadDenseTestData(Stream stream) { var data = Tests.Double.DenseTestDataReader.Read(stream); - var result = new DenseTestData(); - - result.A = ToComplex(data.A); - result.B = ToComplex(data.B); - result.x = ToComplex(data.x); - result.y = ToComplex(data.y); - result.AT = ToComplex(data.AT); - result.BT = ToComplex(data.BT); - result.ApB = ToComplex(data.ApB); - result.AmBT = ToComplex(data.AmBT); - result.ATmB = ToComplex(data.ATmB); - result.Ax = ToComplex(data.Ax); - result.ATy = ToComplex(data.ATy); - result.xTBT = ToComplex(data.xTBT); - - return result; + return new DenseTestData + { + A = ToComplex(data.A), + B = ToComplex(data.B), + x = ToComplex(data.x), + y = ToComplex(data.y), + AT = ToComplex(data.AT), + BT = ToComplex(data.BT), + ApB = ToComplex(data.ApB), + AmBT = ToComplex(data.AmBT), + ATmB = ToComplex(data.ATmB), + Ax = ToComplex(data.Ax), + ATy = ToComplex(data.ATy), + xTBT = ToComplex(data.xTBT) + }; } private static Complex[] ToComplex(double[] vec) @@ -101,26 +94,23 @@ private static DenseColumnMajorStorage ToComplex(DenseColumnMajorStorag private static SparseTestData DenseToSparse(DenseTestData dense) { - var data = new SparseTestData() + return new SparseTestData { RowCount = dense.RowCount, - ColumnCount = dense.ColumnCount + ColumnCount = dense.ColumnCount, + A = DenseToSparse(dense.A), + B = DenseToSparse(dense.B), + x = dense.x, + y = dense.y, + AT = DenseToSparse(dense.AT), + BT = DenseToSparse(dense.BT), + ApB = DenseToSparse(dense.ApB), + AmBT = DenseToSparse(dense.AmBT), + ATmB = DenseToSparse(dense.ATmB), + Ax = dense.Ax, + ATy = dense.ATy, + xTBT = dense.xTBT }; - - data.A = DenseToSparse(dense.A); - data.B = DenseToSparse(dense.B); - data.x = dense.x; - data.y = dense.y; - data.AT = DenseToSparse(dense.AT); - data.BT = DenseToSparse(dense.BT); - data.ApB = DenseToSparse(dense.ApB); - data.AmBT = DenseToSparse(dense.AmBT); - data.ATmB = DenseToSparse(dense.ATmB); - data.Ax = dense.Ax; - data.ATy = dense.ATy; - data.xTBT = dense.xTBT; - - return data; } private static CompressedColumnStorage DenseToSparse(DenseColumnMajorStorage dense) diff --git a/CSparse.Tests/Double/DenseTestDataReader.cs b/CSparse.Tests/Double/DenseTestDataReader.cs index 72b99b5..06504c7 100644 --- a/CSparse.Tests/Double/DenseTestDataReader.cs +++ b/CSparse.Tests/Double/DenseTestDataReader.cs @@ -9,80 +9,77 @@ class DenseTestDataReader { public static DenseTestData Read(Stream stream) { - using (var reader = new StreamReader(stream)) + using var reader = new StreamReader(stream); + + string line = reader.ReadLine(); + + GetItem(line, out string name, out string value); + + if (name != "size") { - string line, name, value; + throw new FormatException("Expected first line = size."); + } - line = reader.ReadLine(); + var data = ReadSize(value); + int m = data.RowCount; + int n = data.ColumnCount; + + while ((line = reader.ReadLine()) != null) + { GetItem(line, out name, out value); - if (name != "size") + if (name == "A") { - throw new FormatException("Expected first line = size."); + data.A = ReadMatrix(value, m, n); } - - var data = ReadSize(value); - - int m = data.RowCount; - int n = data.ColumnCount; - - while ((line = reader.ReadLine()) != null) + else if (name == "B") { - GetItem(line, out name, out value); - - if (name == "A") - { - data.A = ReadMatrix(value, m, n); - } - else if (name == "B") - { - data.B = ReadMatrix(value, m, n); - } - else if (name == "x") - { - data.x = ReadVector(value, n); - } - else if (name == "y") - { - data.y = ReadVector(value, m); - } - else if (name == "A'") - { - data.AT = ReadMatrix(value, n, m); - } - else if (name == "B'") - { - data.BT = ReadMatrix(value, n, m); - } - else if (name == "A+B") - { - data.ApB = ReadMatrix(value, m, n); - } - else if (name == "A*B'") - { - data.AmBT = ReadMatrix(value, m, m); - } - else if (name == "A'*B") - { - data.ATmB = ReadMatrix(value, n, n); - } - else if (name == "A*x") - { - data.Ax = ReadVector(value, m); - } - else if (name == "A'*y") - { - data.ATy = ReadVector(value, n); - } - else if (name == "x'*B'") - { - data.xTBT = ReadVector(value, m); - } + data.B = ReadMatrix(value, m, n); + } + else if (name == "x") + { + data.x = ReadVector(value, n); + } + else if (name == "y") + { + data.y = ReadVector(value, m); + } + else if (name == "A'") + { + data.AT = ReadMatrix(value, n, m); + } + else if (name == "B'") + { + data.BT = ReadMatrix(value, n, m); + } + else if (name == "A+B") + { + data.ApB = ReadMatrix(value, m, n); + } + else if (name == "A*B'") + { + data.AmBT = ReadMatrix(value, m, m); + } + else if (name == "A'*B") + { + data.ATmB = ReadMatrix(value, n, n); + } + else if (name == "A*x") + { + data.Ax = ReadVector(value, m); + } + else if (name == "A'*y") + { + data.ATy = ReadVector(value, n); + } + else if (name == "x'*B'") + { + data.xTBT = ReadVector(value, m); } - - return data; } + + return data; } private static void GetItem(string line, out string name, out string value) diff --git a/CSparse.Tests/Double/MatrixHelper.cs b/CSparse.Tests/Double/MatrixHelper.cs index a2cff13..363332d 100644 --- a/CSparse.Tests/Double/MatrixHelper.cs +++ b/CSparse.Tests/Double/MatrixHelper.cs @@ -5,17 +5,14 @@ namespace CSparse.Tests.Double class MatrixHelper { - private static Dictionary> dense = new Dictionary>(); - - private static Dictionary> sparse = new Dictionary>(); + private static readonly Dictionary> dense = []; + private static readonly Dictionary> sparse = []; public static SparseTestData LoadSparse(int rows, int columns) { string resource = string.Format("test-data-dense-{0}x{1}.txt", rows, columns); - SparseTestData data; - - if (!sparse.TryGetValue(resource, out data)) + if (!sparse.TryGetValue(resource, out SparseTestData data)) { var dense = LoadDense(rows, columns); @@ -31,9 +28,7 @@ public static DenseTestData LoadDense(int rows, int columns) { string resource = string.Format("test-data-dense-{0}x{1}.txt", rows, columns); - DenseTestData data; - - if (!dense.TryGetValue(resource, out data)) + if (!dense.TryGetValue(resource, out DenseTestData data)) { var stream = ResourceLoader.GetStream(resource, "Double"); @@ -47,26 +42,23 @@ public static DenseTestData LoadDense(int rows, int columns) private static SparseTestData DenseToSparse(DenseTestData dense) { - var data = new SparseTestData() + return new SparseTestData { RowCount = dense.RowCount, - ColumnCount = dense.ColumnCount + ColumnCount = dense.ColumnCount, + A = DenseToSparse(dense.A), + B = DenseToSparse(dense.B), + x = dense.x, + y = dense.y, + AT = DenseToSparse(dense.AT), + BT = DenseToSparse(dense.BT), + ApB = DenseToSparse(dense.ApB), + AmBT = DenseToSparse(dense.AmBT), + ATmB = DenseToSparse(dense.ATmB), + Ax = dense.Ax, + ATy = dense.ATy, + xTBT = dense.xTBT }; - - data.A = DenseToSparse(dense.A); - data.B = DenseToSparse(dense.B); - data.x = dense.x; - data.y = dense.y; - data.AT = DenseToSparse(dense.AT); - data.BT = DenseToSparse(dense.BT); - data.ApB = DenseToSparse(dense.ApB); - data.AmBT = DenseToSparse(dense.AmBT); - data.ATmB = DenseToSparse(dense.ATmB); - data.Ax = dense.Ax; - data.ATy = dense.ATy; - data.xTBT = dense.xTBT; - - return data; } private static CompressedColumnStorage DenseToSparse(DenseColumnMajorStorage dense) diff --git a/CSparse.Tests/IO/TestMatrixMarketReader.cs b/CSparse.Tests/IO/TestMatrixMarketReader.cs index 0a26212..d7edfcb 100644 --- a/CSparse.Tests/IO/TestMatrixMarketReader.cs +++ b/CSparse.Tests/IO/TestMatrixMarketReader.cs @@ -10,35 +10,31 @@ public class TestMatrixMarketReader [Test] public void TestSymmetric() { - var stream = ResourceLoader.GetStream("LFAT5.mtx", "Double"); + using var stream = ResourceLoader.GetStream("LFAT5.mtx", "Double"); + using var reader = new StreamReader(stream); - using (var reader = new StreamReader(stream)) - { - var A = MatrixMarketReader.ReadStorage(reader); + var A = MatrixMarketReader.ReadStorage(reader); - Assert.That(14, Is.EqualTo(A.RowCount)); - Assert.That(14, Is.EqualTo(A.ColumnCount)); + Assert.That(14, Is.EqualTo(A.RowCount)); + Assert.That(14, Is.EqualTo(A.ColumnCount)); - // Symmetric mtx file has 30 entries -> auto expand = 2 * 30 - 14 = 46. - Assert.That(46, Is.EqualTo(A.NonZerosCount)); - } + // Symmetric mtx file has 30 entries -> auto expand = 2 * 30 - 14 = 46. + Assert.That(46, Is.EqualTo(A.NonZerosCount)); } [Test] public void TestPatternSymmetric() { - var stream = ResourceLoader.GetStream("bcspwr01.mtx", "Double"); + using var stream = ResourceLoader.GetStream("bcspwr01.mtx", "Double"); + using var reader = new StreamReader(stream); - using (var reader = new StreamReader(stream)) - { - var A = MatrixMarketReader.ReadStorage(reader, false); + var A = MatrixMarketReader.ReadStorage(reader, false); - Assert.That(39, Is.EqualTo(A.RowCount)); - Assert.That(39, Is.EqualTo(A.ColumnCount)); + Assert.That(39, Is.EqualTo(A.RowCount)); + Assert.That(39, Is.EqualTo(A.ColumnCount)); - // Symmetric mtx file has 85 entries, no auto expand. - Assert.That(85, Is.EqualTo(A.NonZerosCount)); - } + // Symmetric mtx file has 85 entries, no auto expand. + Assert.That(85, Is.EqualTo(A.NonZerosCount)); } } } diff --git a/CSparse.Tests/IO/TestMatrixMarketWriter.cs b/CSparse.Tests/IO/TestMatrixMarketWriter.cs index d10c984..e3584b2 100644 --- a/CSparse.Tests/IO/TestMatrixMarketWriter.cs +++ b/CSparse.Tests/IO/TestMatrixMarketWriter.cs @@ -8,12 +8,12 @@ namespace CSparse.Tests.IO public class TestMatrixMarketWriter { - private static readonly double[] DenseA = new[] - { + private static readonly double[] DenseA = + [ 1.0, 0.0, 0.5, 0.0, 2.0, 0.1, 0.5, 0.1, 3.0, - }; + ]; [Test] public void TestWriteSparse() diff --git a/CSparse.Tests/Ordering/TestStronglyConnectedComponents.cs b/CSparse.Tests/Ordering/TestStronglyConnectedComponents.cs index dda086c..2aaa7c7 100644 --- a/CSparse.Tests/Ordering/TestStronglyConnectedComponents.cs +++ b/CSparse.Tests/Ordering/TestStronglyConnectedComponents.cs @@ -25,8 +25,8 @@ public void TestScc() // // Adjacency matrix: - var A = SparseMatrix.OfRowMajor(8, 8, new double[8 * 8] - { + var A = SparseMatrix.OfRowMajor(8, 8, + [ 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, @@ -35,7 +35,7 @@ public void TestScc() 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1 - }); + ]); int n = A.ColumnCount; diff --git a/CSparse.Tests/ResourceLoader.cs b/CSparse.Tests/ResourceLoader.cs index 5e2fa69..dd1df57 100644 --- a/CSparse.Tests/ResourceLoader.cs +++ b/CSparse.Tests/ResourceLoader.cs @@ -11,7 +11,7 @@ static class ResourceLoader { private const string NS = "CSparse.Tests.{Type}.Data"; - private static Dictionary cache = new Dictionary(); + private static readonly Dictionary cache = []; public static Stream GetStream(string resource, string type) { @@ -29,14 +29,13 @@ public static CompressedColumnStorage Get(string resource) string path = NS.Replace("{Type}", type) + "." + resource; - object obj; - if (cache.TryGetValue(path, out obj)) + if (cache.TryGetValue(path, out object obj)) { return (CompressedColumnStorage)obj; } - var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path); + using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path); var matrix = MatrixMarketReader.ReadMatrix(stream); diff --git a/CSparse/CSparse.csproj b/CSparse/CSparse.csproj index b5eb86b..52a920a 100644 --- a/CSparse/CSparse.csproj +++ b/CSparse/CSparse.csproj @@ -9,19 +9,23 @@ CSparse.NET provides numerical methods for sparse LU, Cholesky and QR decomposition of real and complex linear systems. CSparse.NET - Copyright Christian Woltering © 2012-2025 + Copyright Christian Woltering © 2012-2026 Christian Woltering - 4.3.0.0 - 4.3.0.0 - math sparse matrix lu cholesky qr decomposition factorization - 4.3.0 + 4.4.0.0 + 4.4.0.0 + math sparse matrix lu cholesky qr decomposition factorization + 4.4.0 CSparse CSparse LGPL-2.1-only https://github.com/wo80/CSparse.NET https://github.com/wo80/CSparse.NET.git git - Version 4.3.0 + Version 4.4.0 + +* Add Refactorize methods to SparseCholesky, SparseLDL and SparseLU + +Version 4.3.0 * Add net10.0 and remove net6.0 target framework. * Minor optimizations for matrix-vector multiplication.