forked from tsai/mathnet-numerics
8 changed files with 423 additions and 6 deletions
@ -0,0 +1,196 @@ |
|||||
|
// <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.Double.IO |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
using System.IO; |
||||
|
using System.Reflection; |
||||
|
using System.Text.RegularExpressions; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates a <see cref="Matrix"/> 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> |
||||
|
where TMatrix : Matrix |
||||
|
{ |
||||
|
/// <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() |
||||
|
{ |
||||
|
_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) |
||||
|
{ |
||||
|
_delimiter = new Regex("[" + new string(delimiter, 1) + "]+"); |
||||
|
} |
||||
|
|
||||
|
/// <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) |
||||
|
{ |
||||
|
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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,83 @@ |
|||||
|
// <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.Double.IO |
||||
|
{ |
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using Properties; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Base class to read a single <see cref="Matrix"/> from a file or stream.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TMatrix">The type of Matrix to return.</typeparam>
|
||||
|
public abstract class MatrixReader<TMatrix> where TMatrix : Matrix |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="Matrix"/> from a file.
|
||||
|
/// </summary>
|
||||
|
/// <param name="file">The file to read the matrix from.</param>
|
||||
|
/// <returns>A <see cref="Matrix"/> 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 ReadMatrix(string file) |
||||
|
{ |
||||
|
if (file == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException("file", Resources.StringNullOrEmpty); |
||||
|
} |
||||
|
|
||||
|
return ReadMatrix(File.OpenRead(file)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="Matrix"/> 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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,121 @@ |
|||||
|
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.IO |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Globalization; |
||||
|
using System.IO; |
||||
|
using System.Text; |
||||
|
using LinearAlgebra.Double; |
||||
|
using LinearAlgebra.Double.IO; |
||||
|
using MbUnit.Framework; |
||||
|
|
||||
|
[TestFixture] |
||||
|
public class DelimitedReaderTests |
||||
|
{ |
||||
|
[Test] |
||||
|
[MultipleAsserts] |
||||
|
public void CanParseCommaDelimitedData() |
||||
|
{ |
||||
|
const string data = |
||||
|
@"a,b,c
|
||||
|
1 |
||||
|
""2.2"",0.3e1 |
||||
|
'4',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]); |
||||
|
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 CanParseTabDelimtedData() |
||||
|
{ |
||||
|
var data = "1" |
||||
|
+ Environment.NewLine |
||||
|
+ "\"2.2\"\t\t0.3e1" |
||||
|
+ Environment.NewLine |
||||
|
+ "'4'\t5\t6"; |
||||
|
|
||||
|
var reader = new DelimitedReader<DenseMatrix>('\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"" 0.3e1 |
||||
|
'4' 5 6 |
||||
|
";
|
||||
|
var reader = new DelimitedReader<DenseMatrix>(); |
||||
|
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 CanParsePeriodDelimitedData() |
||||
|
{ |
||||
|
const string data = |
||||
|
@"a.b.c
|
||||
|
1 |
||||
|
""2,2"".0,3e1 |
||||
|
'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]); |
||||
|
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]); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue