Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 <<mas-visitor-concept,MAS Visitor concept>>.

== Overloads

Expand Down Expand Up @@ -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 <<mas-visitor-concept,MAS Visitor concept>>. The visitor object is passed by
value.

| IN
| `vertex_descriptor start`
Expand Down Expand Up @@ -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 <<mas-visitor-concept,MAS Visitor concept>>. The visitor object is passed by
value. +
*Default:* `mas_visitor<null_visitor>`

| IN
Expand Down Expand Up @@ -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 <<mas-visitor-concept,MAS Visitor concept>>.

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"]
|===
Expand Down Expand Up @@ -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<G>::edge_descriptor`.
| `s,u` | An object of type `boost::graph_traits<G>::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 <class Edge, class Graph>
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 <class Vertex, class Graph>
void initialize_vertex(Vertex u, const Graph& g) {}

template <class Vertex, class Graph>
void start_vertex(Vertex u, const Graph& g) {}

template <class Edge, class Graph>
void examine_edge(Edge e, const Graph& g) {}

template <class Vertex, class Graph>
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]"
Expand Down
60 changes: 46 additions & 14 deletions include/boost/graph/maximum_adjacency_search.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@
namespace boost
{

template < class Visitor, class Graph >
namespace graph
{

template < class Visitor, class Graph >
struct MASVisitorConcept
{
void constraints()
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -289,7 +290,7 @@ void maximum_adjacency_search(

namespace graph
{
namespace detail
namespace mas_detail
{
template < typename WeightMap > struct mas_dispatch
{
Expand Down Expand Up @@ -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<
Expand Down Expand Up @@ -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<
Expand All @@ -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
Expand All @@ -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));
}

Expand All @@ -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));
}
};
Expand All @@ -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
4 changes: 2 additions & 2 deletions include/boost/graph/stoer_wagner_min_cut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
Expand Down
12 changes: 6 additions & 6 deletions test/mas_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);
}
Expand Down
Loading
Loading