From ad26a784aee3c51731590967090a092fa2c58012 Mon Sep 17 00:00:00 2001 From: Jeremy Siek Date: Mon, 30 Oct 2000 14:27:12 +0000 Subject: [PATCH] some work on out-edge list ordering [SVN r8069] --- docs/adjacency_list.html | 25 ++-- examples/city_visitor.cpp | 63 +++++---- examples/gerdemann.cpp | 2 + include/boost/graph/depth_first_search.hpp | 1 + include/boost/graph/detail/adjacency_list.hpp | 121 +++++++++--------- include/boost/graph/graph_utility.hpp | 19 +++ 6 files changed, 140 insertions(+), 91 deletions(-) diff --git a/docs/adjacency_list.html b/docs/adjacency_list.html index 1de0f401..60c88414 100644 --- a/docs/adjacency_list.html +++ b/docs/adjacency_list.html @@ -702,14 +702,20 @@ for the new edge. For graphs that do not allow parallel edges, if the edge is already in the graph then a duplicate will not be added and the bool flag will be false. Also, if u and v are descriptors for the same vertex (creating a self loop) -then the edge will not be added and the flag will be false. -When the flag is false, the edge descriptor is invalid and -any use of it is undefined. The location of the placement of the edge -in the out-edge list for u is unspecified. If the -VertexList selector is vecS, and if either vertex -descriptor u or v (which are integers) has a value -greater than the current number of vertices in the graph, the graph is -enlarged so that the number of vertices is std::max(u,v) + 1. +and the graph is undirected, then the edge will not be added and the +flag will be false. When the flag is false, the +edge descriptor is invalid and any use of it is undefined. + +

+The placement of the new edge in the out-edge list is in general +unspecified, though ordering of the out-edge list can be accomplished +through the choice of EdgeList. + +If the VertexList selector is +vecS, and if either vertex descriptor u or +v (which are integers) has a value greater than the current +number of vertices in the graph, the graph is enlarged so that the +number of vertices is std::max(u,v) + 1.

If the EdgeList selector is vecS then this operation @@ -777,7 +783,8 @@ void remove_edge(out_edge_iterator iter, adjacency_list& g) This has the same effect as remove_edge(*iter, g). The difference is that this function has constant time complexity -in the case of directed graphs. +in the case of directed graphs, whereas remove_edge(e, g) +has time complexity O(E/V).


diff --git a/examples/city_visitor.cpp b/examples/city_visitor.cpp index e92bb708..9825dce1 100644 --- a/examples/city_visitor.cpp +++ b/examples/city_visitor.cpp @@ -32,6 +32,7 @@ #include #include #include +#include // for boost::make_list /* @@ -51,16 +52,16 @@ The visitor has three main functions: - discover(u) is invoked when the algorithm first arrives at the + discover_vertex(u,g) is invoked when the algorithm first arrives at the vertex u. This will happen in the depth first or breadth first order depending on which algorithm you use. - process(e) is invoked when the algorithm first checks an edge to see + examine_edge(e,g) is invoked when the algorithm first checks an edge to see whether it has already been there. Whether using BFS or DFS, all the edges of vertex u are examined immediately after the call to visit(u). - finish(u) is called when after all the vertices reachable from vertex + finish_vertex(u,g) is called when after all the vertices reachable from vertex u have already been visited. */ @@ -68,32 +69,37 @@ using namespace std; using namespace boost; -struct city_visitor - : public null_visitor -{ - city_visitor(string* n) : names(n) { } - - template - inline void discover(Vertex u) { +struct city_arrival { + city_arrival(string* n) : names(n) { } + typedef on_discover_vertex event_filter; + template + inline void operator()(Vertex u, Graph&) { cout << endl << "arriving at " << names[u] << endl << " neighboring cities are: "; } - - template - inline void process(Edge e, Graph& g) { - cout << names[ target(e,g) ] << ", "; - } - - template - inline void finish(Vertex u) { - cout << endl << "finished with " << names[u] << endl; - } - string* names; }; +struct neighbor_cities { + neighbor_cities(string* n) : names(n) { } + typedef on_examine_edge event_filter; + template + inline void operator()(Edge e, Graph& g) { + cout << names[ target(e, g) ] << ", "; + } + string* names; +}; +struct finish_city { + finish_city(string* n) : names(n) { } + typedef on_finish_vertex event_filter; + template + inline void operator()(Vertex u, Graph&) { + cout << endl << "finished with " << names[u] << endl; + } + string* names; +}; int main(int argc, char* argv[]) { @@ -123,7 +129,11 @@ int main(int argc, char* argv[]) colors_t colors(N); cout << "*** Depth First ***" << endl; - depth_first_search(G, city_visitor(names), colors.begin()); + depth_first_search + (G, make_dfs_visitor(boost::make_list(city_arrival(names), + neighbor_cities(names), + finish_city(names))), + &colors[0]); cout << endl; /* Get the source vertex */ @@ -131,8 +141,11 @@ int main(int argc, char* argv[]) s = vertex(SanJose,G); cout << "*** Breadth First ***" << endl; - breadth_first_search(G, s, city_visitor(names), colors.begin()); - - //end + breadth_first_search + (G, s, make_bfs_visitor(boost::make_list(city_arrival(names), + neighbor_cities(names), + finish_city(names))), + &colors[0]); + return 0; } diff --git a/examples/gerdemann.cpp b/examples/gerdemann.cpp index cb853bf1..91df6016 100644 --- a/examples/gerdemann.cpp +++ b/examples/gerdemann.cpp @@ -81,6 +81,8 @@ struct order_by_name : public std::binary_function { bool operator()(const StoredEdge& e1, const StoredEdge& e2) const { + // Using std::pair operator< as an easy way to get lexicographical + // compare over tuples. return std::make_pair(e1.get_target(), boost::get(boost::edge_name, e1)) < std::make_pair(e2.get_target(), boost::get(boost::edge_name, e2)); } diff --git a/include/boost/graph/depth_first_search.hpp b/include/boost/graph/depth_first_search.hpp index d9849662..d07902e3 100644 --- a/include/boost/graph/depth_first_search.hpp +++ b/include/boost/graph/depth_first_search.hpp @@ -43,6 +43,7 @@ namespace boost { vis.initialize_vertex(u, g); vis.start_vertex(u, g); vis.discover_vertex(u, g); + vis.examine_edge(e, g); vis.tree_edge(e, g); vis.back_edge(e, g); vis.forward_or_cross_edge(e, g); diff --git a/include/boost/graph/detail/adjacency_list.hpp b/include/boost/graph/detail/adjacency_list.hpp index 763c0785..95bdcfeb 100644 --- a/include/boost/graph/detail/adjacency_list.hpp +++ b/include/boost/graph/detail/adjacency_list.hpp @@ -57,16 +57,6 @@ namespace boost { namespace detail { - template - struct target_is { - target_is(const Vertex& v) : m_target(v) { } - template - bool operator()(const StoredEdge& e) const { - return e.get_target() == m_target; - } - Vertex m_target; - }; - template struct directed_category_traits { typedef directed_tag directed_category; @@ -85,6 +75,35 @@ namespace boost { typedef bidirectional_tag directed_category; }; + template + struct target_is { + target_is(const Vertex& v) : m_target(v) { } + template + bool operator()(const StoredEdge& e) const { + return e.get_target() == m_target; + } + Vertex m_target; + }; + + // O(E/V) + template + void erase_from_incidence_list(EdgeList& el, vertex_descriptor v, + allow_parallel_edge_tag) + { + boost::erase_if(el, detail::target_is(v)); + } + // O(log(E/V)) + template + void erase_from_incidence_list(EdgeList& el, vertex_descriptor v, + disallow_parallel_edge_tag) + { + typedef typename EdgeList::value_type StoredEdge; + el.erase(StoredEdge(v)); + } + + //========================================================================= + // Adjacency Iterator Implementation + #ifndef BOOST_NO_ITERATOR_ADAPTORS template struct adjacency_iterator_traits { @@ -163,18 +182,6 @@ namespace boost { }; #endif - template - struct has_property { - enum { value = true }; - typedef true_type type; - }; - template <> - struct has_property { - enum { value = false }; - typedef false_type type; - }; - - //========================================================================= // Out-Edge and In-Edge Iterator Implementation @@ -395,11 +402,9 @@ namespace boost { directed_graph_helper& g_) { typedef typename Config::graph_type graph_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::vertex_descriptor Vertex; + typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast(g_); - typename Config::OutEdgeList& el = g.out_edge_list(u); - boost::erase_if(el, detail::target_is(v)); + detail::erase_from_incidence_list(g.out_edge_list(u), v, Cat()); } namespace detail { @@ -513,12 +518,11 @@ namespace boost { directed_graph_helper& g_) { typedef typename Config::graph_type graph_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::vertex_descriptor Vertex; + typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast(g_); typename Config::vertex_iterator vi, viend; for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi) - boost::erase_if(g.out_edge_list(*vi), detail::target_is(u)); + detail::erase_from_incidence_list(g.out_edge_list(*vi), u, Cat()); g.out_edge_list(u).clear(); // clear() should be a req of Sequence and AssociativeContainer, // or maybe just Container @@ -694,12 +698,10 @@ namespace boost { undirected_graph_helper& g_) { typedef typename Config::graph_type graph_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::vertex_descriptor Vertex; graph_type& g = static_cast(g_); typedef typename Config::edge_parallel_category Cat; detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat()); - boost::erase_if(g.out_edge_list(v), detail::target_is(u)); + detail::erase_from_incidence_list(g.out_edge_list(v), u, Cat()); } template @@ -781,15 +783,14 @@ namespace boost { undirected_graph_helper& g_) { typedef typename Config::graph_type graph_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::vertex_descriptor Vertex; + typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast(g_); typename Config::OutEdgeList& el = g.out_edge_list(u); typename Config::OutEdgeList::iterator ei = el.begin(), ei_end = el.end(); for (; ei != ei_end; ++ei) { - boost::erase_if(g.out_edge_list((*ei).get_target()), - detail::target_is(u)); + detail::erase_from_incidence_list + (g.out_edge_list((*ei).get_target()), u, Cat()); g.m_edges.erase((*ei).get_iter()); } g.out_edge_list(u).clear(); @@ -852,14 +853,14 @@ namespace boost { template inline void remove_edge_and_property(Graph& g, EdgeList& el, Vertex v, - boost::allow_parallel_edge_tag) + boost::allow_parallel_edge_tag cat) { typedef typename EdgeList::value_type StoredEdge; typename EdgeList::iterator i = el.begin(), end = el.end(); for (; i != end; ++i) if ((*i).get_target() == v) g.m_edges.erase((*i).get_iter()); - boost::erase_if(el, target_is(v)); + detail::erase_from_incidence_list(el, v, cat); } // O(log(E/V)) template @@ -1017,12 +1018,10 @@ namespace boost { bidirectional_graph_helper_with_property& g_) { typedef typename Config::graph_type graph_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::vertex_descriptor Vertex; graph_type& g = static_cast(g_); typedef typename Config::edge_parallel_category Cat; detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat()); - boost::erase_if(g.in_edge_list(v), detail::target_is(u)); + detail::erase_from_incidence_list(g.in_edge_list(v), u, Cat()); } // O(E/V) template @@ -1049,23 +1048,22 @@ namespace boost { bidirectional_graph_helper_with_property& g_) { typedef typename Config::graph_type graph_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::vertex_descriptor Vertex; + typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast(g_); typename Config::OutEdgeList& el = g.out_edge_list(u); typename Config::OutEdgeList::iterator ei = el.begin(), ei_end = el.end(); for (; ei != ei_end; ++ei) { - boost::erase_if(g.in_edge_list((*ei).get_target()), - detail::target_is(u)); + detail::erase_from_incidence_list + (g.in_edge_list((*ei).get_target()), u, Cat()); g.m_edges.erase((*ei).get_iter()); } typename Config::InEdgeList& in_el = g.in_edge_list(u); typename Config::InEdgeList::iterator in_ei = in_el.begin(), in_ei_end = in_el.end(); for (; in_ei != in_ei_end; ++in_ei) { - boost::erase_if(g.out_edge_list((*in_ei).get_target()), - detail::target_is(u)); + detail::erase_from_incidence_list + (g.out_edge_list((*in_ei).get_target()), u, Cat()); g.m_edges.erase((*in_ei).get_iter()); } g.out_edge_list(u).clear(); @@ -1202,11 +1200,10 @@ namespace boost { bidirectional_graph_helper_without_property& g_) { typedef typename Config::graph_type graph_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::vertex_descriptor Vertex; + typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast(g_); - boost::erase_if(g.out_edge_list(u), detail::target_is(v)); - boost::erase_if(g.in_edge_list(v), detail::target_is(u)); + detail::erase_from_incidence_list(g.out_edge_list(u), v, Cat()); + detail::erase_from_incidence_list(g.in_edge_list(v), u, Cat()); } // O(E/V) template @@ -1236,20 +1233,19 @@ namespace boost { bidirectional_graph_helper_without_property& g_) { typedef typename Config::graph_type graph_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::vertex_descriptor Vertex; + typedef typename Config::edge_parallel_category Cat; graph_type& g = static_cast(g_); typename Config::out_edge_iterator out_ei, out_ei_end; for (boost::tie(out_ei, out_ei_end) = out_edges(u, g); out_ei != out_ei_end; ++out_ei) - boost::erase_if(g.in_edge_list(target(*out_ei,g)), - detail::target_is(u)); + detail::erase_from_incidence_list + (g.in_edge_list(target(*out_ei,g)), u, Cat()); typename Config::in_edge_iterator in_ei, in_ei_end; for (boost::tie(in_ei, in_ei_end) = in_edges(u, g); in_ei != in_ei_end; ++in_ei) - boost::erase_if(g.out_edge_list(source(*in_ei,g)), - detail::target_is(u)); + detail::erase_from_incidence_list + (g.out_edge_list(source(*in_ei,g)), u, Cat()); g.out_edge_list(u).clear(); g.in_edge_list(u).clear(); @@ -1932,6 +1928,17 @@ namespace boost { namespace detail { + template + struct has_property { + enum { value = true }; + typedef true_type type; + }; + template <> + struct has_property { + enum { value = false }; + typedef false_type type; + }; + //========================================================================= // Adjacency List Generator diff --git a/include/boost/graph/graph_utility.hpp b/include/boost/graph/graph_utility.hpp index a819957f..c10d6ccf 100644 --- a/include/boost/graph/graph_utility.hpp +++ b/include/boost/graph/graph_utility.hpp @@ -276,6 +276,25 @@ namespace boost { return false; } + template + std::pair + make_list(const T1& t1, const T2& t2) + { return std::make_pair(t1, t2); } + + template + std::pair > + make_list(const T1& t1, const T2& t2, const T3& t3) + { return std::make_pair(t1, std::make_pair(t2, t3)); } + + template + std::pair > > + make_list(const T1& t1, const T2& t2, const T3& t3, const T4& t4) + { return std::make_pair(t1, std::make_pair(t2, std::make_pair(t3, t4))); } + + template + std::pair > > > + make_list(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) + { return std::make_pair(t1, std::make_pair(t2, std::make_pair(t3, std::make_pair(t4, t5)))); } } /* namespace boost */