From 550d71bef062875c68596cd60ba5013fb76ab36e Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Wed, 23 Dec 2015 12:14:29 +0100 Subject: [PATCH] Linear Algebra: VectorStorage and MatrixStorage DataContract for ephemeral serialization #350 --- .../Storage/DenseColumnMajorMatrixStorage.cs | 3 + .../Storage/DenseVectorStorage.cs | 3 + .../Storage/DiagonalMatrixStorage.cs | 3 + .../LinearAlgebra/Storage/MatrixStorage.cs | 8 +- .../SparseCompressedRowMatrixStorage.cs | 5 + .../Storage/SparseVectorStorage.cs | 5 + .../LinearAlgebra/Storage/VectorStorage.cs | 4 + .../MatrixStorageSerializationTests.cs | 141 ++++++++++++++++++ .../VectorStorageSerializationTests.cs | 117 +++++++++++++++ src/UnitTests/UnitTests.csproj | 2 + 10 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 src/UnitTests/LinearAlgebraTests/MatrixStorageSerializationTests.cs create mode 100644 src/UnitTests/LinearAlgebraTests/VectorStorageSerializationTests.cs diff --git a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs index 4f9cc1c8..f98cb543 100644 --- a/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DenseColumnMajorMatrixStorage.cs @@ -31,17 +31,20 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using MathNet.Numerics.Properties; using MathNet.Numerics.Threading; namespace MathNet.Numerics.LinearAlgebra.Storage { [Serializable] + [DataContract(Namespace = "urn:MathNet/Numerics/LinearAlgebra")] public class DenseColumnMajorMatrixStorage : MatrixStorage where T : struct, IEquatable, IFormattable { // [ruegg] public fields are OK here + [DataMember(Order = 1)] public readonly T[] Data; internal DenseColumnMajorMatrixStorage(int rows, int columns) diff --git a/src/Numerics/LinearAlgebra/Storage/DenseVectorStorage.cs b/src/Numerics/LinearAlgebra/Storage/DenseVectorStorage.cs index e6bd6e0a..416be866 100644 --- a/src/Numerics/LinearAlgebra/Storage/DenseVectorStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DenseVectorStorage.cs @@ -31,17 +31,20 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using MathNet.Numerics.Properties; using MathNet.Numerics.Threading; namespace MathNet.Numerics.LinearAlgebra.Storage { [Serializable] + [DataContract(Namespace = "urn:MathNet/Numerics/LinearAlgebra")] public class DenseVectorStorage : VectorStorage where T : struct, IEquatable, IFormattable { // [ruegg] public fields are OK here + [DataMember(Order = 1)] public readonly T[] Data; internal DenseVectorStorage(int length) diff --git a/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs index fb4ab694..5f6af897 100644 --- a/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/DiagonalMatrixStorage.cs @@ -31,17 +31,20 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using MathNet.Numerics.Properties; using MathNet.Numerics.Threading; namespace MathNet.Numerics.LinearAlgebra.Storage { [Serializable] + [DataContract(Namespace = "urn:MathNet/Numerics/LinearAlgebra")] public class DiagonalMatrixStorage : MatrixStorage where T : struct, IEquatable, IFormattable { // [ruegg] public fields are OK here + [DataMember(Order = 1)] public readonly T[] Data; internal DiagonalMatrixStorage(int rows, int columns) diff --git a/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs index 3fcdbb45..89e8e5b6 100644 --- a/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/MatrixStorage.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2014 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -30,18 +30,24 @@ using System; using System.Collections.Generic; +using System.Runtime.Serialization; using MathNet.Numerics.Properties; namespace MathNet.Numerics.LinearAlgebra.Storage { [Serializable] + [DataContract(Namespace = "urn:MathNet/Numerics/LinearAlgebra")] public abstract partial class MatrixStorage : IEquatable> where T : struct, IEquatable, IFormattable { // [ruegg] public fields are OK here protected static readonly T Zero = BuilderInstance.Matrix.Zero; + + [DataMember(Order = 1)] public readonly int RowCount; + + [DataMember(Order = 2)] public readonly int ColumnCount; protected MatrixStorage(int rowCount, int columnCount) diff --git a/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs b/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs index e9b9bbd1..ef94ab03 100644 --- a/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/SparseCompressedRowMatrixStorage.cs @@ -31,11 +31,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using MathNet.Numerics.Properties; namespace MathNet.Numerics.LinearAlgebra.Storage { [Serializable] + [DataContract(Namespace = "urn:MathNet/Numerics/LinearAlgebra")] public class SparseCompressedRowMatrixStorage : MatrixStorage where T : struct, IEquatable, IFormattable { @@ -47,18 +49,21 @@ namespace MathNet.Numerics.LinearAlgebra.Storage /// The last value is equal to ValueCount, so that the number of non-zero entries in row "i" is always /// given by RowPointers[i+i] - RowPointers[i]. This array thus has length RowCount+1. /// + [DataMember(Order = 1)] public readonly int[] RowPointers; /// /// An array containing the column indices of the non-zero values. Element "j" of the array /// is the number of the column in matrix that contains the j-th value in the array. /// + [DataMember(Order = 2)] public int[] ColumnIndices; /// /// Array that contains the non-zero elements of matrix. Values of the non-zero elements of matrix are mapped into the values /// array using the row-major storage mapping described in a compressed sparse row (CSR) format. /// + [DataMember(Order = 3)] public T[] Values; /// diff --git a/src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs b/src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs index b9ac6e1f..314baddf 100644 --- a/src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/SparseVectorStorage.cs @@ -32,12 +32,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.Serialization; using MathNet.Numerics.Properties; using MathNet.Numerics.Threading; namespace MathNet.Numerics.LinearAlgebra.Storage { [Serializable] + [DataContract(Namespace = "urn:MathNet/Numerics/LinearAlgebra")] public class SparseVectorStorage : VectorStorage where T : struct, IEquatable, IFormattable { @@ -46,16 +48,19 @@ namespace MathNet.Numerics.LinearAlgebra.Storage /// /// Array that contains the indices of the non-zero values. /// + [DataMember(Order = 1)] public int[] Indices; /// /// Array that contains the non-zero elements of the vector. /// + [DataMember(Order = 2)] public T[] Values; /// /// Gets the number of non-zero elements in the vector. /// + [DataMember(Order = 3)] public int ValueCount; internal SparseVectorStorage(int length) diff --git a/src/Numerics/LinearAlgebra/Storage/VectorStorage.cs b/src/Numerics/LinearAlgebra/Storage/VectorStorage.cs index 48f68bb6..89dba3fe 100644 --- a/src/Numerics/LinearAlgebra/Storage/VectorStorage.cs +++ b/src/Numerics/LinearAlgebra/Storage/VectorStorage.cs @@ -30,17 +30,21 @@ using System; using System.Collections.Generic; +using System.Runtime.Serialization; using MathNet.Numerics.Properties; namespace MathNet.Numerics.LinearAlgebra.Storage { [Serializable] + [DataContract(Namespace = "urn:MathNet/Numerics/LinearAlgebra")] public abstract partial class VectorStorage : IEquatable> where T : struct, IEquatable, IFormattable { // [ruegg] public fields are OK here protected static readonly T Zero = BuilderInstance.Vector.Zero; + + [DataMember(Order = 1)] public readonly int Length; protected VectorStorage(int length) diff --git a/src/UnitTests/LinearAlgebraTests/MatrixStorageSerializationTests.cs b/src/UnitTests/LinearAlgebraTests/MatrixStorageSerializationTests.cs new file mode 100644 index 00000000..69e02baa --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/MatrixStorageSerializationTests.cs @@ -0,0 +1,141 @@ +using System; +using System.IO; +using System.Runtime.Serialization; +using MathNet.Numerics.LinearAlgebra; +using MathNet.Numerics.LinearAlgebra.Storage; +using NUnit.Framework; + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests +{ +#if NOSYSNUMERICS + using Complex64 = Numerics.Complex; +#else + using Complex64 = System.Numerics.Complex; +#endif + + [TestFixture] + public class MatrixStorageSerializationTests + { + static readonly Type[] KnownTypes = + { + typeof(DenseColumnMajorMatrixStorage), typeof(SparseCompressedRowMatrixStorage), typeof(DiagonalMatrixStorage), + typeof(DenseColumnMajorMatrixStorage), typeof(SparseCompressedRowMatrixStorage), typeof(DiagonalMatrixStorage), + typeof(DenseColumnMajorMatrixStorage), typeof(SparseCompressedRowMatrixStorage), typeof(DiagonalMatrixStorage), + typeof(DenseColumnMajorMatrixStorage), typeof(SparseCompressedRowMatrixStorage), typeof(DiagonalMatrixStorage) + }; + + [Test] + public void DenseColumnMajorMatrixStorageOfDoubleDataContractSerializationTest() + { + MatrixStorage expected = Matrix.Build.Dense(2, 2, new[] { 1.0d, 2.0d, 0.0d, 3.0d }).Storage; + + var serializer = new DataContractSerializer(typeof(MatrixStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (MatrixStorage)serializer.ReadObject(stream); + + Assert.That(actual.RowCount, Is.EqualTo(expected.RowCount)); + Assert.That(actual.ColumnCount, Is.EqualTo(expected.ColumnCount)); + Assert.That(actual, Is.TypeOf(typeof(DenseColumnMajorMatrixStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void DenseColumnMajorMatrixStorageOfSingleDataContractSerializationTest() + { + MatrixStorage expected = Matrix.Build.Dense(2, 2, new[] { 1.0f, 2.0f, 0.0f, 3.0f }).Storage; + + var serializer = new DataContractSerializer(typeof(MatrixStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (MatrixStorage)serializer.ReadObject(stream); + + Assert.That(actual.RowCount, Is.EqualTo(expected.RowCount)); + Assert.That(actual.ColumnCount, Is.EqualTo(expected.ColumnCount)); + Assert.That(actual, Is.TypeOf(typeof(DenseColumnMajorMatrixStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void DenseColumnMajorMatrixStorageOfComplex64DataContractSerializationTest() + { + MatrixStorage expected = Matrix.Build.Dense(2, 2, new[] { new Complex64(1.0, -1.0), 2.0, 0.0, 3.0 }).Storage; + + var serializer = new DataContractSerializer(typeof(MatrixStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (MatrixStorage)serializer.ReadObject(stream); + + Assert.That(actual.RowCount, Is.EqualTo(expected.RowCount)); + Assert.That(actual.ColumnCount, Is.EqualTo(expected.ColumnCount)); + Assert.That(actual, Is.TypeOf(typeof(DenseColumnMajorMatrixStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void DenseColumnMajorMatrixStorageOfComplex32DataContractSerializationTest() + { + MatrixStorage expected = Matrix.Build.Dense(2, 2, new[] { new Numerics.Complex32(1.0f, -1.0f), 2.0f, 0.0f, 3.0f }).Storage; + + var serializer = new DataContractSerializer(typeof(MatrixStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (MatrixStorage)serializer.ReadObject(stream); + + Assert.That(actual.RowCount, Is.EqualTo(expected.RowCount)); + Assert.That(actual.ColumnCount, Is.EqualTo(expected.ColumnCount)); + Assert.That(actual, Is.TypeOf(typeof(DenseColumnMajorMatrixStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void SparseCompressedRowMatrixStorageOfDoubleDataContractSerializationTest() + { + MatrixStorage expected = Matrix.Build.SparseOfArray(new[,] { {1.0d, 2.0d}, {0.0d, 3.0d} }).Storage; + + var serializer = new DataContractSerializer(typeof(MatrixStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (MatrixStorage)serializer.ReadObject(stream); + + Assert.That(actual.RowCount, Is.EqualTo(expected.RowCount)); + Assert.That(actual.ColumnCount, Is.EqualTo(expected.ColumnCount)); + Assert.That(actual, Is.TypeOf(typeof(SparseCompressedRowMatrixStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void DiagonalMatrixStorageOfDoubleDataContractSerializationTest() + { + MatrixStorage expected = Matrix.Build.Diagonal(new[] { 1.0d, 2.0d, 0.0d, 3.0d }).Storage; + + var serializer = new DataContractSerializer(typeof(MatrixStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (MatrixStorage)serializer.ReadObject(stream); + + Assert.That(actual.RowCount, Is.EqualTo(expected.RowCount)); + Assert.That(actual.ColumnCount, Is.EqualTo(expected.ColumnCount)); + Assert.That(actual, Is.TypeOf(typeof(DiagonalMatrixStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + } +} diff --git a/src/UnitTests/LinearAlgebraTests/VectorStorageSerializationTests.cs b/src/UnitTests/LinearAlgebraTests/VectorStorageSerializationTests.cs new file mode 100644 index 00000000..ea6c192f --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/VectorStorageSerializationTests.cs @@ -0,0 +1,117 @@ +using System; +using System.IO; +using System.Runtime.Serialization; +using MathNet.Numerics.LinearAlgebra; +using MathNet.Numerics.LinearAlgebra.Storage; +using NUnit.Framework; + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests +{ +#if NOSYSNUMERICS + using Complex64 = Numerics.Complex; +#else + using Complex64 = System.Numerics.Complex; +#endif + + [TestFixture] + public class VectorStorageSerializationTests + { + static readonly Type[] KnownTypes = + { + typeof(DenseVectorStorage), typeof(SparseVectorStorage), + typeof(DenseVectorStorage), typeof(SparseVectorStorage), + typeof(DenseVectorStorage), typeof(SparseVectorStorage), + typeof(DenseVectorStorage), typeof(SparseVectorStorage) + }; + + [Test] + public void DenseVectorStorageOfDoubleDataContractSerializationTest() + { + VectorStorage expected = Vector.Build.DenseOfArray(new[] { 1.0d, 2.0d, 0.0d, 3.0d }).Storage; + + var serializer = new DataContractSerializer(typeof(VectorStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (VectorStorage)serializer.ReadObject(stream); + + Assert.That(actual.Length, Is.EqualTo(expected.Length)); + Assert.That(actual, Is.TypeOf(typeof(DenseVectorStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void DenseVectorStorageOfSingleDataContractSerializationTest() + { + VectorStorage expected = Vector.Build.DenseOfArray(new[] { 1.0f, 2.0f, 0.0f, 3.0f }).Storage; + + var serializer = new DataContractSerializer(typeof(VectorStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (VectorStorage)serializer.ReadObject(stream); + + Assert.That(actual.Length, Is.EqualTo(expected.Length)); + Assert.That(actual, Is.TypeOf(typeof(DenseVectorStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void DenseVectorStorageOfComplex64DataContractSerializationTest() + { + VectorStorage expected = Vector.Build.DenseOfArray(new[] { new Complex64(1.0, -1.0), 2.0, 0.0, 3.0 }).Storage; + + var serializer = new DataContractSerializer(typeof(VectorStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (VectorStorage)serializer.ReadObject(stream); + + Assert.That(actual.Length, Is.EqualTo(expected.Length)); + Assert.That(actual, Is.TypeOf(typeof(DenseVectorStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void DenseVectorStorageOfComplex32DataContractSerializationTest() + { + VectorStorage expected = Vector.Build.DenseOfArray(new[] { new Numerics.Complex32(1.0f, -1.0f), 2.0f, 0.0f, 3.0f }).Storage; + + var serializer = new DataContractSerializer(typeof(VectorStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (VectorStorage)serializer.ReadObject(stream); + + Assert.That(actual.Length, Is.EqualTo(expected.Length)); + Assert.That(actual, Is.TypeOf(typeof(DenseVectorStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void SparseVectorStorageOfDoubleDataContractSerializationTest() + { + VectorStorage expected = Vector.Build.SparseOfArray(new[] { 1.0d, 2.0d, 0.0d, 3.0d }).Storage; + + var serializer = new DataContractSerializer(typeof(VectorStorage), KnownTypes); + var stream = new MemoryStream(); + serializer.WriteObject(stream, expected); + stream.Position = 0; + + var actual = (VectorStorage)serializer.ReadObject(stream); + + Assert.That(actual.Length, Is.EqualTo(expected.Length)); + Assert.That(actual, Is.TypeOf(typeof(SparseVectorStorage))); + Assert.That(actual, Is.EqualTo(expected)); + Assert.That(actual, Is.Not.SameAs(expected)); + } + } +} diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index b64c0ed7..4e523989 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -347,6 +347,8 @@ + +