diff --git a/src/SparseTransform/Convert/ErrorListener.cs b/src/SparseTransform/Convert/ErrorListener.cs new file mode 100644 index 0000000000000000000000000000000000000000..645f40d00504666cf57829efeb7752a849fc8ed4 --- /dev/null +++ b/src/SparseTransform/Convert/ErrorListener.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antlr4.Runtime; +using Antlr4.Runtime.Misc; + +namespace Transform.Convert +{ + internal class EListener : IAntlrErrorListener<IToken> + { + public void SyntaxError([NotNull] IRecognizer recognizer, [Nullable] IToken offendingSymbol, int line, int charPositionInLine, [NotNull] string msg, [Nullable] RecognitionException e) + { + throw new Exception(msg); + } + } +} + diff --git a/src/SparseTransform/Convert/MMFHeader.g4 b/src/SparseTransform/Convert/MMFHeader.g4 new file mode 100644 index 0000000000000000000000000000000000000000..cc54750edcd087fb8dcc67c073ff4753797f26d2 --- /dev/null +++ b/src/SparseTransform/Convert/MMFHeader.g4 @@ -0,0 +1,26 @@ +grammar MMFHeader; + + +header : PERCENT PERCENT MATRIXMARKET MATRIX format; + +format : choice1 | choice2 | choice3; + +choice1 : ( COORDINATE | ARRAY) (REAL | INTEGER | COMPLEX) (GENERAL | SYMMETRIC | SKEW); + +choice2 : ( COORDINATE | ARRAY) COMPLEX HERMITIAN; + +choice3 : COORDINATE PATTERN (GENERAL | SYMMETRIC); + +PERCENT : '%'; +MATRIXMARKET : 'MatrixMarket'; +MATRIX : 'matrix'; +COORDINATE : 'coordinate'; +ARRAY : 'array'; +REAL : 'real'; +INTEGER : 'integer'; +COMPLEX : 'complex'; +GENERAL : 'general'; +SYMMETRIC : 'symmetric'; +SKEW : 'skew-symmetric'; +HERMITIAN : 'Hermitian'; +PATTERN : 'pattern'; \ No newline at end of file diff --git a/src/SparseTransform/Convert/MatrixMarketReader.cs b/src/SparseTransform/Convert/MatrixMarketReader.cs index 4c7cd4f48e6628c6296905836d2b29146a833f18..83e9b24dbc0345ed9b9bcad2122eb7521e2d1a4a 100644 --- a/src/SparseTransform/Convert/MatrixMarketReader.cs +++ b/src/SparseTransform/Convert/MatrixMarketReader.cs @@ -1,27 +1,158 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection; +using System.Reflection.PortableExecutable; using System.Text; using System.Threading.Tasks; +using Antlr4.Runtime; using DataStructures; +using Transform; +using Transform.Convert; + namespace SparseTransform.Convert { internal class MatrixMarketReader : IReader - { + { + public IGraph Read(string matrix) { - throw new NotImplementedException(); + string[] lines = matrix.Split( + new string[] { "\r\n", "\r", "\n" }, + StringSplitOptions.None + ); + + checkComments(lines); + + if (checkHeader(lines[0])) + { + BipartiteGraph graph = new BipartiteGraph(); + return ReadGraph(lines, graph); + } + else + { + AdjacencyGraph graph = new AdjacencyGraph(); + return ReadGraph(lines, graph); + } } - public AdjacencyGraph ReadAdjacency(string matrix) + + private bool checkHeader(string header) { - throw new NotImplementedException(); + 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()); + } + + + private void checkComments(string[] lines) + { + bool leftComments = false; + foreach (string line in lines) + { + if (line != "") + { + if (leftComments && line.StartsWith('%')) + { + throw new Exception("comment section mismatch on input"); + } + else + { + if (!line.StartsWith('%')) + { + leftComments = true; + } + } + } + else + { + leftComments = true; + } + } + } + + + public IGraph ReadGraph(string[] matrix, IGraph graph) + { + string[] values; + int lineCount = getFirstDataLine(matrix); + matrix[lineCount] = "% " + matrix[lineCount]; + try + { + foreach (String line in matrix) + { + if (line != "") + { + if (!line.StartsWith('%')) + { + + values = line.Split(" "); + if (values.Length != 3) + { + throw new Exception(); + } + int xCoordinate = Int32.Parse(values[0]); + int yCoordinate = Int32.Parse(values[1]); + String value = values[2]; + addEdge(xCoordinate, yCoordinate, graph); + } + } + } + return graph; + } + catch (Exception e) + { + throw new Exception("data section mismatch on input"); + } + } + + private void addEdge(int xCoordinate, int yCoordinate, IGraph g) + { + if (xCoordinate != yCoordinate) + { + g.AddEdge(xCoordinate, yCoordinate); + } + } + + 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; } public BipartiteGraph ReadBipartite(string matrix) { throw new NotImplementedException(); } + + public AdjacencyGraph ReadAdjacency(string matrix) + { + throw new NotImplementedException(); + } } -} +} \ No newline at end of file diff --git a/src/SparseTransform/Convert/MatrixMarketWriter.cs b/src/SparseTransform/Convert/MatrixMarketWriter.cs index 5bff1cc87f3a52000b564ed28287fa56bb876e93..bd78c3ba008da6ef4b3164e177683aca31993b0d 100644 --- a/src/SparseTransform/Convert/MatrixMarketWriter.cs +++ b/src/SparseTransform/Convert/MatrixMarketWriter.cs @@ -41,7 +41,7 @@ namespace SparseTransform.Convert private void CalculateCompressedMatrix() { - + } } } \ No newline at end of file diff --git a/src/SparseTransform/Convert/VisitorHeader.cs b/src/SparseTransform/Convert/VisitorHeader.cs new file mode 100644 index 0000000000000000000000000000000000000000..cd244b6217fe8ad3ff75a260bb0f5fe6a4d9a45a --- /dev/null +++ b/src/SparseTransform/Convert/VisitorHeader.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antlr4.Runtime.Misc; +using Antlr4.Runtime.Tree; +using DataStructures; +using SparseTransform.Convert; + +namespace Transform.Convert +{ + internal class VisitorHeader : MMFHeaderBaseVisitor<bool> + { + public override bool VisitHeader([NotNull] MMFHeaderParser.HeaderContext context) + { + if ((context.format().choice1() is null || context.format().choice1().GENERAL() is null) + && (context.format().choice3() is null || context.format().choice3().GENERAL() is null)) + { + return false; + } + else + { + return true; + } + } + } +}