From ffa9f92a06e76a8bc67f7622d28a20ade18aef04 Mon Sep 17 00:00:00 2001 From: Marcus Cuda Date: Thu, 14 Oct 2010 21:07:16 +0800 Subject: [PATCH] matlab: first take at then new matlab parser, still needs work --- src/MathNet.Numerics.5.1.ReSharper | 6 +- .../Complex/IO/DelimitedWriter.cs | 70 + .../LinearAlgebra/Complex/IO/MatlabReader.cs | 53 + .../Complex32/IO/DelimitedWriter.cs | 70 + .../Complex32/IO/MatlabReader.cs | 53 + .../Double/IO/DelimitedWriter.cs | 70 + .../Double/IO/Matlab/MatlabFile.cs | 219 --- .../Double/IO/Matlab/MatlabParser.cs | 536 ------ .../LinearAlgebra/Double/IO/MatlabReader.cs | 145 +- .../{Common => }/IO/Matlab/ArrayClass.cs | 2 +- .../{Common => }/IO/Matlab/ArrayFlags.cs | 2 +- .../{Common => }/IO/Matlab/DataType.cs | 2 +- .../LinearAlgebra/IO/Matlab/MatlabFile.cs | 84 + .../LinearAlgebra/IO/Matlab/MatlabParser.cs | 1534 +++++++++++++++++ src/Numerics/LinearAlgebra/IO/MatlabReader.cs | 192 +++ .../Single/IO/DelimitedWriter.cs | 70 + .../Single/IO/Matlab/MatlabFile.cs | 219 --- .../Single/IO/Matlab/MatlabParser.cs | 536 ------ .../LinearAlgebra/Single/IO/MatlabReader.cs | 145 +- src/Numerics/Numerics.csproj | 19 +- .../Complex/IO/DelimitedWriterTests.cs | 10 +- .../Complex/IO/MatlabReaderTests.cs | 70 + .../Complex32/IO/DelimitedWriterTests.cs | 10 +- .../Complex32/IO/MatlabReaderTests.cs | 70 + .../Double/IO/DelimitedWriterTests.cs | 10 +- .../Single/IO/DelimitedWriterTests.cs | 10 +- src/UnitTests/UnitTests.csproj | 2 + 27 files changed, 2385 insertions(+), 1824 deletions(-) create mode 100644 src/Numerics/LinearAlgebra/Complex/IO/DelimitedWriter.cs create mode 100644 src/Numerics/LinearAlgebra/Complex/IO/MatlabReader.cs create mode 100644 src/Numerics/LinearAlgebra/Complex32/IO/DelimitedWriter.cs create mode 100644 src/Numerics/LinearAlgebra/Complex32/IO/MatlabReader.cs create mode 100644 src/Numerics/LinearAlgebra/Double/IO/DelimitedWriter.cs delete mode 100644 src/Numerics/LinearAlgebra/Double/IO/Matlab/MatlabFile.cs delete mode 100644 src/Numerics/LinearAlgebra/Double/IO/Matlab/MatlabParser.cs rename src/Numerics/LinearAlgebra/{Common => }/IO/Matlab/ArrayClass.cs (98%) rename src/Numerics/LinearAlgebra/{Common => }/IO/Matlab/ArrayFlags.cs (96%) rename src/Numerics/LinearAlgebra/{Common => }/IO/Matlab/DataType.cs (98%) create mode 100644 src/Numerics/LinearAlgebra/IO/Matlab/MatlabFile.cs create mode 100644 src/Numerics/LinearAlgebra/IO/Matlab/MatlabParser.cs create mode 100644 src/Numerics/LinearAlgebra/IO/MatlabReader.cs create mode 100644 src/Numerics/LinearAlgebra/Single/IO/DelimitedWriter.cs delete mode 100644 src/Numerics/LinearAlgebra/Single/IO/Matlab/MatlabFile.cs delete mode 100644 src/Numerics/LinearAlgebra/Single/IO/Matlab/MatlabParser.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Complex/IO/MatlabReaderTests.cs create mode 100644 src/UnitTests/LinearAlgebraTests/Complex32/IO/MatlabReaderTests.cs diff --git a/src/MathNet.Numerics.5.1.ReSharper b/src/MathNet.Numerics.5.1.ReSharper index 934aa504..108ae5fe 100644 --- a/src/MathNet.Numerics.5.1.ReSharper +++ b/src/MathNet.Numerics.5.1.ReSharper @@ -14,7 +14,11 @@ Wikipedia Marsaglia Xorshift -λ +λ +Matlab +Matlab +Matlab +Endian diff --git a/src/Numerics/LinearAlgebra/Complex/IO/DelimitedWriter.cs b/src/Numerics/LinearAlgebra/Complex/IO/DelimitedWriter.cs new file mode 100644 index 00000000..1a4627d7 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex/IO/DelimitedWriter.cs @@ -0,0 +1,70 @@ +// +// 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. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex.IO +{ + using Generic; + using LinearAlgebra.IO; + + /// + /// Writes an to delimited text file. If the user does not + /// specify a delimiter, a tab separator is used. + /// + public class DelimitedWriter : DelimitedWriter + { + /// + /// Initializes a new instance of the class. + /// a comma as the delimiter. + /// + public DelimitedWriter() + { + } + + /// + /// Initializes a new instance of the class. + /// using the given delimiter. + /// + /// + /// the delimiter to use. + /// + public DelimitedWriter(char delimiter) : base(delimiter) + { + } + + /// + /// Initializes a new instance of the class. + /// using the given delimiter. + /// + /// + /// the delimiter to use. + /// + public DelimitedWriter(string delimiter) : base(delimiter) + { + } + } +} diff --git a/src/Numerics/LinearAlgebra/Complex/IO/MatlabReader.cs b/src/Numerics/LinearAlgebra/Complex/IO/MatlabReader.cs new file mode 100644 index 00000000..1f838d96 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex/IO/MatlabReader.cs @@ -0,0 +1,53 @@ +// +// 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. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex.IO +{ + using System.IO; + using LinearAlgebra.IO; + + /// + /// Creates matrices from Matlab files. + /// + public class MatlabMatrixReader : MatlabMatrixReader + { + /// + /// Initializes a new instance of the class. + /// + /// Name of the file to read matrices from. + public MatlabMatrixReader(string filename) : base(filename) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The stream to reader matrices from. + public MatlabMatrixReader(Stream stream) : base(stream) + { + } + } +} diff --git a/src/Numerics/LinearAlgebra/Complex32/IO/DelimitedWriter.cs b/src/Numerics/LinearAlgebra/Complex32/IO/DelimitedWriter.cs new file mode 100644 index 00000000..1a7906a2 --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex32/IO/DelimitedWriter.cs @@ -0,0 +1,70 @@ +// +// 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. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex32.IO +{ + using Generic; + using LinearAlgebra.IO; + + /// + /// Writes an to delimited text file. If the user does not + /// specify a delimiter, a tab separator is used. + /// + public class DelimitedWriter : DelimitedWriter + { + /// + /// Initializes a new instance of the class. + /// a comma as the delimiter. + /// + public DelimitedWriter() + { + } + + /// + /// Initializes a new instance of the class. + /// using the given delimiter. + /// + /// + /// the delimiter to use. + /// + public DelimitedWriter(char delimiter) : base(delimiter) + { + } + + /// + /// Initializes a new instance of the class. + /// using the given delimiter. + /// + /// + /// the delimiter to use. + /// + public DelimitedWriter(string delimiter) : base(delimiter) + { + } + } +} diff --git a/src/Numerics/LinearAlgebra/Complex32/IO/MatlabReader.cs b/src/Numerics/LinearAlgebra/Complex32/IO/MatlabReader.cs new file mode 100644 index 00000000..534f1eac --- /dev/null +++ b/src/Numerics/LinearAlgebra/Complex32/IO/MatlabReader.cs @@ -0,0 +1,53 @@ +// +// 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. +// + +namespace MathNet.Numerics.LinearAlgebra.Complex32.IO +{ + using System.IO; + using LinearAlgebra.IO; + + /// + /// Creates matrices from Matlab files. + /// + public class MatlabMatrixReader : MatlabMatrixReader + { + /// + /// Initializes a new instance of the class. + /// + /// Name of the file to read matrices from. + public MatlabMatrixReader(string filename) : base(filename) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The stream to reader matrices from. + public MatlabMatrixReader(Stream stream) : base(stream) + { + } + } +} diff --git a/src/Numerics/LinearAlgebra/Double/IO/DelimitedWriter.cs b/src/Numerics/LinearAlgebra/Double/IO/DelimitedWriter.cs new file mode 100644 index 00000000..a2f8eb5f --- /dev/null +++ b/src/Numerics/LinearAlgebra/Double/IO/DelimitedWriter.cs @@ -0,0 +1,70 @@ +// +// 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. +// + +namespace MathNet.Numerics.LinearAlgebra.Double.IO +{ + using Generic; + using LinearAlgebra.IO; + + /// + /// Writes an to delimited text file. If the user does not + /// specify a delimiter, a tab separator is used. + /// + public class DelimitedWriter : DelimitedWriter + { + /// + /// Initializes a new instance of the class. + /// a comma as the delimiter. + /// + public DelimitedWriter() + { + } + + /// + /// Initializes a new instance of the class. + /// using the given delimiter. + /// + /// + /// the delimiter to use. + /// + public DelimitedWriter(char delimiter) : base(delimiter) + { + } + + /// + /// Initializes a new instance of the class. + /// using the given delimiter. + /// + /// + /// the delimiter to use. + /// + public DelimitedWriter(string delimiter) : base(delimiter) + { + } + } +} diff --git a/src/Numerics/LinearAlgebra/Double/IO/Matlab/MatlabFile.cs b/src/Numerics/LinearAlgebra/Double/IO/Matlab/MatlabFile.cs deleted file mode 100644 index c2de1b77..00000000 --- a/src/Numerics/LinearAlgebra/Double/IO/Matlab/MatlabFile.cs +++ /dev/null @@ -1,219 +0,0 @@ -// -// 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. -// - -namespace MathNet.Numerics.LinearAlgebra.Double.IO.Matlab -{ - using System.Collections.Generic; - using Generic; - - /// - /// Represents a Matlab file - /// - internal class MatlabFile - { - /// - /// Matrices in a matlab file stored as 1-D arrays - /// - private readonly IDictionary> _matrices = new SortedList>(); - - /// - /// Gets or sets the header text. - /// - /// The header text. - public string HeaderText { get; set; } - - /// - /// Gets or sets the first name of the matrix. - /// - /// The first name of the matrix. - public string FirstMatrixName { get; set; } - - /// - /// Gets the first matrix. - /// - /// The first matrix. - public Matrix FirstMatrix - { - get - { - if (string.IsNullOrEmpty(FirstMatrixName) || !_matrices.ContainsKey(FirstMatrixName)) - { - return null; - } - - return _matrices[FirstMatrixName]; - } - } - - /// - /// Gets the matrices. - /// - /// The matrices. - public IDictionary> Matrices - { - get { return _matrices; } - } - } - - /* - /// - /// An - /// - /// - /// - internal class ListDictionary : IDictionary - { - private readonly IList _keys = new List(); - private readonly IList _values = new List(); - - public void Add(T key, K value) - { - _keys.Add(key); - _values.Add(value); - } - - public bool ContainsKey(T key) - { - return _keys.Contains(key); - } - - public ICollection Keys - { - get { return _keys; } - } - - public bool Remove(T key) - { - if (_keys.Contains(key)) - { - int pos = _keys.IndexOf(key); - _values.RemoveAt(pos); - _values.RemoveAt(pos); - return true; - } - return false; - } - - public bool TryGetValue(T key, out K value) - { - if (_keys.Contains(key)) - { - value = _values[_keys.IndexOf(key)]; - return true; - } - value = default(K); - return false; - } - - public ICollection Values - { - get { return _values; } - } - - public K this[T key] - { - get - { - if (_keys.Contains(key)) - { - return _values[_keys.IndexOf(key)]; - } - throw new KeyNotFoundException(); - } - set - { - if (_keys.Contains(key)) - { - _values[_keys.IndexOf(key)] = value; - } - else - { - Add(key, value); - } - } - } - - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - public void Clear() - { - _keys.Clear(); - _values.Clear(); - } - - public bool Contains(KeyValuePair item) - { - return _keys.Contains(item.Key) && _values[_keys.IndexOf(item.Key)].Equals(item.Value); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - for (int i = 0; i < _keys.Count; i++) - { - array[arrayIndex + i] = new KeyValuePair(_keys[i], _values[i]); - } - } - - public int Count - { - get { return _keys.Count; } - } - - public bool IsReadOnly - { - get { return false; } - } - - public bool Remove(KeyValuePair item) - { - if (Contains(item)) - { - Remove(item.Key); - return true; - } - return false; - } - - public IEnumerator> GetEnumerator() - { - for (int i = 0; i < _keys.Count; i++) - { - yield return new KeyValuePair(_keys[i], _values[i]); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - }*/ -} diff --git a/src/Numerics/LinearAlgebra/Double/IO/Matlab/MatlabParser.cs b/src/Numerics/LinearAlgebra/Double/IO/Matlab/MatlabParser.cs deleted file mode 100644 index bd61214e..00000000 --- a/src/Numerics/LinearAlgebra/Double/IO/Matlab/MatlabParser.cs +++ /dev/null @@ -1,536 +0,0 @@ -// -// 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. -// - -namespace MathNet.Numerics.LinearAlgebra.Double.IO.Matlab -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using Common.IO.Matlab; - using Generic; - using Properties; - using zlib; - - /// - /// Parse a Matlab file - /// - internal class MatlabParser - { - /// - /// 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 decompressed = new MemoryStream()) - { - using (var decompressor = new ZOutputStream(decompressed)) - { - decompressor.Write(compressed, 0, compressed.Length); - 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; - - if (isComplex) - { - throw new NotSupportedException(Resources.ComplexMatricesNotSupported); - } - - // 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, rows, columns, size); - break; - case ArrayClass.Function: - case ArrayClass.Character: - case ArrayClass.Object: - case ArrayClass.Structure: - case ArrayClass.Cell: - case ArrayClass.Unknown: - throw new NotImplementedException(); - default: - matrix = PopulateDenseMatrix(type, reader, rows, columns); - break; - } - - file.Matrices.Add(name, matrix); - if (file.FirstMatrixName == null) - { - file.FirstMatrixName = name; - } - } - } - } - - /// - /// Populates a sparse matrix. - /// - /// The reader. - /// The number of rows. - /// The number of columns. - /// The size of the block. - /// A populated sparse matrix. - private static Matrix PopulateSparseMatrix(BinaryReader reader, 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(); - - // skip length since we already no it for the number of rows - reader.BaseStream.Seek(4, SeekOrigin.Current); - - Matrix matrix = new SparseMatrix(rows, columns); - var col = 0; - for (var i = 0; i < ir.Length; i++) - { - var row = ir[i]; - if (jc[col + 1] == i) - { - col++; - } - - switch (type) - { - case DataType.Int8: - matrix[row, col] = reader.ReadSByte(); - break; - case DataType.UInt8: - matrix[row, col] = reader.ReadByte(); - break; - case DataType.Int16: - matrix[row, col] = reader.ReadInt16(); - break; - - case DataType.UInt16: - matrix[row, col] = reader.ReadUInt16(); - break; - case DataType.Int32: - matrix[row, col] = reader.ReadInt32(); - break; - - case DataType.UInt32: - matrix[row, col] = reader.ReadUInt32(); - break; - case DataType.Single: - matrix[row, col] = reader.ReadSingle(); - break; - case DataType.Int64: - matrix[row, col] = reader.ReadInt64(); - break; - case DataType.UInt64: - matrix[row, col] = reader.ReadUInt64(); - break; - case DataType.Double: - matrix[row, col] = reader.ReadDouble(); - break; - default: - throw new NotSupportedException(); - } - } - - return matrix; - } - - /// - /// Populates a dense matrix. - /// - /// The type of data. - /// The reader. - /// The number of rows. - /// The number of columns. - /// Returns a populated dense matrix. - private static Matrix PopulateDenseMatrix(DataType type, BinaryReader reader, int rows, int columns) - { - Matrix matrix = new DenseMatrix(rows, columns); - switch (type) - { - case DataType.Int8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadSByte(); - } - } - - break; - case DataType.UInt8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadByte(); - } - } - - break; - case DataType.Int16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadInt16(); - } - } - - break; - case DataType.UInt16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadUInt16(); - } - } - - break; - case DataType.Int32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadInt32(); - } - } - - break; - case DataType.UInt32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadUInt32(); - } - } - - break; - case DataType.Single: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadSingle(); - } - } - - break; - case DataType.Int64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadInt64(); - } - } - - break; - case DataType.UInt64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadUInt64(); - } - } - - break; - case DataType.Double: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadDouble(); - } - } - - break; - default: - throw new NotSupportedException(); - } - - return matrix; - } - } -} diff --git a/src/Numerics/LinearAlgebra/Double/IO/MatlabReader.cs b/src/Numerics/LinearAlgebra/Double/IO/MatlabReader.cs index f673a724..b502929a 100644 --- a/src/Numerics/LinearAlgebra/Double/IO/MatlabReader.cs +++ b/src/Numerics/LinearAlgebra/Double/IO/MatlabReader.cs @@ -3,9 +3,7 @@ // 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 @@ -28,163 +26,28 @@ namespace MathNet.Numerics.LinearAlgebra.Double.IO { - using System; - using System.Collections.Generic; using System.IO; - using Generic; - using Matlab; - using Properties; + using LinearAlgebra.IO; /// /// Creates matrices from Matlab files. /// - public class MatlabMatrixReader + public class MatlabMatrixReader : MatlabMatrixReader { - /// - /// The name of the file to read from. - /// - private readonly string _filename; - - /// - /// The stream to read from if we are not reading from a file directly. - /// - private readonly Stream _stream; - /// /// Initializes a new instance of the class. /// /// Name of the file to read matrices from. - public MatlabMatrixReader(string filename) + public MatlabMatrixReader(string filename) : base(filename) { - if (string.IsNullOrEmpty(filename)) - { - throw new ArgumentException(Resources.StringNullOrEmpty, "filename"); - } - - if (!File.Exists(filename)) - { - throw new FileNotFoundException(Resources.FileDoesNotExist, "filename"); - } - - _filename = filename; } /// /// Initializes a new instance of the class. /// /// The stream to reader matrices from. - public MatlabMatrixReader(Stream stream) - { - if (stream == null) - { - throw new ArgumentNullException("stream"); - } - - _stream = stream; - } - - /// - /// Reads the first matrix from the file or stream. - /// - /// - /// If the matrix is stored as a sparse matrix, then a is returned. Otherwise, a - /// is returned. - /// - public Matrix ReadMatrix() - { - return ReadMatrix(null); - } - - /// - /// Reads the named matrix from the file or stream. - /// - /// The name of the matrix to read. - /// - /// If the matrix is stored as a sparse matrix, then a is returned. Otherwise, a - /// is returned. is returned if a matrix with the requests name doesn't exist. - /// - public Matrix ReadMatrix(string matrixName) + public MatlabMatrixReader(Stream stream) : base(stream) { - Stream stream; - if (_filename == null) - { - stream = _stream; - _stream.Seek(0, SeekOrigin.Begin); - } - else - { - stream = new FileStream(_filename, FileMode.Open, FileAccess.Read); - } - - var names = string.IsNullOrEmpty(matrixName) ? new string[] { } : new[] { matrixName }; - var parser = new MatlabParser(stream, names); - var file = parser.Parse(); - - Matrix matrix = null; - if (string.IsNullOrEmpty(matrixName)) - { - matrix = file.FirstMatrix; - } - else if (file.Matrices.ContainsKey(matrixName)) - { - matrix = file.Matrices[matrixName]; - } - - if (_filename != null) - { - stream.Close(); - stream.Dispose(); - } - - return matrix; - } - - /// - /// Reads all matrices from the file or stream. - /// - /// All matrices from the file or stream. - public Matrix[] ReadMatrices() - { - return ReadMatrices(new string[] { }); - } - - /// - /// Reads the named matrices from the file or stream. - /// - /// The names of the matrices to retrieve. - /// - /// The named matrices from the file or stream. - /// - public Matrix[] ReadMatrices(IEnumerable names) - { - Stream stream; - if (_filename == null) - { - stream = _stream; - _stream.Seek(0, SeekOrigin.Begin); - } - else - { - stream = new BufferedStream(new FileStream(_filename, FileMode.Open, FileAccess.Read)); - } - - var parser = new MatlabParser(stream, names); - var file = parser.Parse(); - - var matrices = new Matrix[file.Matrices.Count]; - var i = 0; - foreach (var matrix in file.Matrices.Values) - { - matrices[i++] = matrix; - } - - if (_filename != null) - { - stream.Close(); - stream.Dispose(); - } - - return matrices; } } } diff --git a/src/Numerics/LinearAlgebra/Common/IO/Matlab/ArrayClass.cs b/src/Numerics/LinearAlgebra/IO/Matlab/ArrayClass.cs similarity index 98% rename from src/Numerics/LinearAlgebra/Common/IO/Matlab/ArrayClass.cs rename to src/Numerics/LinearAlgebra/IO/Matlab/ArrayClass.cs index bd6fb887..174dcda0 100644 --- a/src/Numerics/LinearAlgebra/Common/IO/Matlab/ArrayClass.cs +++ b/src/Numerics/LinearAlgebra/IO/Matlab/ArrayClass.cs @@ -26,7 +26,7 @@ // OTHER DEALINGS IN THE SOFTWARE. // -namespace MathNet.Numerics.LinearAlgebra.Common.IO.Matlab +namespace MathNet.Numerics.LinearAlgebra.IO.Matlab { /// /// Enumeration for the Matlab array types diff --git a/src/Numerics/LinearAlgebra/Common/IO/Matlab/ArrayFlags.cs b/src/Numerics/LinearAlgebra/IO/Matlab/ArrayFlags.cs similarity index 96% rename from src/Numerics/LinearAlgebra/Common/IO/Matlab/ArrayFlags.cs rename to src/Numerics/LinearAlgebra/IO/Matlab/ArrayFlags.cs index 823def1f..621d6603 100644 --- a/src/Numerics/LinearAlgebra/Common/IO/Matlab/ArrayFlags.cs +++ b/src/Numerics/LinearAlgebra/IO/Matlab/ArrayFlags.cs @@ -26,7 +26,7 @@ // OTHER DEALINGS IN THE SOFTWARE. // -namespace MathNet.Numerics.LinearAlgebra.Common.IO.Matlab +namespace MathNet.Numerics.LinearAlgebra.IO.Matlab { using System; diff --git a/src/Numerics/LinearAlgebra/Common/IO/Matlab/DataType.cs b/src/Numerics/LinearAlgebra/IO/Matlab/DataType.cs similarity index 98% rename from src/Numerics/LinearAlgebra/Common/IO/Matlab/DataType.cs rename to src/Numerics/LinearAlgebra/IO/Matlab/DataType.cs index 53995bbe..2938e444 100644 --- a/src/Numerics/LinearAlgebra/Common/IO/Matlab/DataType.cs +++ b/src/Numerics/LinearAlgebra/IO/Matlab/DataType.cs @@ -26,7 +26,7 @@ // OTHER DEALINGS IN THE SOFTWARE. // -namespace MathNet.Numerics.LinearAlgebra.Common.IO.Matlab +namespace MathNet.Numerics.LinearAlgebra.IO.Matlab { /// /// Matlab data types diff --git a/src/Numerics/LinearAlgebra/IO/Matlab/MatlabFile.cs b/src/Numerics/LinearAlgebra/IO/Matlab/MatlabFile.cs new file mode 100644 index 00000000..482395a7 --- /dev/null +++ b/src/Numerics/LinearAlgebra/IO/Matlab/MatlabFile.cs @@ -0,0 +1,84 @@ +// +// 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. +// + +namespace MathNet.Numerics.LinearAlgebra.IO.Matlab +{ + using System; + using System.Collections.Generic; + using Generic; + + /// + /// 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 + /// + private readonly IDictionary> _matrices = new SortedList>(); + + /// + /// Gets or sets the header text. + /// + /// The header text. + public string HeaderText { get; set; } + + /// + /// Gets or sets the first name of the matrix. + /// + /// The first name of the matrix. + public string FirstMatrixName { get; set; } + + /// + /// Gets the first matrix. + /// + /// The first matrix. + public Matrix FirstMatrix + { + get + { + if (string.IsNullOrEmpty(FirstMatrixName) || !_matrices.ContainsKey(FirstMatrixName)) + { + return null; + } + + return _matrices[FirstMatrixName]; + } + } + + /// + /// Gets the matrices. + /// + /// The matrices. + public IDictionary> Matrices + { + get { return _matrices; } + } + } +} diff --git a/src/Numerics/LinearAlgebra/IO/Matlab/MatlabParser.cs b/src/Numerics/LinearAlgebra/IO/Matlab/MatlabParser.cs new file mode 100644 index 00000000..7e4b6010 --- /dev/null +++ b/src/Numerics/LinearAlgebra/IO/Matlab/MatlabParser.cs @@ -0,0 +1,1534 @@ +// +// 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. +// + +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 zlib; + 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 decompressed = new MemoryStream()) + { + using (var decompressor = new ZOutputStream(decompressed)) + { + decompressor.Write(compressed, 0, compressed.Length); + 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); + 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(); + + // skip length since we already no it for the number of rows + reader.BaseStream.Seek(4, SeekOrigin.Current); + + 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); + } + else if (dataType == typeof(Complex32)) + { + PopulateComplex32SparseMatrix((Matrix)(object)matrix, type, isComplex, ir, jc, reader); + } + 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) + { + 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. + private static void PopulateComplexSparseMatrix(Matrix matrix, DataType type, bool isComplex, 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, reader.ReadDouble()); + break; + default: + throw new NotSupportedException(); + } + } + + if (isComplex) + { + // skip header + reader.ReadBytes(8); + 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. + private static void PopulateComplex32SparseMatrix(Matrix matrix, DataType type, bool isComplex, 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(); + } + } + + if (isComplex) + { + // skip header + reader.ReadBytes(8); + 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. + /// Returns a populated dense matrix. + private static Matrix PopulateDenseMatrix(DataType type, BinaryReader reader, bool isComplex, int rows, int columns) + { + 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); + } + else if (dataType == typeof(Complex32)) + { + PopulateComplex32DenseMatrix((Matrix)(object)matrix, type, isComplex, reader, rows, columns); + } + 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. + public static void PopulateComplexDenseMatrix(Matrix matrix, DataType type, bool isComplex, 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(); + } + + if (isComplex) + { + 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. + public static void PopulateComplex32DenseMatrix(Matrix matrix, DataType type, bool isComplex, 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(); + } + + if (isComplex) + { + 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 }); + } + } +} diff --git a/src/Numerics/LinearAlgebra/IO/MatlabReader.cs b/src/Numerics/LinearAlgebra/IO/MatlabReader.cs new file mode 100644 index 00000000..138e38c8 --- /dev/null +++ b/src/Numerics/LinearAlgebra/IO/MatlabReader.cs @@ -0,0 +1,192 @@ +// +// 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. +// + +namespace MathNet.Numerics.LinearAlgebra.IO +{ + using System; + using System.Collections.Generic; + using System.IO; + using Generic; + using Matlab; + using Properties; + + /// + /// Creates matrices from Matlab files. + /// + /// The data type of the Matrix. It can be either: double, float, Complex, or Complex32. + public class MatlabMatrixReader where TDataType : struct, IEquatable, IFormattable + { + /// + /// The name of the file to read from. + /// + private readonly string _filename; + + /// + /// The stream to read from if we are not reading from a file directly. + /// + private readonly Stream _stream; + + /// + /// Initializes a new instance of the class. + /// + /// Name of the file to read matrices from. + public MatlabMatrixReader(string filename) + { + if (string.IsNullOrEmpty(filename)) + { + throw new ArgumentException(Resources.StringNullOrEmpty, "filename"); + } + + if (!File.Exists(filename)) + { + throw new FileNotFoundException(Resources.FileDoesNotExist, "filename"); + } + + _filename = filename; + } + + /// + /// Initializes a new instance of the class. + /// + /// The stream to reader matrices from. + public MatlabMatrixReader(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException("stream"); + } + + _stream = stream; + } + + /// + /// Reads the first matrix from the file or stream. + /// + /// + /// A sparse or dense matrix depending on how the matrix + /// is defined in the Matlab file. + /// + public Matrix ReadMatrix() + { + return ReadMatrix(null); + } + + /// + /// Reads the named matrix from the file or stream. + /// + /// The name of the matrix to read. + /// + /// A sparse or dense matrix depending on how the matrix + /// is defined in the Matlab file. + /// is returned if a matrix with the requests name doesn't exist. + /// + public Matrix ReadMatrix(string matrixName) + { + Stream stream; + if (_filename == null) + { + stream = _stream; + _stream.Seek(0, SeekOrigin.Begin); + } + else + { + stream = new FileStream(_filename, FileMode.Open, FileAccess.Read); + } + + var names = string.IsNullOrEmpty(matrixName) ? new string[] { } : new[] { matrixName }; + var parser = new MatlabParser(stream, names); + var file = parser.Parse(); + + Matrix matrix = null; + if (string.IsNullOrEmpty(matrixName)) + { + matrix = file.FirstMatrix; + } + else if (file.Matrices.ContainsKey(matrixName)) + { + matrix = file.Matrices[matrixName]; + } + + if (_filename != null) + { + stream.Close(); + stream.Dispose(); + } + + return matrix; + } + + /// + /// Reads all matrices from the file or stream. + /// + /// All matrices from the file or stream. + public Matrix[] ReadMatrices() + { + return ReadMatrices(new string[] { }); + } + + /// + /// Reads the named matrices from the file or stream. + /// + /// The names of the matrices to retrieve. + /// + /// The named matrices from the file or stream. + /// + public Matrix[] ReadMatrices(IEnumerable names) + { + Stream stream; + if (_filename == null) + { + stream = _stream; + _stream.Seek(0, SeekOrigin.Begin); + } + else + { + stream = new BufferedStream(new FileStream(_filename, FileMode.Open, FileAccess.Read)); + } + + var parser = new MatlabParser(stream, names); + var file = parser.Parse(); + + var matrices = new Matrix[file.Matrices.Count]; + var i = 0; + foreach (var matrix in file.Matrices.Values) + { + matrices[i++] = matrix; + } + + if (_filename != null) + { + stream.Close(); + stream.Dispose(); + } + + return matrices; + } + } +} diff --git a/src/Numerics/LinearAlgebra/Single/IO/DelimitedWriter.cs b/src/Numerics/LinearAlgebra/Single/IO/DelimitedWriter.cs new file mode 100644 index 00000000..f674105e --- /dev/null +++ b/src/Numerics/LinearAlgebra/Single/IO/DelimitedWriter.cs @@ -0,0 +1,70 @@ +// +// 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. +// + +namespace MathNet.Numerics.LinearAlgebra.Single.IO +{ + using Generic; + using LinearAlgebra.IO; + + /// + /// Writes an to delimited text file. If the user does not + /// specify a delimiter, a tab separator is used. + /// + public class DelimitedWriter : DelimitedWriter + { + /// + /// Initializes a new instance of the class. + /// a comma as the delimiter. + /// + public DelimitedWriter() + { + } + + /// + /// Initializes a new instance of the class. + /// using the given delimiter. + /// + /// + /// the delimiter to use. + /// + public DelimitedWriter(char delimiter) : base(delimiter) + { + } + + /// + /// Initializes a new instance of the class. + /// using the given delimiter. + /// + /// + /// the delimiter to use. + /// + public DelimitedWriter(string delimiter) : base(delimiter) + { + } + } +} diff --git a/src/Numerics/LinearAlgebra/Single/IO/Matlab/MatlabFile.cs b/src/Numerics/LinearAlgebra/Single/IO/Matlab/MatlabFile.cs deleted file mode 100644 index 01b216fe..00000000 --- a/src/Numerics/LinearAlgebra/Single/IO/Matlab/MatlabFile.cs +++ /dev/null @@ -1,219 +0,0 @@ -// -// 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. -// - -namespace MathNet.Numerics.LinearAlgebra.Single.IO.Matlab -{ - using System.Collections.Generic; - using Generic; - - /// - /// Represents a Matlab file - /// - internal class MatlabFile - { - /// - /// Matrices in a matlab file stored as 1-D arrays - /// - private readonly IDictionary> _matrices = new SortedList>(); - - /// - /// Gets or sets the header text. - /// - /// The header text. - public string HeaderText { get; set; } - - /// - /// Gets or sets the first name of the matrix. - /// - /// The first name of the matrix. - public string FirstMatrixName { get; set; } - - /// - /// Gets the first matrix. - /// - /// The first matrix. - public Matrix FirstMatrix - { - get - { - if (string.IsNullOrEmpty(FirstMatrixName) || !_matrices.ContainsKey(FirstMatrixName)) - { - return null; - } - - return _matrices[FirstMatrixName]; - } - } - - /// - /// Gets the matrices. - /// - /// The matrices. - public IDictionary> Matrices - { - get { return _matrices; } - } - } - - /* - /// - /// An - /// - /// - /// - internal class ListDictionary : IDictionary - { - private readonly IList _keys = new List(); - private readonly IList _values = new List(); - - public void Add(T key, K value) - { - _keys.Add(key); - _values.Add(value); - } - - public bool ContainsKey(T key) - { - return _keys.Contains(key); - } - - public ICollection Keys - { - get { return _keys; } - } - - public bool Remove(T key) - { - if (_keys.Contains(key)) - { - int pos = _keys.IndexOf(key); - _values.RemoveAt(pos); - _values.RemoveAt(pos); - return true; - } - return false; - } - - public bool TryGetValue(T key, out K value) - { - if (_keys.Contains(key)) - { - value = _values[_keys.IndexOf(key)]; - return true; - } - value = default(K); - return false; - } - - public ICollection Values - { - get { return _values; } - } - - public K this[T key] - { - get - { - if (_keys.Contains(key)) - { - return _values[_keys.IndexOf(key)]; - } - throw new KeyNotFoundException(); - } - set - { - if (_keys.Contains(key)) - { - _values[_keys.IndexOf(key)] = value; - } - else - { - Add(key, value); - } - } - } - - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - public void Clear() - { - _keys.Clear(); - _values.Clear(); - } - - public bool Contains(KeyValuePair item) - { - return _keys.Contains(item.Key) && _values[_keys.IndexOf(item.Key)].Equals(item.Value); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - for (int i = 0; i < _keys.Count; i++) - { - array[arrayIndex + i] = new KeyValuePair(_keys[i], _values[i]); - } - } - - public int Count - { - get { return _keys.Count; } - } - - public bool IsReadOnly - { - get { return false; } - } - - public bool Remove(KeyValuePair item) - { - if (Contains(item)) - { - Remove(item.Key); - return true; - } - return false; - } - - public IEnumerator> GetEnumerator() - { - for (int i = 0; i < _keys.Count; i++) - { - yield return new KeyValuePair(_keys[i], _values[i]); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - }*/ -} diff --git a/src/Numerics/LinearAlgebra/Single/IO/Matlab/MatlabParser.cs b/src/Numerics/LinearAlgebra/Single/IO/Matlab/MatlabParser.cs deleted file mode 100644 index 5c626022..00000000 --- a/src/Numerics/LinearAlgebra/Single/IO/Matlab/MatlabParser.cs +++ /dev/null @@ -1,536 +0,0 @@ -// -// 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. -// - -namespace MathNet.Numerics.LinearAlgebra.Single.IO.Matlab -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using Common.IO.Matlab; - using Generic; - using Properties; - using zlib; - - /// - /// Parse a Matlab file - /// - internal class MatlabParser - { - /// - /// 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 decompressed = new MemoryStream()) - { - using (var decompressor = new ZOutputStream(decompressed)) - { - decompressor.Write(compressed, 0, compressed.Length); - 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; - - if (isComplex) - { - throw new NotSupportedException(Resources.ComplexMatricesNotSupported); - } - - // 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, rows, columns, size); - break; - case ArrayClass.Function: - case ArrayClass.Character: - case ArrayClass.Object: - case ArrayClass.Structure: - case ArrayClass.Cell: - case ArrayClass.Unknown: - throw new NotImplementedException(); - default: - matrix = PopulateDenseMatrix(type, reader, rows, columns); - break; - } - - file.Matrices.Add(name, matrix); - if (file.FirstMatrixName == null) - { - file.FirstMatrixName = name; - } - } - } - } - - /// - /// Populates a sparse matrix. - /// - /// The reader. - /// The number of rows. - /// The number of columns. - /// The size of the block. - /// A populated sparse matrix. - private static Matrix PopulateSparseMatrix(BinaryReader reader, 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(); - - // skip length since we already no it for the number of rows - reader.BaseStream.Seek(4, SeekOrigin.Current); - - Matrix matrix = new SparseMatrix(rows, columns); - var col = 0; - for (var i = 0; i < ir.Length; i++) - { - var row = ir[i]; - if (jc[col + 1] == i) - { - col++; - } - - switch (type) - { - case DataType.Int8: - matrix[row, col] = reader.ReadSByte(); - break; - case DataType.UInt8: - matrix[row, col] = reader.ReadByte(); - break; - case DataType.Int16: - matrix[row, col] = reader.ReadInt16(); - break; - - case DataType.UInt16: - matrix[row, col] = reader.ReadUInt16(); - break; - case DataType.Int32: - matrix[row, col] = reader.ReadInt32(); - break; - - case DataType.UInt32: - matrix[row, col] = reader.ReadUInt32(); - break; - case DataType.Single: - matrix[row, col] = reader.ReadSingle(); - break; - case DataType.Int64: - matrix[row, col] = reader.ReadInt64(); - break; - case DataType.UInt64: - matrix[row, col] = reader.ReadUInt64(); - break; - case DataType.Double: - matrix[row, col] = (float)reader.ReadDouble(); - break; - default: - throw new NotSupportedException(); - } - } - - return matrix; - } - - /// - /// Populates a dense matrix. - /// - /// The type of data. - /// The reader. - /// The number of rows. - /// The number of columns. - /// Returns a populated dense matrix. - private static Matrix PopulateDenseMatrix(DataType type, BinaryReader reader, int rows, int columns) - { - Matrix matrix = new DenseMatrix(rows, columns); - switch (type) - { - case DataType.Int8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadSByte(); - } - } - - break; - case DataType.UInt8: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadByte(); - } - } - - break; - case DataType.Int16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadInt16(); - } - } - - break; - case DataType.UInt16: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadUInt16(); - } - } - - break; - case DataType.Int32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadInt32(); - } - } - - break; - case DataType.UInt32: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadUInt32(); - } - } - - break; - case DataType.Single: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadSingle(); - } - } - - break; - case DataType.Int64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadInt64(); - } - } - - break; - case DataType.UInt64: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = reader.ReadUInt64(); - } - } - - break; - case DataType.Double: - for (var j = 0; j < columns; j++) - { - for (var i = 0; i < rows; i++) - { - matrix[i, j] = (float)reader.ReadDouble(); - } - } - - break; - default: - throw new NotSupportedException(); - } - - return matrix; - } - } -} diff --git a/src/Numerics/LinearAlgebra/Single/IO/MatlabReader.cs b/src/Numerics/LinearAlgebra/Single/IO/MatlabReader.cs index 2c748eaa..9544af0b 100644 --- a/src/Numerics/LinearAlgebra/Single/IO/MatlabReader.cs +++ b/src/Numerics/LinearAlgebra/Single/IO/MatlabReader.cs @@ -3,9 +3,7 @@ // 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 @@ -28,163 +26,28 @@ namespace MathNet.Numerics.LinearAlgebra.Single.IO { - using System; - using System.Collections.Generic; using System.IO; - using Generic; - using Matlab; - using Properties; + using LinearAlgebra.IO; /// /// Creates matrices from Matlab files. /// - public class MatlabMatrixReader + public class MatlabMatrixReader : MatlabMatrixReader { - /// - /// The name of the file to read from. - /// - private readonly string _filename; - - /// - /// The stream to read from if we are not reading from a file directly. - /// - private readonly Stream _stream; - /// /// Initializes a new instance of the class. /// /// Name of the file to read matrices from. - public MatlabMatrixReader(string filename) + public MatlabMatrixReader(string filename) : base(filename) { - if (string.IsNullOrEmpty(filename)) - { - throw new ArgumentException(Resources.StringNullOrEmpty, "filename"); - } - - if (!File.Exists(filename)) - { - throw new FileNotFoundException(Resources.FileDoesNotExist, "filename"); - } - - _filename = filename; } /// /// Initializes a new instance of the class. /// /// The stream to reader matrices from. - public MatlabMatrixReader(Stream stream) - { - if (stream == null) - { - throw new ArgumentNullException("stream"); - } - - _stream = stream; - } - - /// - /// Reads the first matrix from the file or stream. - /// - /// - /// If the matrix is stored as a sparse matrix, then a is returned. Otherwise, a - /// is returned. - /// - public Matrix ReadMatrix() - { - return ReadMatrix(null); - } - - /// - /// Reads the named matrix from the file or stream. - /// - /// The name of the matrix to read. - /// - /// If the matrix is stored as a sparse matrix, then a is returned. Otherwise, a - /// is returned. is returned if a matrix with the requests name doesn't exist. - /// - public Matrix ReadMatrix(string matrixName) + public MatlabMatrixReader(Stream stream) : base(stream) { - Stream stream; - if (_filename == null) - { - stream = _stream; - _stream.Seek(0, SeekOrigin.Begin); - } - else - { - stream = new FileStream(_filename, FileMode.Open, FileAccess.Read); - } - - var names = string.IsNullOrEmpty(matrixName) ? new string[] { } : new[] { matrixName }; - var parser = new MatlabParser(stream, names); - var file = parser.Parse(); - - Matrix matrix = null; - if (string.IsNullOrEmpty(matrixName)) - { - matrix = file.FirstMatrix; - } - else if (file.Matrices.ContainsKey(matrixName)) - { - matrix = file.Matrices[matrixName]; - } - - if (_filename != null) - { - stream.Close(); - stream.Dispose(); - } - - return matrix; - } - - /// - /// Reads all matrices from the file or stream. - /// - /// All matrices from the file or stream. - public Matrix[] ReadMatrices() - { - return ReadMatrices(new string[] { }); - } - - /// - /// Reads the named matrices from the file or stream. - /// - /// The names of the matrices to retrieve. - /// - /// The named matrices from the file or stream. - /// - public Matrix[] ReadMatrices(IEnumerable names) - { - Stream stream; - if (_filename == null) - { - stream = _stream; - _stream.Seek(0, SeekOrigin.Begin); - } - else - { - stream = new BufferedStream(new FileStream(_filename, FileMode.Open, FileAccess.Read)); - } - - var parser = new MatlabParser(stream, names); - var file = parser.Parse(); - - var matrices = new Matrix[file.Matrices.Count]; - var i = 0; - foreach (var matrix in file.Matrices.Values) - { - matrices[i++] = matrix; - } - - if (_filename != null) - { - stream.Close(); - stream.Dispose(); - } - - return matrices; } } } diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index b40e4363..d76d3fb4 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -124,9 +124,15 @@ - - - + + + + + + + + + @@ -222,9 +228,8 @@ + - - @@ -261,8 +266,8 @@ - - + + diff --git a/src/UnitTests/LinearAlgebraTests/Complex/IO/DelimitedWriterTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/IO/DelimitedWriterTests.cs index a60a3893..d2a2575b 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex/IO/DelimitedWriterTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex/IO/DelimitedWriterTests.cs @@ -5,7 +5,7 @@ using System.Numerics; using System.IO; using LinearAlgebra.Complex; - using LinearAlgebra.IO; + using LinearAlgebra.Complex.IO; using MbUnit.Framework; [TestFixture] @@ -15,7 +15,7 @@ public void CanWriteCommaDelimitedData() { var matrix = new DenseMatrix(new[,] { { new Complex(1.1, 1.1), new Complex(2.2, 2.2), new Complex(3.3, 3.3) }, { new Complex(4.4, 4.4), new Complex(5.5, 5.5), new Complex(6.6, 6.6) }, { new Complex(7.7, 7.7), new Complex(8.8, 8.8), new Complex(9.9, 9.9) } }); - var writer = new DelimitedWriter(','); + var writer = new DelimitedWriter(','); var stream = new MemoryStream(); writer.WriteMatrix(matrix, stream); var data = stream.ToArray(); @@ -32,7 +32,7 @@ { var matrix = new DenseMatrix(new[,] { { new Complex(1.1, 1.1), new Complex(2.2, 2.2), new Complex(3.3, 3.3) }, { new Complex(4.4, 4.4), new Complex(5.5, 5.5), new Complex(6.6, 6.6) }, { new Complex(7.7, 7.7), new Complex(8.8, 8.8), new Complex(9.9, 9.9) } }); var culture = new CultureInfo("tr-TR"); - var writer = new DelimitedWriter('.') + var writer = new DelimitedWriter('.') { CultureInfo = culture }; @@ -51,7 +51,7 @@ public void CanWriteSpaceDelimitedData() { var matrix = new DenseMatrix(new[,] { { new Complex(1.1, 1.1), new Complex(2.2, 2.2), new Complex(3.3, 3.3) }, { new Complex(4.4, 4.4), new Complex(5.5, 5.5), new Complex(6.6, 6.6) }, { new Complex(7.7, 7.7), new Complex(8.8, 8.8), new Complex(9.9, 9.9) } }); - var writer = new DelimitedWriter(' '); + var writer = new DelimitedWriter(' '); var stream = new MemoryStream(); writer.WriteMatrix(matrix, stream); var data = stream.ToArray(); @@ -68,7 +68,7 @@ { var matrix = new DenseMatrix(new[,] { { new Complex(1.1, 1.1), new Complex(2.2, 2.2), new Complex(3.3, 3.3) }, { new Complex(4.4, 4.4), new Complex(5.5, 5.5), new Complex(6.6, 6.6) }, { new Complex(7.7, 7.7), new Complex(8.8, 8.8), new Complex(9.9, 9.9) } }); var headers = new[] { "a", "b", "c" }; - var writer = new DelimitedWriter('\t') + var writer = new DelimitedWriter('\t') { ColumnHeaders = headers }; diff --git a/src/UnitTests/LinearAlgebraTests/Complex/IO/MatlabReaderTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/IO/MatlabReaderTests.cs new file mode 100644 index 00000000..d401fc78 --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Complex/IO/MatlabReaderTests.cs @@ -0,0 +1,70 @@ + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.IO +{ + using LinearAlgebra.Double; + using LinearAlgebra.Double.IO; + using MbUnit.Framework; + + [TestFixture] + public class MatlabMatrixReaderTest + { + [Test] + public void CanReadNonComplexAllMatrices() + { + var dmr = new MatlabMatrixReader("./data/Matlab/collection.mat"); + var matrices = dmr.ReadMatrices(); + Assert.AreEqual(30, matrices.Length); + foreach (var matrix in matrices) + { + Assert.AreEqual(typeof(DenseMatrix), matrix.GetType()); + } + } + + [Test] + public void CanReadNonComplexFirstMatrix() + { + var dmr = new MatlabMatrixReader("./data/Matlab/A.mat"); + var matrix = dmr.ReadMatrix(); + Assert.AreEqual(100, matrix.RowCount); + Assert.AreEqual(100, matrix.ColumnCount); + Assert.AreEqual(typeof(DenseMatrix), matrix.GetType()); + AssertHelpers.AlmostEqual(100.108979553704, matrix.FrobeniusNorm(), 13); + } + + + [Test] + public void CanReadNonComplexNamedMatrices() + { + var dmr = new MatlabMatrixReader("./data/Matlab/collection.mat"); + var matrices = dmr.ReadMatrices(new[] { "Ad", "Au64" }); + Assert.AreEqual(2, matrices.Length); + foreach (var matrix in matrices) + { + Assert.AreEqual(typeof(DenseMatrix), matrix.GetType()); + } + } + + [Test] + public void CanReadNonComplexNamedMatrix() + { + var dmr = new MatlabMatrixReader("./data/Matlab/collection.mat"); + var matrices = dmr.ReadMatrices(new[] { "Ad" }); + Assert.AreEqual(1, matrices.Length); + Assert.AreEqual(100, matrices[0].RowCount); + Assert.AreEqual(100, matrices[0].ColumnCount); + AssertHelpers.AlmostEqual(100.431635988639, matrices[0].FrobeniusNorm(), 13); + Assert.AreEqual(typeof(DenseMatrix), matrices[0].GetType()); + } + + [Test] + public void CanReadNonComplexNamedSparseMatrix() + { + var dmr = new MatlabMatrixReader("./data/Matlab/sparse-small.mat"); + var matrix = dmr.ReadMatrix("S"); + Assert.AreEqual(100, matrix.RowCount); + Assert.AreEqual(100, matrix.ColumnCount); + Assert.AreEqual(typeof(SparseMatrix), matrix.GetType()); + AssertHelpers.AlmostEqual(17.6385090630805, matrix.FrobeniusNorm(), 12); + } + } +} diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/IO/DelimitedWriterTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/IO/DelimitedWriterTests.cs index b65a3737..f8c7a9a9 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex32/IO/DelimitedWriterTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex32/IO/DelimitedWriterTests.cs @@ -4,8 +4,8 @@ using System.Globalization; using System.IO; using LinearAlgebra.Complex32; + using LinearAlgebra.Complex32.IO; using Numerics; - using LinearAlgebra.IO; using MbUnit.Framework; [TestFixture] @@ -15,7 +15,7 @@ public void CanWriteCommaDelimitedData() { var matrix = new DenseMatrix(new[,] { { new Complex32(1.1f, 1.1f), new Complex32(2.2f, 2.2f), new Complex32(3.3f, 3.3f) }, { new Complex32(4.4f, 4.4f), new Complex32(5.5f, 5.5f), new Complex32(6.6f, 6.6f) }, { new Complex32(7.7f, 7.7f), new Complex32(8.8f, 8.8f), new Complex32(9.9f, 9.9f) } }); - var writer = new DelimitedWriter(','); + var writer = new DelimitedWriter(','); var stream = new MemoryStream(); writer.WriteMatrix(matrix, stream); var data = stream.ToArray(); @@ -32,7 +32,7 @@ { var matrix = new DenseMatrix(new[,] { { new Complex32(1.1f, 1.1f), new Complex32(2.2f, 2.2f), new Complex32(3.3f, 3.3f) }, { new Complex32(4.4f, 4.4f), new Complex32(5.5f, 5.5f), new Complex32(6.6f, 6.6f) }, { new Complex32(7.7f, 7.7f), new Complex32(8.8f, 8.8f), new Complex32(9.9f, 9.9f) } }); var culture = new CultureInfo("tr-TR"); - var writer = new DelimitedWriter('.') + var writer = new DelimitedWriter('.') { CultureInfo = culture }; @@ -51,7 +51,7 @@ public void CanWriteSpaceDelimitedData() { var matrix = new DenseMatrix(new[,] { { new Complex32(1.1f, 1.1f), new Complex32(2.2f, 2.2f), new Complex32(3.3f, 3.3f) }, { new Complex32(4.4f, 4.4f), new Complex32(5.5f, 5.5f), new Complex32(6.6f, 6.6f) }, { new Complex32(7.7f, 7.7f), new Complex32(8.8f, 8.8f), new Complex32(9.9f, 9.9f) } }); - var writer = new DelimitedWriter(' '); + var writer = new DelimitedWriter(' '); var stream = new MemoryStream(); writer.WriteMatrix(matrix, stream); var data = stream.ToArray(); @@ -68,7 +68,7 @@ { var matrix = new DenseMatrix(new[,] { { new Complex32(1.1f, 1.1f), new Complex32(2.2f, 2.2f), new Complex32(3.3f, 3.3f) }, { new Complex32(4.4f, 4.4f), new Complex32(5.5f, 5.5f), new Complex32(6.6f, 6.6f) }, { new Complex32(7.7f, 7.7f), new Complex32(8.8f, 8.8f), new Complex32(9.9f, 9.9f) } }); var headers = new[] { "a", "b", "c" }; - var writer = new DelimitedWriter('\t') + var writer = new DelimitedWriter('\t') { ColumnHeaders = headers }; diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/IO/MatlabReaderTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/IO/MatlabReaderTests.cs new file mode 100644 index 00000000..47504e3b --- /dev/null +++ b/src/UnitTests/LinearAlgebraTests/Complex32/IO/MatlabReaderTests.cs @@ -0,0 +1,70 @@ + +namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.IO +{ + using LinearAlgebra.Double; + using LinearAlgebra.Double.IO; + using MbUnit.Framework; + + [TestFixture] + public class MatlabMatrixReaderTest + { + [Test] + public void CanReadNonComplexAllMatrices() + { + var dmr = new MatlabMatrixReader("./data/Matlab/collection.mat"); + var matrices = dmr.ReadMatrices(); + Assert.AreEqual(30, matrices.Length); + foreach (var matrix in matrices) + { + Assert.AreEqual(typeof(DenseMatrix), matrix.GetType()); + } + } + + [Test] + public void CanReadNonComplexFirstMatrix() + { + var dmr = new MatlabMatrixReader("./data/Matlab/A.mat"); + var matrix = dmr.ReadMatrix(); + Assert.AreEqual(100, matrix.RowCount); + Assert.AreEqual(100, matrix.ColumnCount); + Assert.AreEqual(typeof(DenseMatrix), matrix.GetType()); + AssertHelpers.AlmostEqual(100.108979553704, matrix.FrobeniusNorm(), 13); + } + + + [Test] + public void CanReadNonComplexNamedMatrices() + { + var dmr = new MatlabMatrixReader("./data/Matlab/collection.mat"); + var matrices = dmr.ReadMatrices(new[] { "Ad", "Au64" }); + Assert.AreEqual(2, matrices.Length); + foreach (var matrix in matrices) + { + Assert.AreEqual(typeof(DenseMatrix), matrix.GetType()); + } + } + + [Test] + public void CanReadNonComplexNamedMatrix() + { + var dmr = new MatlabMatrixReader("./data/Matlab/collection.mat"); + var matrices = dmr.ReadMatrices(new[] { "Ad" }); + Assert.AreEqual(1, matrices.Length); + Assert.AreEqual(100, matrices[0].RowCount); + Assert.AreEqual(100, matrices[0].ColumnCount); + AssertHelpers.AlmostEqual(100.431635988639, matrices[0].FrobeniusNorm(), 13); + Assert.AreEqual(typeof(DenseMatrix), matrices[0].GetType()); + } + + [Test] + public void CanReadNonComplexNamedSparseMatrix() + { + var dmr = new MatlabMatrixReader("./data/Matlab/sparse-small.mat"); + var matrix = dmr.ReadMatrix("S"); + Assert.AreEqual(100, matrix.RowCount); + Assert.AreEqual(100, matrix.ColumnCount); + Assert.AreEqual(typeof(SparseMatrix), matrix.GetType()); + AssertHelpers.AlmostEqual(17.6385090630805, matrix.FrobeniusNorm(), 12); + } + } +} diff --git a/src/UnitTests/LinearAlgebraTests/Double/IO/DelimitedWriterTests.cs b/src/UnitTests/LinearAlgebraTests/Double/IO/DelimitedWriterTests.cs index 62cef298..8fa3cf63 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/IO/DelimitedWriterTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/IO/DelimitedWriterTests.cs @@ -4,7 +4,7 @@ using System.Globalization; using System.IO; using LinearAlgebra.Double; - using LinearAlgebra.IO; + using LinearAlgebra.Double.IO; using MbUnit.Framework; [TestFixture] @@ -14,7 +14,7 @@ public void CanWriteCommaDelimitedData() { var matrix = new DenseMatrix(new[,] { { 1.1, 2.2, 3.3 }, { 4.4, 5.5, 6.6 }, { 7.7, 8.8, 9.9 } }); - var writer = new DelimitedWriter(','); + var writer = new DelimitedWriter(','); var stream = new MemoryStream(); writer.WriteMatrix(matrix, stream); var data = stream.ToArray(); @@ -31,7 +31,7 @@ { var matrix = new DenseMatrix(new[,] { { 1.1, 2.2, 3.3 }, { 4.4, 5.5, 6.6 }, { 7.7, 8.8, 9.9 } }); var culture = new CultureInfo("tr-TR"); - var writer = new DelimitedWriter('.') + var writer = new DelimitedWriter('.') { CultureInfo = culture }; @@ -50,7 +50,7 @@ public void CanWriteSpaceDelimitedData() { var matrix = new SparseMatrix(new[,] { { 1.1, 0, 0 }, { 0, 5.5, 0 }, { 0, 0, 9.9 } }); - var writer = new DelimitedWriter(' '); + var writer = new DelimitedWriter(' '); var stream = new MemoryStream(); writer.WriteMatrix(matrix, stream); var data = stream.ToArray(); @@ -67,7 +67,7 @@ { var matrix = new UserDefinedMatrix(new[,] { { 1.1, 2.2, 3.3 }, { 4.4, 5.5, 6.6 }, { 7.7, 8.8, 9.9 } }); var headers = new[] { "a", "b", "c" }; - var writer = new DelimitedWriter('\t') + var writer = new DelimitedWriter('\t') { ColumnHeaders = headers }; diff --git a/src/UnitTests/LinearAlgebraTests/Single/IO/DelimitedWriterTests.cs b/src/UnitTests/LinearAlgebraTests/Single/IO/DelimitedWriterTests.cs index d819220e..e8c1c3fc 100644 --- a/src/UnitTests/LinearAlgebraTests/Single/IO/DelimitedWriterTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Single/IO/DelimitedWriterTests.cs @@ -3,8 +3,6 @@ using System; using System.Globalization; using System.IO; - using System.Text; - using LinearAlgebra.IO; using LinearAlgebra.Single; using LinearAlgebra.Single.IO; using MbUnit.Framework; @@ -16,7 +14,7 @@ public void CanWriteCommaDelimitedData() { var matrix = new DenseMatrix(new[,] { { 1.1f, 2.2f, 3.3f }, { 4.4f, 5.5f, 6.6f }, { 7.7f, 8.8f, 9.9f } }); - var writer = new DelimitedWriter(','); + var writer = new DelimitedWriter(','); var stream = new MemoryStream(); writer.WriteMatrix(matrix, stream); var data = stream.ToArray(); @@ -33,7 +31,7 @@ { var matrix = new DenseMatrix(new[,] { { 1.1f, 2.2f, 3.3f }, { 4.4f, 5.5f, 6.6f }, { 7.7f, 8.8f, 9.9f } }); var culture = new CultureInfo("tr-TR"); - var writer = new DelimitedWriter('.') + var writer = new DelimitedWriter('.') { CultureInfo = culture }; @@ -52,7 +50,7 @@ public void CanWriteSpaceDelimitedData() { var matrix = new SparseMatrix(new[,] { { 1.1f, 0, 0 }, { 0, 5.5f, 0 }, { 0, 0, 9.9f } }); - var writer = new DelimitedWriter(' '); + var writer = new DelimitedWriter(' '); var stream = new MemoryStream(); writer.WriteMatrix(matrix, stream); var data = stream.ToArray(); @@ -69,7 +67,7 @@ { var matrix = new UserDefinedMatrix(new[,] { { 1.1f, 2.2f, 3.3f }, { 4.4f, 5.5f, 6.6f }, { 7.7f, 8.8f, 9.9f } }); var headers = new[] { "a", "b", "c" }; - var writer = new DelimitedWriter('\t') + var writer = new DelimitedWriter('\t') { ColumnHeaders = headers }; diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index 57a8d2ac..40aca2c6 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -138,6 +138,7 @@ + @@ -182,6 +183,7 @@ +