diff --git a/input/GD01_b.mtx b/input/GD01_b.mtx new file mode 100644 index 0000000000..b976da40c2 --- /dev/null +++ b/input/GD01_b.mtx @@ -0,0 +1,39 @@ +%%MatrixMarket matrix coordinate pattern general +18 18 37 +1 1 +7 1 +1 2 +8 2 +2 3 +6 3 +9 3 +3 4 +16 4 +4 5 +9 5 +5 6 +6 7 +8 7 +2 8 +7 8 +3 9 +5 9 +4 10 +17 10 +10 11 +11 12 +15 12 +18 12 +12 13 +13 13 +13 14 +15 14 +18 14 +14 15 +11 16 +14 16 +17 16 +10 17 +16 17 +12 18 +14 18 diff --git a/input/Hamrle1.mtx b/input/Hamrle1.mtx new file mode 100644 index 0000000000..fbe36a4cae --- /dev/null +++ b/input/Hamrle1.mtx @@ -0,0 +1,100 @@ +%%MatrixMarket matrix coordinate real general +32 32 98 +1 1 .8499999999999999 +2 1 .2039265503510711 +21 1 1 +23 1 1 +25 1 1 +1 2 .15000000000000013 +2 2 -.2039265503510711 +22 2 1 +24 2 1 +26 2 1 +1 3 -.21772222037194985 +2 3 -.04492168652740657 +3 3 1 +17 3 1 +1 4 -.21772222037195 +2 4 .2545562236553039 +3 4 1 +18 4 1 +4 5 .2213493690543944 +21 5 -1 +4 6 -.2213493690543944 +22 6 -1 +4 7 -.0004256718635661431 +5 7 1 +17 7 1 +4 8 .0004256718635661431 +5 8 1 +18 8 1 +6 9 .2039265503510711 +23 9 -1 +6 10 -.2039265503510711 +24 10 -1 +6 11 -.04492168652740657 +7 11 1 +17 11 1 +6 12 .2545562236553039 +7 12 1 +18 12 1 +8 13 .20392655035107113 +27 13 -1 +8 14 -.20392655035107113 +28 14 -1 +8 15 -.2545562236553039 +9 15 1 +19 15 1 +8 16 .04492168652740657 +9 16 1 +20 16 1 +10 17 .2213493690543944 +29 17 -1 +10 18 -.2213493690543944 +30 18 -1 +10 19 -.0004256718635661431 +11 19 1 +19 19 1 +10 20 .0004256718635661431 +11 20 1 +20 20 1 +12 21 .20392655035107113 +31 21 -1 +12 22 -.20392655035107113 +32 22 -1 +12 23 -.2545562236553039 +19 23 1 +12 24 .04492168652740657 +20 24 1 +13 25 -1 +27 25 1 +29 25 1 +31 25 1 +14 26 -1 +28 26 1 +30 26 1 +32 26 1 +15 27 -1 +19 27 -1 +16 28 -1 +20 28 -1 +13 29 1.0838782686107287 +14 29 -.08387826861072856 +15 29 -156.78998795556143 +16 29 156.78998795556143 +25 29 -1 +13 30 -.08387826861072856 +14 30 1.0838782686107287 +15 30 156.78998795556143 +16 30 -156.78998795556143 +26 30 -1 +13 31 -.0011292951794637206 +14 31 3.0394080562621574e-5 +15 31 1.0838782686107287 +16 31 -.08387826861072858 +17 31 1 +13 32 3.0394080562621574e-5 +14 32 -.0011292951794637206 +15 32 -.08387826861072858 +16 32 1.0838782686107287 +18 32 1 diff --git a/input/LFAT5.mtx b/input/LFAT5.mtx new file mode 100644 index 0000000000..061c19483c --- /dev/null +++ b/input/LFAT5.mtx @@ -0,0 +1,32 @@ +%%MatrixMarket matrix coordinate real symmetric +14 14 30 +1 1 1.57088 +4 1 -94.2528 +5 1 .78544 +2 2 1.25664e7 +6 2 -6.2832e6 +3 3 .6088062015503876 +7 3 -.3044031007751938 +4 4 15080.447999999997 +8 4 -7540.223999999998 +9 4 94.2528 +5 5 3.14176 +8 5 -94.2528 +9 5 .78544 +6 6 1.25664e7 +10 6 -6.2832e6 +7 7 .6088062015503876 +11 7 -.3044031007751938 +8 8 15080.447999999997 +12 8 -7540.223999999998 +13 8 94.2528 +9 9 3.14176 +12 9 -94.2528 +13 9 .78544 +10 10 1.25664e7 +11 11 .6088062015503876 +12 12 15080.447999999997 +14 12 94.2528 +13 13 3.14176 +14 13 .78544 +14 14 1.57088 diff --git a/input/README.md b/input/README.md index 2411f2499d..6b7389d930 100644 --- a/input/README.md +++ b/input/README.md @@ -15,6 +15,7 @@ This folder contains many smaller graphs. They are used in the testing suite and | caidaRouterLevel.graph | Format.METIS | METISGraphReader | 7490360 | 192244 | 609066 | FALSE | FALSE | n/a | | celegans_metabolic.graph | Format.METIS | METISGraphReader | 16015 | 453 | 2025 | FALSE | FALSE | n/a | | celegans_metabolic.thrill | Format.THRILL | ThrillGraphReader | 8554 | 453 | 2025 | FALSE | FALSE | n/a | +| chesapeake.mtx | n/a | MatrixMarketReader | 1053 | 39 | 170 | FALSE | FALSE | n/a | | comments.edgelist | Format.EdgeListTabOne | EdgeListReader | 127 | 10 | 10 | FALSE | FALSE | n/a | | community_overlapping.cover | n/a | CoverReader | 61 | n/a | n/a | n/a | n/a | n/a | | community_overlapping.dat | n/a | EdgeListCoverReader | 83 | n/a | n/a | n/a | n/a | n/a | @@ -27,8 +28,10 @@ This folder contains many smaller graphs. They are used in the testing suite and | example2.dgs | n/a | DGSReader | 161 | n/a | n/a | n/a | n/a | n/a | | foodweb-baydry.konect | Format.KONECT | KONECTGraphReader | 42847 | 128 | 2137 | TRUE | TRUE | n/a | | foodweb-baydry.networkit | Format.NETWORKITBINARY | NetworkitBinaryReader | 42491 | 128 | 2137 | TRUE | TRUE | n/a | +| GD01_b.mtx | n/a | MatrixMarketReader | 244 | 18 | 37 | TRUE | FALSE | n/a | | grid-5x5-dist-arch.graph | Format.METIS | METISGraphReader | 218 | 25 | 40 | FALSE | FALSE | n/a | | hamming6-4.edgelist | Format.EdgeListSpaceOne | EdgeListReader | 4088 | 64 | 704 | FALSE | FALSE | n/a | +| Hamrle1.mtx | n/a | MatrixMarketReader | 1571 | 32 | 98 | TRUE | TRUE | n/a | | hep-th.graph | Format.METIS | METISGraphReader | 157814 | 8361 | 15751 | FALSE | FALSE | n/a | | jazz.graph | Format.METIS | METISGraphReader | 19445 | 198 | 2742 | FALSE | FALSE | n/a | | jazz2_directed.gml | Format.GML | GMLGraphReader | 289 | 5 | 4 | TRUE | FALSE | n/a | @@ -37,6 +40,7 @@ This folder contains many smaller graphs. They are used in the testing suite and | johnson8-4-4.edgelist | Format.EdgeListSpaceOne | EdgeListReader | 10716 | 70 | 1855 | FALSE | FALSE | n/a | | karate.graph | Format.METIS | METISGraphReader | 450 | 34 | 78 | FALSE | FALSE | n/a | | lesmis.graph | Format.METIS | METISGraphReader | 2630 | 77 | 254 | FALSE | TRUE | n/a | +| LFAT5.mtx | n/a | MatrixMarketReader | 553 | 14 | 30 | FALSE | TRUE | n/a | | looptest1.gml | Format.GML | GMLGraphReader | 676 | 9 | 12 | FALSE | FALSE | n/a | | looptest2.gml | Format.GML | GMLGraphReader | 754 | 9 | 14 | FALSE | FALSE | n/a | | MIT8.edgelist | Format.EdgeListTabZero | EdgeListReader | 2425755 | 6440 | 251252 | FALSE | FALSE | n/a | @@ -46,6 +50,7 @@ This folder contains many smaller graphs. They are used in the testing suite and | polblogs.graph | Format.METIS | METISGraphReader | 143808 | 1490 | 16715 | FALSE | FALSE | n/a | | power.graph | Format.METIS | METISGraphReader | 67968 | 4941 | 6594 | FALSE | FALSE | n/a | | power.gt | Format.GraphToolBinary | GraphToolBinaryReader | 172599 | 4941 | 6594 | FALSE | FALSE | n/a | +| Ragusa16.mtx | n/a | MatrixMarketReader | 664 | 24 | 81 | TRUE | TRUE | n/a | | spaceseparated_weighted.edgelist | Format.EdgeListSpaceOne | EdgeListReader | 17 | 3 | 3 | FALSE | TRUE | n/a | | spaceseparated.edgelist | Format.EdgeListSpaceOne | EdgeListReader | 86 | 10 | 10 | FALSE | FALSE | n/a | | staticTest.gexf | GEXFReader | n/a | 141043 | n/a | n/a | n/a | n/a | n/a | diff --git a/input/Ragusa16.mtx b/input/Ragusa16.mtx new file mode 100644 index 0000000000..e9573ef900 --- /dev/null +++ b/input/Ragusa16.mtx @@ -0,0 +1,83 @@ +%%MatrixMarket matrix coordinate integer general +24 24 81 +14 2 1 +5 3 2 +11 3 1 +22 3 1 +11 4 1 +22 4 1 +1 5 1 +3 5 1 +5 5 4 +8 5 1 +9 5 1 +11 5 4 +14 5 1 +16 5 2 +19 5 1 +20 5 1 +24 5 3 +7 6 1 +20 6 1 +7 7 1 +9 7 1 +11 7 1 +14 7 1 +8 8 1 +11 8 1 +13 8 1 +20 8 1 +5 9 1 +9 9 1 +16 9 1 +20 9 1 +24 9 1 +8 10 1 +11 10 1 +24 10 2 +5 11 4 +7 11 1 +8 11 1 +10 11 2 +11 11 1 +12 11 1 +13 11 1 +14 11 1 +18 11 1 +22 11 1 +24 11 1 +5 12 1 +8 12 1 +10 12 1 +12 12 1 +13 12 1 +17 12 1 +22 12 2 +23 12 1 +5 13 2 +22 13 1 +5 14 3 +7 14 1 +22 14 1 +23 14 1 +5 15 1 +3 16 1 +16 16 1 +11 19 1 +19 19 1 +8 20 1 +11 20 1 +20 20 1 +22 20 1 +9 21 1 +1 22 2 +9 22 1 +10 22 1 +12 22 5 +13 22 1 +14 22 4 +22 22 6 +24 22 1 +3 24 1 +5 24 1 +8 24 1 diff --git a/input/chesapeake.mtx b/input/chesapeake.mtx new file mode 100644 index 0000000000..acf84e3a8e --- /dev/null +++ b/input/chesapeake.mtx @@ -0,0 +1,173 @@ +%%MatrixMarket matrix coordinate pattern symmetric +% kind: undirected graph +39 39 170 +7 1 +8 1 +11 1 +12 1 +13 1 +22 1 +23 1 +34 1 +35 1 +37 1 +39 1 +7 2 +8 2 +9 2 +11 2 +12 2 +13 2 +22 2 +23 2 +35 2 +36 2 +39 2 +14 3 +15 3 +16 3 +17 3 +18 3 +36 3 +39 3 +17 4 +36 4 +37 4 +39 4 +6 5 +34 5 +35 5 +39 5 +7 6 +35 6 +39 6 +8 7 +9 7 +11 7 +12 7 +13 7 +35 7 +39 7 +9 8 +10 8 +20 8 +21 8 +22 8 +23 8 +24 8 +35 8 +38 8 +39 8 +10 9 +35 9 +36 9 +39 9 +35 10 +36 10 +39 10 +19 11 +35 11 +36 11 +39 11 +19 12 +26 12 +35 12 +36 12 +38 12 +39 12 +35 13 +36 13 +38 13 +39 13 +25 14 +26 14 +27 14 +28 14 +29 14 +36 14 +39 14 +19 15 +25 15 +26 15 +27 15 +28 15 +29 15 +36 15 +39 15 +19 16 +27 16 +36 16 +39 16 +36 17 +39 17 +19 18 +25 18 +26 18 +27 18 +29 18 +32 18 +36 18 +39 18 +33 19 +36 19 +38 19 +39 19 +36 20 +38 20 +39 20 +33 21 +36 21 +38 21 +39 21 +27 22 +28 22 +30 22 +31 22 +32 22 +33 22 +35 22 +36 22 +38 22 +39 22 +30 23 +32 23 +33 23 +35 23 +36 23 +38 23 +39 23 +36 24 +38 24 +39 24 +36 25 +38 25 +39 25 +36 26 +38 26 +39 26 +30 27 +36 27 +38 27 +39 27 +36 28 +38 28 +39 28 +36 29 +38 29 +39 29 +36 30 +38 30 +39 30 +32 31 +36 31 +38 31 +39 31 +36 32 +38 32 +39 32 +36 33 +38 33 +39 33 +37 34 +36 35 +37 35 diff --git a/networkit/cpp/io/MatrixMarketReader.cpp b/networkit/cpp/io/MatrixMarketReader.cpp index 36849d2520..ec872def6d 100644 --- a/networkit/cpp/io/MatrixMarketReader.cpp +++ b/networkit/cpp/io/MatrixMarketReader.cpp @@ -9,13 +9,15 @@ #include #include +#include #include namespace NetworKit { namespace { static constexpr char COMMENT_CHAR = '%'; -static const std::string MAGIC = "%%matrixmarket"; +static const std::string MAGIC1 = "%matrixmarket"; +static const std::string MAGIC2 = "%" + MAGIC1; std::string tolower(const std::string &str) { std::string out; @@ -54,8 +56,8 @@ CSRMatrix MatrixMarketReader::read(std::istream &in) { format = tolower(format); data = tolower(data); qualifier = tolower(qualifier); - if (magic != MAGIC) { - throw std::runtime_error(MAGIC + " not found"); + if (magic != MAGIC1 && magic != MAGIC2) { + throw std::runtime_error(MAGIC1 + " or " + MAGIC2 + " not found"); } if (format != "coordinate") { throw std::runtime_error("Unsupported format: " + format); @@ -63,7 +65,12 @@ CSRMatrix MatrixMarketReader::read(std::istream &in) { if (data == "pattern") { weighted = false; } else if (data != "real") { - throw std::runtime_error("Unsupported data type: " + data); + if (data == "integer") + WARN( + "Weights in NetworKit are stored as double precision floating point number while the given file uses integer weights.\ + This means that weights bigger than 4.5e15 will be recorded imprecisely."); + else + throw std::runtime_error("Unsupported data type: " + data); } if (qualifier == "symmetric") { diff --git a/networkit/cpp/io/test/IOGTest.cpp b/networkit/cpp/io/test/IOGTest.cpp index 5ff3b49fd9..e9f9b45bed 100644 --- a/networkit/cpp/io/test/IOGTest.cpp +++ b/networkit/cpp/io/test/IOGTest.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -1225,4 +1227,69 @@ TEST_F(IOGTest, testNetworkitBinaryZigzag) { } } +TEST_F(IOGTest, testMatrixMarketReaderUnweightedUndirected) { + CSRMatrix csr = MatrixMarketReader{}.read("input/chesapeake.mtx"); + EXPECT_EQ(csr.numberOfRows(), 39); + EXPECT_EQ(csr.nnz(), 170 * 2); // double due to being undirected + EXPECT_EQ(csr(7, 0), 1.0); + EXPECT_EQ(csr(21, 1), 1.0); + EXPECT_EQ(csr(5, 4), 1.0); + EXPECT_EQ(csr(10, 6), 1.0); + EXPECT_EQ(csr(35, 10), 1.0); + EXPECT_EQ(csr(26, 13), 1.0); + csr.forNonZeroElementsInRowOrder( + [&](index i, index j, double) { EXPECT_EQ(csr(i, j), csr(j, i)); }); +} + +TEST_F(IOGTest, testMatrixMarketReaderUnweightedDirected) { + CSRMatrix csr = MatrixMarketReader{}.read("input/GD01_b.mtx"); + EXPECT_EQ(csr.numberOfRows(), 18); + EXPECT_EQ(csr.nnz(), 37); + EXPECT_EQ(csr(7, 1), 1.0); + EXPECT_EQ(csr(2, 3), 1.0); + EXPECT_EQ(csr(15, 3), 1.0); + EXPECT_EQ(csr(3, 9), 1.0); + EXPECT_EQ(csr(11, 12), 1.0); + EXPECT_EQ(csr(17, 13), 1.0); +} + +TEST_F(IOGTest, testMatrixMarketReaderWeightedUndirected) { + CSRMatrix csr = MatrixMarketReader{}.read("input/LFAT5.mtx"); + EXPECT_EQ(csr.numberOfRows(), 14); + // double due to being undirected but we don't double count self loops + EXPECT_EQ(csr.nnz(), 30 * 2 - 14); + EXPECT_EQ(csr(5, 1), -6.2832e6); + EXPECT_EQ(csr(3, 3), 15080.447999999997); + EXPECT_EQ(csr(8, 3), 94.2528); + EXPECT_EQ(csr(5, 5), 1.25664e7); + EXPECT_EQ(csr(11, 8), -94.2528); + EXPECT_EQ(csr(13, 11), 94.2528); + csr.forNonZeroElementsInRowOrder( + [&](index i, index j, double) { EXPECT_EQ(csr(i, j), csr(j, i)); }); +} + +TEST_F(IOGTest, testMatrixMarketReaderWeightedDirected) { + CSRMatrix csr = MatrixMarketReader{}.read("input/Hamrle1.mtx"); + EXPECT_EQ(csr.numberOfRows(), 32); + EXPECT_EQ(csr.nnz(), 98); + EXPECT_EQ(csr(0, 0), 0.8499999999999999); + EXPECT_EQ(csr(2, 2), 1.0); + EXPECT_EQ(csr(3, 4), 0.2213493690543944); + EXPECT_EQ(csr(5, 9), -0.2039265503510711); + EXPECT_EQ(csr(9, 16), 0.2213493690543944); + EXPECT_EQ(csr(11, 23), 0.04492168652740657); +} + +TEST_F(IOGTest, testMatrixMarketReaderIntegerWeights) { + CSRMatrix csr = MatrixMarketReader{}.read("input/Ragusa16.mtx"); + EXPECT_EQ(csr.numberOfRows(), 24); + EXPECT_EQ(csr.nnz(), 81); + EXPECT_EQ(csr(0, 4), 1.0); + EXPECT_EQ(csr(23, 4), 3.0); + EXPECT_EQ(csr(10, 6), 1.0); + EXPECT_EQ(csr(23, 9), 2.0); + EXPECT_EQ(csr(4, 10), 4.0); + EXPECT_EQ(csr(21, 21), 6.0); +} + } /* namespace NetworKit */