diff --git a/src/Data/Matlab/Formatter.cs b/src/Data/Matlab/Formatter.cs
new file mode 100644
index 00000000..28b5cfad
--- /dev/null
+++ b/src/Data/Matlab/Formatter.cs
@@ -0,0 +1,732 @@
+//
+// Math.NET Numerics, part of the Math.NET Project
+// http://numerics.mathdotnet.com
+// http://github.com/mathnet/mathnet-numerics
+// http://mathnetnumerics.codeplex.com
+//
+// Copyright (c) 2009-2014 Math.NET
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Numerics;
+using System.Text;
+using MathNet.Numerics.LinearAlgebra;
+using MathNet.Numerics.LinearAlgebra.Storage;
+using MathNet.Numerics.Properties;
+
+namespace MathNet.Numerics.Data.Matlab
+{
+ ///
+ /// Format a MATLAB file.
+ ///
+ internal static class Formatter
+ {
+ ///
+ /// The file header value
+ ///
+ const string HeaderText = "MATLAB 5.0 MAT-file, Platform: .NET 4 - Math.NET Numerics, Created on: ";
+
+ ///
+ /// The length of the header text.
+ ///
+ const int HeaderTextLength = 116;
+
+ ///
+ /// Format a matrix block byte array
+ ///
+ internal static MatlabMatrix FormatMatrix(Matrix matrix, string name)
+ where T : struct, IEquatable, IFormattable
+ {
+ if (matrix == null)
+ {
+ throw new ArgumentNullException("matrix");
+ }
+
+ if (string.IsNullOrEmpty(name))
+ {
+ throw new ArgumentException(Resources.StringNullOrEmpty, "name");
+ }
+
+ if (name.IndexOf(' ') > -1)
+ {
+ throw new ArgumentException(string.Format(Resources.NameCannotContainASpace, name), "name");
+ }
+
+ if (typeof(T) == typeof(double))
+ {
+ var sparse = matrix as LinearAlgebra.Double.SparseMatrix;
+ return sparse != null
+ ? GetSparseDataArray(sparse, name)
+ : GetDenseDataArray((LinearAlgebra.Double.Matrix)(object)matrix, name);
+ }
+
+ if (typeof(T) == typeof(float))
+ {
+ var sparse = matrix as LinearAlgebra.Single.SparseMatrix;
+ return sparse != null
+ ? GetSparseDataArray(sparse, name)
+ : GetDenseDataArray((LinearAlgebra.Single.Matrix)(object)matrix, name);
+ }
+
+ if (typeof(T) == typeof(Complex))
+ {
+ var sparse = matrix as LinearAlgebra.Complex.SparseMatrix;
+ return sparse != null
+ ? GetSparseDataArray(sparse, name)
+ : GetDenseDataArray((LinearAlgebra.Complex.Matrix)(object)matrix, name);
+ }
+
+ if (typeof(T) == typeof(Complex32))
+ {
+ var sparse = matrix as LinearAlgebra.Complex32.SparseMatrix;
+ return sparse != null
+ ? GetSparseDataArray(sparse, name)
+ : GetDenseDataArray((LinearAlgebra.Complex32.Matrix)(object)matrix, name);
+ }
+
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// Writes all matrix blocks to a stream.
+ ///
+ internal static void FormatFile(Stream stream, IEnumerable matrices)
+ {
+ using (var buffer = new BufferedStream(stream))
+ using (var writer = new BinaryWriter(buffer))
+ {
+ WriteHeader(writer);
+
+ foreach (var matrix in matrices)
+ {
+ // write data type
+ writer.Write((int)DataType.Compressed);
+
+ WriteCompressedData(writer, matrix.Data);
+ }
+
+ writer.Flush();
+ writer.Close();
+ }
+ }
+
+ ///
+ /// Writes the matrix tag and name.
+ ///
+ /// The writer we are using.
+ /// The array class we are writing.
+ /// if set to true if this a complex matrix.
+ /// The name of the matrix.
+ /// The number of rows.
+ /// The columns of columns.
+ /// The maximum number of non-zero elements.
+ static void WriteMatrixTagAndName(BinaryWriter writer, ArrayClass arrayClass, bool isComplex,
+ string name, int rows, int columns, int nzmax)
+ {
+ writer.Write((int)DataType.Matrix);
+
+ // add place holder for data size
+ writer.Write(0);
+
+ // write flag, data type and size
+ writer.Write((int)DataType.UInt32);
+ writer.Write(8);
+
+ // write array class and flags
+ writer.Write((byte)arrayClass);
+ if (isComplex)
+ {
+ writer.Write((byte)ArrayFlags.Complex);
+ }
+ else
+ {
+ writer.Write((byte)0);
+ }
+
+ writer.Write((short)0);
+ writer.Write(nzmax);
+
+ // write dimensions
+ writer.Write((int)DataType.Int32);
+ writer.Write(8);
+ writer.Write(rows);
+ writer.Write(columns);
+
+ var nameBytes = Encoding.ASCII.GetBytes(name);
+
+ // write name
+ if (nameBytes.Length > 4)
+ {
+ writer.Write((int)DataType.Int8);
+ writer.Write(nameBytes.Length);
+ writer.Write(nameBytes);
+ var pad = 8 - (nameBytes.Length%8);
+ PadData(writer, pad);
+ }
+ else
+ {
+ writer.Write((short)DataType.Int8);
+ writer.Write((short)nameBytes.Length);
+ writer.Write(nameBytes);
+ PadData(writer, 4 - nameBytes.Length);
+ }
+ }
+
+ ///
+ /// Gets the dense data array.
+ ///
+ /// The matrix to get the data from.
+ /// The name of the matrix.
+ /// The matrix data as an array.
+ static MatlabMatrix GetDenseDataArray(Matrix matrix, string name)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ WriteMatrixTagAndName(writer, ArrayClass.Double, false, name, matrix.RowCount, matrix.ColumnCount, 0);
+
+ // write data
+ writer.Write((int)DataType.Double);
+ writer.Write(matrix.RowCount*matrix.ColumnCount*8);
+
+ for (var j = 0; j < matrix.ColumnCount; j++)
+ {
+ var column = matrix.Column(j);
+ foreach (var value in column)
+ {
+ writer.Write(value);
+ }
+ }
+
+ writer.Flush();
+ return new MatlabMatrix(name, stream.ToArray());
+ }
+
+ }
+
+ ///
+ /// Gets the dense data array.
+ ///
+ /// The matrix to get the data from.
+ /// The name of the matrix.
+ /// The matrix data as an array.
+ static MatlabMatrix GetDenseDataArray(Matrix matrix, string name)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ WriteMatrixTagAndName(writer, ArrayClass.Single, false, name, matrix.RowCount, matrix.ColumnCount, 0);
+
+ // write data
+ int size = matrix.RowCount*matrix.ColumnCount*4;
+ writer.Write((int)DataType.Single);
+ writer.Write(size);
+
+ for (var j = 0; j < matrix.ColumnCount; j++)
+ {
+ var column = matrix.Column(j);
+ foreach (var value in column)
+ {
+ writer.Write(value);
+ }
+ }
+
+ PadData(writer, size%8);
+
+ writer.Flush();
+ return new MatlabMatrix(name, stream.ToArray());
+ }
+ }
+
+ ///
+ /// Gets the dense data array.
+ ///
+ /// The matrix to get the data from.
+ /// The name of the matrix.
+ /// The matrix data as an array.
+ static MatlabMatrix GetDenseDataArray(Matrix matrix, string name)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ WriteMatrixTagAndName(writer, ArrayClass.Double, true, name, matrix.RowCount, matrix.ColumnCount, 0);
+
+ // write data
+ int size = matrix.RowCount*matrix.ColumnCount*8;
+ writer.Write((int)DataType.Double);
+ writer.Write(size);
+
+ for (var j = 0; j < matrix.ColumnCount; j++)
+ {
+ var column = matrix.Column(j);
+ foreach (var value in column)
+ {
+ writer.Write(value.Real);
+ }
+ }
+
+ writer.Write((int)DataType.Double);
+ writer.Write(size);
+
+ for (var j = 0; j < matrix.ColumnCount; j++)
+ {
+ var column = matrix.Column(j);
+ foreach (var value in column)
+ {
+ writer.Write(value.Imaginary);
+ }
+ }
+
+ writer.Flush();
+ return new MatlabMatrix(name, stream.ToArray());
+ }
+ }
+
+ ///
+ /// Gets the dense data array.
+ ///
+ /// The matrix to get the data from.
+ /// The name of the matrix.
+ /// The matrix data as an array.
+ static MatlabMatrix GetDenseDataArray(Matrix matrix, string name)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ WriteMatrixTagAndName(writer, ArrayClass.Single, true, name, matrix.RowCount, matrix.ColumnCount, 0);
+
+ // write data
+ int size = matrix.RowCount*matrix.ColumnCount*4;
+ writer.Write((int)DataType.Single);
+ writer.Write(size);
+
+ for (var j = 0; j < matrix.ColumnCount; j++)
+ {
+ var column = matrix.Column(j);
+ foreach (var value in column)
+ {
+ writer.Write(value.Real);
+ }
+ }
+
+ PadData(writer, size%8);
+
+ writer.Write((int)DataType.Single);
+ writer.Write(size);
+
+ for (var j = 0; j < matrix.ColumnCount; j++)
+ {
+ var column = matrix.Column(j);
+ foreach (var value in column)
+ {
+ writer.Write(value.Real);
+ }
+ }
+
+ PadData(writer, size%8);
+
+ writer.Flush();
+ return new MatlabMatrix(name, stream.ToArray());
+ }
+ }
+
+ ///
+ /// Gets the sparse data array.
+ ///
+ /// The matrix to get the data from.
+ /// The name of the matrix.
+ /// The matrix data as an array.
+ static MatlabMatrix GetSparseDataArray(LinearAlgebra.Double.SparseMatrix matrix, string name)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ var nzmax = matrix.NonZerosCount;
+ WriteMatrixTagAndName(writer, ArrayClass.Sparse, false, name, matrix.RowCount, matrix.ColumnCount, nzmax);
+
+ // write ir
+ writer.Write((int)DataType.Int32);
+ writer.Write(nzmax*4);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item1);
+ }
+ }
+
+ // add pad if needed
+ if (nzmax%2 == 1)
+ {
+ writer.Write(0);
+ }
+
+ // write jc
+ writer.Write((int)DataType.Int32);
+ writer.Write((matrix.ColumnCount + 1)*4);
+ writer.Write(0);
+ var count = 0;
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ count += ((SparseVectorStorage)column.Storage).ValueCount;
+ writer.Write(count);
+ }
+
+ // add pad if needed
+ if (matrix.ColumnCount%2 == 0)
+ {
+ writer.Write(0);
+ }
+
+ // write data
+ writer.Write((int)DataType.Double);
+ writer.Write(nzmax*8);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item2);
+ }
+ }
+
+ writer.Flush();
+ return new MatlabMatrix(name, stream.ToArray());
+ }
+ }
+
+ ///
+ /// Gets the sparse data array.
+ ///
+ /// The matrix to get the data from.
+ /// The name of the matrix.
+ /// The matrix data as an array.
+ static MatlabMatrix GetSparseDataArray(LinearAlgebra.Single.SparseMatrix matrix, string name)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ var nzmax = matrix.NonZerosCount;
+ WriteMatrixTagAndName(writer, ArrayClass.Sparse, false, name, matrix.RowCount, matrix.ColumnCount,
+ nzmax);
+
+ // write ir
+ writer.Write((int)DataType.Int32);
+ writer.Write(nzmax*4);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item1);
+ }
+ }
+
+ // add pad if needed
+ if (nzmax%2 == 1)
+ {
+ writer.Write(0);
+ }
+
+ // write jc
+ writer.Write((int)DataType.Int32);
+ writer.Write((matrix.ColumnCount + 1)*4);
+ writer.Write(0);
+ var count = 0;
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ count += ((SparseVectorStorage)column.Storage).ValueCount;
+ writer.Write(count);
+ }
+
+ // add pad if needed
+ if (matrix.ColumnCount%2 == 0)
+ {
+ writer.Write(0);
+ }
+
+ // write data
+ writer.Write((int)DataType.Single);
+ writer.Write(nzmax*4);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item2);
+ }
+ }
+
+ var pad = nzmax*4%8;
+ PadData(writer, pad);
+
+ writer.Flush();
+ return new MatlabMatrix(name, stream.ToArray());
+ }
+ }
+
+ ///
+ /// Gets the sparse data array.
+ ///
+ /// The matrix to get the data from.
+ /// The name of the matrix.
+ /// The matrix data as an array.
+ static MatlabMatrix GetSparseDataArray(LinearAlgebra.Complex.SparseMatrix matrix, string name)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ var nzmax = matrix.NonZerosCount;
+ WriteMatrixTagAndName(writer, ArrayClass.Sparse, true, name, matrix.RowCount, matrix.ColumnCount,
+ nzmax);
+
+ // write ir
+ writer.Write((int)DataType.Int32);
+ writer.Write(nzmax*4);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item1);
+ }
+ }
+
+ // add pad if needed
+ if (nzmax%2 == 1)
+ {
+ writer.Write(0);
+ }
+
+ // write jc
+ writer.Write((int)DataType.Int32);
+ writer.Write((matrix.ColumnCount + 1)*4);
+ writer.Write(0);
+ var count = 0;
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ count += ((SparseVectorStorage)column.Storage).ValueCount;
+ writer.Write(count);
+ }
+
+ // add pad if needed
+ if (matrix.ColumnCount%2 == 0)
+ {
+ writer.Write(0);
+ }
+
+ // write data
+ writer.Write((int)DataType.Double);
+ writer.Write(nzmax*8);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item2.Real);
+ }
+ }
+
+ writer.Write((int)DataType.Double);
+ writer.Write(nzmax*8);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item2.Imaginary);
+ }
+ }
+
+ writer.Flush();
+ return new MatlabMatrix(name, stream.ToArray());
+ }
+ }
+
+ ///
+ /// Gets the sparse data array.
+ ///
+ /// The matrix to get the data from.
+ /// The name of the matrix.
+ /// The matrix data as an array.
+ static MatlabMatrix GetSparseDataArray(LinearAlgebra.Complex32.SparseMatrix matrix, string name)
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ var nzmax = matrix.NonZerosCount;
+ WriteMatrixTagAndName(writer, ArrayClass.Sparse, true, name, matrix.RowCount, matrix.ColumnCount,
+ nzmax);
+
+ // write ir
+ writer.Write((int)DataType.Int32);
+ writer.Write(nzmax*4);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item1);
+ }
+ }
+
+ // add pad if needed
+ if (nzmax%2 == 1)
+ {
+ writer.Write(0);
+ }
+
+ // write jc
+ writer.Write((int)DataType.Int32);
+ writer.Write((matrix.ColumnCount + 1)*4);
+ writer.Write(0);
+ var count = 0;
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ count += ((SparseVectorStorage)column.Storage).ValueCount;
+ writer.Write(count);
+ }
+
+ // add pad if needed
+ if (matrix.ColumnCount%2 == 0)
+ {
+ writer.Write(0);
+ }
+
+ // write data
+ writer.Write((int)DataType.Single);
+ writer.Write(nzmax*4);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item2.Real);
+ }
+ }
+
+ var pad = nzmax*4%8;
+ PadData(writer, pad);
+
+ writer.Write((int)DataType.Single);
+ writer.Write(nzmax*4);
+
+ foreach (var column in matrix.EnumerateColumns())
+ {
+ foreach (var row in column.EnumerateNonZeroIndexed())
+ {
+ writer.Write(row.Item2.Imaginary);
+ }
+ }
+
+ PadData(writer, pad);
+
+ writer.Flush();
+ return new MatlabMatrix(name, stream.ToArray());
+ }
+ }
+
+ ///
+ /// Writes the file header.
+ ///
+ static void WriteHeader(BinaryWriter writer)
+ {
+ var header = Encoding.ASCII.GetBytes(HeaderText + DateTime.Now.ToString(Resources.MatlabDateHeaderFormat));
+ writer.Write(header);
+ PadData(writer, HeaderTextLength - header.Length + 8, 32);
+
+ // write version
+ writer.Write((short)0x100);
+
+ // write little endian indicator
+ writer.Write((byte)0x49);
+ writer.Write((byte)0x4D);
+ }
+
+ ///
+ /// Pads the data with the given byte.
+ ///
+ /// Where to write the pad values.
+ /// The number of bytes to pad.
+ /// What value to pad with.
+ static void PadData(BinaryWriter writer, int bytes, byte pad = (byte)0)
+ {
+ for (var i = 0; i < bytes; i++)
+ {
+ writer.Write(pad);
+ }
+ }
+
+ ///
+ /// Writes the compressed data.
+ ///
+ /// The data to write.
+ static void WriteCompressedData(BinaryWriter writer, byte[] data)
+ {
+ // fill in data size
+ var size = BitConverter.GetBytes(data.Length);
+ data[4] = size[0];
+ data[5] = size[1];
+ data[6] = size[2];
+ data[7] = size[3];
+
+ // compress data
+ var compressedData = CompressData(data);
+
+ // write compressed data to file
+ writer.Write(compressedData.Length);
+ writer.Write(compressedData);
+ }
+
+ ///
+ /// Compresses the data array.
+ ///
+ /// The data to compress.
+ /// The compressed data.
+ static byte[] CompressData(byte[] data)
+ {
+ var adler = BitConverter.GetBytes(Adler32.Compute(data));
+ using (var compressedStream = new MemoryStream())
+ {
+ compressedStream.WriteByte(0x58);
+ compressedStream.WriteByte(0x85);
+ using (var outputStream = new DeflateStream(compressedStream, CompressionMode.Compress, true))
+ {
+ outputStream.Write(data, 0, data.Length);
+ }
+
+ compressedStream.WriteByte(adler[3]);
+ compressedStream.WriteByte(adler[2]);
+ compressedStream.WriteByte(adler[1]);
+ compressedStream.WriteByte(adler[0]);
+ return compressedStream.ToArray();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Data/Matlab/Matlab.csproj b/src/Data/Matlab/Matlab.csproj
index 08710462..76631e7a 100644
--- a/src/Data/Matlab/Matlab.csproj
+++ b/src/Data/Matlab/Matlab.csproj
@@ -52,6 +52,7 @@
+
diff --git a/src/Data/Matlab/MatlabMatrix.cs b/src/Data/Matlab/MatlabMatrix.cs
index 00f99c04..0d25634d 100644
--- a/src/Data/Matlab/MatlabMatrix.cs
+++ b/src/Data/Matlab/MatlabMatrix.cs
@@ -37,18 +37,16 @@ namespace MathNet.Numerics.Data.Matlab
/// Name of the matrix
public string Name { get; private set; }
- /// Matrix size in bytes
- public int Size { get; private set; }
-
- /// Number of dimensions
- public int Dimensions { get; private set; }
+ /// Size of the packed matrix in bytes
+ public int ByteSize
+ {
+ get { return Data.Length; }
+ }
- internal MatlabMatrix(string name, int size, int dimensions, byte[] data)
+ internal MatlabMatrix(string name, byte[] data)
{
Data = data;
Name = name;
- Size = size;
- Dimensions = dimensions;
}
}
}
diff --git a/src/Data/Matlab/MatlabReader.cs b/src/Data/Matlab/MatlabReader.cs
index 73f95ea1..5ad36534 100644
--- a/src/Data/Matlab/MatlabReader.cs
+++ b/src/Data/Matlab/MatlabReader.cs
@@ -37,7 +37,7 @@ using MathNet.Numerics.LinearAlgebra;
namespace MathNet.Numerics.Data.Matlab
{
///
- /// Creates matrices from MATLAB files.
+ /// Creates matrices from MATLAB 5 files.
///
public static class MatlabReader
{
@@ -46,7 +46,7 @@ namespace MathNet.Numerics.Data.Matlab
///
public static List List(Stream stream)
{
- return Parser.ParseAll(stream);
+ return Parser.ParseFile(stream);
}
///
@@ -56,7 +56,7 @@ namespace MathNet.Numerics.Data.Matlab
{
using (var stream = File.OpenRead(filePath))
{
- return Parser.ParseAll(stream);
+ return List(stream);
}
}
@@ -67,7 +67,7 @@ namespace MathNet.Numerics.Data.Matlab
public static Matrix Unpack(MatlabMatrix matrixData)
where TDataType : struct, IEquatable, IFormattable
{
- return Parser.ReadMatrixBlock(matrixData.Data);
+ return Parser.ParseMatrix(matrixData.Data);
}
///
@@ -77,11 +77,11 @@ namespace MathNet.Numerics.Data.Matlab
public static Matrix Read(Stream stream, string matrixName = null)
where TDataType : struct, IEquatable, IFormattable
{
- var matrices = Parser.ParseAll(stream);
+ var matrices = List(stream);
if (string.IsNullOrEmpty(matrixName))
{
- return Parser.ReadMatrixBlock(matrices.First().Data);
+ return Unpack(matrices.First());
}
var matrix = matrices.Find(m => m.Name == matrixName);
@@ -90,7 +90,7 @@ namespace MathNet.Numerics.Data.Matlab
throw new KeyNotFoundException("Matrix with the provided name was not found.");
}
- return Parser.ReadMatrixBlock(matrix.Data);
+ return Unpack(matrix);
}
///
@@ -114,9 +114,9 @@ namespace MathNet.Numerics.Data.Matlab
where TDataType : struct, IEquatable, IFormattable
{
var names = new HashSet(matrixNames);
- return Parser.ParseAll(stream)
+ return List(stream)
.Where(m => names.Count == 0 || names.Contains(m.Name))
- .ToDictionary(m => m.Name, m => Parser.ReadMatrixBlock(m.Data));
+ .ToDictionary(m => m.Name, Unpack);
}
///
diff --git a/src/Data/Matlab/MatlabWriter.cs b/src/Data/Matlab/MatlabWriter.cs
index ab43ecd5..a12359ee 100644
--- a/src/Data/Matlab/MatlabWriter.cs
+++ b/src/Data/Matlab/MatlabWriter.cs
@@ -31,789 +31,86 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.IO.Compression;
-using System.Numerics;
-using System.Text;
+using System.Linq;
using MathNet.Numerics.LinearAlgebra;
-using MathNet.Numerics.LinearAlgebra.Storage;
-using MathNet.Numerics.Properties;
namespace MathNet.Numerics.Data.Matlab
{
///
- /// Writes matrices to a MATLAB file.
+ /// Writes matrices to a MATLAB 5 file.
///
- public class MatlabWriter : IDisposable
+ public static class MatlabWriter
{
- ///
- /// The file header value
- ///
- const string HeaderText = "MATLAB 5.0 MAT-file, Platform: .NET 4 - Math.NET Numerics, Created on: ";
-
- ///
- /// The length of the header text.
- ///
- const int HeaderTextLength = 116;
-
- ///
- /// Have we written the header yet.
- ///
- bool _headerWritten;
-
- ///
- /// The binary writer to write to.
- ///
- BinaryWriter _writer;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The name of the MATLAB file to save the matrices to.
- public MatlabWriter(string filename)
+ public static void Store(Stream stream, IEnumerable matrices)
{
- if (string.IsNullOrEmpty(filename))
- {
- throw new ArgumentException(Resources.StringNullOrEmpty, "filename");
- }
-
- _writer =
- new BinaryWriter(
- new BufferedStream(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None)));
+ Formatter.FormatFile(stream, matrices);
}
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- ///
- public void Dispose()
+ public static void Store(string filePath, IEnumerable matrices)
{
- if (_writer != null)
+ using (var stream = File.OpenWrite(filePath))
{
- _writer.Flush();
- _writer.Close();
- _writer = null;
+ Store(stream, matrices);
}
}
- ///
- /// Writes the given to the file.
- ///
- /// The matrix to write.
- /// The name of the matrix to store in the file.
- /// If either or is null.
/// The data type of the Matrix. It can be either: double, float, Complex, or Complex32.
- public void WriteMatrix(Matrix matrix, string name)
+ public static MatlabMatrix Pack(Matrix matrix, string matrixName)
where TDataType : struct, IEquatable, IFormattable
{
- if (matrix == null)
- {
- throw new ArgumentNullException("matrix");
- }
-
- if (string.IsNullOrEmpty(name))
- {
- throw new ArgumentException(Resources.StringNullOrEmpty, "name");
- }
-
- if (name.IndexOf(' ') > -1)
- {
- throw new ArgumentException(string.Format(Resources.NameCannotContainASpace, name), "name");
- }
-
- if (!_headerWritten)
- {
- WriteHeader();
- _headerWritten = true;
- }
-
- // write data type
- _writer.Write((int)DataType.Compressed);
-
- byte[] data;
-
- if (typeof (TDataType) == typeof (double))
- {
- var o = matrix as LinearAlgebra.Double.SparseMatrix;
- data = o != null
- ? GetSparseDataArray((LinearAlgebra.Double.SparseMatrix)(object)matrix, name)
- : GetDenseDataArray((LinearAlgebra.Double.Matrix)(object)matrix, name);
- }
- else if (typeof (TDataType) == typeof (float))
- {
- var o = matrix as LinearAlgebra.Single.SparseMatrix;
- data = o != null
- ? GetSparseDataArray((LinearAlgebra.Single.SparseMatrix)(object)matrix, name)
- : GetDenseDataArray((LinearAlgebra.Single.Matrix)(object)matrix, name);
- }
- else if (typeof (TDataType) == typeof (Complex))
- {
- var o = matrix as LinearAlgebra.Complex.SparseMatrix;
- data = o != null
- ? GetSparseDataArray((LinearAlgebra.Complex.SparseMatrix)(object)matrix, name)
- : GetDenseDataArray((LinearAlgebra.Complex.Matrix)(object)matrix, name);
- }
- else if (typeof (TDataType) == typeof (Complex32))
- {
- var o = matrix as LinearAlgebra.Complex32.SparseMatrix;
- data = o != null
- ? GetSparseDataArray((LinearAlgebra.Complex32.SparseMatrix)(object)matrix, name)
- : GetDenseDataArray((LinearAlgebra.Complex32.Matrix)(object)matrix, name);
- }
- else
- {
- throw new NotSupportedException();
- }
-
- WriteCompressedData(data);
+ return Formatter.FormatMatrix(matrix, matrixName);
}
- ///
- /// Writes the given to the file.
- ///
- /// The matrices to write.
- /// The names of the matrices to store in the file.
- /// If either or is null.
/// The data type of the Matrix. It can be either: double, float, Complex, or Complex32.
- public void WriteMatrices(IList> matrices, IList names)
+ public static void Write(Stream stream, Matrix matrix, string matrixName)
where TDataType : struct, IEquatable, IFormattable
{
- if (matrices == null)
- {
- throw new ArgumentNullException("matrices");
- }
-
- if (names == null)
- {
- throw new ArgumentNullException("names");
- }
-
- if (matrices.Count != names.Count)
- {
- throw new ArgumentException(Resources.ArgumentMatrixDimensions);
- }
-
- for (var i = 0; i < matrices.Count; i++)
- {
- WriteMatrix(matrices[i], names[i]);
- }
- }
-
- ///
- /// Closes the stream the being written to.
- ///
- /// Calls .
- public void Close()
- {
- Dispose();
- }
-
- ///
- /// Writes the matrix tag and name.
- ///
- /// The writer we are using.
- /// The array class we are writing.
- /// if set to true if this a complex matrix.
- /// The name of the matrix.
- /// The number of rows.
- /// The columns of columns.
- /// The maximum number of non-zero elements.
- static void WriteMatrixTagAndName(BinaryWriter writer, ArrayClass arrayClass, bool isComplex,
- string name, int rows, int columns, int nzmax)
- {
- writer.Write((int)DataType.Matrix);
-
- // add place holder for data size
- writer.Write(0);
-
- // write flag, data type and size
- writer.Write((int)DataType.UInt32);
- writer.Write(8);
-
- // write array class and flags
- writer.Write((byte)arrayClass);
- if (isComplex)
- {
- writer.Write((byte)ArrayFlags.Complex);
- }
- else
- {
- writer.Write((byte)0);
- }
-
- writer.Write((short)0);
- writer.Write(nzmax);
-
- // write dimensions
- writer.Write((int)DataType.Int32);
- writer.Write(8);
- writer.Write(rows);
- writer.Write(columns);
-
- var nameBytes = Encoding.ASCII.GetBytes(name);
-
- // write name
- if (nameBytes.Length > 4)
- {
- writer.Write((int)DataType.Int8);
- writer.Write(nameBytes.Length);
- writer.Write(nameBytes);
- var pad = 8 - (nameBytes.Length%8);
- PadData(writer, pad);
- }
- else
- {
- writer.Write((short)DataType.Int8);
- writer.Write((short)nameBytes.Length);
- writer.Write(nameBytes);
- PadData(writer, 4 - nameBytes.Length);
- }
- }
-
- ///
- /// Compresses the data array.
- ///
- /// The data to compress.
- /// The compressed data.
- static byte[] CompressData(byte[] data)
- {
- var adler = BitConverter.GetBytes(Adler32.Compute(data));
- using (var compressedStream = new MemoryStream())
- {
- compressedStream.WriteByte(0x58);
- compressedStream.WriteByte(0x85);
- using (var outputStream = new DeflateStream(compressedStream, CompressionMode.Compress, true))
- {
- outputStream.Write(data, 0, data.Length);
- }
-
- compressedStream.WriteByte(adler[3]);
- compressedStream.WriteByte(adler[2]);
- compressedStream.WriteByte(adler[1]);
- compressedStream.WriteByte(adler[0]);
- return compressedStream.ToArray();
- }
- }
-
- ///
- /// Gets the dense data array.
- ///
- /// The matrix to get the data from.
- /// The name of the matrix.
- /// The matrix data as an array.
- static byte[] GetDenseDataArray(Matrix matrix, string name)
- {
- byte[] data;
- using (var dataMemoryStream = new MemoryStream())
- using (var dataWriter = new BinaryWriter(dataMemoryStream))
- {
- WriteMatrixTagAndName(dataWriter, ArrayClass.Double, false, name, matrix.RowCount, matrix.ColumnCount, 0);
-
- // write data
- dataWriter.Write((int)DataType.Double);
- dataWriter.Write(matrix.RowCount*matrix.ColumnCount*8);
-
- for (var j = 0; j < matrix.ColumnCount; j++)
- {
- var column = matrix.Column(j);
- foreach (var value in column)
- {
- dataWriter.Write(value);
- }
- }
-
- data = dataMemoryStream.ToArray();
- }
-
- return data;
- }
-
- ///
- /// Gets the dense data array.
- ///
- /// The matrix to get the data from.
- /// The name of the matrix.
- /// The matrix data as an array.
- static byte[] GetDenseDataArray(Matrix matrix, string name)
- {
- byte[] data;
- using (var dataMemoryStream = new MemoryStream())
- using (var dataWriter = new BinaryWriter(dataMemoryStream))
- {
- WriteMatrixTagAndName(dataWriter, ArrayClass.Single, false, name, matrix.RowCount, matrix.ColumnCount, 0);
-
- // write data
- dataWriter.Write((int)DataType.Single);
-
- dataWriter.Write(matrix.RowCount*matrix.ColumnCount*4);
-
- for (var j = 0; j < matrix.ColumnCount; j++)
- {
- var column = matrix.Column(j);
- foreach (var value in column)
- {
- dataWriter.Write(value);
- }
- }
-
- var pad = (matrix.RowCount*matrix.ColumnCount*4)%8;
- PadData(dataWriter, pad);
-
- data = dataMemoryStream.ToArray();
- }
-
- return data;
- }
-
- ///
- /// Gets the dense data array.
- ///
- /// The matrix to get the data from.
- /// The name of the matrix.
- /// The matrix data as an array.
- static byte[] GetDenseDataArray(Matrix matrix, string name)
- {
- byte[] data;
- using (var dataMemoryStream = new MemoryStream())
- using (var dataWriter = new BinaryWriter(dataMemoryStream))
- {
- WriteMatrixTagAndName(dataWriter, ArrayClass.Double, true, name, matrix.RowCount, matrix.ColumnCount, 0);
-
- // write data
- dataWriter.Write((int)DataType.Double);
- dataWriter.Write(matrix.RowCount*matrix.ColumnCount*8);
-
- for (var j = 0; j < matrix.ColumnCount; j++)
- {
- var column = matrix.Column(j);
- foreach (var value in column)
- {
- dataWriter.Write(value.Real);
- }
- }
-
- dataWriter.Write((int)DataType.Double);
- dataWriter.Write(matrix.RowCount*matrix.ColumnCount*8);
-
- for (var j = 0; j < matrix.ColumnCount; j++)
- {
- var column = matrix.Column(j);
- foreach (var value in column)
- {
- dataWriter.Write(value.Imaginary);
- }
- }
-
- data = dataMemoryStream.ToArray();
- }
-
- return data;
- }
-
- ///
- /// Gets the dense data array.
- ///
- /// The matrix to get the data from.
- /// The name of the matrix.
- /// The matrix data as an array.
- static byte[] GetDenseDataArray(Matrix matrix, string name)
- {
- byte[] data;
- using (var dataMemoryStream = new MemoryStream())
- using (var dataWriter = new BinaryWriter(dataMemoryStream))
- {
- WriteMatrixTagAndName(dataWriter, ArrayClass.Single, true, name, matrix.RowCount, matrix.ColumnCount, 0);
-
- // write data
- dataWriter.Write((int)DataType.Single);
- dataWriter.Write(matrix.RowCount*matrix.ColumnCount*4);
-
- for (var j = 0; j < matrix.ColumnCount; j++)
- {
- var column = matrix.Column(j);
- foreach (var value in column)
- {
- dataWriter.Write(value.Real);
- }
- }
-
- var pad = (matrix.RowCount*matrix.ColumnCount*4)%8;
- PadData(dataWriter, pad);
-
- dataWriter.Write((int)DataType.Single);
- dataWriter.Write(matrix.RowCount*matrix.ColumnCount*4);
-
- for (var j = 0; j < matrix.ColumnCount; j++)
- {
- var column = matrix.Column(j);
- foreach (var value in column)
- {
- dataWriter.Write(value.Real);
- }
- }
-
- PadData(dataWriter, pad);
-
- data = dataMemoryStream.ToArray();
- }
-
- return data;
- }
-
- ///
- /// Gets the sparse data array.
- ///
- /// The matrix to get the data from.
- /// The name of the matrix.
- /// The matrix data as an array.
- static byte[] GetSparseDataArray(LinearAlgebra.Double.SparseMatrix matrix, string name)
- {
- byte[] data;
- using (var dataMemoryStream = new MemoryStream())
- using (var dataWriter = new BinaryWriter(dataMemoryStream))
- {
- var nzmax = matrix.NonZerosCount;
- WriteMatrixTagAndName(dataWriter, ArrayClass.Sparse, false, name, matrix.RowCount, matrix.ColumnCount,
- nzmax);
-
- // write ir
- dataWriter.Write((int)DataType.Int32);
- dataWriter.Write(nzmax*4);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item1);
- }
- }
-
- // add pad if needed
- if (nzmax%2 == 1)
- {
- dataWriter.Write(0);
- }
-
- // write jc
- dataWriter.Write((int)DataType.Int32);
- dataWriter.Write((matrix.ColumnCount + 1)*4);
- dataWriter.Write(0);
- var count = 0;
- foreach (var column in matrix.EnumerateColumns())
- {
- count += ((SparseVectorStorage)column.Storage).ValueCount;
- dataWriter.Write(count);
- }
-
- // add pad if needed
- if (matrix.ColumnCount%2 == 0)
- {
- dataWriter.Write(0);
- }
-
- // write data
- dataWriter.Write((int)DataType.Double);
- dataWriter.Write(nzmax*8);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item2);
- }
- }
-
- data = dataMemoryStream.ToArray();
- }
-
- return data;
+ Store(stream, new[] { Pack(matrix, matrixName) });
}
- ///
- /// Gets the sparse data array.
- ///
- /// The matrix to get the data from.
- /// The name of the matrix.
- /// The matrix data as an array.
- static byte[] GetSparseDataArray(LinearAlgebra.Single.SparseMatrix matrix, string name)
+ /// The data type of the Matrix. It can be either: double, float, Complex, or Complex32.
+ public static void Write(string filePath, Matrix matrix, string matrixName)
+ where TDataType : struct, IEquatable, IFormattable
{
- byte[] data;
- using (var dataMemoryStream = new MemoryStream())
- using (var dataWriter = new BinaryWriter(dataMemoryStream))
- {
- var nzmax = matrix.NonZerosCount;
- WriteMatrixTagAndName(dataWriter, ArrayClass.Sparse, false, name, matrix.RowCount, matrix.ColumnCount,
- nzmax);
-
- // write ir
- dataWriter.Write((int)DataType.Int32);
- dataWriter.Write(nzmax*4);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item1);
- }
- }
-
- // add pad if needed
- if (nzmax%2 == 1)
- {
- dataWriter.Write(0);
- }
-
- // write jc
- dataWriter.Write((int)DataType.Int32);
- dataWriter.Write((matrix.ColumnCount + 1)*4);
- dataWriter.Write(0);
- var count = 0;
- foreach (var column in matrix.EnumerateColumns())
- {
- count += ((SparseVectorStorage)column.Storage).ValueCount;
- dataWriter.Write(count);
- }
-
- // add pad if needed
- if (matrix.ColumnCount%2 == 0)
- {
- dataWriter.Write(0);
- }
-
- // write data
- dataWriter.Write((int)DataType.Single);
- dataWriter.Write(nzmax*4);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item2);
- }
- }
-
- var pad = (nzmax*4)%8;
- PadData(dataWriter, pad);
-
- data = dataMemoryStream.ToArray();
- }
-
- return data;
+ Store(filePath, new[] { Pack(matrix, matrixName) });
}
- ///
- /// Gets the sparse data array.
- ///
- /// The matrix to get the data from.
- /// The name of the matrix.
- /// The matrix data as an array.
- static byte[] GetSparseDataArray(LinearAlgebra.Complex.SparseMatrix matrix, string name)
+ /// The data type of the Matrix. It can be either: double, float, Complex, or Complex32.
+ public static void Write(Stream stream, IList> matrices, IList names)
+ where TDataType : struct, IEquatable, IFormattable
{
- byte[] data;
- using (var dataMemoryStream = new MemoryStream())
- using (var dataWriter = new BinaryWriter(dataMemoryStream))
+ if (matrices.Count != names.Count)
{
- var nzmax = matrix.NonZerosCount;
- WriteMatrixTagAndName(dataWriter, ArrayClass.Sparse, true, name, matrix.RowCount, matrix.ColumnCount,
- nzmax);
-
- // write ir
- dataWriter.Write((int)DataType.Int32);
- dataWriter.Write(nzmax*4);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item1);
- }
- }
-
- // add pad if needed
- if (nzmax%2 == 1)
- {
- dataWriter.Write(0);
- }
-
- // write jc
- dataWriter.Write((int)DataType.Int32);
- dataWriter.Write((matrix.ColumnCount + 1)*4);
- dataWriter.Write(0);
- var count = 0;
- foreach (var column in matrix.EnumerateColumns())
- {
- count += ((SparseVectorStorage)column.Storage).ValueCount;
- dataWriter.Write(count);
- }
-
- // add pad if needed
- if (matrix.ColumnCount%2 == 0)
- {
- dataWriter.Write(0);
- }
-
- // write data
- dataWriter.Write((int)DataType.Double);
- dataWriter.Write(nzmax*8);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item2.Real);
- }
- }
-
- dataWriter.Write((int)DataType.Double);
- dataWriter.Write(nzmax*8);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item2.Real);
- }
- }
-
- data = dataMemoryStream.ToArray();
+ throw new ArgumentException("Each matrix must have a name. Number of matrices must equal to the number of names.");
}
- return data;
+ Store(stream, matrices.Zip(names, Pack));
}
- ///
- /// Gets the sparse data array.
- ///
- /// The matrix to get the data from.
- /// The name of the matrix.
- /// The matrix data as an array.
- static byte[] GetSparseDataArray(LinearAlgebra.Complex32.SparseMatrix matrix, string name)
+ /// The data type of the Matrix. It can be either: double, float, Complex, or Complex32.
+ public static void Write(string filePath, IList> matrices, IList names)
+ where TDataType : struct, IEquatable, IFormattable
{
- byte[] data;
- using (var dataMemoryStream = new MemoryStream())
- using (var dataWriter = new BinaryWriter(dataMemoryStream))
+ if (matrices.Count != names.Count)
{
- var nzmax = matrix.NonZerosCount;
- WriteMatrixTagAndName(dataWriter, ArrayClass.Sparse, true, name, matrix.RowCount, matrix.ColumnCount,
- nzmax);
-
- // write ir
- dataWriter.Write((int)DataType.Int32);
- dataWriter.Write(nzmax*4);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item1);
- }
- }
-
- // add pad if needed
- if (nzmax%2 == 1)
- {
- dataWriter.Write(0);
- }
-
- // write jc
- dataWriter.Write((int)DataType.Int32);
- dataWriter.Write((matrix.ColumnCount + 1)*4);
- dataWriter.Write(0);
- var count = 0;
- foreach (var column in matrix.EnumerateColumns())
- {
- count += ((SparseVectorStorage)column.Storage).ValueCount;
- dataWriter.Write(count);
- }
-
- // add pad if needed
- if (matrix.ColumnCount%2 == 0)
- {
- dataWriter.Write(0);
- }
-
- // write data
- dataWriter.Write((int)DataType.Single);
- dataWriter.Write(nzmax*4);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item2.Real);
- }
- }
-
- var pad = (nzmax*4)%8;
- PadData(dataWriter, pad);
-
- dataWriter.Write((int)DataType.Single);
- dataWriter.Write(nzmax*4);
-
- foreach (var column in matrix.EnumerateColumns())
- {
- foreach (var row in column.EnumerateNonZeroIndexed())
- {
- dataWriter.Write(row.Item2.Real);
- }
- }
-
- PadData(dataWriter, pad);
-
- data = dataMemoryStream.ToArray();
+ throw new ArgumentException("Each matrix must have a name. Number of matrices must equal to the number of names.");
}
- return data;
+ Store(filePath, matrices.Zip(names, Pack));
}
- ///
- /// Writes the compressed data.
- ///
- /// The data to write.
- void WriteCompressedData(byte[] data)
- {
- // fill in data size
- var size = BitConverter.GetBytes(data.Length);
- data[4] = size[0];
- data[5] = size[1];
- data[6] = size[2];
- data[7] = size[3];
-
- // compress data
- var compressedData = CompressData(data);
-
- // write compressed data to file
- _writer.Write(compressedData.Length);
- _writer.Write(compressedData);
- }
-
- ///
- /// Writes the file header.
- ///
- void WriteHeader()
+ /// The data type of the Matrix. It can be either: double, float, Complex, or Complex32.
+ public static void Write(Stream stream, IEnumerable>> matrices)
+ where TDataType : struct, IEquatable, IFormattable
{
- var header = Encoding.ASCII.GetBytes(HeaderText + DateTime.Now.ToString(Resources.MatlabDateHeaderFormat));
- _writer.Write(header);
- PadData(_writer, HeaderTextLength - header.Length + 8, 32);
-
- // write version
- _writer.Write((short)0x100);
-
- // write little endian indicator
- _writer.Write((byte)0x49);
- _writer.Write((byte)0x4D);
+ Store(stream, matrices.Select(kv => Pack(kv.Value, kv.Key)));
}
- ///
- /// Pads the data with the given byte.
- ///
- /// Where to write the pad values.
- /// The number of bytes to pad.
- /// What value to pad with.
- static void PadData(BinaryWriter writer, int bytes, byte pad = (byte)0)
+ /// The data type of the Matrix. It can be either: double, float, Complex, or Complex32.
+ public static void Write(string filePath, IEnumerable>> matrices)
+ where TDataType : struct, IEquatable, IFormattable
{
- for (var i = 0; i < bytes; i++)
- {
- writer.Write(pad);
- }
+ Store(filePath, matrices.Select(kv => Pack(kv.Value, kv.Key)));
}
}
}
diff --git a/src/Data/Matlab/Parser.cs b/src/Data/Matlab/Parser.cs
index a2f297be..b4533cc5 100644
--- a/src/Data/Matlab/Parser.cs
+++ b/src/Data/Matlab/Parser.cs
@@ -59,9 +59,79 @@ namespace MathNet.Numerics.Data.Matlab
const int SmallBlockSize = 4;
///
- /// Extracts all matrix blocks in a format we support.
+ /// Parse a matrix block byte array
///
- internal static List ParseAll(Stream stream)
+ internal static Matrix ParseMatrix(byte[] data)
+ where T : struct, IEquatable, IFormattable
+ {
+ using (var stream = new MemoryStream(data))
+ using (var reader = new BinaryReader(stream))
+ {
+ // skip tag - doesn't tell us anything we don't already know
+ reader.BaseStream.Seek(8, SeekOrigin.Current);
+
+ var arrayClass = (ArrayClass)reader.ReadByte();
+ var flags = reader.ReadByte();
+ var isComplex = (flags & (byte)ArrayFlags.Complex) == (byte)ArrayFlags.Complex;
+
+ // skip unneeded bytes
+ reader.BaseStream.Seek(10, SeekOrigin.Current);
+
+ var numDimensions = reader.ReadInt32()/8;
+ if (numDimensions > 2)
+ {
+ throw new NotSupportedException(Resources.MoreThan2D);
+ }
+
+ var rows = reader.ReadInt32();
+ var columns = reader.ReadInt32();
+
+ // skip name and unneeded bytes
+ reader.BaseStream.Seek(2, SeekOrigin.Current);
+ int size = reader.ReadInt16();
+ var smallBlock = true;
+ if (size == 0)
+ {
+ size = reader.ReadInt32();
+ smallBlock = false;
+ }
+
+ reader.BaseStream.Seek(size, SeekOrigin.Current);
+ AlignData(reader.BaseStream, size, smallBlock);
+
+ var type = (DataType)reader.ReadInt16();
+ size = reader.ReadInt16();
+ if (size == 0)
+ {
+ size = reader.ReadInt32();
+ }
+
+ Matrix matrix;
+ switch (arrayClass)
+ {
+ case ArrayClass.Sparse:
+ matrix = SparseArrayReader.PopulateSparseMatrix(reader, isComplex, rows, columns, size);
+ break;
+ case ArrayClass.Function:
+ case ArrayClass.Character:
+ case ArrayClass.Object:
+ case ArrayClass.Structure:
+ case ArrayClass.Cell:
+ case ArrayClass.Unknown:
+ throw new NotSupportedException();
+ default:
+ matrix = NumericArrayReader.PopulateDenseMatrix(type, reader, isComplex, rows, columns, size);
+ break;
+ }
+
+ return matrix;
+ }
+ }
+
+ ///
+ /// Extracts all matrix blocks in a format we support from a stream.
+ ///
+ internal static List ParseFile(Stream stream)
{
var matrices = new List();
@@ -122,7 +192,7 @@ namespace MathNet.Numerics.Data.Matlab
var matrixName = Encoding.ASCII.GetString(matrixReader.ReadBytes(matrixSize));
- matrices.Add(new MatlabMatrix(matrixName, matrixSize, matrixDim, data));
+ matrices.Add(new MatlabMatrix(matrixName, data));
}
}
}
@@ -176,72 +246,5 @@ namespace MathNet.Numerics.Data.Matlab
return data;
}
-
- internal static Matrix ReadMatrixBlock(byte[] data)
- where TDataType : struct, IEquatable, IFormattable
- {
- using (var stream = new MemoryStream(data))
- using (var reader = new BinaryReader(stream))
- {
- // skip tag - doesn't tell us anything we don't already know
- reader.BaseStream.Seek(8, SeekOrigin.Current);
-
- var arrayClass = (ArrayClass)reader.ReadByte();
- var flags = reader.ReadByte();
- var isComplex = (flags & (byte)ArrayFlags.Complex) == (byte)ArrayFlags.Complex;
-
- // skip unneeded bytes
- reader.BaseStream.Seek(10, SeekOrigin.Current);
-
- var numDimensions = reader.ReadInt32()/8;
- if (numDimensions > 2)
- {
- throw new NotSupportedException(Resources.MoreThan2D);
- }
-
- var rows = reader.ReadInt32();
- var columns = reader.ReadInt32();
-
- // skip name and unneeded bytes
- reader.BaseStream.Seek(2, SeekOrigin.Current);
- int size = reader.ReadInt16();
- var smallBlock = true;
- if (size == 0)
- {
- size = reader.ReadInt32();
- smallBlock = false;
- }
-
- reader.BaseStream.Seek(size, SeekOrigin.Current);
- AlignData(reader.BaseStream, size, smallBlock);
-
- var type = (DataType)reader.ReadInt16();
- size = reader.ReadInt16();
- if (size == 0)
- {
- size = reader.ReadInt32();
- }
-
- Matrix matrix;
- switch (arrayClass)
- {
- case ArrayClass.Sparse:
- matrix = SparseArrayReader.PopulateSparseMatrix(reader, isComplex, rows, columns, size);
- break;
- case ArrayClass.Function:
- case ArrayClass.Character:
- case ArrayClass.Object:
- case ArrayClass.Structure:
- case ArrayClass.Cell:
- case ArrayClass.Unknown:
- throw new NotSupportedException();
- default:
- matrix = NumericArrayReader.PopulateDenseMatrix(type, reader, isComplex, rows, columns, size);
- break;
- }
-
- return matrix;
- }
- }
}
}
diff --git a/src/DataUnitTests/Matlab/MatlabWriterTests.cs b/src/DataUnitTests/Matlab/MatlabWriterTests.cs
index 1e879711..fd50abba 100644
--- a/src/DataUnitTests/Matlab/MatlabWriterTests.cs
+++ b/src/DataUnitTests/Matlab/MatlabWriterTests.cs
@@ -28,158 +28,120 @@ using System;
using System.IO;
using System.Numerics;
using MathNet.Numerics.Data.Matlab;
+using MathNet.Numerics.LinearAlgebra;
using NUnit.Framework;
namespace MathNet.Numerics.Data.UnitTests.Matlab
{
///
- /// Matlab matrix writer tests.
+ /// MATLAB matrix writer tests.
///
[TestFixture]
public class MatlabWriterTests
{
- ///
- /// Invalid constructor throws ArgumentException.
- ///
- [Test]
- public void InvalidConstructorThrowsArgumentException()
- {
- Assert.Throws(() => new MatlabWriter(string.Empty));
- Assert.Throws(() => new MatlabWriter(null));
- }
-
- ///
- /// Write bad matrices throws ArgumentException.
- ///
[Test]
public void WriteBadMatricesThrowsArgumentException()
{
- var matrix = new LinearAlgebra.Single.DenseMatrix(1, 1);
- var writer = new MatlabWriter("somefile3");
- Assert.Throws(() => writer.WriteMatrices(new[] { matrix }, new[] { string.Empty }));
- Assert.Throws(() => writer.WriteMatrices(new[] { matrix }, new string[] { null }));
- Assert.Throws(() => writer.WriteMatrices(new[] { matrix, matrix }, new[] { "matrix" }));
- Assert.Throws(() => writer.WriteMatrices(new[] { matrix }, new[] { "some matrix" }));
- writer.Dispose();
- }
-
- ///
- /// Write null matrices throws ArgumentNullException.
- ///
- [Test]
- public void WriteNullMatricesThrowsArgumentNullException()
- {
- var writer = new MatlabWriter("somefile4");
- Assert.Throws(() => writer.WriteMatrices(new LinearAlgebra.Single.Matrix[] { null }, new[] { "matrix" }));
- var matrix = new LinearAlgebra.Single.DenseMatrix(1, 1);
- Assert.Throws(() => writer.WriteMatrices(new LinearAlgebra.Single.Matrix[] { matrix }, null));
- writer.Dispose();
+ Matrix matrix = Matrix.Build.Dense(1, 1);
+ Assert.Throws(() => MatlabWriter.Write("somefile3", matrix, string.Empty));
+ Assert.Throws(() => MatlabWriter.Write("somefile3", matrix, null));
+ Assert.Throws(() => MatlabWriter.Write("somefile3", matrix, "some matrix"));
+ Assert.Throws(() => MatlabWriter.Write("somefile3", new[] { matrix }, new[] { string.Empty }));
+ Assert.Throws(() => MatlabWriter.Write("somefile3", new[] { matrix }, new string[] { null }));
+ Assert.Throws(() => MatlabWriter.Write("somefile3", new[] { matrix, matrix }, new[] { "matrix" }));
+ Assert.Throws(() => MatlabWriter.Write("somefile3", new[] { matrix }, new[] { "some matrix" }));
}
- ///
- /// Can write double matrices.
- ///
[Test]
public void CanWriteDoubleMatrices()
{
- var mat1 = new LinearAlgebra.Double.DenseMatrix(5, 3);
+ Matrix mat1 = Matrix.Build.Dense(5, 5);
for (var i = 0; i < mat1.ColumnCount; i++)
{
mat1[i, i] = i + .1;
}
- var mat2 = new LinearAlgebra.Double.DenseMatrix(4, 5);
+ Matrix mat2 = Matrix.Build.Dense(4, 5);
for (var i = 0; i < mat2.RowCount; i++)
{
mat2[i, i] = i + .1;
}
- var mat3 = new LinearAlgebra.Double.SparseMatrix(5, 4);
+ Matrix mat3 = Matrix.Build.Sparse(5, 4);
mat3[0, 0] = 1.1;
mat3[0, 2] = 2.2;
mat3[4, 3] = 3.3;
- var mat4 = new LinearAlgebra.Double.SparseMatrix(3, 5);
+ Matrix mat4 = Matrix.Build.Sparse(3, 5);
mat4[0, 0] = 1.1;
mat4[0, 2] = 2.2;
mat4[2, 4] = 3.3;
- var write = new LinearAlgebra.Double.Matrix[] { mat1, mat2, mat3, mat4 };
+ Matrix[] write = { mat1, mat2, mat3, mat4 };
+ string[] names = { "mat1", "dense_matrix_2", "s1", "sparse2" };
- var names = new[] { "mat1", "dense_matrix_2", "s1", "sparse2" };
if (File.Exists("testd.mat"))
{
File.Delete("testd.mat");
}
- var writer = new MatlabWriter("testd.mat");
- writer.WriteMatrices(write, names);
- writer.Dispose();
+ MatlabWriter.Write("testd.mat", write, names);
var read = MatlabReader.ReadAll("testd.mat", names);
-
Assert.AreEqual(write.Length, read.Count);
for (var i = 0; i < write.Length; i++)
{
var w = write[i];
var r = read[names[i]];
-
Assert.AreEqual(w.RowCount, r.RowCount);
Assert.AreEqual(w.ColumnCount, r.ColumnCount);
Assert.IsTrue(w.Equals(r));
}
}
- ///
- /// Can write float matrices.
- ///
[Test]
public void CanWriteFloatMatrices()
{
- var mat1 = new LinearAlgebra.Single.DenseMatrix(5, 3);
+ Matrix mat1 = Matrix.Build.Dense(5, 3);
for (var i = 0; i < mat1.ColumnCount; i++)
{
mat1[i, i] = i + .1f;
}
- var mat2 = new LinearAlgebra.Single.DenseMatrix(4, 5);
+ Matrix mat2 = Matrix.Build.Dense(4, 5);
for (var i = 0; i < mat2.RowCount; i++)
{
mat2[i, i] = i + .1f;
}
- var mat3 = new LinearAlgebra.Single.SparseMatrix(5, 4);
+ Matrix mat3 = Matrix.Build.Sparse(5, 4);
mat3[0, 0] = 1.1f;
mat3[0, 2] = 2.2f;
mat3[4, 3] = 3.3f;
- var mat4 = new LinearAlgebra.Single.SparseMatrix(3, 5);
+ Matrix mat4 = Matrix.Build.Sparse(3, 5);
mat4[0, 0] = 1.1f;
mat4[0, 2] = 2.2f;
mat4[2, 4] = 3.3f;
- var write = new LinearAlgebra.Single.Matrix[] { mat1, mat2, mat3, mat4 };
+ Matrix[] write = { mat1, mat2, mat3, mat4 };
+ string[] names = { "mat1", "dense_matrix_2", "s1", "sparse2" };
- var names = new[] { "mat1", "dense_matrix_2", "s1", "sparse2" };
if (File.Exists("tests.mat"))
{
File.Delete("tests.mat");
}
- var writer = new MatlabWriter("tests.mat");
- writer.WriteMatrices(write, names);
- writer.Dispose();
+ MatlabWriter.Write("tests.mat", write, names);
var read = MatlabReader.ReadAll("tests.mat", names);
-
Assert.AreEqual(write.Length, read.Count);
for (var i = 0; i < write.Length; i++)
{
var w = write[i];
var r = read[names[i]];
-
Assert.AreEqual(w.RowCount, r.RowCount);
Assert.AreEqual(w.ColumnCount, r.ColumnCount);
Assert.IsTrue(w.Equals(r));
@@ -192,40 +154,37 @@ namespace MathNet.Numerics.Data.UnitTests.Matlab
[Test]
public void CanWriteComplex32Matrices()
{
- var mat1 = new LinearAlgebra.Complex32.DenseMatrix(5, 3);
+ Matrix mat1 = Matrix.Build.Dense(5, 3);
for (var i = 0; i < mat1.ColumnCount; i++)
{
mat1[i, i] = new Complex32(i + .1f, i + .1f);
}
- var mat2 = new LinearAlgebra.Complex32.DenseMatrix(4, 5);
+ Matrix mat2 = Matrix.Build.Dense(4, 5);
for (var i = 0; i < mat2.RowCount; i++)
{
mat2[i, i] = new Complex32(i + .1f, i + .1f);
}
- var mat3 = new LinearAlgebra.Complex32.SparseMatrix(5, 4);
+ Matrix mat3 = Matrix.Build.Sparse(5, 4);
mat3[0, 0] = new Complex32(1.1f, 1.1f);
mat3[0, 2] = new Complex32(2.2f, 2.2f);
mat3[4, 3] = new Complex32(3.3f, 3.3f);
- var mat4 = new LinearAlgebra.Complex32.SparseMatrix(3, 5);
+ Matrix mat4 = Matrix.Build.Sparse(3, 5);
mat4[0, 0] = new Complex32(1.1f, 1.1f);
mat4[0, 2] = new Complex32(2.2f, 2.2f);
mat4[2, 4] = new Complex32(3.3f, 3.3f);
- var write = new LinearAlgebra.Complex32.Matrix[] { mat1, mat2, mat3, mat4 };
+ Matrix[] write = { mat1, mat2, mat3, mat4 };
+ string[] names = { "mat1", "dense_matrix_2", "s1", "sparse2" };
- var names = new[] { "mat1", "dense_matrix_2", "s1", "sparse2" };
if (File.Exists("testc.mat"))
{
File.Delete("testc.mat");
}
- var writer = new MatlabWriter("testc.mat");
- writer.WriteMatrices(write, names);
- writer.Dispose();
-
+ MatlabWriter.Write("testc.mat", write, names);
var read = MatlabReader.ReadAll("testc.mat", names);
Assert.AreEqual(write.Length, read.Count);
@@ -234,7 +193,6 @@ namespace MathNet.Numerics.Data.UnitTests.Matlab
{
var w = write[i];
var r = read[names[i]];
-
Assert.AreEqual(w.RowCount, r.RowCount);
Assert.AreEqual(w.ColumnCount, r.ColumnCount);
Assert.IsTrue(w.Equals(r));
@@ -247,49 +205,45 @@ namespace MathNet.Numerics.Data.UnitTests.Matlab
[Test]
public void CanWriteComplexMatrices()
{
- var mat1 = new LinearAlgebra.Complex.DenseMatrix(5, 3);
+ Matrix mat1 = Matrix.Build.Dense(5, 3);
for (var i = 0; i < mat1.ColumnCount; i++)
{
mat1[i, i] = new Complex(i + .1, i + .1);
}
- var mat2 = new LinearAlgebra.Complex.DenseMatrix(4, 5);
+ Matrix mat2 = Matrix.Build.Dense(4, 5);
for (var i = 0; i < mat2.RowCount; i++)
{
mat2[i, i] = new Complex(i + .1, i + .1);
}
- var mat3 = new LinearAlgebra.Complex.SparseMatrix(5, 4);
+ Matrix mat3 = Matrix.Build.Sparse(5, 4);
mat3[0, 0] = new Complex(1.1, 1.1);
mat3[0, 2] = new Complex(2.2, 2.2);
mat3[4, 3] = new Complex(3.3, 3.3);
- var mat4 = new LinearAlgebra.Complex.SparseMatrix(3, 5);
+ Matrix mat4 = Matrix.Build.Sparse(3, 5);
mat4[0, 0] = new Complex(1.1, 1.1);
mat4[0, 2] = new Complex(2.2, 2.2);
mat4[2, 4] = new Complex(3.3, 3.3);
- var write = new LinearAlgebra.Complex.Matrix[] { mat1, mat2, mat3, mat4 };
+ Matrix[] write = { mat1, mat2, mat3, mat4 };
+ string[] names = { "mat1", "dense_matrix_2", "s1", "sparse2" };
- var names = new[] { "mat1", "dense_matrix_2", "s1", "sparse2" };
if (File.Exists("testz.mat"))
{
File.Delete("testz.mat");
}
- var writer = new MatlabWriter("testz.mat");
- writer.WriteMatrices(write, names);
- writer.Dispose();
+ MatlabWriter.Write("testz.mat", write, names);
var read = MatlabReader.ReadAll("testz.mat", names);
-
Assert.AreEqual(write.Length, read.Count);
for (var i = 0; i < write.Length; i++)
{
var w = write[i];
var r = read[names[i]];
-
Assert.AreEqual(w.RowCount, r.RowCount);
Assert.AreEqual(w.ColumnCount, r.ColumnCount);
Assert.IsTrue(w.Equals(r));
@@ -302,11 +256,9 @@ namespace MathNet.Numerics.Data.UnitTests.Matlab
[Test]
public void WriteBadMatrixThrowsArgumentException()
{
- var matrix = new LinearAlgebra.Single.DenseMatrix(1, 1);
- var writer = new MatlabWriter("somefile1");
- Assert.Throws(() => writer.WriteMatrix(matrix, string.Empty));
- Assert.Throws(() => writer.WriteMatrix(matrix, null));
- writer.Dispose();
+ var matrix = Matrix.Build.Dense(1, 1);
+ Assert.Throws(() => MatlabWriter.Write("somefile1", matrix, string.Empty));
+ Assert.Throws(() => MatlabWriter.Write("somefile1", matrix, null));
}
///
@@ -315,9 +267,7 @@ namespace MathNet.Numerics.Data.UnitTests.Matlab
[Test]
public void WriteNullMatrixThrowsArgumentNullException()
{
- var writer = new MatlabWriter("somefile2");
- Assert.Throws(() => writer.WriteMatrix(null, "matrix"));
- writer.Dispose();
+ Assert.Throws(() => MatlabWriter.Write("somefile2", null, "matrix"));
}
}
}