// graph-tool -- a general graph modification and manipulation thingy // // Copyright (C) 2006-2019 Tiago de Paula Peixoto // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 3 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #ifndef GRAPH_ADAPTOR_HH #define GRAPH_ADAPTOR_HH #include #include #include #include #include #include "transform_iterator.hh" namespace boost { //============================================================================== // undirected_adaptor // This class encapsulates a directed graph with parallel edges and provides a // view of the graph as undirected with parallel edges. //============================================================================== template class undirected_adaptor { public: undirected_adaptor(const Graph& g) : _g(const_cast(g)){} typedef typename vertex_property_type::type vertex_property_type; typedef typename edge_property_type::type edge_property_type; typedef typename Graph::graph_tag graph_tag; typedef Graph graph_type; typedef Graph original_graph_t; typedef typename graph_traits >::vertex_descriptor vertex_descriptor; typedef typename graph_traits >::edge_descriptor edge_descriptor; typedef undirected_tag directed_category; typedef allow_parallel_edge_tag edge_parallel_category; typedef typename graph_traits::traversal_category traversal_category; typedef typename Graph::out_edge_iterator all_edge_iterator; typedef typename Graph::out_edge_iterator all_edge_iterator_reversed; const Graph& original_graph() const {return _g;} Graph& original_graph() {return _g;} static vertex_descriptor null_vertex() {graph_traits::null_vertex();} private: Graph& _g; }; template struct get_iterator_category { typedef typename graph_traits::out_edge_iterator iter_t; typedef typename std::iterator_traits::iterator_category type; }; //============================================================================== // graph_traits // this defines all the necessary types associated with undirected_adaptor //============================================================================== template struct graph_traits > { typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::edge_descriptor edge_descriptor; typedef typename graph_traits::adjacency_iterator adjacency_iterator; typedef typename graph_traits::out_edge_iterator out_edge_iterator; typedef typename graph_traits::in_edge_iterator in_edge_iterator; typedef typename graph_traits::vertex_iterator vertex_iterator; typedef typename graph_traits::edge_iterator edge_iterator; typedef undirected_tag directed_category; typedef allow_parallel_edge_tag edge_parallel_category; typedef typename graph_traits::traversal_category traversal_category; typedef typename graph_traits::vertices_size_type vertices_size_type; typedef typename graph_traits::edges_size_type edges_size_type; typedef typename graph_traits::degree_size_type degree_size_type; static vertex_descriptor null_vertex() { return graph_traits::null_vertex(); } private: typedef is_convertible::out_edge_iterator>::iterator_category, std::random_access_iterator_tag> is_orig_ra; typedef is_convertible::iterator_category, std::random_access_iterator_tag> is_ra; BOOST_STATIC_ASSERT((!is_orig_ra::value || is_ra::value)); }; template struct graph_traits< const undirected_adaptor >: public graph_traits > {}; //============================================================================== // Nonmember functions // these provide manipulation of the graph //============================================================================== //============================================================================== // source(e,g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] [[gnu::pure]] inline auto source(const typename graph_traits >::edge_descriptor& e, const undirected_adaptor& g) { return source(e, g.original_graph()); } //============================================================================== // target(e,g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] [[gnu::pure]] inline auto target(const typename graph_traits >::edge_descriptor& e, const undirected_adaptor& g) { return target(e, g.original_graph()); } //============================================================================== // vertex(n,g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] [[gnu::pure]] inline auto vertex(typename graph_traits >::vertices_size_type n, const undirected_adaptor& g) { return vertex(n, g.original_graph()); } //============================================================================== // vertices(g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto vertices(const undirected_adaptor& g) { return vertices(g.original_graph()); } //============================================================================== // edges(g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto edges(const undirected_adaptor& g) { return edges(g.original_graph()); } //============================================================================== // edge(u, v, g) //============================================================================== template [[gnu::flatten]] inline auto edge(typename graph_traits >::vertex_descriptor u, typename graph_traits >::vertex_descriptor v, const undirected_adaptor& g) { auto res = edge(u, v, g.original_graph()); if (!res.second) { res = edge(v, u, g.original_graph()); std::swap(res.first.s, res.first.t); } return res; } //============================================================================== // out_edges(u,g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto out_edges(typename graph_traits>::vertex_descriptor u, const undirected_adaptor& g) { return _all_edges_out(u, g.original_graph()); } template [[gnu::always_inline]] [[gnu::flatten]] inline auto _all_edges_out(typename graph_traits>::vertex_descriptor u, const undirected_adaptor& g) { return out_edges(u, g); } //============================================================================== // in_edges(u,g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto in_edges(typename graph_traits>::vertex_descriptor, const undirected_adaptor&) { typedef typename graph_traits>::in_edge_iterator iter_t; return std::make_pair(iter_t(), iter_t()); } template [[gnu::always_inline]] [[gnu::flatten]] inline auto _all_edges_in(typename graph_traits>::vertex_descriptor u, const undirected_adaptor& g) { return _all_edges_in(u, g.original_graph()); } template [[gnu::always_inline]] [[gnu::flatten]] inline auto all_edges(typename graph_traits>::vertex_descriptor u, const undirected_adaptor& g) { return out_edges(u, g); } //============================================================================== // out_neighbors(u, g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto out_neighbors(typename graph_traits >::vertex_descriptor u, const undirected_adaptor& g) { return all_neighbors(u, g.original_graph()); } //============================================================================== // in_neighbors(u, g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto in_neighbors(typename graph_traits >::vertex_descriptor u, const undirected_adaptor& g) { return out_neighbors(u, g); } //============================================================================== // all_neighbors(u, g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto all_neighbors(typename graph_traits >::vertex_descriptor u, const undirected_adaptor& g) { return out_neighbors(u, g); } //============================================================================== // adjacent_vertices(u,g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto adjacent_vertices (typename graph_traits >::vertex_descriptor u, const undirected_adaptor& g) { return out_neighbors(u, g); } //============================================================================== // num_vertices(g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto num_vertices(const undirected_adaptor& g) { return num_vertices(g.original_graph()); } //============================================================================== // num_edges(g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto num_edges(const undirected_adaptor& g) { return num_edges(g.original_graph()); } //============================================================================== // out_degree(u,g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto out_degree(typename graph_traits >::vertex_descriptor u, const undirected_adaptor& g) { return degree(u, g.original_graph()); } //============================================================================== // in_degree(u,g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto in_degree(typename graph_traits >::vertex_descriptor, const undirected_adaptor&) { return 0; } //============================================================================== // degree(u,g) //============================================================================== template [[gnu::always_inline]] [[gnu::flatten]] inline auto degree(typename graph_traits >::vertex_descriptor u, const undirected_adaptor& g) { return out_degree(u, g); } //============================================================================== // add_vertex(g) //============================================================================== template [[gnu::flatten]] inline auto add_vertex(undirected_adaptor& g) { return add_vertex(g.original_graph()); } //============================================================================== // add_vertex(vp,g) //============================================================================== template [[gnu::flatten]] inline auto add_vertex(const VertexProperties& p, undirected_adaptor& g) { return add_vertex(p, g.original_graph()); } //============================================================================== // clear_vertex(u,g) //============================================================================== template [[gnu::flatten]] inline void clear_vertex(typename graph_traits >::vertex_descriptor u, undirected_adaptor& g) { clear_vertex(u, g.original_graph()); } //============================================================================== // clear_vertex(u,g,pred) //============================================================================== template [[gnu::flatten]] inline void clear_vertex(typename graph_traits >::vertex_descriptor u, undirected_adaptor& g, Pred&& pred) { clear_vertex(u, g.original_graph(), pred); } //============================================================================== // remove_vertex(u,g) //============================================================================== template [[gnu::flatten]] inline void remove_vertex(typename graph_traits >::vertex_descriptor u, undirected_adaptor& g) { remove_vertex(u, g.original_graph()); } //============================================================================== // remove_vertex_fast(u,g) //============================================================================== template [[gnu::flatten]] inline void remove_vertex_fast(typename graph_traits >::vertex_descriptor u, undirected_adaptor& g) { remove_vertex_fast(u, g.original_graph()); } //============================================================================== // add_edge(u,v,g) //============================================================================== template [[gnu::flatten]] inline std::pair >::edge_descriptor, bool> add_edge(typename graph_traits >::vertex_descriptor u, typename graph_traits >::vertex_descriptor v, undirected_adaptor& g) { return add_edge(u, v, g.original_graph()); } //============================================================================== // add_edge(u,v,ep,g) //============================================================================== template [[gnu::flatten]] inline auto add_edge(typename graph_traits >::vertex_descriptor u, typename graph_traits >::vertex_descriptor v, const EdgeProperties& ep, undirected_adaptor& g) { return add_edge(u, v, ep, g.original_graph()); } //============================================================================== // remove_edge(u,v,g) //============================================================================== template [[gnu::flatten]] inline void remove_edge(typename graph_traits >::vertex_descriptor u, typename graph_traits >::vertex_descriptor v, undirected_adaptor& g) { auto e = edge(u, v, g); if (e.second) remove_edge(e.first, g); } //============================================================================== // remove_edge(e,g) //============================================================================== template [[gnu::flatten]] inline void remove_edge(typename graph_traits >::edge_descriptor e, undirected_adaptor& g) { auto& u = g.original_graph(); u.reverse_edge(e); remove_edge(e, u); } //============================================================================== // remove_edge(e_iter,g) //============================================================================== template [[gnu::flatten]] inline void remove_edge(const typename graph_traits >::out_edge_iterator& iter, undirected_adaptor& g) { remove_edge(*iter, g); } //============================================================================== // remove_out_edge_if(v,predicate,g) //============================================================================== template inline void remove_out_edge_if(typename graph_traits >::vertex_descriptor v, Predicate predicate, undirected_adaptor& g) { std::vector::EdgeDescriptor> removed_edges; auto edge_range = out_edges(v,g); for(auto iter = edge_range.first; iter != edge_range.second; ++iter) if (predicate(*iter)) removed_edges.push_back(*iter); for(auto& e : removed_edges) remove_edge(e, g); } //============================================================================== // remove_in_edge_if(v,predicate,g) //============================================================================== template void remove_in_edge_if(typename graph_traits >::vertex_descriptor v, Predicate predicate, undirected_adaptor& g) { std::vector::EdgeDescriptor> removed_edges; auto edge_range = in_edges(v,g); for(auto iter = edge_range.first; iter != edge_range.second; ++iter) if (predicate(*iter)) removed_edges.push_back(*iter); for(auto& e : removed_edges) remove_edge(e, g); } //============================================================================== // Property maps //============================================================================== //============================================================================== // vertex_property //============================================================================== template class vertex_property > { public: typedef typename vertex_property::type type; }; //============================================================================== // vertex_property_type //============================================================================== template class vertex_property_type > { public: typedef typename vertex_property_type::type type; }; //============================================================================== // edge_property //============================================================================== template class edge_property > { public: typedef typename edge_property::type type; }; //============================================================================== // edge_property_type //============================================================================== template class edge_property_type > { public: typedef typename edge_property_type::type type; }; //============================================================================== // property_map //============================================================================== template class property_map, PropertyTag> { public: typedef typename property_map::type type; typedef typename property_map::const_type const_type; }; //============================================================================== // property_map //============================================================================== template class property_map, T Bundle::*> { public: typedef typename property_map::type type; typedef typename property_map::const_type const_type; }; //============================================================================== // get(tag,g) //============================================================================== template inline typename property_map, PropertyTag>::type get(PropertyTag tag, undirected_adaptor& g) { return get(tag, g.original_graph()); } //============================================================================== // const get(tag,g) //============================================================================== template inline typename property_map, PropertyTag>::const_type get(PropertyTag tag, const undirected_adaptor& g) { return get(tag, g.original_graph()); } //============================================================================== // get(tag,g,v) //============================================================================== template inline typename property_traits , PropertyTag>::const_type >::value_type get(PropertyTag tag, const undirected_adaptor& g, typename graph_traits >::vertex_descriptor v) { return get(tag, g.original_graph(), v); } //============================================================================== // get(tag,g,e) //============================================================================== template inline typename property_traits , PropertyTag>::const_type >::value_type get(PropertyTag tag, const undirected_adaptor& g, const typename graph_traits >::edge_descriptor& e) { return get(tag, g.original_graph(), e); } //============================================================================== // put(tag, g, v, value) //============================================================================== template inline void put(PropertyTag tag, undirected_adaptor& g, typename graph_traits >::vertex_descriptor v, const Value& value) { put(tag, g.original_graph(), v, value); } //============================================================================== // put(tag, g, e, value) //============================================================================== template inline void put(PropertyTag tag, const undirected_adaptor& g, const typename graph_traits >::edge_descriptor& e, const Value &value) { put(tag, g.original_graph(), e, value); } //============================================================================== // get_property(g,tag) //============================================================================== template inline typename property_value::type& get_property(undirected_adaptor& g, GraphPropertyTag tag) { get_property(g.original_graph(), tag); } //============================================================================== // const get_property(g,tag) //============================================================================== template inline const typename property_value::type& get_property(const undirected_adaptor& g, GraphPropertyTag tag) { get_property(g.original_graph(), tag); } } // namespace boost #endif // GRAPH_ADAPTOR_HH