// // 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-2010 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.IO.Compression; namespace MathNet.Numerics.LinearAlgebra.IO.Matlab { using System; using System.Collections.Generic; using System.IO; using System.Numerics; using System.Reflection; using System.Text; using Generic; using Properties; using Complex32 = Numerics.Complex32; /// /// Parse a Matlab file /// /// The data type of the matrix. internal class MatlabParser where TDataType : struct, IEquatable, IFormattable { /// /// Large Block Size /// private const int LargeBlockSize = 8; /// /// Little Endian Indicator /// private const byte LittleEndianIndicator = 0x49; /// /// Small Block Size /// private const int SmallBlockSize = 4; /// /// Holds the names of the matrices in the file. /// private readonly IList _names = new List(); /// /// The stream to read the matlab file from. /// private readonly Stream _stream; /// /// Initializes a new instance of the class. /// /// Name of the file. public MatlabParser(string fileName) : this(fileName, new string[0]) { } /// /// Initializes a new instance of the class. /// /// The stream to read from. public MatlabParser(Stream stream) : this(stream, new string[0]) { } /// /// Initializes a new instance of the class. /// /// The stream to read from. /// The name of the objects to retrieve. public MatlabParser(Stream stream, IEnumerable objectNames) { if (stream == null) { throw new ArgumentNullException("stream"); } _stream = stream; SetNames(objectNames); } /// /// Initializes a new instance of the class. /// /// Name of the file. /// The name of the objects to retrieve. public MatlabParser(string fileName, IEnumerable objectNames) { if (string.IsNullOrEmpty(fileName)) { throw new ArgumentException(Resources.StringNullOrEmpty, "filename"); } _stream = File.OpenRead(fileName); SetNames(objectNames); } /// /// Copies the names of the objects to retrieve to a local field. /// /// The name of the objects to retrieve. private void SetNames(IEnumerable objectNames) { foreach (var name in objectNames) { _names.Add(name); } } /// /// Parses the file. /// /// The parsed Matlab file as a object. public MatlabFile Parse() { var file = new MatlabFile(); using (var reader = new BinaryReader(_stream)) { file.HeaderText = Encoding.ASCII.GetString(reader.ReadBytes(116)); // skipping subsystem offsets reader.BaseStream.Position = 126; if (reader.ReadByte() != LittleEndianIndicator) { throw new NotSupportedException(Resources.BigEndianNotSupported); } // skip version since it is always 0x0100. reader.BaseStream.Position = 128; var length = _stream.Length; // for each data block add a matlab object to the file. while (reader.BaseStream.Position < length) { var type = (DataType)reader.ReadInt16(); int size = reader.ReadInt16(); var smallBlock = true; if (size == 0) { size = reader.ReadInt32(); smallBlock = false; } byte[] data; if (type == DataType.Compressed) { data = DecompressBlock(reader.ReadBytes(size), ref type); } else { data = new byte[size]; reader.Read(data, 0, size); AlignData(reader.BaseStream, size, smallBlock); } if (type == DataType.Matrix) { AddMatrix(data, file); } else { throw new NotSupportedException(string.Format(Resources.NotSupportedType, type)); } } } return file; } /// /// Aligns the data. /// /// The stream. /// The size of the array. /// if set to true if reading from a small block. private static void AlignData(Stream stream, int size, bool smallBlock) { var blockSize = smallBlock ? SmallBlockSize : LargeBlockSize; var offset = 0; var mod = size % blockSize; if (mod != 0) { offset = blockSize - mod; } stream.Seek(offset, SeekOrigin.Current); } /// /// Decompresses the block. /// /// The compressed data. /// The type data type contained in the block. /// The decompressed block. private static byte[] DecompressBlock(byte[] compressed, ref DataType type) { 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()) { 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. /// /// The data of the matrix. /// The instance. private void AddMatrix(byte[] data, MatlabFile file) { using (var ms = new MemoryStream(data)) { 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. private 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(); } 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 = 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 = CreateMatrix(true, rows, columns); var dataType = typeof(TDataType); 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((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."); } 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. private 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]; // if (jc[col + 1] == 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, reader.ReadDouble()); break; default: throw new NotSupportedException(); } } } /// /// Populates the float sparse matrix. /// /// The matrix to populate /// The Matlab data type. /// The row indices. /// The column indices. /// The reader to read from. private 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]; if (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(); } } } /// /// 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. private 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]; if (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, 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]; if (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. private 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]; if (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]; if (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. private static Matrix PopulateDenseMatrix(DataType type, BinaryReader reader, bool isComplex, int rows, int columns, int size) { var matrix = CreateMatrix(false, rows, columns); var dataType = typeof(TDataType); 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())); } } 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) { 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(); } } } /// /// 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(); } } /// /// Creates a matrix. /// /// if set to true, creates a sparse matrix. /// The number of rows. /// The number of columns. /// A matrix with the specified storage. private static Matrix CreateMatrix(bool sparse, int rows, int columns) { ConstructorInfo constructor; var dataType = typeof(TDataType); if (sparse) { if (dataType == typeof(double)) { constructor = typeof(LinearAlgebra.Double.SparseMatrix).GetConstructor(new[] { typeof(int), typeof(int) }); } else if (dataType == typeof(float)) { constructor = typeof(LinearAlgebra.Single.SparseMatrix).GetConstructor(new[] { typeof(int), typeof(int) }); } else if (dataType == typeof(Complex)) { constructor = typeof(LinearAlgebra.Complex.SparseMatrix).GetConstructor(new[] { typeof(int), typeof(int) }); } else if (dataType == typeof(Complex32)) { constructor = typeof(LinearAlgebra.Complex32.SparseMatrix).GetConstructor(new[] { typeof(int), typeof(int) }); } else { throw new NotSupportedException(); } } else { if (dataType == typeof(double)) { constructor = typeof(LinearAlgebra.Double.DenseMatrix).GetConstructor(new[] { typeof(int), typeof(int) }); } else if (dataType == typeof(float)) { constructor = typeof(LinearAlgebra.Single.DenseMatrix).GetConstructor(new[] { typeof(int), typeof(int) }); } else if (dataType == typeof(Complex)) { constructor = typeof(LinearAlgebra.Complex.DenseMatrix).GetConstructor(new[] { typeof(int), typeof(int) }); } else if (dataType == typeof(Complex32)) { constructor = typeof(LinearAlgebra.Complex32.DenseMatrix).GetConstructor(new[] { typeof(int), typeof(int) }); } else { throw new NotSupportedException(); } } return (Matrix)constructor.Invoke(new object[] { rows, columns }); } } }