/* * Copyright (c) 2015, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Intel Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** \file * \brief Functions for graph manipulation that aren't in the base BGL toolkit. */ #ifndef UTIL_GRAPH_H #define UTIL_GRAPH_H #include "container.h" #include "ue2common.h" #include "util/graph_range.h" #include "util/ue2_containers.h" #include #include #include #include namespace ue2 { /** \brief True if the given vertex has no out-edges. */ template bool isLeafNode(const typename Graph::vertex_descriptor& v, const Graph& g) { typename Graph::adjacency_iterator ai, ae; std::tie(ai, ae) = adjacent_vertices(v, g); return ai == ae; // no out edges } /** \brief True if the out-degree of vertex \a v is greater than the given * limit. */ template bool hasGreaterOutDegree(size_t limit, const typename Graph::vertex_descriptor& v, const Graph& g) { typename Graph::out_edge_iterator ei, ee; for (std::tie(ei, ee) = out_edges(v, g); ei != ee; ++ei) { if (limit-- == 0) { return true; } } return false; } /** \brief Returns true if the in-degree of vertex \a v is greater than the * given limit. */ template bool hasGreaterInDegree(size_t limit, const typename Graph::vertex_descriptor& v, const Graph& g) { typename Graph::in_edge_iterator ei, ee; for (std::tie(ei, ee) = in_edges(v, g); ei != ee; ++ei) { if (limit-- == 0) { return true; } } return false; } /** * \brief True if the degree of vertex \a v is greater than the given limit. */ template bool has_greater_degree(size_t limit, const typename Graph::vertex_descriptor &v, const Graph &g) { typename Graph::in_edge_iterator ei, ee; for (std::tie(ei, ee) = in_edges(v, g); ei != ee; ++ei) { if (limit-- == 0) { return true; } } typename Graph::out_edge_iterator oi, oe; for (std::tie(oi, oe) = out_edges(v, g); oi != oe; ++oi) { if (limit-- == 0) { return true; } } return false; } /** \brief True if vertex \a v has an edge to itself. */ template bool hasSelfLoop(const typename Graph::vertex_descriptor &v, const Graph &g) { return edge(v, v, g).second; } /** \brief True if any vertex in [it, end) has an edge to itself. */ template bool anySelfLoop(const Graph &g, Iterator it, const Iterator &end) { for (; it != end; ++it) { if (hasSelfLoop(*it, g)) { return true; } } return false; } /** \brief Returns the out-degree of vertex \a v, ignoring self-loops. */ template 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); } /** \brief Returns the in-degree of vertex \a v, ignoring self-loops. */ template 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); } /** \brief Returns true iff the in-degree of vertex \a v is \a expected */ template bool in_degree_equal_to(const typename Graph::vertex_descriptor &v, const Graph &g, size_t expected) { size_t seen = 0; typename Graph::in_edge_iterator ei, ee; for (std::tie(ei, ee) = in_edges(v, g);; ++ei, seen++) { if (seen == expected) { return ei == ee; } if (ei == ee) { return false; } } } /** \brief same as edge(s, t, g) by finds edge by inspecting in-edges of target. * Should be used when it is known that t has a small in-degree and when s * may have a large out-degree. */ template std::pair edge_by_target(const typename Graph::vertex_descriptor &s, const typename Graph::vertex_descriptor &t, const Graph &g) { typename Graph::in_edge_iterator ei, ee; for (std::tie(ei, ee) = in_edges(t, g); ei != ee; ++ei) { if (source(*ei, g) == s) { return std::make_pair(*ei, true); } } return std::make_pair(typename Graph::edge_descriptor(), false); } /** \brief True if vertex \a v has at least one successor. */ template bool has_successor(const typename Graph::vertex_descriptor &v, const Graph &g) { typename Graph::adjacency_iterator ai, ae; std::tie(ai, ae) = adjacent_vertices(v, g); return ai != ae; } /** \brief True if vertex \a v has at least one successor other than itself. */ template 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; // skip self-loop } return ai != ae; } /** \brief A version of clear_vertex that explicitly removes in- and out-edges * for vertex \a v. For many graphs, this is faster than the BGL clear_vertex * function, which walks the graph's full edge list. */ template void clear_vertex_faster(typename Graph::vertex_descriptor v, Graph &g) { typename Graph::in_edge_iterator ei, ee; tie(ei, ee) = in_edges(v, g); while (ei != ee) { remove_edge(*ei++, g); } typename Graph::out_edge_iterator oi, oe; tie(oi, oe) = out_edges(v, g); while (oi != oe) { // NOTE: version that takes out_edge_iterator is faster according to // the BGL docs. remove_edge(oi++, g); } } /** \brief Find the set of vertices that are reachable from the vertices in \a * sources. */ template void find_reachable(const Graph &g, const SourceCont &sources, OutCont *out) { using vertex_descriptor = typename Graph::vertex_descriptor; ue2::unordered_map 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); } } /** \brief Find the set of vertices that are NOT reachable from the vertices in * \a sources. */ template void find_unreachable(const Graph &g, const SourceCont &sources, OutCont *out) { using vertex_descriptor = typename Graph::vertex_descriptor; ue2::unordered_set reachable; find_reachable(g, sources, &reachable); for (const auto &v : vertices_range(g)) { if (!contains(reachable, v)) { out->insert(v); } } } template bool has_parallel_edge(const Graph &g) { using vertex_descriptor = typename Graph::vertex_descriptor; ue2::unordered_set> 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 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 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 std::pair add_edge_if_not_present(typename Graph::vertex_descriptor u, typename Graph::vertex_descriptor v, Graph &g) { std::pair e = edge(u, v, g); if (!e.second) { e = add_edge(u, v, g); } return e; } template std::pair 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 e = edge(u, v, g); if (!e.second) { e = add_edge(u, v, prop, g); } return e; } } // namespace ue2 #endif // UTIL_GRAPH_H