#ifndef UTIL_GRAPH_H
#define UTIL_GRAPH_H
#include "container.h"
#include "ue2common.h"
#include "util/flat_containers.h"
#include "util/graph_range.h"
#include "util/unordered.h"
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/range/adaptor/map.hpp>
#include <algorithm>
#include <map>
#include <set>
#include <utility>
#include <vector>
namespace ue2 {
template<class Graph>
bool isLeafNode(const typename Graph::vertex_descriptor& v, const Graph& g) {
return out_degree(v, g) == 0;
}
template<class Graph>
bool hasSelfLoop(const typename Graph::vertex_descriptor &v, const Graph &g) {
return edge(v, v, g).second;
}
template<class Graph, class Iterator>
bool anySelfLoop(const Graph &g, Iterator it, const Iterator &end) {
for (; it != end; ++it) {
if (hasSelfLoop(*it, g)) {
return true;
}
}
return false;
}
template<class Graph>
size_t proper_out_degree(const typename Graph::vertex_descriptor &v,
const Graph &g) {
return out_degree(v, g) - (edge(v, v, g).second ? 1 : 0);
}
template<class Graph>
size_t proper_in_degree(const typename Graph::vertex_descriptor &v,
const Graph &g) {
return in_degree(v, g) - (edge(v, v, g).second ? 1 : 0);
}
template<class Graph>
bool has_successor(const typename Graph::vertex_descriptor &v, const Graph &g) {
return out_degree(v, g) > 0;
}
template<class Graph>
bool has_proper_successor(const typename Graph::vertex_descriptor &v,
const Graph &g) {
typename Graph::adjacency_iterator ai, ae;
std::tie(ai, ae) = adjacent_vertices(v, g);
if (ai == ae) {
return false;
}
if (*ai == v) {
++ai; }
return ai != ae;
}
template<class Graph, class SourceCont, class OutCont>
void find_reachable(const Graph &g, const SourceCont &sources, OutCont *out) {
using vertex_descriptor = typename Graph::vertex_descriptor;
std::unordered_map<vertex_descriptor, boost::default_color_type> colours;
for (auto v : sources) {
boost::depth_first_visit(g, v,
boost::make_dfs_visitor(boost::null_visitor()),
boost::make_assoc_property_map(colours));
}
for (const auto &e : colours) {
out->insert(e.first);
}
}
template<class Graph, class SourceCont, class OutCont>
void find_unreachable(const Graph &g, const SourceCont &sources, OutCont *out) {
using vertex_descriptor = typename Graph::vertex_descriptor;
std::unordered_set<vertex_descriptor> reachable;
find_reachable(g, sources, &reachable);
for (const auto &v : vertices_range(g)) {
if (!contains(reachable, v)) {
out->insert(v);
}
}
}
template <class Graph>
flat_set<typename Graph::vertex_descriptor>
find_vertices_in_cycles(const Graph &g) {
using vertex_descriptor = typename Graph::vertex_descriptor;
std::map<vertex_descriptor, size_t> comp_map;
boost::strong_components(g, boost::make_assoc_property_map(comp_map));
std::map<size_t, std::vector<vertex_descriptor>> comps;
for (const auto &e : comp_map) {
comps[e.second].push_back(e.first);
}
flat_set<vertex_descriptor> rv;
for (const auto &comp : comps | boost::adaptors::map_values) {
assert(!comp.empty());
if (comp.size() > 1) {
insert(&rv, comp);
continue;
}
vertex_descriptor v = *comp.begin();
if (hasSelfLoop(v, g)) {
rv.insert(v);
}
}
return rv;
}
template <class Graph>
bool has_parallel_edge(const Graph &g) {
using vertex_descriptor = typename Graph::vertex_descriptor;
ue2_unordered_set<std::pair<vertex_descriptor, vertex_descriptor>> seen;
for (const auto &e : edges_range(g)) {
auto u = source(e, g);
auto v = target(e, g);
if (!seen.emplace(u, v).second) {
return true;
}
}
return false;
}
struct found_back_edge {};
struct detect_back_edges : public boost::default_dfs_visitor {
explicit detect_back_edges(bool ignore_self_in)
: ignore_self(ignore_self_in) {}
template <class Graph>
void back_edge(const typename Graph::edge_descriptor &e,
const Graph &g) const {
if (ignore_self && source(e, g) == target(e, g)) {
return;
}
throw found_back_edge();
}
bool ignore_self;
};
template <class Graph>
bool is_dag(const Graph &g, bool ignore_self_loops = false) {
try {
depth_first_search(g, visitor(detect_back_edges(ignore_self_loops)));
} catch (const found_back_edge &) {
return false;
}
return true;
}
template<typename Cont>
class vertex_recorder : public boost::default_dfs_visitor {
public:
explicit vertex_recorder(Cont &o) : out(o) {}
template<class G>
void discover_vertex(typename Cont::value_type v, const G &) {
out.insert(v);
}
Cont &out;
};
template<typename Cont>
vertex_recorder<Cont> make_vertex_recorder(Cont &o) {
return vertex_recorder<Cont>(o);
}
template<typename Bitset>
class vertex_index_bitset_recorder : public boost::default_dfs_visitor {
public:
explicit vertex_index_bitset_recorder(Bitset &o) : out(o) {}
template<class Graph>
void discover_vertex(typename Graph::vertex_descriptor v, const Graph &g) {
assert(g[v].index < out.size());
out.set(g[v].index);
}
Bitset &out;
};
template<typename Bitset>
vertex_index_bitset_recorder<Bitset>
make_vertex_index_bitset_recorder(Bitset &o) {
return vertex_index_bitset_recorder<Bitset>(o);
}
template <class Graph>
std::pair<typename Graph::edge_descriptor, bool>
add_edge_if_not_present(typename Graph::vertex_descriptor u,
typename Graph::vertex_descriptor v, Graph &g) {
std::pair<typename Graph::edge_descriptor, bool> e = edge(u, v, g);
if (!e.second) {
e = add_edge(u, v, g);
}
return e;
}
template <class Graph>
std::pair<typename Graph::edge_descriptor, bool> add_edge_if_not_present(
typename Graph::vertex_descriptor u, typename Graph::vertex_descriptor v,
const typename Graph::edge_property_type &prop, Graph &g) {
std::pair<typename Graph::edge_descriptor, bool> e = edge(u, v, g);
if (!e.second) {
e = add_edge(u, v, prop, g);
}
return e;
}
#ifndef NDEBUG
template <class Graph>
bool hasCorrectlyNumberedVertices(const Graph &g) {
auto count = num_vertices(g);
std::vector<bool> ids(count, false);
for (auto v : vertices_range(g)) {
auto id = g[v].index;
if (id >= count || ids[id]) {
return false; }
ids[id] = true;
}
return std::find(ids.begin(), ids.end(), false) == ids.end()
&& count == vertex_index_upper_bound(g);
}
template <class Graph>
bool hasCorrectlyNumberedEdges(const Graph &g) {
auto count = num_edges(g);
std::vector<bool> ids(count, false);
for (const auto &e : edges_range(g)) {
auto id = g[e].index;
if (id >= count || ids[id]) {
return false; }
ids[id] = true;
}
return std::find(ids.begin(), ids.end(), false) == ids.end()
&& count == edge_index_upper_bound(g);
}
#endif
}
#endif