Browse Source

refactored DelimitedReader

pull/36/head
Marcus Cuda 16 years ago
parent
commit
36ccd67603
  1. 71
      src/Numerics/LinearAlgebra/Complex/IO/DelimitedReader.cs
  2. 71
      src/Numerics/LinearAlgebra/Complex32/IO/DelimitedReader.cs
  3. 137
      src/Numerics/LinearAlgebra/Double/IO/DelimitedReader.cs
  4. 290
      src/Numerics/LinearAlgebra/IO/DelimitedReader.cs
  5. 9
      src/Numerics/LinearAlgebra/IO/MatrixReader.cs
  6. 2
      src/Numerics/LinearAlgebra/IO/MatrixWriter.cs
  7. 137
      src/Numerics/LinearAlgebra/Single/IO/DelimitedReader.cs
  8. 84
      src/Numerics/LinearAlgebra/Single/IO/MatrixReader.cs
  9. 8
      src/Numerics/Numerics.csproj
  10. 125
      src/UnitTests/LinearAlgebraTests/Complex/IO/DelimitedReaderTests.cs
  11. 126
      src/UnitTests/LinearAlgebraTests/Complex32/IO/DelimitedReaderTests.cs
  12. 2
      src/UnitTests/UnitTests.csproj

71
src/Numerics/LinearAlgebra/Complex/IO/DelimitedReader.cs

@ -0,0 +1,71 @@
// <copyright file="DelimitedReader.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Complex.IO
{
using System;
using System.Numerics;
using Generic;
using LinearAlgebra.IO;
/// <summary>
/// Creates a <see cref="Matrix{T}"/> from a delimited text file. If the user does not
/// specify a delimiter, then any whitespace is used.
/// </summary>
/// <typeparam name="TMatrix">The type of the matrix to return.</typeparam>
public class DelimitedReader<TMatrix> : DelimitedReader<TMatrix, Complex>
where TMatrix : Matrix<Complex>
{
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class using
/// any whitespace as the delimiter.
/// </summary>
public DelimitedReader()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class.
/// </summary>
/// <param name="delimiter">The delimiter to use.</param>
public DelimitedReader(char delimiter) : base(delimiter)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class.
/// </summary>
/// <param name="delimiter">
/// The delimiter to use.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="delimiter"/> is <see langword="null"/>.
/// </exception>
public DelimitedReader(string delimiter) : base(delimiter)
{
}
}
}

71
src/Numerics/LinearAlgebra/Complex32/IO/DelimitedReader.cs

@ -0,0 +1,71 @@
// <copyright file="DelimitedReader.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Complex32.IO
{
using System;
using Generic;
using LinearAlgebra.IO;
using Numerics;
/// <summary>
/// Creates a <see cref="Matrix{T}"/> from a delimited text file. If the user does not
/// specify a delimiter, then any whitespace is used.
/// </summary>
/// <typeparam name="TMatrix">The type of the matrix to return.</typeparam>
public class DelimitedReader<TMatrix> : DelimitedReader<TMatrix, Complex32>
where TMatrix : Matrix<Complex32>
{
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class using
/// any whitespace as the delimiter.
/// </summary>
public DelimitedReader()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class.
/// </summary>
/// <param name="delimiter">The delimiter to use.</param>
public DelimitedReader(char delimiter) : base(delimiter)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class.
/// </summary>
/// <param name="delimiter">
/// The delimiter to use.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="delimiter"/> is <see langword="null"/>.
/// </exception>
public DelimitedReader(string delimiter) : base(delimiter)
{
}
}
}

137
src/Numerics/LinearAlgebra/Double/IO/DelimitedReader.cs

@ -27,57 +27,31 @@
namespace MathNet.Numerics.LinearAlgebra.Double.IO
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using Generic;
using LinearAlgebra.IO;
/// <summary>
/// Creates a <see cref="Matrix{T}"/> from a delimited text file. If the user does not
/// specify a delimiter, then any whitespace is used.
/// </summary>
/// <typeparam name="TMatrix">The type of the matrix to return.</typeparam>
public class DelimitedReader<TMatrix> : MatrixReader<TMatrix>
public class DelimitedReader<TMatrix> : DelimitedReader<TMatrix, double>
where TMatrix : Matrix<double>
{
/// <summary>
/// Constructor to create matrix instance.
/// </summary>
private static readonly ConstructorInfo Constructor = typeof(TMatrix).GetConstructor(new[] { typeof(int), typeof(int) });
/// <summary>
/// Whitespace regular expression.
/// </summary>
private static readonly Regex WhiteSpace = new Regex(@"[\s]+");
/// <summary>
/// The delimiter to use.
/// </summary>
private readonly Regex _delimiter;
/// <summary>
/// The <see cref="CultureInfo"/> to use.
/// </summary>
private CultureInfo _cultureInfo = CultureInfo.CurrentCulture;
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class using
/// any whitespace as the delimiter.
/// </summary>
public DelimitedReader()
public DelimitedReader()
{
_delimiter = WhiteSpace;
}
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class.
/// </summary>
/// <param name="delimiter">The delimiter to use.</param>
public DelimitedReader(char delimiter)
public DelimitedReader(char delimiter) : base(delimiter)
{
_delimiter = new Regex("[" + new string(delimiter, 1) + "]+");
}
/// <summary>
@ -89,109 +63,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double.IO
/// <exception cref="ArgumentNullException">
/// If <paramref name="delimiter"/> is <see langword="null"/>.
/// </exception>
public DelimitedReader(string delimiter)
public DelimitedReader(string delimiter) : base(delimiter)
{
if (delimiter == null)
{
throw new ArgumentNullException("delimiter");
}
_delimiter = new Regex("[" + delimiter + "]+");
}
/// <summary>
/// Gets or sets the <see cref="CultureInfo"/> to use when parsing the numbers.
/// </summary>
/// <value>The culture info.</value>
/// <remarks>Defaults to <c>CultureInfo.CurrentCulture</c>.</remarks>
public CultureInfo CultureInfo
{
get
{
return _cultureInfo;
}
set
{
if (value != null)
{
_cultureInfo = value;
}
}
}
/// <summary>
/// Gets or sets a value indicating whether the files has a header row.
/// </summary>
/// <value>
/// <c>true</c> if this instance has a header row; otherwise, <c>false</c>.
/// </value>
/// <remarks>Defaults to <see langword="false"/>.</remarks>
public bool HasHeaderRow
{
get;
set;
}
/// <summary>
/// Performs the actual reading.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to read the matrix from.</param>
/// <returns>
/// A matrix containing the data from the <see cref="Stream"/>. <see langword="null"/> is returned if the <see cref="Stream"/> is empty.
/// </returns>
protected override TMatrix DoReadMatrix(Stream stream)
{
var data = new List<string[]>();
// max is used to supports files like:
// 1,2
// 3,4,5,6
// 7
// this creates a 3x4 matrix:
// 1, 2, 0 ,0
// 3, 4, 5, 6
// 7, 0, 0, 0
var max = -1;
var reader = new StreamReader(stream);
var line = reader.ReadLine();
if (HasHeaderRow)
{
line = reader.ReadLine();
}
while (line != null)
{
line = line.Trim();
if (line.Length > 0)
{
var row = _delimiter.Split(line);
max = Math.Max(max, row.Length);
data.Add(row);
}
line = reader.ReadLine();
}
var ret = (TMatrix)Constructor.Invoke(new object[] { data.Count, max });
if (data.Count != 0)
{
for (var i = 0; i < data.Count; i++)
{
var row = data[i];
for (var j = 0; j < row.Length; j++)
{
// strip off quotes
var value = row[j].Replace("'", string.Empty).Replace("\"", string.Empty);
ret[i, j] = double.Parse(value, NumberStyles.Any, _cultureInfo);
}
}
}
reader.Close();
reader.Dispose();
return ret;
}
}
}

290
src/Numerics/LinearAlgebra/IO/DelimitedReader.cs

@ -0,0 +1,290 @@
// <copyright file="DelimitedReader.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.IO
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Text.RegularExpressions;
using Generic;
using Numerics;
/// <summary>
/// Creates a <see cref="Matrix{T}"/> from a delimited text file. If the user does not
/// specify a delimiter, then any whitespace is used.
/// </summary>
/// <typeparam name="TMatrix">The type of the matrix to return.</typeparam>
/// <typeparam name="TDataType">The data type of the Matrix. It can be either: double, float, Complex, or Complex32.</typeparam>
public class DelimitedReader<TMatrix, TDataType> : MatrixReader<TMatrix, TDataType>
where TMatrix : Matrix<TDataType>
where TDataType : struct, IEquatable<TDataType>, IFormattable
{
/// <summary>
/// Converts a string into the given data type.
/// </summary>
/// <param name="number">
/// The number as a string to convert.
/// </param>
/// <returns>The converted number.</returns>
private delegate object ParseNumber(string number);
/// <summary>
/// The function that will do the conversion for a given type.
/// </summary>
private ParseNumber _parseFunction;
/// <summary>
/// Initializes static members of the <see cref="DelimitedReader{TMatrix, TDataType}"/> class.
/// </summary>
private void SetParser()
{
var type = typeof(TDataType);
if (type == typeof(double))
{
_parseFunction = ConvertDouble;
}
else if (type == typeof(float))
{
_parseFunction = ConvertFloat;
}
else if (type == typeof(Complex))
{
_parseFunction = ConvertComplex;
}
else if (type == typeof(Complex32))
{
_parseFunction = ConvertComplex32;
}
else
{
throw new NotSupportedException();
}
}
/// <summary>
/// Converts the string into a Complex32.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <returns>The converted number.</returns>
private object ConvertComplex32(string number)
{
return number.ToComplex32(_cultureInfo);
}
/// <summary>
/// Converts the string into a Complex.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <returns>The converted number.</returns>
private object ConvertComplex(string number)
{
return number.ToComplex(_cultureInfo);
}
/// <summary>
/// Converts the string into a double.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <returns>The converted number.</returns>
private object ConvertDouble(string number)
{
return double.Parse(number, NumberStyles.Any, _cultureInfo);
}
/// <summary>
/// Converts the string into a float.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <returns>The converted number.</returns>
private object ConvertFloat(string number)
{
return float.Parse(number, NumberStyles.Any, _cultureInfo);
}
/// <summary>
/// Constructor to create matrix instance.
/// </summary>
private static readonly ConstructorInfo Constructor = typeof(TMatrix).GetConstructor(new[] { typeof(int), typeof(int) });
/// <summary>
/// The base regular expression.
/// </summary>
private static readonly string Base = "\\([^\\)]*\\)|'[^']*'|\"[^\"]*\"|[^{0}]*";
/// <summary>
/// The regular expression to use.
/// </summary>
private readonly Regex _regex;
/// <summary>
/// The <see cref="CultureInfo"/> to use.
/// </summary>
private CultureInfo _cultureInfo = CultureInfo.CurrentCulture;
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix, TDataType}"/> class using
/// any whitespace as the delimiter.
/// </summary>
public DelimitedReader()
{
_regex = new Regex(string.Format(Base, @"\s", RegexOptions.Compiled));
SetParser();
}
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix, TDataType}"/> class.
/// </summary>
/// <param name="delimiter">The delimiter to use.</param>
public DelimitedReader(char delimiter)
{
_regex = new Regex(string.Format(Base, delimiter), RegexOptions.Compiled);
SetParser();
}
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix, TDataType}"/> class.
/// </summary>
/// <param name="delimiter">
/// The delimiter to use.
/// </param>
/// <exception cref="ArgumentNullException">
/// If <paramref name="delimiter"/> is <see langword="null"/>.
/// </exception>
public DelimitedReader(string delimiter)
{
if (delimiter == null)
{
throw new ArgumentNullException("delimiter");
}
_regex = new Regex(string.Format(Base, delimiter, RegexOptions.Compiled));
SetParser();
}
/// <summary>
/// Gets or sets the <see cref="CultureInfo"/> to use when parsing the numbers.
/// </summary>
/// <value>The culture info.</value>
/// <remarks>Defaults to <c>CultureInfo.CurrentCulture</c>.</remarks>
public CultureInfo CultureInfo
{
get
{
return _cultureInfo;
}
set
{
if (value != null)
{
_cultureInfo = value;
}
}
}
/// <summary>
/// Gets or sets a value indicating whether the files has a header row.
/// </summary>
/// <value>
/// <c>true</c> if this instance has a header row; otherwise, <c>false</c>.
/// </value>
/// <remarks>Defaults to <see langword="false"/>.</remarks>
public bool HasHeaderRow
{
get;
set;
}
/// <summary>
/// Performs the actual reading.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to read the matrix from.</param>
/// <returns>
/// A matrix containing the data from the <see cref="Stream"/>. <see langword="null"/> is returned if the <see cref="Stream"/> is empty.
/// </returns>
protected override TMatrix DoReadMatrix(Stream stream)
{
var data = new List<string[]>();
// max is used to supports files like:
// 1,2
// 3,4,5,6
// 7
// this creates a 3x4 matrix:
// 1, 2, 0 ,0
// 3, 4, 5, 6
// 7, 0, 0, 0
var max = -1;
var reader = new StreamReader(stream);
var line = reader.ReadLine();
if (HasHeaderRow)
{
line = reader.ReadLine();
}
var dataType = typeof(TDataType);
while (line != null)
{
line = line.Trim();
if (line.Length > 0)
{
var matches = _regex.Matches(line);
var row = (from Match match in matches where match.Length > 0 select match.Value).ToArray();
max = Math.Max(max, row.Length);
data.Add(row);
}
line = reader.ReadLine();
}
var ret = (TMatrix)Constructor.Invoke(new object[] { data.Count, max });
if (data.Count != 0)
{
for (var i = 0; i < data.Count; i++)
{
var row = data[i];
for (var j = 0; j < row.Length; j++)
{
// strip off quotes
var value = row[j].Replace("'", string.Empty).Replace("\"", string.Empty);
ret[i, j] = (TDataType)_parseFunction(value);
}
}
}
reader.Close();
reader.Dispose();
return ret;
}
}
}

9
src/Numerics/LinearAlgebra/Double/IO/MatrixReader.cs → src/Numerics/LinearAlgebra/IO/MatrixReader.cs

@ -24,7 +24,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Double.IO
namespace MathNet.Numerics.LinearAlgebra.IO
{
using System;
using System.IO;
@ -35,7 +35,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double.IO
/// Base class to read a single <see cref="Matrix{T}"/> from a file or stream.
/// </summary>
/// <typeparam name="TMatrix">The type of Matrix to return.</typeparam>
public abstract class MatrixReader<TMatrix> where TMatrix : Matrix<double>
/// <typeparam name="TDataType">The data type of the Matrix. It can be either: double, float, Complex, or Complex32.</typeparam>
public abstract class MatrixReader<TMatrix, TDataType>
where TMatrix : Matrix<TDataType>
where TDataType : struct, IEquatable<TDataType>, IFormattable
{
/// <summary>
/// Reads a <see cref="Matrix{T}"/> from a file.
@ -46,7 +49,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.IO
/// <exception cref="IOException">If the file doesn't exist.</exception>
/// <exception cref="FormatException">If a value is not a number or not in a valid format.</exception>
/// <exception cref="OverflowException">If a value represents a number less than <see cref="Double.MinValue"/> or greater than <see cref="Double.MaxValue"/>.</exception>
public Matrix<double> ReadMatrix(string file)
public TMatrix ReadMatrix(string file)
{
if (file == null)
{

2
src/Numerics/LinearAlgebra/IO/MatrixWriter.cs

@ -36,7 +36,7 @@ namespace MathNet.Numerics.LinearAlgebra.IO
/// <summary>
/// Base class to write a single <see cref="Matrix{DataType}"/> to a file or stream.
/// </summary>
/// <typeparam name="TDataType">The data type of the matrix.</typeparam>
/// <typeparam name="TDataType">The data type of the Matrix. It can be either: double, float, Complex, or Complex32.</typeparam>
public abstract class MatrixWriter<TDataType> where TDataType : struct, IEquatable<TDataType>, IFormattable
{
/// <summary>

137
src/Numerics/LinearAlgebra/Single/IO/DelimitedReader.cs

@ -27,57 +27,31 @@
namespace MathNet.Numerics.LinearAlgebra.Single.IO
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using Generic;
using LinearAlgebra.IO;
/// <summary>
/// Creates a <see cref="Matrix{T}"/> from a delimited text file. If the user does not
/// specify a delimiter, then any whitespace is used.
/// </summary>
/// <typeparam name="TMatrix">The type of the matrix to return.</typeparam>
public class DelimitedReader<TMatrix> : MatrixReader<TMatrix>
public class DelimitedReader<TMatrix> : DelimitedReader<TMatrix, float>
where TMatrix : Matrix<float>
{
/// <summary>
/// Constructor to create matrix instance.
/// </summary>
private static readonly ConstructorInfo Constructor = typeof(TMatrix).GetConstructor(new[] { typeof(int), typeof(int) });
/// <summary>
/// Whitespace regular expression.
/// </summary>
private static readonly Regex WhiteSpace = new Regex(@"[\s]+");
/// <summary>
/// The delimiter to use.
/// </summary>
private readonly Regex _delimiter;
/// <summary>
/// The <see cref="CultureInfo"/> to use.
/// </summary>
private CultureInfo _cultureInfo = CultureInfo.CurrentCulture;
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class using
/// any whitespace as the delimiter.
/// </summary>
public DelimitedReader()
public DelimitedReader()
{
_delimiter = WhiteSpace;
}
/// <summary>
/// Initializes a new instance of the <see cref="DelimitedReader{TMatrix}"/> class.
/// </summary>
/// <param name="delimiter">The delimiter to use.</param>
public DelimitedReader(char delimiter)
public DelimitedReader(char delimiter) : base(delimiter)
{
_delimiter = new Regex("[" + new string(delimiter, 1) + "]+");
}
/// <summary>
@ -89,109 +63,8 @@ namespace MathNet.Numerics.LinearAlgebra.Single.IO
/// <exception cref="ArgumentNullException">
/// If <paramref name="delimiter"/> is <see langword="null"/>.
/// </exception>
public DelimitedReader(string delimiter)
public DelimitedReader(string delimiter) : base(delimiter)
{
if (delimiter == null)
{
throw new ArgumentNullException("delimiter");
}
_delimiter = new Regex("[" + delimiter + "]+");
}
/// <summary>
/// Gets or sets the <see cref="CultureInfo"/> to use when parsing the numbers.
/// </summary>
/// <value>The culture info.</value>
/// <remarks>Defaults to <c>CultureInfo.CurrentCulture</c>.</remarks>
public CultureInfo CultureInfo
{
get
{
return _cultureInfo;
}
set
{
if (value != null)
{
_cultureInfo = value;
}
}
}
/// <summary>
/// Gets or sets a value indicating whether the files has a header row.
/// </summary>
/// <value>
/// <c>true</c> if this instance has a header row; otherwise, <c>false</c>.
/// </value>
/// <remarks>Defaults to <see langword="false"/>.</remarks>
public bool HasHeaderRow
{
get;
set;
}
/// <summary>
/// Performs the actual reading.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to read the matrix from.</param>
/// <returns>
/// A matrix containing the data from the <see cref="Stream"/>. <see langword="null"/> is returned if the <see cref="Stream"/> is empty.
/// </returns>
protected override TMatrix DoReadMatrix(Stream stream)
{
var data = new List<string[]>();
// max is used to supports files like:
// 1,2
// 3,4,5,6
// 7
// this creates a 3x4 matrix:
// 1, 2, 0 ,0
// 3, 4, 5, 6
// 7, 0, 0, 0
var max = -1;
var reader = new StreamReader(stream);
var line = reader.ReadLine();
if (HasHeaderRow)
{
line = reader.ReadLine();
}
while (line != null)
{
line = line.Trim();
if (line.Length > 0)
{
var row = _delimiter.Split(line);
max = Math.Max(max, row.Length);
data.Add(row);
}
line = reader.ReadLine();
}
var ret = (TMatrix)Constructor.Invoke(new object[] { data.Count, max });
if (data.Count != 0)
{
for (var i = 0; i < data.Count; i++)
{
var row = data[i];
for (var j = 0; j < row.Length; j++)
{
// strip off quotes
var value = row[j].Replace("'", string.Empty).Replace("\"", string.Empty);
ret[i, j] = float.Parse(value, NumberStyles.Any, _cultureInfo);
}
}
}
reader.Close();
reader.Dispose();
return ret;
}
}
}

84
src/Numerics/LinearAlgebra/Single/IO/MatrixReader.cs

@ -1,84 +0,0 @@
// <copyright file="MatrixReader.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.LinearAlgebra.Single.IO
{
using System;
using System.IO;
using Generic;
using Properties;
/// <summary>
/// Base class to read a single <see cref="Matrix{T}"/> from a file or stream.
/// </summary>
/// <typeparam name="TMatrix">The type of Matrix to return.</typeparam>
public abstract class MatrixReader<TMatrix> where TMatrix : Matrix<float>
{
/// <summary>
/// Reads a <see cref="Matrix{T}"/> from a file.
/// </summary>
/// <param name="file">The file to read the matrix from.</param>
/// <returns>A <see cref="Matrix{T}"/> containing the data from the file. <see langword="null" /> is returned if the file is empty.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="file"/> is <see langword="null" />.</exception>
/// <exception cref="IOException">If the file doesn't exist.</exception>
/// <exception cref="FormatException">If a value is not a number or not in a valid format.</exception>
/// <exception cref="OverflowException">If a value represents a number less than <see cref="Double.MinValue"/> or greater than <see cref="Double.MaxValue"/>.</exception>
public Matrix<float> ReadMatrix(string file)
{
if (file == null)
{
throw new ArgumentNullException("file", Resources.StringNullOrEmpty);
}
return ReadMatrix(File.OpenRead(file));
}
/// <summary>
/// Reads a <see cref="Matrix{T}"/> from a <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to read the matrix from.</param>
/// <returns>A matrix containing the data from the <see cref="Stream"/>. <see langword="null" /> is returned if the <see cref="Stream"/> is empty.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="stream"/> is <see langword="null" />.</exception>
/// <exception cref="FormatException">If a value is not a number or not in a valid format.</exception>
/// <exception cref="OverflowException">If a value represents a number less than <see cref="Double.MinValue"/> or greater than <see cref="Double.MaxValue"/>.</exception>
public TMatrix ReadMatrix(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
return DoReadMatrix(stream);
}
/// <summary>
/// Subclasses override this method to do the actual reading.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to read the matrix from.</param>
/// <returns>A matrix containing the data from the <see cref="Stream"/>. <see langword="null" /> is returned if the <see cref="Stream"/> is empty.</returns>
protected abstract TMatrix DoReadMatrix(Stream stream);
}
}

8
src/Numerics/Numerics.csproj

@ -142,6 +142,7 @@
<Compile Include="LinearAlgebra\Complex32\Factorization\UserLU.cs" />
<Compile Include="LinearAlgebra\Complex32\Factorization\UserQR.cs" />
<Compile Include="LinearAlgebra\Complex32\Factorization\UserSvd.cs" />
<Compile Include="LinearAlgebra\Complex32\IO\DelimitedReader.cs" />
<Compile Include="LinearAlgebra\Complex32\Solvers\Iterative\BiCgStab.cs" />
<Compile Include="LinearAlgebra\Complex32\Solvers\Iterative\CompositeSolver.cs" />
<Compile Include="LinearAlgebra\Complex32\Solvers\Iterative\GpBiCg.cs" />
@ -174,6 +175,7 @@
<Compile Include="LinearAlgebra\Complex\Factorization\UserLU.cs" />
<Compile Include="LinearAlgebra\Complex\Factorization\UserQR.cs" />
<Compile Include="LinearAlgebra\Complex\Factorization\UserSvd.cs" />
<Compile Include="LinearAlgebra\Complex\IO\DelimitedReader.cs" />
<Compile Include="LinearAlgebra\Complex\Solvers\Iterative\BiCgStab.cs" />
<Compile Include="LinearAlgebra\Complex\Solvers\Iterative\CompositeSolver.cs" />
<Compile Include="LinearAlgebra\Complex\Solvers\Iterative\GpBiCg.cs" />
@ -197,9 +199,12 @@
<Compile Include="LinearAlgebra\Double\Factorization\DenseGramSchmidt.cs" />
<Compile Include="LinearAlgebra\Double\Factorization\DenseEvd.cs" />
<Compile Include="LinearAlgebra\Double\Factorization\UserEvd.cs" />
<Compile Include="LinearAlgebra\Double\IO\DelimitedReader.cs" />
<Compile Include="LinearAlgebra\Generic\Factorization\GramSchmidt.cs" />
<Compile Include="LinearAlgebra\Generic\Factorization\Evd.cs" />
<Compile Include="LinearAlgebra\IO\DelimitedReader.cs" />
<Compile Include="LinearAlgebra\IO\DelimitedWriter.cs" />
<Compile Include="LinearAlgebra\IO\MatrixReader.cs" />
<Compile Include="LinearAlgebra\IO\MatrixWriter.cs" />
<Compile Include="LinearAlgebra\Single\DenseMatrix.cs" />
<Compile Include="LinearAlgebra\Single\DenseVector.cs" />
@ -220,7 +225,6 @@
<Compile Include="LinearAlgebra\Single\IO\MatlabReader.cs" />
<Compile Include="LinearAlgebra\Single\IO\Matlab\MatlabFile.cs" />
<Compile Include="LinearAlgebra\Single\IO\Matlab\MatlabParser.cs" />
<Compile Include="LinearAlgebra\Single\IO\MatrixReader.cs" />
<Compile Include="LinearAlgebra\Single\Solvers\Iterative\BiCgStab.cs" />
<Compile Include="LinearAlgebra\Single\Solvers\Iterative\CompositeSolver.cs" />
<Compile Include="LinearAlgebra\Single\Solvers\Iterative\GpBiCg.cs" />
@ -256,11 +260,9 @@
<Compile Include="LinearAlgebra\Double\Factorization\UserLU.cs" />
<Compile Include="LinearAlgebra\Double\Factorization\UserQR.cs" />
<Compile Include="LinearAlgebra\Double\Factorization\UserSvd.cs" />
<Compile Include="LinearAlgebra\Double\IO\DelimitedReader.cs" />
<Compile Include="LinearAlgebra\Double\IO\MatlabReader.cs" />
<Compile Include="LinearAlgebra\Double\IO\Matlab\MatlabFile.cs" />
<Compile Include="LinearAlgebra\Double\IO\Matlab\MatlabParser.cs" />
<Compile Include="LinearAlgebra\Double\IO\MatrixReader.cs" />
<Compile Include="LinearAlgebra\Generic\ISolver.cs" />
<Compile Include="LinearAlgebra\Generic\Solvers\IIterativeSolver.cs" />
<Compile Include="LinearAlgebra\Generic\Solvers\IIterativeSolverSetup.cs" />

125
src/UnitTests/LinearAlgebraTests/Complex/IO/DelimitedReaderTests.cs

@ -0,0 +1,125 @@
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.IO
{
using System;
using System.Globalization;
using System.IO;
using System.Text;
using LinearAlgebra.Complex;
using LinearAlgebra.Complex.IO;
using MbUnit.Framework;
[TestFixture]
public class DelimitedReaderTests
{
[Test]
[MultipleAsserts]
public void CanParseCommaDelimitedData()
{
const string data =
@"a,b,c
(1,2)
""2.2"",0.3e1
'(4,-5)',5,6
";
var reader = new DelimitedReader<DenseMatrix>(',')
{
HasHeaderRow = true
};
var matrix = reader.ReadMatrix(new MemoryStream(Encoding.UTF8.GetBytes(data)));
Assert.AreEqual(3, matrix.RowCount);
Assert.AreEqual(3, matrix.ColumnCount);
Assert.AreEqual(1.0, matrix[0, 0].Real);
Assert.AreEqual(2.0, matrix[0, 0].Imaginary);
Assert.AreEqual(0.0, matrix[0, 1]);
Assert.AreEqual(0.0, matrix[0, 2]);
Assert.AreEqual(2.2, matrix[1, 0]);
Assert.AreEqual(3.0, matrix[1, 1]);
Assert.AreEqual(0.0, matrix[1, 2]);
Assert.AreEqual(4.0, matrix[2, 0].Real);
Assert.AreEqual(-5.0, matrix[2, 0].Imaginary);
Assert.AreEqual(5.0, matrix[2, 1]);
Assert.AreEqual(6.0, matrix[2, 2]);
}
[Test]
[MultipleAsserts]
public void CanParseTabDelimtedData()
{
var data = "1"
+ Environment.NewLine
+ "\"2.2\"\t\t0.3e1"
+ Environment.NewLine
+ "'4'\t5\t6";
var reader = new DelimitedReader<SparseMatrix>('\t');
var matrix = reader.ReadMatrix(new MemoryStream(Encoding.UTF8.GetBytes(data)));
Assert.AreEqual(3, matrix.RowCount);
Assert.AreEqual(3, matrix.ColumnCount);
Assert.AreEqual(1.0, matrix[0, 0]);
Assert.AreEqual(0.0, matrix[0, 1]);
Assert.AreEqual(0.0, matrix[0, 2]);
Assert.AreEqual(2.2, matrix[1, 0]);
Assert.AreEqual(3.0, matrix[1, 1]);
Assert.AreEqual(0.0, matrix[1, 2]);
Assert.AreEqual(4.0, matrix[2, 0]);
Assert.AreEqual(5.0, matrix[2, 1]);
Assert.AreEqual(6.0, matrix[2, 2]);
}
[Test]
[MultipleAsserts]
public void CanParseWhiteSpaceDelimitedData()
{
const string data =
@"1
""(2.2,3.3)"" 0.3e1
'4' 5 6
";
var reader = new DelimitedReader<UserDefinedMatrix>();
var matrix = reader.ReadMatrix(new MemoryStream(Encoding.UTF8.GetBytes(data)));
Assert.AreEqual(3, matrix.RowCount);
Assert.AreEqual(3, matrix.ColumnCount);
Assert.AreEqual(1.0, matrix[0, 0]);
Assert.AreEqual(0.0, matrix[0, 1]);
Assert.AreEqual(0.0, matrix[0, 2]);
Assert.AreEqual(2.2, matrix[1, 0].Real);
Assert.AreEqual(3.3, matrix[1, 0].Imaginary);
Assert.AreEqual(3.0, matrix[1, 1]);
Assert.AreEqual(0.0, matrix[1, 2]);
Assert.AreEqual(4.0, matrix[2, 0]);
Assert.AreEqual(5.0, matrix[2, 1]);
Assert.AreEqual(6.0, matrix[2, 2]);
}
[Test]
[MultipleAsserts]
public void CanParsePeriodDelimitedData()
{
const string data =
@"a.b.c
1
""2,2"".0,3e1+0,2e1i
'4,0'.5,0.6,0
";
var reader = new DelimitedReader<DenseMatrix>('.')
{
HasHeaderRow = true,
CultureInfo = new CultureInfo("tr-TR")
};
var matrix = reader.ReadMatrix(new MemoryStream(Encoding.UTF8.GetBytes(data)));
Assert.AreEqual(3, matrix.RowCount);
Assert.AreEqual(3, matrix.ColumnCount);
Assert.AreEqual(1.0, matrix[0, 0]);
Assert.AreEqual(0.0, matrix[0, 1]);
Assert.AreEqual(0.0, matrix[0, 2]);
Assert.AreEqual(2.2, matrix[1, 0]);
Assert.AreEqual(3.0, matrix[1, 1].Real);
Assert.AreEqual(2.0, matrix[1, 1].Imaginary);
Assert.AreEqual(0.0, matrix[1, 2]);
Assert.AreEqual(4.0, matrix[2, 0]);
Assert.AreEqual(5.0, matrix[2, 1]);
Assert.AreEqual(6.0, matrix[2, 2]);
}
}
}

126
src/UnitTests/LinearAlgebraTests/Complex32/IO/DelimitedReaderTests.cs

@ -0,0 +1,126 @@
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.IO
{
using System;
using System.Globalization;
using System.IO;
using System.Text;
using LinearAlgebra.Complex32;
using LinearAlgebra.Complex32.IO;
using MbUnit.Framework;
using Numerics;
[TestFixture]
public class DelimitedReaderTests
{
[Test]
[MultipleAsserts]
public void CanParseCommaDelimitedData()
{
const string data =
@"a,b,c
(1,2)
""2.2"",0.3e1
'(4,-5)',5,6
";
var reader = new DelimitedReader<DenseMatrix>(',')
{
HasHeaderRow = true
};
var matrix = reader.ReadMatrix(new MemoryStream(Encoding.UTF8.GetBytes(data)));
Assert.AreEqual(3, matrix.RowCount);
Assert.AreEqual(3, matrix.ColumnCount);
Assert.AreEqual(1.0f, matrix[0, 0].Real);
Assert.AreEqual(2.0f, matrix[0, 0].Imaginary);
Assert.AreEqual(0.0f, matrix[0, 1]);
Assert.AreEqual(0.0f, matrix[0, 2]);
Assert.AreEqual(2.2f, matrix[1, 0]);
Assert.AreEqual(3.0f, matrix[1, 1]);
Assert.AreEqual(0.0f, matrix[1, 2]);
Assert.AreEqual(4.0f, matrix[2, 0].Real);
Assert.AreEqual(-5.0f, matrix[2, 0].Imaginary);
Assert.AreEqual(5.0f, matrix[2, 1]);
Assert.AreEqual(6.0f, matrix[2, 2]);
}
[Test]
[MultipleAsserts]
public void CanParseTabDelimtedData()
{
var data = "1"
+ Environment.NewLine
+ "\"2.2\"\t\t0.3e1"
+ Environment.NewLine
+ "'4'\t5\t6";
var reader = new DelimitedReader<SparseMatrix>('\t');
var matrix = reader.ReadMatrix(new MemoryStream(Encoding.UTF8.GetBytes(data)));
Assert.AreEqual(3, matrix.RowCount);
Assert.AreEqual(3, matrix.ColumnCount);
Assert.AreEqual(1.0f, matrix[0, 0]);
Assert.AreEqual(0.0f, matrix[0, 1]);
Assert.AreEqual(0.0f, matrix[0, 2]);
Assert.AreEqual(2.2f, matrix[1, 0]);
Assert.AreEqual(3.0f, matrix[1, 1]);
Assert.AreEqual(0.0f, matrix[1, 2]);
Assert.AreEqual(4.0f, matrix[2, 0]);
Assert.AreEqual(5.0f, matrix[2, 1]);
Assert.AreEqual(6.0f, matrix[2, 2]);
}
[Test]
[MultipleAsserts]
public void CanParseWhiteSpaceDelimitedData()
{
const string data =
@"1
""(2.2,3.3)"" 0.3e1
'4' 5 6
";
var reader = new DelimitedReader<UserDefinedMatrix>();
var matrix = reader.ReadMatrix(new MemoryStream(Encoding.UTF8.GetBytes(data)));
Assert.AreEqual(3, matrix.RowCount);
Assert.AreEqual(3, matrix.ColumnCount);
Assert.AreEqual(1.0f, matrix[0, 0]);
Assert.AreEqual(0.0f, matrix[0, 1]);
Assert.AreEqual(0.0f, matrix[0, 2]);
Assert.AreEqual(2.2f, matrix[1, 0].Real);
Assert.AreEqual(3.3f, matrix[1, 0].Imaginary);
Assert.AreEqual(3.0f, matrix[1, 1]);
Assert.AreEqual(0.0f, matrix[1, 2]);
Assert.AreEqual(4.0f, matrix[2, 0]);
Assert.AreEqual(5.0f, matrix[2, 1]);
Assert.AreEqual(6.0f, matrix[2, 2]);
}
[Test]
[MultipleAsserts]
public void CanParsePeriodDelimitedData()
{
const string data =
@"a.b.c
1
""2,2"".0,3e1+0,2e1i
'4,0'.5,0.6,0
";
var reader = new DelimitedReader<DenseMatrix>('.')
{
HasHeaderRow = true,
CultureInfo = new CultureInfo("tr-TR")
};
var matrix = reader.ReadMatrix(new MemoryStream(Encoding.UTF8.GetBytes(data)));
Assert.AreEqual(3, matrix.RowCount);
Assert.AreEqual(3, matrix.ColumnCount);
Assert.AreEqual(1.0f, matrix[0, 0]);
Assert.AreEqual(0.0f, matrix[0, 1]);
Assert.AreEqual(0.0f, matrix[0, 2]);
Assert.AreEqual(2.2f, matrix[1, 0]);
Assert.AreEqual(3.0f, matrix[1, 1].Real);
Assert.AreEqual(2.0f, matrix[1, 1].Imaginary);
Assert.AreEqual(0.0f, matrix[1, 2]);
Assert.AreEqual(4.0f, matrix[2, 0]);
Assert.AreEqual(5.0f, matrix[2, 1]);
Assert.AreEqual(6.0f, matrix[2, 2]);
}
}
}

2
src/UnitTests/UnitTests.csproj

@ -136,6 +136,7 @@
<Compile Include="LinearAlgebraTests\Complex32\Factorization\UserLUTests.cs" />
<Compile Include="LinearAlgebraTests\Complex32\Factorization\UserQRTests.cs" />
<Compile Include="LinearAlgebraTests\Complex32\Factorization\UserSvdTests.cs" />
<Compile Include="LinearAlgebraTests\Complex32\IO\DelimitedReaderTests.cs" />
<Compile Include="LinearAlgebraTests\Complex32\IO\DelimitedWriterTests.cs" />
<Compile Include="LinearAlgebraTests\Complex32\MatrixLoader.cs" />
<Compile Include="LinearAlgebraTests\Complex32\MatrixTests.Arithmetic.cs" />
@ -179,6 +180,7 @@
<Compile Include="LinearAlgebraTests\Complex\Factorization\UserLUTests.cs" />
<Compile Include="LinearAlgebraTests\Complex\Factorization\UserQRTests.cs" />
<Compile Include="LinearAlgebraTests\Complex\Factorization\UserSvdTests.cs" />
<Compile Include="LinearAlgebraTests\Complex\IO\DelimitedReaderTests.cs" />
<Compile Include="LinearAlgebraTests\Complex\IO\DelimitedWriterTests.cs" />
<Compile Include="LinearAlgebraTests\Complex\MatrixLoader.cs" />
<Compile Include="LinearAlgebraTests\Complex\MatrixTests.Arithmetic.cs" />

Loading…
Cancel
Save