From 5ff5a75389a4571812af92013560ad1ddf6093da Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Wed, 9 Sep 2015 17:23:58 +0200 Subject: [PATCH 1/2] LA: fix a critical bug in SparseMatrix.Add when adding a matrix to itself #341 --- .../LinearAlgebra/Complex/SparseMatrix.cs | 2 +- .../LinearAlgebra/Complex32/SparseMatrix.cs | 2 +- .../LinearAlgebra/Double/SparseMatrix.cs | 2 +- .../LinearAlgebra/Single/SparseMatrix.cs | 6 +-- .../Complex/MatrixTests.Arithmetic.cs | 40 ++++++++++++++++++ .../Complex32/MatrixTests.Arithmetic.cs | 40 ++++++++++++++++++ .../Double/MatrixTests.Arithmetic.cs | 41 ++++++++++++++++++- .../Single/MatrixTests.Arithmetic.cs | 40 ++++++++++++++++++ 8 files changed, 166 insertions(+), 7 deletions(-) diff --git a/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs index d76c7b34..baa3d8e9 100644 --- a/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex/SparseMatrix.cs @@ -726,7 +726,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex CopyTo(result); } - Control.LinearAlgebraProvider.ScaleArray(2.0, _storage.Values, _storage.Values); + Control.LinearAlgebraProvider.ScaleArray(2.0, sparseResult._storage.Values, sparseResult._storage.Values); return; } diff --git a/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs index ff9fefe2..f1e606aa 100644 --- a/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Complex32/SparseMatrix.cs @@ -721,7 +721,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32 CopyTo(result); } - Control.LinearAlgebraProvider.ScaleArray(2.0f, _storage.Values, _storage.Values); + Control.LinearAlgebraProvider.ScaleArray(2.0f, sparseResult._storage.Values, sparseResult._storage.Values); return; } diff --git a/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs index 1de758ad..5e300128 100644 --- a/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Double/SparseMatrix.cs @@ -721,7 +721,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double CopyTo(result); } - Control.LinearAlgebraProvider.ScaleArray(2.0, _storage.Values, _storage.Values); + Control.LinearAlgebraProvider.ScaleArray(2.0, sparseResult._storage.Values, sparseResult._storage.Values); return; } diff --git a/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs b/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs index 5e01087f..e61a9f95 100644 --- a/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs +++ b/src/Numerics/LinearAlgebra/Single/SparseMatrix.cs @@ -155,7 +155,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single { return OfColumnArrays(data.Select(v => v.ToArray()).ToArray()); } - + /// /// Create a new sparse matrix as a copy of the given enumerable of enumerable columns. /// Each enumerable in the master enumerable specifies a column. @@ -725,7 +725,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single CopyTo(result); } - Control.LinearAlgebraProvider.ScaleArray(2.0f, _storage.Values, _storage.Values); + Control.LinearAlgebraProvider.ScaleArray(2.0f, sparseResult._storage.Values, sparseResult._storage.Values); return; } @@ -1095,7 +1095,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single for (var i = 0; i < RowCount; i++) { // Multiply row of matrix A on row of matrix B - + var startIndexThis = rowPointers[i]; var endIndexThis = rowPointers[i + 1]; diff --git a/src/UnitTests/LinearAlgebraTests/Complex/MatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Complex/MatrixTests.Arithmetic.cs index da96f1e2..a65559b9 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex/MatrixTests.Arithmetic.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex/MatrixTests.Arithmetic.cs @@ -251,6 +251,46 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex } } + /// + /// Can add a matrix. + /// + /// Matrix name. + [TestCase("Square3x3")] + [TestCase("Tall3x2")] + public void CanAddMatrixToSelf(string mtx) + { + var matrix = TestMatrices[mtx].Clone(); + + var result = matrix.Add(matrix); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(result[i, j], 2*matrix[i, j]); + } + } + } + + /// + /// Can subtract a matrix. + /// + /// Matrix name. + [TestCase("Square3x3")] + [TestCase("Tall3x2")] + public void CanSubtractMatrixFromSelf(string mtx) + { + var matrix = TestMatrices[mtx].Clone(); + + var result = matrix.Subtract(matrix); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(result[i, j], Complex.Zero); + } + } + } + /// /// Adding a matrix with fewer columns throws ArgumentOutOfRangeException. /// diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/MatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Complex32/MatrixTests.Arithmetic.cs index 48f7ebeb..3d55aadb 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex32/MatrixTests.Arithmetic.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex32/MatrixTests.Arithmetic.cs @@ -247,6 +247,46 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32 } } + /// + /// Can add a matrix. + /// + /// Matrix name. + [TestCase("Square3x3")] + [TestCase("Tall3x2")] + public void CanAddMatrixToSelf(string mtx) + { + var matrix = TestMatrices[mtx].Clone(); + + var result = matrix.Add(matrix); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(result[i, j], 2*matrix[i, j]); + } + } + } + + /// + /// Can subtract a matrix. + /// + /// Matrix name. + [TestCase("Square3x3")] + [TestCase("Tall3x2")] + public void CanSubtractMatrixFromSelf(string mtx) + { + var matrix = TestMatrices[mtx].Clone(); + + var result = matrix.Subtract(matrix); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(result[i, j], Complex32.Zero); + } + } + } + /// /// Adding a matrix with fewer columns throws ArgumentOutOfRangeException. /// diff --git a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs index e270f0e2..59cb3e27 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/MatrixTests.Arithmetic.cs @@ -27,7 +27,6 @@ using System; using MathNet.Numerics.Distributions; using MathNet.Numerics.LinearAlgebra; -using MathNet.Numerics.LinearAlgebra.Double; using NUnit.Framework; namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double @@ -241,6 +240,46 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double } } + /// + /// Can add a matrix. + /// + /// Matrix name. + [TestCase("Square3x3")] + [TestCase("Tall3x2")] + public void CanAddMatrixToSelf(string mtx) + { + var matrix = TestMatrices[mtx].Clone(); + + var result = matrix.Add(matrix); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(result[i, j], 2*matrix[i, j]); + } + } + } + + /// + /// Can subtract a matrix. + /// + /// Matrix name. + [TestCase("Square3x3")] + [TestCase("Tall3x2")] + public void CanSubtractMatrixFromSelf(string mtx) + { + var matrix = TestMatrices[mtx].Clone(); + + var result = matrix.Subtract(matrix); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(result[i, j], 0d); + } + } + } + /// /// Adding a matrix with fewer columns throws ArgumentOutOfRangeException. /// diff --git a/src/UnitTests/LinearAlgebraTests/Single/MatrixTests.Arithmetic.cs b/src/UnitTests/LinearAlgebraTests/Single/MatrixTests.Arithmetic.cs index f693dd16..9f1149ac 100644 --- a/src/UnitTests/LinearAlgebraTests/Single/MatrixTests.Arithmetic.cs +++ b/src/UnitTests/LinearAlgebraTests/Single/MatrixTests.Arithmetic.cs @@ -241,6 +241,46 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single } } + /// + /// Can add a matrix. + /// + /// Matrix name. + [TestCase("Square3x3")] + [TestCase("Tall3x2")] + public void CanAddMatrixToSelf(string mtx) + { + var matrix = TestMatrices[mtx].Clone(); + + var result = matrix.Add(matrix); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(result[i, j], 2*matrix[i, j]); + } + } + } + + /// + /// Can subtract a matrix. + /// + /// Matrix name. + [TestCase("Square3x3")] + [TestCase("Tall3x2")] + public void CanSubtractMatrixFromSelf(string mtx) + { + var matrix = TestMatrices[mtx].Clone(); + + var result = matrix.Subtract(matrix); + for (var i = 0; i < matrix.RowCount; i++) + { + for (var j = 0; j < matrix.ColumnCount; j++) + { + Assert.AreEqual(result[i, j], 0f); + } + } + } + /// /// Adding a matrix with fewer columns throws ArgumentOutOfRangeException. /// From 3edc64018d0609979b0e7656a95de37027f832c9 Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Mon, 21 Sep 2015 18:28:27 +0200 Subject: [PATCH 2/2] Release v3.7.1 --- RELEASENOTES.md | 3 +++ src/FSharp/AssemblyInfo.fs | 6 +++--- src/FSharpUnitTests/AssemblyInfo.fs | 6 +++--- src/Numerics/Properties/AssemblyInfo.cs | 6 +++--- src/UnitTests/Properties/AssemblyInfo.cs | 6 +++--- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 233b6411..5a01885f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,3 +1,6 @@ +### 3.7.1 - 2015-09-10 +* BUG: Linear Algebra: fix optimized path of adding a sparse matrix to itself. + ### 3.7.0 - 2015-05-09 * Statistics: RunningStatistics now propagates min/max on Combine, handles NaN on Push. * Statistics: new MovingStatistics providing descriptive statistics over a moving window *~Marcus Cuda* diff --git a/src/FSharp/AssemblyInfo.fs b/src/FSharp/AssemblyInfo.fs index 6a535df6..f60ad09b 100644 --- a/src/FSharp/AssemblyInfo.fs +++ b/src/FSharp/AssemblyInfo.fs @@ -45,9 +45,9 @@ open System.Runtime.InteropServices [] [] -[] -[] -[] +[] +[] +[] #if PORTABLE #else diff --git a/src/FSharpUnitTests/AssemblyInfo.fs b/src/FSharpUnitTests/AssemblyInfo.fs index bccb3b72..0e7581a3 100644 --- a/src/FSharpUnitTests/AssemblyInfo.fs +++ b/src/FSharpUnitTests/AssemblyInfo.fs @@ -10,9 +10,9 @@ open System.Runtime.InteropServices [] [] -[] -[] -[] +[] +[] +[] #if PORTABLE #else diff --git a/src/Numerics/Properties/AssemblyInfo.cs b/src/Numerics/Properties/AssemblyInfo.cs index 6fa17890..c5c5b248 100644 --- a/src/Numerics/Properties/AssemblyInfo.cs +++ b/src/Numerics/Properties/AssemblyInfo.cs @@ -45,9 +45,9 @@ using System.Runtime.InteropServices; [assembly: CLSCompliant(true)] [assembly: NeutralResourcesLanguage("en")] -[assembly: AssemblyVersion("3.7.0.0")] -[assembly: AssemblyFileVersion("3.7.0.0")] -[assembly: AssemblyInformationalVersion("3.7.0")] +[assembly: AssemblyVersion("3.7.1.0")] +[assembly: AssemblyFileVersion("3.7.1.0")] +[assembly: AssemblyInformationalVersion("3.7.1")] #if PORTABLE diff --git a/src/UnitTests/Properties/AssemblyInfo.cs b/src/UnitTests/Properties/AssemblyInfo.cs index 52fdd7bd..3269faf2 100644 --- a/src/UnitTests/Properties/AssemblyInfo.cs +++ b/src/UnitTests/Properties/AssemblyInfo.cs @@ -9,8 +9,8 @@ using MathNet.Numerics.UnitTests; [assembly: ComVisible(false)] [assembly: Guid("04157581-63f3-447b-a277-83c6e69126a4")] -[assembly: AssemblyVersion("3.7.0.0")] -[assembly: AssemblyFileVersion("3.7.0.0")] -[assembly: AssemblyInformationalVersion("3.7.0")] +[assembly: AssemblyVersion("3.7.1.0")] +[assembly: AssemblyFileVersion("3.7.1.0")] +[assembly: AssemblyInformationalVersion("3.7.1")] [assembly: UseLinearAlgebraProvider]