↰ Return to documentation for file (include/networkit/io/METISGraphReaderImpl.hpp)
/*
* METISGraphReaderImpl.hpp
*
* Created on: 17.01.2013
* Author: Christian Staudt
*/
#ifndef NETWORKIT_IO_METIS_GRAPH_READER_IMPL_HPP_
#define NETWORKIT_IO_METIS_GRAPH_READER_IMPL_HPP_
#include <limits>
#include <stdexcept>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <networkit/auxiliary/Log.hpp>
#include <networkit/auxiliary/StringTools.hpp>
#include <networkit/io/METISGraphReader.hpp>
#include <networkit/io/METISParser.hpp>
namespace NetworKit {
template <class GraphT>
GraphT GenericMETISGraphReader<GraphT>::read(std::string_view path) {
using NodeT = typename GraphT::NodeT;
using EdgeWeightT = typename GraphT::EdgeWeightT;
METISParser parser(path);
std::tuple<count, count, index, count> header = parser.getHeader();
count n = std::get<0>(header);
count m = std::get<1>(header);
index fmt = std::get<2>(header);
count ncon = std::get<3>(header);
// The node ids 0, ..., n - 1 must be representable by NodeT and differ from NullNodeId<NodeT>,
// which marks "no node". Since NullNodeId<NodeT> is the largest NodeT, this allows at most
// max() nodes; the static_assert catches a change of NullNodeId that would invalidate this.
// The 1-based ids 1, ..., n in the file then fit into NodeT as well.
static_assert(NullNodeId<NodeT> == std::numeric_limits<NodeT>::max());
constexpr auto maxNumberOfNodes = static_cast<count>(std::numeric_limits<NodeT>::max());
if (n > maxNumberOfNodes) {
throw std::runtime_error("METIS file " + std::string(path) + " has " + std::to_string(n)
+ " nodes, but the node type of the graph can hold at most "
+ std::to_string(maxNumberOfNodes) + " nodes");
}
bool weighted;
if (fmt % 10 == 1) {
weighted = true;
DEBUG("graph has been identified as weighted");
} else {
weighted = false;
}
count ignoreFirst = 0;
if (fmt / 10 == 1) {
DEBUG("first ", ncon, " value(s) will be ignored");
ignoreFirst = ncon;
}
GraphT G(n, weighted);
std::string graphName =
Aux::StringTools::split(Aux::StringTools::split(path, '/').back(), '.').front();
INFO("\n[BEGIN] reading graph G(n=", n, ", m=", m, ") from METIS file: ", graphName);
#ifndef NETWORKIT_RELEASE_LOGGING
// percentage for progress bar
double p = 0.0;
#endif // NETWORKIT_RELEASE_LOGGING
// u is in [0, n) and thus fits into NodeT (checked above)
count u = 0; // begin with 0
count edgeCounter = 0;
count selfLoops = 0;
// Adds the edge from u to the 1-based METIS node id metisV, returns false if it is skipped.
const auto addEdge = [&](NodeT metisV, EdgeWeightT weight) -> bool {
if (metisV == NodeT{0}) {
ERROR("METIS Node ID should not be 0, edge ignored.");
return false;
}
if (metisV <= NodeT{0} || static_cast<count>(metisV) > n) {
throw std::runtime_error("METIS file " + std::string(path) + " has node id "
+ std::to_string(metisV) + ", but the valid ids are 1 to "
+ std::to_string(n));
}
const auto v = static_cast<NodeT>(metisV - 1); // METIS-indices are 1-based
// correct edgeCounter for selfloops
if (u == static_cast<count>(v)) {
++edgeCounter;
++selfLoops;
}
if (!G.addPartialEdge(unsafe, static_cast<NodeT>(u), v, weight, 0, true)) {
WARN("Not adding edge ", u, "-", v, " since it is already present.");
return false;
}
return true;
};
while (parser.hasNext() && u < n) {
if (weighted) {
const std::vector<std::pair<NodeT, EdgeWeightT>> adjacencies =
parser.getNextWithWeights<NodeT, EdgeWeightT>(ignoreFirst);
edgeCounter += adjacencies.size();
DEBUG("node ", u, " has ", adjacencies.size(), " edges");
for (const auto &[v, weight] : adjacencies) {
if (addEdge(v, weight)) {
// The cast prints 8-bit integral weights as numbers instead of characters.
TRACE("(", u, ",", v - 1, ",",
static_cast<std::common_type_t<EdgeWeightT, int>>(weight), ")");
}
}
} else {
const std::vector<NodeT> adjacencies = parser.getNext<NodeT>(ignoreFirst);
edgeCounter += adjacencies.size();
for (const NodeT v : adjacencies) {
addEdge(v, EdgeWeightT{1});
}
}
++u; // next node
#ifndef NETWORKIT_RELEASE_LOGGING
if ((u % ((n + 10) / 10)) == 0) {
p = ((double)(u - 1) / (double)n) * 100;
DEBUG(p, "% ");
}
#endif // NETWORKIT_RELEASE_LOGGING
}
G.setEdgeCount(unsafe, edgeCounter / 2);
G.setNumberOfSelfLoops(unsafe, selfLoops);
if (G.numberOfEdges() != m) {
ERROR("METIS file ", path,
" is corrupted: actual number of added edges doesn't match the specifed number of "
"edges");
}
if (edgeCounter != 2 * m) {
WARN("METIS file is corrupted: not every edge is listed twice");
}
INFO("\n[DONE]\n");
return G;
}
} /* namespace NetworKit */
#endif // NETWORKIT_IO_METIS_GRAPH_READER_IMPL_HPP_