diff --git a/doc/modules/ROOT/pages/algorithms/utility/maximum_adjacency_search.adoc b/doc/modules/ROOT/pages/algorithms/utility/maximum_adjacency_search.adoc index 79847b8ae..5fc801e32 100644 --- a/doc/modules/ROOT/pages/algorithms/utility/maximum_adjacency_search.adoc +++ b/doc/modules/ROOT/pages/algorithms/utility/maximum_adjacency_search.adoc @@ -23,7 +23,7 @@ adapting the generic MAS algorithm to the many situations in which it can be used. In the pseudo-code below, the event points for MAS are the labels on the right. The user-defined actions must be provided in the form of a visitor object, that is, an object whose type meets the -requirements for a MAS Visitor. +requirements for the <>. == Overloads @@ -65,8 +65,8 @@ void maximum_adjacency_search( | IN | `MASVisitor vis` | A visitor object that is invoked inside the algorithm at the event-points - specified by the MAS Visitor concept. The visitor object is passed by - value <<1,[1]>>. + specified by the <>. The visitor object is passed by + value. | IN | `vertex_descriptor start` @@ -219,8 +219,8 @@ void maximum_adjacency_search( | IN | `visitor(MASVisitor vis)` | A visitor object that is invoked inside the algorithm at the event-points - specified by the MAS Visitor concept. The visitor object is passed by - value <<1,[1]>>. + + specified by the <>. The visitor object is passed by + value. + *Default:* `mas_visitor` | IN @@ -286,7 +286,30 @@ void maximum_adjacency_search( |=== -== Pseudo-Code +== Visitor + +The `maximum_adjacency_search()` function invokes user-defined actions at four +event points during the traversal. You supply these actions through a visitor +object whose type models the <>. + +Since the visitor parameter is passed by value, if the +visitor contains state then any changes to the state during the algorithm +will be made to a copy of the visitor object, not the visitor object +passed in. Therefore you may want the visitor to hold this state by +pointer or reference. + +[WARNING] +==== +These symbols moved to `namespace boost::graph`. The `boost::` aliases are kept +for backward compatibility but are deprecated. Removal planned for Boost 1.95. + +* `boost::mas_visitor` -> `boost::graph::mas_visitor` +* `boost::make_mas_visitor` -> `boost::graph::make_mas_visitor` +* `boost::default_mas_visitor` -> `boost::graph::default_mas_visitor` +* `boost::MASVisitorConcept` -> `boost::graph::MASVisitorConcept` +==== + +=== Pseudo-Code [cols="1a,1a"] |=== @@ -330,31 +353,102 @@ finish vertex u ---- |=== -== Visitor Event Points -* *`vis.initialize_vertex(s, g)`* is invoked on every vertex of the - graph before the start of the graph search. -* *`vis.start_vertex(s, g)`* is invoked on the source vertex once - before processing its out edges. -* *`vis.examine_edge(e, g)`* is invoked on every out-edge of each - vertex after it is started. -* *`vis.finish_vertex(u, g)`* is invoked on a vertex after all of its - out edges have been examined and the reach counts of the unvisited - targets have been updated. +[#mas-visitor-concept] +=== Visitor Concept + +The `MASVisitor` template parameter must be a model of the MAS Visitor +concept, which defines the event points at which the algorithm invokes +user-defined actions. + +==== Refinement of + +Copy Constructible (copying a visitor should be a lightweight operation). + +==== Notation + +[cols=",",] +|=== +| `V` | A type that is a model of MAS Visitor. +| `vis` | An object of type `V`. +| `G` | A type that is a model of Graph. +| `g` | An object of type `G`. +| `e` | An object of type `boost::graph_traits::edge_descriptor`. +| `s,u` | An object of type `boost::graph_traits::vertex_descriptor`. +|=== + +==== Valid Expressions + +[cols=",,,",options="header",] +|=== +| Name | Expression | Return Type | Description + +| Initialize Vertex +| `vis.initialize_vertex(s, g)` +| `void` +| Invoked on every vertex of the graph before the start of the search. + +| Start Vertex +| `vis.start_vertex(s, g)` +| `void` +| Invoked on the source vertex once before processing its out-edges. + +| Examine Edge +| `vis.examine_edge(e, g)` +| `void` +| Invoked on every out-edge of each vertex after it is started. + +| Finish Vertex +| `vis.finish_vertex(u, g)` +| `void` +| Invoked on a vertex after all of its out-edges have been examined and the + reach counts of the unvisited targets have been updated. +|=== + +=== Minimal Implementation + +Two ways to write a visitor. + +Inherit from `default_mas_visitor` and shadow only the relevant handlers. The +base supplies a no-op for every other event. + +[source,cpp] +---- +struct my_mas_visitor : boost::graph::default_mas_visitor +{ + template + void examine_edge(Edge e, const Graph& g) + { + // logic here + } +}; +---- + +Or copy the full struct and fill in each handler. All four must be declared. + +[source,cpp] +---- +struct my_mas_visitor +{ + template + void initialize_vertex(Vertex u, const Graph& g) {} + + template + void start_vertex(Vertex u, const Graph& g) {} + + template + void examine_edge(Edge e, const Graph& g) {} + + template + void finish_vertex(Vertex u, const Graph& g) {} +}; +---- == Throws `bad_graph`:: If `num_vertices(g)` is less than 2. `std::invalid_argument`:: If a max-priority queue is given as an argument and it is not empty. -== Notes - -[#1]#[1]# Since the visitor parameter is passed by value, if your -visitor contains state then any changes to the state during the algorithm -will be made to a copy of the visitor object, not the visitor object -passed in. Therefore you may want the visitor to hold this state by -pointer or reference. - == References * David Matula (1993). "http://dl.acm.org/citation.cfm?id=313872&dl=ACM&coll=DL&CFID=85991501&CFTOKEN=44461131[A linear time 2 + epsilon approximation algorithm for edge connectivity]" diff --git a/include/boost/graph/maximum_adjacency_search.hpp b/include/boost/graph/maximum_adjacency_search.hpp index 1a8c2781b..a37264e87 100644 --- a/include/boost/graph/maximum_adjacency_search.hpp +++ b/include/boost/graph/maximum_adjacency_search.hpp @@ -56,7 +56,10 @@ namespace boost { -template < class Visitor, class Graph > +namespace graph +{ + +template < class Visitor, class Graph > struct MASVisitorConcept { void constraints() @@ -114,14 +117,12 @@ mas_visitor< Visitors > make_mas_visitor(Visitors vis) return mas_visitor< Visitors >(vis); } -typedef mas_visitor<> default_mas_visitor; +using default_mas_visitor = mas_visitor<>; -namespace graph -{ -namespace detail +namespace mas_detail { -// Maximum adjacency sweep over an already populated queue. +// Maximum adjacency sweep over an already populated queue. // Shared engine behind both maximum_adjacency_search and stoer_wagner_min_cut. // The graph may be contracted through assignments (each vertex maps to its representative) // with assigned_vertices listing the contracted vertices. @@ -185,7 +186,7 @@ void mas_sweep( vis.finish_vertex(u, g); } } -} // namespace detail +} // namespace mas_detail // Public maximum adjacency search. // Seeds the queue, gives the start vertex the @@ -234,7 +235,7 @@ void maximum_adjacency_search( // no contraction: identity assignment map and empty contracted set const boost::typed_identity_property_map< vertex_descriptor > identity_map; const std::set< vertex_descriptor > no_assigned_vertices; - detail::mas_sweep(g, weight_map, vis, identity_map, no_assigned_vertices, pq); + mas_detail::mas_sweep(g, weight_map, vis, identity_map, no_assigned_vertices, pq); } // Convenience overload that defaults only the priority queue. Building the @@ -289,7 +290,7 @@ void maximum_adjacency_search( namespace graph { - namespace detail + namespace mas_detail { template < typename WeightMap > struct mas_dispatch { @@ -320,7 +321,7 @@ namespace graph = pq_gen(g, params); boost::null_visitor null_vis; - boost::mas_visitor< boost::null_visitor > default_visitor( + boost::graph::mas_visitor< boost::null_visitor > default_visitor( null_vis); vertex_descriptor v = vertex_descriptor(); boost::detail::make_property_map_from_arg_pack_gen< @@ -371,7 +372,7 @@ namespace graph = pq_gen(g, params); boost::null_visitor null_vis; - boost::mas_visitor< boost::null_visitor > default_visitor( + boost::graph::mas_visitor< boost::null_visitor > default_visitor( null_vis); vertex_descriptor v = vertex_descriptor(); boost::detail::make_property_map_from_arg_pack_gen< @@ -388,7 +389,7 @@ namespace graph params[_vertex_assignment_map | default_map], pq); } }; - } // end namespace detail + } // end namespace mas_detail } // end namespace graph // Named parameter interface @@ -405,7 +406,7 @@ void maximum_adjacency_search( // do the dispatch based on WeightMap typedef typename get_param_type< edge_weight_t, bgl_named_params< P, T, R > >::type W; - graph::detail::mas_dispatch< W >::apply( + graph::mas_detail::mas_dispatch< W >::apply( g, arg_pack, get_param(params, edge_weight)); } @@ -423,7 +424,7 @@ namespace graph // call the function that does the dispatching typedef typename get_param_type< edge_weight_t, ArgPack >::type W; - graph::detail::mas_dispatch< W >::apply( + graph::mas_detail::mas_dispatch< W >::apply( g, arg_pack, get_param(arg_pack, edge_weight)); } }; @@ -432,6 +433,37 @@ namespace graph BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(maximum_adjacency_search, 1, 5) } // end namespace graph + +// -- deprecated aliases: the MAS visitor types moved into boost::graph. -- +// Kept in boost:: for backward compatibility. Removal planned for Boost 1.95. +// +// BOOST_DEPRECATED (__declspec on MSVC) does not parse inside an +// alias-declaration, so follow the Boost.URL pattern: delegate to +// BOOST_DEPRECATED on gcc/clang and drop the attribute on MSVC. This keeps the +// BOOST_ALLOW_DEPRECATED_SYMBOLS opt-out working on gcc/clang. +#if defined(BOOST_MSVC) +#define BOOST_GRAPH_MAS_DEPRECATED_ALIAS(msg) +#else +#define BOOST_GRAPH_MAS_DEPRECATED_ALIAS(msg) BOOST_DEPRECATED(msg) +#endif + +template < class Visitor, class Graph > +using MASVisitorConcept BOOST_GRAPH_MAS_DEPRECATED_ALIAS("use boost::graph::MASVisitorConcept") = graph::MASVisitorConcept< Visitor, Graph >; + +template < class Visitors = null_visitor > +using mas_visitor BOOST_GRAPH_MAS_DEPRECATED_ALIAS("use boost::graph::mas_visitor") = graph::mas_visitor< Visitors >; + +using default_mas_visitor BOOST_GRAPH_MAS_DEPRECATED_ALIAS("use boost::graph::default_mas_visitor") = graph::default_mas_visitor; + +#undef BOOST_GRAPH_MAS_DEPRECATED_ALIAS + +template < class Visitors > +BOOST_DEPRECATED("use boost::graph::make_mas_visitor") +graph::mas_visitor< Visitors > make_mas_visitor(Visitors vis) +{ + return graph::make_mas_visitor(vis); +} + } // end namespace boost #endif // BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H diff --git a/include/boost/graph/stoer_wagner_min_cut.hpp b/include/boost/graph/stoer_wagner_min_cut.hpp index 5c93df102..eb07e1cb0 100644 --- a/include/boost/graph/stoer_wagner_min_cut.hpp +++ b/include/boost/graph/stoer_wagner_min_cut.hpp @@ -34,7 +34,7 @@ namespace detail // start_vertex before popping each vertex, so its key at that moment is the // reach count. template < class UndirectedGraph, class KeyMap, class WeightType > - struct mas_phase_recorder : public default_mas_visitor + struct mas_phase_recorder : public boost::graph::default_mas_visitor { using vertex_descriptor = typename boost::graph_traits< UndirectedGraph >::vertex_descriptor; @@ -129,7 +129,7 @@ namespace detail using vis_t = mas_phase_recorder< UndirectedGraph, typename KeyedUpdatablePriorityQueue::key_map, weight_type >; vis_t recorder(s, t, w, keys); - boost::graph::detail::mas_sweep(g, weights, recorder, assignments, assignedVertices, pq); + boost::graph::mas_detail::mas_sweep(g, weights, recorder, assignments, assignedVertices, pq); return boost::make_tuple(s, t, w); } diff --git a/test/mas_test.cpp b/test/mas_test.cpp index 0a69e5c6d..3e3cba503 100644 --- a/test/mas_test.cpp +++ b/test/mas_test.cpp @@ -41,7 +41,7 @@ struct edge_t }; template < typename Graph, typename KeyedUpdatablePriorityQueue > -class mas_test_visitor : public boost::default_mas_visitor +class mas_test_visitor : public boost::graph::default_mas_visitor { public: using vertex_descriptor = typename boost::graph_traits< Graph >::vertex_descriptor; @@ -120,8 +120,8 @@ void test0() expected_weights_when_visited1.cend()); // convenience overload: start vertex and priority queue are defaulted - boost::graph::maximum_adjacency_search(g, weight_map, boost::make_mas_visitor(boost::null_visitor())); - boost::graph::maximum_adjacency_search(g, weight_map, boost::default_mas_visitor()); + boost::graph::maximum_adjacency_search(g, weight_map, boost::graph::make_mas_visitor(boost::null_visitor())); + boost::graph::maximum_adjacency_search(g, weight_map, boost::graph::default_mas_visitor()); test_vis.clear(); @@ -418,7 +418,7 @@ void check_visit_order_invariants(const undirected_graph& g, const std::vector< } // Records every visitor event. -class recording_visitor : public boost::default_mas_visitor +class recording_visitor : public boost::graph::default_mas_visitor { public: recording_visitor(std::size_t& initialize_count, std::size_t& examine_count, std::vector< vertex_descriptor >& start_order, std::vector< vertex_descriptor >& finish_order) @@ -507,7 +507,7 @@ void test_exceptions() undirected_graph too_small; add_vertex(too_small); auto weight_map = get(boost::edge_weight, too_small); - boost::default_mas_visitor visitor; + boost::graph::default_mas_visitor visitor; BOOST_TEST_THROWS(boost::graph::maximum_adjacency_search(too_small, weight_map, visitor), boost::bad_graph); } @@ -517,7 +517,7 @@ void test_exceptions() cv_maxheap_type pq = make_weighted_maxheap(g); pq.push(0); auto weight_map = get(boost::edge_weight, g); - boost::default_mas_visitor visitor; + boost::graph::default_mas_visitor visitor; const vertex_descriptor start = *vertices(g).first; BOOST_TEST_THROWS(boost::graph::maximum_adjacency_search(g, weight_map, visitor, start, pq), std::invalid_argument); } diff --git a/test/mas_test_old.cpp b/test/mas_test_old.cpp index 5dc6fcd26..d05e1ee3e 100644 --- a/test/mas_test_old.cpp +++ b/test/mas_test_old.cpp @@ -4,8 +4,10 @@ // (See accompanying file LICENSE_1_0.txt or the copy at // http://www.boost.org/LICENSE_1_0.txt) -// This test exercises the deprecated named parameter and assignment-map -// interfaces on purpose, so silence the deprecation warnings. +// This test exercises the deprecated interfaces on purpose (the named +// parameter and assignment-map overloads, and the boost:: visitor aliases +// mas_visitor / make_mas_visitor / default_mas_visitor that now live in +// boost::graph), so silence the deprecation warnings. #define BOOST_ALLOW_DEPRECATED_SYMBOLS #include