Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
MatrixMarketReader.cs 5.54 KiB
using Antlr4.Runtime;
using SparseTransform.DataStructures;
using SparseTransform.Convert;
namespace SparseTransform.Convert
{
/// <summary>
/// Provides an IReader implementation to read a MatrixMarket string.
/// </summary>
public class MatrixMarketReader : IReader
{
public IGraph ReadGraph(String matrix)
{
String[] lines = matrix.Split(
new String[] { "\r\n", "\r", "\n" },
StringSplitOptions.None
);
checkComments(lines);
if (checkHeader(lines[0]))
{
BipartiteGraph graph = new BipartiteGraph();
ReadContent(lines, (i, j, value) => {
graph.AddEdge(i, j);
});
return graph;
}
else
{
AdjacencyGraph graph = new AdjacencyGraph();
ReadContent(lines, (i, j, value) => {
graph.AddEdge(i, j);
});
return graph;
}
}
public DoubleMatrix ReadMatrix(String matrix)
{
String[] lines = matrix.Split(
new String[] { "\r\n", "\r", "\n" },
StringSplitOptions.None
);
checkComments(lines);
String dimLine = lines[getFirstDataLine(lines)];
String[] dimensions = dimLine.Split(" ");
DoubleMatrix mat = new DoubleMatrix(Int32.Parse(dimensions[0]), Int32.Parse(dimensions[1]));
ReadContent(lines, (i, j, value) =>
{
mat[i - 1, j - 1] = value;
});
return mat;
}
/// <summary>
/// checks with ANTLR4.0 whether the header is a valid instance. The header grammar can be found in the file MMFHeader.g4
/// </summary>
/// <param name="header">header of the MMF-input</param>
/// <returns>true if matrix is not symmetric</returns>
private bool checkHeader(String header)
{
AntlrInputStream stream = new AntlrInputStream(header);
MMFHeaderLexer lexer = new MMFHeaderLexer(stream);
CommonTokenStream commonTokenStream = new CommonTokenStream(lexer);
MMFHeaderParser speakParser = new MMFHeaderParser(commonTokenStream);
EListener errorHandler = new EListener();
speakParser.AddErrorListener(errorHandler);
VisitorHeader visitor = new VisitorHeader();
return visitor.Visit(speakParser.header());
}
/// <summary>
/// checks whether the comment-section is valid.
/// </summary>
/// <param name="lines">entire input split by newlines</param>
/// <exception cref="FormatException"></exception>
private void checkComments(String[] lines)
{
bool leftComments = false;
foreach (String line in lines)
{
if (line != "")
{
if (leftComments && line.StartsWith('%'))
{
throw new FormatException("Syntax Error in MatrixMarket file: Encountered more comments in between data lines.");
}
else
{
if (!line.StartsWith('%'))
{
leftComments = true;
}
}
}
else
{
leftComments = true;
}
}
}
/// <summary>
/// creates a graph from the data-section of the MMF-input and meanwhile checks whether the data-section is valid
/// </summary>
/// <param name="matrix"></param>
/// <param name="graph"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public void ReadContent(String[] matrix, Action<int, int, double> processor)
{
String[] values;
int lineCount = getFirstDataLine(matrix);
matrix[lineCount] = "% " + matrix[lineCount];
foreach (String line in matrix)
{
if (line != "")
{
if (!line.StartsWith('%'))
{
values = line.Split(" ");
if (values.Length != 3)
{
throw new ArgumentException("Syntax Error in MatrixMarket file: Data line did not contain three elements.");
}
int i = Int32.Parse(values[0]);
int j = Int32.Parse(values[1]);
processor(i, j, Double.Parse(values[2]));
}
}
}
}
/// <summary>
/// computes the first data-line in the MMF-input
/// </summary>
/// <param name="lines"></param>
/// <returns></returns>
private int getFirstDataLine(String[] lines)
{
int firstDataLine = 0;
foreach (String line in lines)
{
if (line != "")
{
if (line[0] != '%')
{
break;
}
else
{
firstDataLine++;
}
}
else
{
firstDataLine++;
}
}
return firstDataLine;
}
}
}