diff --git a/src/Data/Matlab/ArrayClass.cs b/src/Data/Matlab/ArrayClass.cs index 13d48cde..3241fe2e 100644 --- a/src/Data/Matlab/ArrayClass.cs +++ b/src/Data/Matlab/ArrayClass.cs @@ -31,7 +31,7 @@ namespace MathNet.Numerics.Data.Matlab { /// - /// Enumeration for the Matlab array types + /// Enumeration for the MATLAB array types /// internal enum ArrayClass : byte { diff --git a/src/Data/Matlab/ArrayFlags.cs b/src/Data/Matlab/ArrayFlags.cs index d46b7d1e..5e1debc7 100644 --- a/src/Data/Matlab/ArrayFlags.cs +++ b/src/Data/Matlab/ArrayFlags.cs @@ -33,7 +33,7 @@ using System; namespace MathNet.Numerics.Data.Matlab { /// - /// Matlab Array Flags + /// MATLAB Array Flags /// [Flags] internal enum ArrayFlags diff --git a/src/Data/Matlab/DataType.cs b/src/Data/Matlab/DataType.cs index e3ef4dac..df850313 100644 --- a/src/Data/Matlab/DataType.cs +++ b/src/Data/Matlab/DataType.cs @@ -31,7 +31,7 @@ namespace MathNet.Numerics.Data.Matlab { /// - /// Matlab data types + /// MATLAB data types /// internal enum DataType { diff --git a/src/Data/Matlab/Matlab.csproj b/src/Data/Matlab/Matlab.csproj index c70a1bc7..6e4f7cff 100644 --- a/src/Data/Matlab/Matlab.csproj +++ b/src/Data/Matlab/Matlab.csproj @@ -51,6 +51,8 @@ + + diff --git a/src/Data/Matlab/MatlabFile.cs b/src/Data/Matlab/MatlabFile.cs index 46322ec6..ab4cd184 100644 --- a/src/Data/Matlab/MatlabFile.cs +++ b/src/Data/Matlab/MatlabFile.cs @@ -35,13 +35,13 @@ using MathNet.Numerics.LinearAlgebra; namespace MathNet.Numerics.Data.Matlab { /// - /// Represents a Matlab file + /// Represents a MATLAB file /// /// The data type of the matrix to return. internal class MatlabFile where TDataType : struct, IEquatable, IFormattable { /// - /// Matrices in a matlab file stored as 1-D arrays + /// Matrices in a MATLAB file stored as 1-D arrays /// readonly IDictionary> _matrices = new SortedList>(); @@ -49,19 +49,19 @@ namespace MathNet.Numerics.Data.Matlab /// Gets or sets the header text. /// /// The header text. - public string HeaderText { get; set; } + internal string HeaderText { get; set; } /// /// Gets or sets the first name of the matrix. /// /// The first name of the matrix. - public string FirstMatrixName { get; set; } + internal string FirstMatrixName { get; set; } /// /// Gets the first matrix. /// /// The first matrix. - public Matrix FirstMatrix + internal Matrix FirstMatrix { get { @@ -78,7 +78,7 @@ namespace MathNet.Numerics.Data.Matlab /// Gets the matrices. /// /// The matrices. - public IDictionary> Matrices + internal IDictionary> Matrices { get { return _matrices; } } diff --git a/src/Data/Matlab/MatlabParser.cs b/src/Data/Matlab/MatlabParser.cs index 31f44b9b..addf924e 100644 --- a/src/Data/Matlab/MatlabParser.cs +++ b/src/Data/Matlab/MatlabParser.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// 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 @@ -32,7 +32,6 @@ 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.Properties; @@ -40,7 +39,7 @@ using MathNet.Numerics.Properties; namespace MathNet.Numerics.Data.Matlab { /// - /// Parse a Matlab file + /// Parse a MATLAB file /// /// The data type of the matrix. internal class MatlabParser @@ -67,7 +66,7 @@ namespace MathNet.Numerics.Data.Matlab readonly IList _names = new List(); /// - /// The stream to read the matlab file from. + /// The stream to read the MATLAB file from. /// readonly Stream _stream; @@ -75,7 +74,7 @@ namespace MathNet.Numerics.Data.Matlab /// Initializes a new instance of the class. /// /// Name of the file. - public MatlabParser(string fileName) + internal MatlabParser(string fileName) : this(fileName, new string[0]) { } @@ -84,7 +83,7 @@ namespace MathNet.Numerics.Data.Matlab /// Initializes a new instance of the class. /// /// The stream to read from. - public MatlabParser(Stream stream) + internal MatlabParser(Stream stream) : this(stream, new string[0]) { } @@ -94,7 +93,7 @@ namespace MathNet.Numerics.Data.Matlab /// /// The stream to read from. /// The name of the objects to retrieve. - public MatlabParser(Stream stream, IEnumerable objectNames) + internal MatlabParser(Stream stream, IEnumerable objectNames) { if (stream == null) { @@ -110,7 +109,7 @@ namespace MathNet.Numerics.Data.Matlab /// /// Name of the file. /// The name of the objects to retrieve. - public MatlabParser(string fileName, IEnumerable objectNames) + MatlabParser(string fileName, IEnumerable objectNames) { if (string.IsNullOrEmpty(fileName)) { @@ -136,8 +135,8 @@ namespace MathNet.Numerics.Data.Matlab /// /// Parses the file. /// - /// The parsed Matlab file as a object. - public MatlabFile Parse() + /// The parsed MATLAB file as a object. + internal MatlabFile Parse() { var file = new MatlabFile(); @@ -157,7 +156,7 @@ namespace MathNet.Numerics.Data.Matlab reader.BaseStream.Position = 128; var length = _stream.Length; - // for each data block add a Matlab object to the file. + // for each data block add a MATLAB object to the file. while (reader.BaseStream.Position < length) { var type = (DataType)reader.ReadInt16(); @@ -201,7 +200,7 @@ namespace MathNet.Numerics.Data.Matlab /// The stream. /// The size of the array. /// if set to true if reading from a small block. - static void AlignData(Stream stream, int size, bool smallBlock) + internal static void AlignData(Stream stream, int size, bool smallBlock) { var blockSize = smallBlock ? SmallBlockSize : LargeBlockSize; var offset = 0; @@ -224,1363 +223,102 @@ namespace MathNet.Numerics.Data.Matlab { byte[] data; using (var compressedStream = new MemoryStream(compressed, 2, compressed.Length - 6)) + using (var decompressor = new DeflateStream(compressedStream, CompressionMode.Decompress)) + using (var decompressed = new MemoryStream()) { - using (var decompressor = new DeflateStream(compressedStream, CompressionMode.Decompress)) - using (var decompressed = new MemoryStream()) - { - decompressor.CopyTo(decompressed); - decompressed.Position = 0; - var buf = new byte[4]; - decompressed.Read(buf, 0, 4); - type = (DataType)BitConverter.ToInt32(buf, 0); - decompressed.Read(buf, 0, 4); - var size = BitConverter.ToInt32(buf, 0); - data = new byte[size]; - decompressed.Read(data, 0, size); - } + decompressor.CopyTo(decompressed); + decompressed.Position = 0; + var buf = new byte[4]; + decompressed.Read(buf, 0, 4); + type = (DataType)BitConverter.ToInt32(buf, 0); + decompressed.Read(buf, 0, 4); + var size = BitConverter.ToInt32(buf, 0); + data = new byte[size]; + decompressed.Read(data, 0, size); } return data; } /// - /// Adds a matrix from the actual file into our presentation of a matlab file. + /// Adds a matrix from the actual file into our presentation of a MATLAB file. /// /// The data of the matrix. /// The instance. void AddMatrix(byte[] data, MatlabFile file) { using (var ms = new MemoryStream(data)) + using (var reader = new BinaryReader(ms)) { - using (var reader = new BinaryReader(ms)) - { - // 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 unneeded bytes - reader.BaseStream.Seek(2, SeekOrigin.Current); - int size = reader.ReadInt16(); - var smallBlock = true; - if (size == 0) - { - size = reader.ReadInt32(); - smallBlock = false; - } - - var name = Encoding.ASCII.GetString(reader.ReadBytes(size)); - AlignData(reader.BaseStream, size, smallBlock); - - // only grab wanted objects - if (_names.Count != 0 && !_names.Contains(name)) - { - return; - } - - var type = (DataType)reader.ReadInt16(); - size = reader.ReadInt16(); - if (size == 0) - { - size = reader.ReadInt32(); - } - - Matrix matrix; - switch (arrayClass) - { - case ArrayClass.Sparse: - matrix = 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 = PopulateDenseMatrix(type, reader, isComplex, rows, columns, size); - break; - } - - file.Matrices.Add(name, matrix); - if (file.FirstMatrixName == null) - { - file.FirstMatrixName = name; - } - } - } - } - - /// - /// Populates a sparse matrix. - /// - /// The reader. - /// if set to true if the Matlab complex flag is set. - /// The number of rows. - /// The number of columns. - /// The size of the block. - /// A populated sparse matrix. - static Matrix PopulateSparseMatrix(BinaryReader reader, bool isComplex, int rows, int columns, int size) - { - // populate the row data array - var ir = new int[size/4]; - for (var i = 0; i < ir.Length; i++) - { - ir[i] = reader.ReadInt32(); - } + // skip tag - doesn't tell us anything we don't already know + reader.BaseStream.Seek(8, SeekOrigin.Current); - AlignData(reader.BaseStream, size, false); + var arrayClass = (ArrayClass)reader.ReadByte(); + var flags = reader.ReadByte(); + var isComplex = (flags & (byte)ArrayFlags.Complex) == (byte)ArrayFlags.Complex; - // skip data type since it will always be int32 - reader.BaseStream.Seek(4, SeekOrigin.Current); + // skip unneeded bytes + reader.BaseStream.Seek(10, SeekOrigin.Current); - // populate the column data array - var jcsize = reader.ReadInt32(); - var jc = new int[jcsize/4]; - for (var j = 0; j < jc.Length; j++) - { - jc[j] = reader.ReadInt32(); - } - - AlignData(reader.BaseStream, jcsize, false); - - var type = (DataType)reader.ReadInt32(); - var dataSize = reader.ReadInt32(); - - var matrix = Matrix.Build.Sparse(rows, columns); - var dataType = typeof (TDataType); - - if (dataType == typeof (double)) - { - if (isComplex) + var numDimensions = reader.ReadInt32()/8; + if (numDimensions > 2) { - throw new ArgumentException("Invalid TDataType. Matrix is stored as a complex matrix, but a real data type was given."); + throw new NotSupportedException(Resources.MoreThan2D); } - PopulateDoubleSparseMatrix((Matrix)(object)matrix, type, ir, jc, reader); - } - else if (dataType == typeof (float)) - { - if (isComplex) - { - throw new ArgumentException("Invalid TDataType. Matrix is stored as a complex matrix, but a real data type was given."); - } + var rows = reader.ReadInt32(); + var columns = reader.ReadInt32(); - PopulateSingleSparseMatrix((Matrix)(object)matrix, type, ir, jc, reader); - } - else if (dataType == typeof (Complex)) - { - PopulateComplexSparseMatrix((Matrix)(object)matrix, type, isComplex, ir, jc, reader, dataSize); - } - else if (dataType == typeof (Complex32)) - { - PopulateComplex32SparseMatrix((Matrix)(object)matrix, type, isComplex, ir, jc, reader, dataSize); - } - else - { - throw new NotSupportedException(); - } - - return matrix; - } - - /// - /// Populates the double sparse matrix. - /// - /// The matrix to populate - /// The Matlab data type. - /// The row indices. - /// The column indices. - /// The reader to read from. - static void PopulateDoubleSparseMatrix(Matrix matrix, DataType type, IList ir, IList jc, BinaryReader reader) - { - var col = 0; - for (var i = 0; i < ir.Count; i++) - { - var row = ir[i]; - while (jc[col + 1] == i) + // skip unneeded bytes + reader.BaseStream.Seek(2, SeekOrigin.Current); + int size = reader.ReadInt16(); + var smallBlock = true; + if (size == 0) { - col++; + size = reader.ReadInt32(); + smallBlock = false; } - switch (type) - { - case DataType.Int8: - matrix.At(row, col, reader.ReadSByte()); - break; - case DataType.UInt8: - matrix.At(row, col, reader.ReadByte()); - break; - case DataType.Int16: - matrix.At(row, col, reader.ReadInt16()); - break; - case DataType.UInt16: - matrix.At(row, col, reader.ReadUInt16()); - break; - case DataType.Int32: - matrix.At(row, col, reader.ReadInt32()); - break; - case DataType.UInt32: - matrix.At(row, col, reader.ReadUInt32()); - break; - case DataType.Single: - matrix.At(row, col, reader.ReadSingle()); - break; - case DataType.Int64: - matrix.At(row, col, reader.ReadInt64()); - break; - case DataType.UInt64: - matrix.At(row, col, reader.ReadUInt64()); - break; - case DataType.Double: - matrix.At(row, col, reader.ReadDouble()); - break; - default: - throw new NotSupportedException(); - } - } - } + var name = Encoding.ASCII.GetString(reader.ReadBytes(size)); + AlignData(reader.BaseStream, size, smallBlock); - /// - /// Populates the float sparse matrix. - /// - /// The matrix to populate - /// The Matlab data type. - /// The row indices. - /// The column indices. - /// The reader to read from. - static void PopulateSingleSparseMatrix(Matrix matrix, DataType type, IList ir, IList jc, BinaryReader reader) - { - var col = 0; - for (var i = 0; i < ir.Count; i++) - { - var row = ir[i]; - while (jc[col + 1] == i) + // only grab wanted objects + if (_names.Count != 0 && !_names.Contains(name)) { - col++; + return; } - switch (type) + var type = (DataType)reader.ReadInt16(); + size = reader.ReadInt16(); + if (size == 0) { - case DataType.Int8: - matrix.At(row, col, reader.ReadSByte()); - break; - case DataType.UInt8: - matrix.At(row, col, reader.ReadByte()); - break; - case DataType.Int16: - matrix.At(row, col, reader.ReadInt16()); - break; - case DataType.UInt16: - matrix.At(row, col, reader.ReadUInt16()); - break; - case DataType.Int32: - matrix.At(row, col, reader.ReadInt32()); - break; - case DataType.UInt32: - matrix.At(row, col, reader.ReadUInt32()); - break; - case DataType.Single: - matrix.At(row, col, reader.ReadSingle()); - break; - case DataType.Int64: - matrix.At(row, col, reader.ReadInt64()); - break; - case DataType.UInt64: - matrix.At(row, col, reader.ReadUInt64()); - break; - case DataType.Double: - matrix.At(row, col, Convert.ToSingle(reader.ReadDouble())); - break; - default: - throw new NotSupportedException(); - } - } - } - - /// - /// Populates the complex sparse matrix. - /// - /// The matrix to populate - /// The Matlab data type. - /// if set to true if the Matlab complex flag is set. - /// The row indices. - /// The column indices. - /// The reader to read from. - /// The length of the stored data. - static void PopulateComplexSparseMatrix(Matrix matrix, DataType type, bool isComplex, IList ir, IList jc, BinaryReader reader, int dataSize) - { - var col = 0; - for (var i = 0; i < ir.Count; i++) - { - var row = ir[i]; - while (jc[col + 1] == i) - { - col++; + size = reader.ReadInt32(); } - switch (type) + Matrix matrix; + switch (arrayClass) { - case DataType.Int8: - matrix.At(row, col, reader.ReadSByte()); - break; - case DataType.UInt8: - matrix.At(row, col, reader.ReadByte()); - break; - case DataType.Int16: - matrix.At(row, col, reader.ReadInt16()); - break; - case DataType.UInt16: - matrix.At(row, col, reader.ReadUInt16()); - break; - case DataType.Int32: - matrix.At(row, col, reader.ReadInt32()); - break; - case DataType.UInt32: - matrix.At(row, col, reader.ReadUInt32()); - break; - case DataType.Single: - matrix.At(row, col, reader.ReadSingle()); - break; - case DataType.Int64: - matrix.At(row, col, reader.ReadInt64()); - break; - case DataType.UInt64: - matrix.At(row, col, reader.ReadUInt64()); - break; - case DataType.Double: - matrix.At(row, col, reader.ReadDouble()); - break; - default: + 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(); - } - } - - if (isComplex) - { - var skip = dataSize%8; - - // skip pad - reader.ReadBytes(skip); - - // skip header - type = (DataType)reader.ReadInt32(); - reader.ReadInt32(); - col = 0; - for (var i = 0; i < ir.Count; i++) - { - var row = ir[i]; - while (jc[col + 1] == i) - { - col++; - } - - var real = matrix.At(row, col).Real; - switch (type) - { - case DataType.Int8: - matrix.At(row, col, new Complex(real, reader.ReadSByte())); - break; - case DataType.UInt8: - matrix.At(row, col, new Complex(real, reader.ReadByte())); - break; - case DataType.Int16: - matrix.At(row, col, new Complex(real, reader.ReadInt16())); - break; - case DataType.UInt16: - matrix.At(row, col, new Complex(real, reader.ReadUInt16())); - break; - case DataType.Int32: - matrix.At(row, col, new Complex(real, reader.ReadInt32())); - break; - case DataType.UInt32: - matrix.At(row, col, new Complex(real, reader.ReadUInt32())); - break; - case DataType.Single: - matrix.At(row, col, new Complex(real, reader.ReadSingle())); - break; - case DataType.Int64: - matrix.At(row, col, new Complex(real, reader.ReadInt64())); - break; - case DataType.UInt64: - matrix.At(row, col, new Complex(real, reader.ReadUInt64())); - break; - case DataType.Double: - matrix.At(row, col, new Complex(real, reader.ReadDouble())); - break; - default: - throw new NotSupportedException(); - } - } - } - } - - /// - /// Populates the complex32 sparse matrix. - /// - /// The matrix to populate - /// The Matlab data type. - /// if set to true if the Matlab complex flag is set. - /// The row indices. - /// The column indices. - /// The reader to read from. - /// The length of the stored data. - static void PopulateComplex32SparseMatrix(Matrix matrix, DataType type, bool isComplex, IList ir, IList jc, BinaryReader reader, int dataSize) - { - var col = 0; - for (var i = 0; i < ir.Count; i++) - { - var row = ir[i]; - while (jc[col + 1] == i) - { - col++; - } - - switch (type) - { - case DataType.Int8: - matrix.At(row, col, reader.ReadSByte()); - break; - case DataType.UInt8: - matrix.At(row, col, reader.ReadByte()); - break; - case DataType.Int16: - matrix.At(row, col, reader.ReadInt16()); - break; - case DataType.UInt16: - matrix.At(row, col, reader.ReadUInt16()); - break; - case DataType.Int32: - matrix.At(row, col, reader.ReadInt32()); - break; - case DataType.UInt32: - matrix.At(row, col, reader.ReadUInt32()); - break; - case DataType.Single: - matrix.At(row, col, reader.ReadSingle()); - break; - case DataType.Int64: - matrix.At(row, col, reader.ReadInt64()); - break; - case DataType.UInt64: - matrix.At(row, col, reader.ReadUInt64()); - break; - case DataType.Double: - matrix.At(row, col, Convert.ToSingle(reader.ReadDouble())); - break; default: - throw new NotSupportedException(); - } - } - - if (isComplex) - { - var skip = dataSize%8; - - // skip pad - reader.ReadBytes(skip); - - // skip header - type = (DataType)reader.ReadInt32(); - reader.ReadInt32(); - - col = 0; - for (var i = 0; i < ir.Count; i++) - { - var row = ir[i]; - while (jc[col + 1] == i) - { - col++; - } - - var real = matrix.At(row, col).Real; - switch (type) - { - case DataType.Int8: - matrix.At(row, col, new Complex32(real, reader.ReadSByte())); - break; - case DataType.UInt8: - matrix.At(row, col, new Complex32(real, reader.ReadByte())); - break; - case DataType.Int16: - matrix.At(row, col, new Complex32(real, reader.ReadInt16())); - break; - case DataType.UInt16: - matrix.At(row, col, new Complex32(real, reader.ReadUInt16())); - break; - case DataType.Int32: - matrix.At(row, col, new Complex32(real, reader.ReadInt32())); - break; - case DataType.UInt32: - matrix.At(row, col, new Complex32(real, reader.ReadUInt32())); - break; - case DataType.Single: - matrix.At(row, col, new Complex32(real, reader.ReadSingle())); - break; - case DataType.Int64: - matrix.At(row, col, new Complex32(real, reader.ReadInt64())); - break; - case DataType.UInt64: - matrix.At(row, col, new Complex32(real, reader.ReadUInt64())); - break; - case DataType.Double: - matrix.At(row, col, new Complex32(real, Convert.ToSingle(reader.ReadDouble()))); - break; - default: - throw new NotSupportedException(); - } - } - } - } - - /// - /// Populates a dense matrix. - /// - /// The Matlab data type. - /// The reader to read from. - /// if set to true if the Matlab complex flag is set. - /// The number of rows. - /// The number of columns. - /// The length of the stored data. - /// Returns a populated dense matrix. - static Matrix PopulateDenseMatrix(DataType type, BinaryReader reader, bool isComplex, int rows, int columns, int size) - { - var dataType = typeof (TDataType); - Matrix matrix; - if (type == DataType.Double && dataType == typeof (double)) - { - var count = rows*columns; - var data = new double[count]; - Buffer.BlockCopy(reader.ReadBytes(count*Constants.SizeOfDouble), 0, data, 0, count*Constants.SizeOfDouble); - matrix = (Matrix)(object)new LinearAlgebra.Double.DenseMatrix(rows, columns, data); - } - else if (type == DataType.Single && dataType == typeof (float)) - { - var count = rows*columns; - var data = new float[count]; - Buffer.BlockCopy(reader.ReadBytes(count*Constants.SizeOfFloat), 0, data, 0, count*Constants.SizeOfFloat); - matrix = (Matrix)(object)new LinearAlgebra.Single.DenseMatrix(rows, columns, data); - } - else - { - matrix = Matrix.Build.Dense(rows, columns); - - if (dataType == typeof (double)) - { - if (isComplex) - { - throw new ArgumentException("Invalid TDataType. Matrix is stored as a complex matrix, but a real data type was given."); - } - - PopulateDoubleDenseMatrix((Matrix)(object)matrix, type, reader, rows, columns); - } - else if (dataType == typeof (float)) - { - if (isComplex) - { - throw new ArgumentException("Invalid TDataType. Matrix is stored as a complex matrix, but a real data type was given."); - } - - PopulateSingleDenseMatrix((Matrix)(object)matrix, type, reader, rows, columns); - } - else if (dataType == typeof (Complex)) - { - PopulateComplexDenseMatrix((Matrix)(object)matrix, type, isComplex, reader, rows, columns, size); - } - else if (dataType == typeof (Complex32)) - { - PopulateComplex32DenseMatrix((Matrix)(object)matrix, type, isComplex, reader, rows, columns, size); - } - else - { - throw new NotSupportedException(); - } - } - - return matrix; - } - - /// - /// Populates the double dense matrix. - /// - /// The matrix to populate. - /// The Matlab data type. - /// The reader to read from. - /// The number of rows. - /// The number of columns. - public static void PopulateDoubleDenseMatrix(Matrix matrix, DataType type, BinaryReader reader, int rows, int columns) - { - switch (type) - { - case DataType.Int8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadSByte()); - } - } - - break; - - case DataType.UInt8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadByte()); - } - } - - break; - - case DataType.Int16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt16()); - } - } - - break; - - case DataType.UInt16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt16()); - } - } - - break; - - case DataType.Int32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt32()); - } - } - - break; - - case DataType.UInt32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt32()); - } - } - - break; - - case DataType.Single: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadSingle()); - } - } - - break; - - case DataType.Int64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt64()); - } - } - - break; - - case DataType.UInt64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt64()); - } - } - - break; - - case DataType.Double: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadDouble()); - } - } - - break; - - default: - throw new NotSupportedException(); - } - } - - /// - /// Populates the complex dense matrix. - /// - /// The matrix to populate. - /// The Matlab data type. - /// if set to true if the Matlab complex flag is set. - /// The reader to read from. - /// The number of rows. - /// The number of columns. - /// The length of the stored data. - public static void PopulateComplexDenseMatrix(Matrix matrix, DataType type, bool isComplex, BinaryReader reader, int rows, int columns, int dataSize) - { - switch (type) - { - case DataType.Int8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadSByte()); - } - } - - break; - - case DataType.UInt8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadByte()); - } - } - - break; - - case DataType.Int16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt16()); - } - } - - break; - - case DataType.UInt16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt16()); - } - } - - break; - - case DataType.Int32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt32()); - } - } - - break; - - case DataType.UInt32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt32()); - } - } - - break; - - case DataType.Single: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadSingle()); - } - } - - break; - - case DataType.Int64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt64()); - } - } - - break; - - case DataType.UInt64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt64()); - } - } - - break; - - case DataType.Double: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadDouble()); - } - } - - break; - - default: - throw new NotSupportedException(); - } - - if (isComplex) - { - var skip = dataSize%8; - - // skip pad - reader.ReadBytes(skip); - - // skip header - type = (DataType)reader.ReadInt32(); - reader.ReadInt32(); - - switch (type) - { - case DataType.Int8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadSByte())); - } - } - - break; - - case DataType.UInt8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadByte())); - } - } - - break; - - case DataType.Int16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadInt16())); - } - } - - break; - - case DataType.UInt16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadUInt16())); - } - } - - break; - - case DataType.Int32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadInt32())); - } - } - - break; - - case DataType.UInt32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadUInt32())); - } - } - - break; - - case DataType.Single: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadSingle())); - } - } - + matrix = NumericArrayReader.PopulateDenseMatrix(type, reader, isComplex, rows, columns, size); break; - - case DataType.Int64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadInt64())); - } - } - - break; - - case DataType.UInt64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadUInt64())); - } - } - - break; - - case DataType.Double: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex(matrix.At(i, j).Real, reader.ReadDouble())); - } - } - - break; - - default: - throw new NotSupportedException(); } - } - } - - /// - /// Populates the complex32 dense matrix. - /// - /// The matrix to populate. - /// The Matlab data type. - /// if set to true if the Matlab complex flag is set. - /// The reader to read from. - /// The number of rows. - /// The number of columns. - /// The length of the stored data. - public static void PopulateComplex32DenseMatrix(Matrix matrix, DataType type, bool isComplex, BinaryReader reader, int rows, int columns, int dataSize) - { - switch (type) - { - case DataType.Int8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadSByte()); - } - } - - break; - - case DataType.UInt8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadByte()); - } - } - - break; - - case DataType.Int16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt16()); - } - } - - break; - - case DataType.UInt16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt16()); - } - } - - break; - - case DataType.Int32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt32()); - } - } - - break; - - case DataType.UInt32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt32()); - } - } - - break; - - case DataType.Single: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadSingle()); - } - } - - break; - - case DataType.Int64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt64()); - } - } - - break; - - case DataType.UInt64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt64()); - } - } - - break; - - case DataType.Double: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, Convert.ToSingle(reader.ReadDouble())); - } - } - break; - - default: - throw new NotSupportedException(); - } - - if (isComplex) - { - var skip = dataSize%8; - - // skip pad - reader.ReadBytes(skip); - - // skip header - type = (DataType)reader.ReadInt32(); - reader.ReadInt32(); - - switch (type) + file.Matrices.Add(name, matrix); + if (file.FirstMatrixName == null) { - case DataType.Int8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, reader.ReadSByte())); - } - } - - break; - - case DataType.UInt8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, reader.ReadByte())); - } - } - - break; - - case DataType.Int16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, reader.ReadInt16())); - } - } - - break; - - case DataType.UInt16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, reader.ReadUInt16())); - } - } - - break; - - case DataType.Int32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, reader.ReadInt32())); - } - } - - break; - - case DataType.UInt32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, reader.ReadUInt32())); - } - } - - break; - - case DataType.Single: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, reader.ReadSingle())); - } - } - - break; - - case DataType.Int64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, reader.ReadInt64())); - } - } - - break; - - case DataType.UInt64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, reader.ReadUInt64())); - } - } - - break; - - case DataType.Double: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, new Complex32(matrix.At(i, j).Real, Convert.ToSingle(reader.ReadDouble()))); - } - } - - break; - - default: - throw new NotSupportedException(); + file.FirstMatrixName = name; } } } - - /// - /// Populates the float dense matrix. - /// - /// The matrix to populate. - /// The Matlab data type. - /// The reader to read from. - /// The number of rows. - /// The number of columns. - public static void PopulateSingleDenseMatrix(Matrix matrix, DataType type, BinaryReader reader, int rows, int columns) - { - switch (type) - { - case DataType.Int8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadSByte()); - } - } - - break; - - case DataType.UInt8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadByte()); - } - } - - break; - - case DataType.Int16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt16()); - } - } - - break; - - case DataType.UInt16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt16()); - } - } - - break; - - case DataType.Int32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt32()); - } - } - - break; - - case DataType.UInt32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt32()); - } - } - - break; - - case DataType.Single: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadSingle()); - } - } - - break; - - case DataType.Int64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadInt64()); - } - } - - break; - - case DataType.UInt64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, reader.ReadUInt64()); - } - } - - break; - - case DataType.Double: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix.At(i, j, Convert.ToSingle(reader.ReadDouble())); - } - } - - break; - - default: - throw new NotSupportedException(); - } - } } } diff --git a/src/Data/Matlab/MatlabReader.cs b/src/Data/Matlab/MatlabReader.cs index d4043df4..fdef0882 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 files. /// public static class MatlabMatrixReader { diff --git a/src/Data/Matlab/MatlabWriter.cs b/src/Data/Matlab/MatlabWriter.cs index bb9967ae..3445d156 100644 --- a/src/Data/Matlab/MatlabWriter.cs +++ b/src/Data/Matlab/MatlabWriter.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// 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 @@ -41,7 +41,7 @@ using MathNet.Numerics.Properties; namespace MathNet.Numerics.Data.Matlab { /// - /// Writes matrices to a Matlab file. + /// Writes matrices to a MATLAB file. /// public class MatlabMatrixWriter : IDisposable { @@ -68,7 +68,7 @@ namespace MathNet.Numerics.Data.Matlab /// /// Initializes a new instance of the class. /// - /// The name of the Matlab file to save the matrices to. + /// The name of the MATLAB file to save the matrices to. public MatlabMatrixWriter(string filename) { if (string.IsNullOrEmpty(filename)) @@ -95,7 +95,7 @@ namespace MathNet.Numerics.Data.Matlab } /// - /// Writes the given to the file. + /// Writes the given to the file. /// /// The matrix to write. /// The name of the matrix to store in the file. @@ -125,7 +125,7 @@ namespace MathNet.Numerics.Data.Matlab _headerWritten = true; } - // write datatype + // write data type _writer.Write((int)DataType.Compressed); byte[] data; @@ -212,7 +212,7 @@ namespace MathNet.Numerics.Data.Matlab /// The writer we are using. /// The array class we are writing. /// if set to true if this a complex matrix. - /// The name name of the matrix. + /// The name of the matrix. /// The number of rows. /// The columns of columns. /// The maximum number of non-zero elements. @@ -228,7 +228,7 @@ namespace MathNet.Numerics.Data.Matlab writer.Write((int)DataType.UInt32); writer.Write(8); - // write array class and flags + // write array class and flags writer.Write((byte)arrayClass); if (isComplex) { diff --git a/src/Data/Matlab/NumericArrayReader.cs b/src/Data/Matlab/NumericArrayReader.cs new file mode 100644 index 00000000..799ce4c2 --- /dev/null +++ b/src/Data/Matlab/NumericArrayReader.cs @@ -0,0 +1,257 @@ +// +// 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.IO; +using System.Numerics; +using MathNet.Numerics.LinearAlgebra; + +namespace MathNet.Numerics.Data.Matlab +{ + internal static class NumericArrayReader + where TDataType : struct, IEquatable, IFormattable + { + /// + /// Populates a dense matrix. + /// + /// The MATLAB data type. + /// The reader to read from. + /// if set to true if the MATLAB complex flag is set. + /// The number of rows. + /// The number of columns. + /// The length of the stored data. + /// Returns a populated dense matrix. + public static Matrix PopulateDenseMatrix(DataType type, BinaryReader reader, bool isComplex, int rows, int columns, int size) + { + var dataType = typeof (TDataType); + Matrix matrix; + if (type == DataType.Double && dataType == typeof (double)) + { + var count = rows*columns; + var data = new double[count]; + Buffer.BlockCopy(reader.ReadBytes(count*Constants.SizeOfDouble), 0, data, 0, count*Constants.SizeOfDouble); + matrix = (Matrix)(object)new LinearAlgebra.Double.DenseMatrix(rows, columns, data); + } + else if (type == DataType.Single && dataType == typeof (float)) + { + var count = rows*columns; + var data = new float[count]; + Buffer.BlockCopy(reader.ReadBytes(count*Constants.SizeOfFloat), 0, data, 0, count*Constants.SizeOfFloat); + matrix = (Matrix)(object)new LinearAlgebra.Single.DenseMatrix(rows, columns, data); + } + else + { + matrix = Matrix.Build.Dense(rows, columns); + + if (dataType == typeof (double)) + { + if (isComplex) + { + throw new ArgumentException("Invalid TDataType. Matrix is stored as a complex matrix, but a real data type was given."); + } + + PopulateDoubleDenseMatrix((Matrix)(object)matrix, type, reader, rows, columns); + } + else if (dataType == typeof (float)) + { + if (isComplex) + { + throw new ArgumentException("Invalid TDataType. Matrix is stored as a complex matrix, but a real data type was given."); + } + + PopulateSingleDenseMatrix((Matrix)(object)matrix, type, reader, rows, columns); + } + else if (dataType == typeof (Complex)) + { + PopulateComplexDenseMatrix((Matrix)(object)matrix, type, isComplex, reader, rows, columns, size); + } + else if (dataType == typeof (Complex32)) + { + PopulateComplex32DenseMatrix((Matrix)(object)matrix, type, isComplex, reader, rows, columns, size); + } + else + { + throw new NotSupportedException(); + } + } + + return matrix; + } + + /// + /// Populates the double dense matrix. + /// + /// The matrix to populate. + /// The MATLAB data type. + /// The reader to read from. + /// The number of rows. + /// The number of columns. + static void PopulateDoubleDenseMatrix(Matrix matrix, DataType type, BinaryReader reader, int rows, int columns) + { + for (var j = 0; j < columns; j++) + { + for (var i = 0; i < rows; i++) + { + matrix.At(i, j, ReadDoubleValue(type, reader)); + } + } + } + + /// + /// Populates the complex dense matrix. + /// + /// The matrix to populate. + /// The MATLAB data type. + /// if set to true if the MATLAB complex flag is set. + /// The reader to read from. + /// The number of rows. + /// The number of columns. + /// The length of the stored data. + static void PopulateComplexDenseMatrix(Matrix matrix, DataType type, bool isComplex, BinaryReader reader, int rows, int columns, int dataSize) + { + for (var j = 0; j < columns; j++) + { + for (var i = 0; i < rows; i++) + { + matrix.At(i, j, ReadDoubleValue(type, reader)); + } + } + + if (isComplex) + { + var skip = dataSize%8; + + // skip pad + reader.ReadBytes(skip); + + // skip header + type = (DataType)reader.ReadInt32(); + reader.ReadInt32(); + + for (var j = 0; j < columns; j++) + { + for (var i = 0; i < rows; i++) + { + matrix.At(i, j, new Complex(matrix.At(i, j).Real, ReadDoubleValue(type, reader))); + } + } + } + } + + /// + /// Populates the complex32 dense matrix. + /// + /// The matrix to populate. + /// The MATLAB data type. + /// if set to true if the MATLAB complex flag is set. + /// The reader to read from. + /// The number of rows. + /// The number of columns. + /// The length of the stored data. + static void PopulateComplex32DenseMatrix(Matrix matrix, DataType type, bool isComplex, BinaryReader reader, int rows, int columns, int dataSize) + { + for (var j = 0; j < columns; j++) + { + for (var i = 0; i < rows; i++) + { + matrix.At(i, j, (float)ReadDoubleValue(type, reader)); + } + } + + if (isComplex) + { + var skip = dataSize%8; + + // skip pad + reader.ReadBytes(skip); + + // skip header + type = (DataType)reader.ReadInt32(); + reader.ReadInt32(); + + for (var j = 0; j < columns; j++) + { + for (var i = 0; i < rows; i++) + { + matrix.At(i, j, new Complex32(matrix.At(i, j).Real, (float)ReadDoubleValue(type, reader))); + } + } + } + } + + /// + /// Populates the float dense matrix. + /// + /// The matrix to populate. + /// The MATLAB data type. + /// The reader to read from. + /// The number of rows. + /// The number of columns. + static void PopulateSingleDenseMatrix(Matrix matrix, DataType type, BinaryReader reader, int rows, int columns) + { + for (var j = 0; j < columns; j++) + { + for (var i = 0; i < rows; i++) + { + matrix.At(i, j, (float)ReadDoubleValue(type, reader)); + } + } + } + + static double ReadDoubleValue(DataType type, BinaryReader reader) + { + switch (type) + { + case DataType.Double: + return reader.ReadDouble(); + case DataType.Int8: + return reader.ReadSByte(); + case DataType.UInt8: + return reader.ReadByte(); + case DataType.Int16: + return reader.ReadInt16(); + case DataType.UInt16: + return reader.ReadUInt16(); + case DataType.Int32: + return reader.ReadInt32(); + case DataType.UInt32: + return reader.ReadUInt32(); + case DataType.Single: + return reader.ReadSingle(); + case DataType.Int64: + return reader.ReadInt64(); + case DataType.UInt64: + return reader.ReadUInt64(); + default: + throw new NotSupportedException(); + } + } + } +} diff --git a/src/Data/Matlab/SparseArrayReader.cs b/src/Data/Matlab/SparseArrayReader.cs new file mode 100644 index 00000000..3d7aabf3 --- /dev/null +++ b/src/Data/Matlab/SparseArrayReader.cs @@ -0,0 +1,251 @@ +// +// 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.IO; +using System.Numerics; +using MathNet.Numerics.LinearAlgebra; +using MathNet.Numerics.LinearAlgebra.Storage; + +namespace MathNet.Numerics.Data.Matlab +{ + internal static class SparseArrayReader + where TDataType : struct, IEquatable, IFormattable + { + /// + /// Populates a sparse matrix. + /// + /// The reader. + /// if set to true if the MATLAB complex flag is set. + /// The number of rows. + /// The number of columns. + /// The size of the block. + /// A populated sparse matrix. + public static Matrix PopulateSparseMatrix(BinaryReader reader, bool isComplex, int rows, int columns, int size) + { + // Create matrix with CSR storage. + var matrix = Matrix.Build.Sparse(columns, rows); + + // MATLAB sparse matrices are actually stored as CSC, so just read the data and then transpose. + var storage = matrix.Storage as SparseCompressedRowMatrixStorage; + + // populate the row data array + var ir = storage.ColumnIndices = new int[size/4]; + for (var i = 0; i < ir.Length; i++) + { + ir[i] = reader.ReadInt32(); + } + + MatlabParser.AlignData(reader.BaseStream, size, false); + + // skip data type since it will always be int32 + reader.BaseStream.Seek(4, SeekOrigin.Current); + + // populate the column data array + var jcsize = reader.ReadInt32(); + var jc = storage.RowPointers; + if (jc.Length != jcsize/4) + { + throw new Exception("invalid jcsize"); + } + + for (var j = 0; j < jc.Length; j++) + { + jc[j] = reader.ReadInt32(); + } + + MatlabParser.AlignData(reader.BaseStream, jcsize, false); + + var type = (DataType)reader.ReadInt32(); + var dataSize = reader.ReadInt32(); + + var dataType = typeof (TDataType); + + // Allocate memory for matrix values + var data = storage.Values = new TDataType[jc[columns]]; + + if (dataType == typeof (double)) + { + if (isComplex) + { + throw new ArgumentException("Invalid TDataType. Matrix is stored as a complex matrix, but a real data type was given."); + } + + PopulateDoubleSparseMatrix(type, (double[])(object)data, reader); + } + else if (dataType == typeof (float)) + { + if (isComplex) + { + throw new ArgumentException("Invalid TDataType. Matrix is stored as a complex matrix, but a real data type was given."); + } + + PopulateSingleSparseMatrix(type, (float[])(object)data, reader); + } + else if (dataType == typeof (Complex)) + { + PopulateComplexSparseMatrix(type, isComplex, (Complex[])(object)data, reader, dataSize); + } + else if (dataType == typeof (Complex32)) + { + PopulateComplex32SparseMatrix(type, isComplex, (Complex32[])(object)data, reader, dataSize); + } + else + { + throw new NotSupportedException(); + } + + return matrix.Transpose(); + } + + /// + /// Populates the double sparse matrix. + /// + /// The MATLAB data type. + /// The matrix values array. + /// The reader to read from. + static void PopulateDoubleSparseMatrix(DataType type, double[] data, BinaryReader reader) + { + for (var i = 0; i < data.Length; i++) + { + data[i] = ReadDoubleValue(type, reader); + } + } + + /// + /// Populates the float sparse matrix. + /// + /// The MATLAB data type. + /// The matrix values array. + /// The reader to read from. + static void PopulateSingleSparseMatrix(DataType type, float[] data, BinaryReader reader) + { + for (var i = 0; i < data.Length; i++) + { + data[i] = (float)ReadDoubleValue(type, reader); + } + } + + /// + /// Populates the complex sparse matrix. + /// + /// The MATLAB data type. + /// if set to true if the MATLAB complex flag is set. + /// The matrix values array. + /// The reader to read from. + /// The length of the stored data. + static void PopulateComplexSparseMatrix(DataType type, bool isComplex, Complex[] data, BinaryReader reader, int dataSize) + { + for (var i = 0; i < data.Length; i++) + { + data[i] = ReadDoubleValue(type, reader); + } + + if (isComplex) + { + var skip = dataSize%8; + + // skip pad + reader.ReadBytes(skip); + + // skip header + type = (DataType)reader.ReadInt32(); + reader.ReadInt32(); + + for (var i = 0; i < data.Length; i++) + { + data[i] += new Complex(0.0, ReadDoubleValue(type, reader)); + } + } + } + + /// + /// Populates the complex32 sparse matrix. + /// + /// The MATLAB data type. + /// if set to true if the MATLAB complex flag is set. + /// The matrix values array. + /// The reader to read from. + /// The length of the stored data. + static void PopulateComplex32SparseMatrix(DataType type, bool isComplex, Complex32[] data, BinaryReader reader, int dataSize) + { + for (var i = 0; i < data.Length; i++) + { + data[i] = (float)ReadDoubleValue(type, reader); + } + + if (isComplex) + { + var skip = dataSize%8; + + // skip pad + reader.ReadBytes(skip); + + // skip header + type = (DataType)reader.ReadInt32(); + reader.ReadInt32(); + + for (var i = 0; i < data.Length; i++) + { + data[i] += new Complex32(0.0f, (float)ReadDoubleValue(type, reader)); + } + } + } + + static double ReadDoubleValue(DataType type, BinaryReader reader) + { + switch (type) + { + case DataType.Double: + return reader.ReadDouble(); + case DataType.Int8: + return reader.ReadSByte(); + case DataType.UInt8: + return reader.ReadByte(); + case DataType.Int16: + return reader.ReadInt16(); + case DataType.UInt16: + return reader.ReadUInt16(); + case DataType.Int32: + return reader.ReadInt32(); + case DataType.UInt32: + return reader.ReadUInt32(); + case DataType.Single: + return reader.ReadSingle(); + case DataType.Int64: + return reader.ReadInt64(); + case DataType.UInt64: + return reader.ReadUInt64(); + default: + throw new NotSupportedException(); + } + } + } +}