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
@@ -1,26 +1,53 @@
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/maximum_adjacency_search.hpp>
#include <boost/graph/detail/d_ary_heap.hpp>
#include <boost/property_map/shared_array_property_map.hpp>
#include <functional>
#include <iostream>
#include <vector>

struct Edge { int weight; };

int main() {
using namespace boost;
using Graph = adjacency_list<vecS, vecS, undirectedS, no_property, Edge>;
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, boost::no_property, Edge>;
using vertex_descriptor = boost::graph_traits<Graph>::vertex_descriptor;
using weight_type = int;

// records the vertices in the order the search visits them
struct order_recorder : boost::default_mas_visitor {
std::vector<vertex_descriptor>& order;
explicit order_recorder(std::vector<vertex_descriptor>& o) : order(o) {}
void finish_vertex(vertex_descriptor u, const Graph&) { order.push_back(u); }
};

int main() {
Graph g(5);
add_edge(0, 1, Edge{2}, g);
add_edge(0, 4, Edge{3}, g);
add_edge(1, 2, Edge{3}, g);
add_edge(1, 4, Edge{2}, g);
add_edge(2, 3, Edge{4}, g);
add_edge(3, 4, Edge{1}, g);

// Bundled weight via member pointer — passed through the named parameter.
maximum_adjacency_search(g,
boost::weight_map(get(&Edge::weight, g)));

std::cout << "Maximum adjacency search completed\n";
std::cout << "Last vertex visited has highest connectivity\n";
boost::add_edge(0, 1, Edge{2}, g);
boost::add_edge(0, 4, Edge{3}, g);
boost::add_edge(1, 2, Edge{3}, g);
boost::add_edge(1, 4, Edge{2}, g);
boost::add_edge(2, 3, Edge{4}, g);
boost::add_edge(3, 4, Edge{1}, g);

auto weight_map = boost::get(&Edge::weight, g);

// keyed max priority queue the search runs on: reach counts plus heap positions
using index_map_type = boost::property_map<Graph, boost::vertex_index_t>::const_type;
using distances_map_type = boost::shared_array_property_map<weight_type, index_map_type>;
using index_in_heap_type = std::vector<vertex_descriptor>::size_type;
using indices_map_type = boost::shared_array_property_map<index_in_heap_type, index_map_type>;
using max_priority_queue_type = boost::d_ary_heap_indirect<vertex_descriptor, 4, indices_map_type, distances_map_type, std::greater<weight_type>>;

auto distances_map = boost::make_shared_array_property_map(boost::num_vertices(g), weight_type(0), boost::get(boost::vertex_index, g));
auto indices_map = boost::make_shared_array_property_map(boost::num_vertices(g), index_in_heap_type(-1), boost::get(boost::vertex_index, g));
max_priority_queue_type pq(distances_map, indices_map);

std::vector<vertex_descriptor> order;
order_recorder visitor(order);
vertex_descriptor start = *boost::vertices(g).first;

boost::graph::maximum_adjacency_search(g, weight_map, visitor, start, pq);

std::cout << "Visit order:";
for (vertex_descriptor v : order) std::cout << ' ' << v;
std::cout << "\nLast visited vertex (highest connectivity): " << order.back() << '\n';
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Maximum adjacency search completed
Last vertex visited has highest connectivity
Visit order: 0 4 1 2 3
Last visited vertex (highest connectivity): 3
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/maximum_adjacency_search.hpp>
#include <iostream>
#include <vector>

struct Edge { int weight; };

using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, boost::no_property, Edge>;
using vertex_descriptor = boost::graph_traits<Graph>::vertex_descriptor;

// records the vertices in the order the search visits them
struct order_recorder : boost::default_mas_visitor {
std::vector<vertex_descriptor>& order;
explicit order_recorder(std::vector<vertex_descriptor>& o) : order(o) {}
void finish_vertex(vertex_descriptor u, const Graph&) { order.push_back(u); }
};

int main() {
Graph g(5);
boost::add_edge(0, 1, Edge{2}, g);
boost::add_edge(0, 4, Edge{3}, g);
boost::add_edge(1, 2, Edge{3}, g);
boost::add_edge(1, 4, Edge{2}, g);
boost::add_edge(2, 3, Edge{4}, g);
boost::add_edge(3, 4, Edge{1}, g);

auto weight_map = boost::get(&Edge::weight, g);

std::vector<vertex_descriptor> order;
order_recorder visitor(order);

boost::graph::maximum_adjacency_search(g, weight_map, visitor, *vertices(g).first);

std::cout << "Visit order:";
for (vertex_descriptor v : order) std::cout << ' ' << v;
std::cout << "\nLast visited vertex (highest connectivity): " << order.back() << '\n';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Visit order: 0 4 1 2 3
Last visited vertex (highest connectivity): 3
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,40 @@ Traverses vertices of an undirected graph, always visiting next the vertex with
*Complexity:* _O(E + V)_ +
*Defined in:* `<boost/graph/maximum_adjacency_search.hpp>`

== Example
== Description

[source,cpp]
----
include::example$algorithms/utility/maximum_adjacency_search.cpp[]
----
The `maximum_adjacency_search()` function performs a traversal of the
vertices in an undirected graph. The next vertex visited is the vertex
that has the most visited neighbors at any time. In the case of an
unweighted, undirected graph, the number of visited neighbors of the very
last vertex visited in the graph is also the number of edge-disjoint
paths between that vertex and the next-to-last vertex visited. These can
be retrieved from a visitor, an example of which is in the test harness
mas_test.cpp.

[,text]
----
include::example$algorithms/utility/maximum_adjacency_search.txt[]
----
The `maximum_adjacency_search()` function invokes user-defined actions at
certain event-points within the algorithm. This provides a mechanism for
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.

'''
== Overloads

=== (1) Positional version
=== (1) Fully Positional

[source,cpp]
----
template <class Graph, class WeightMap, class MASVisitor>
namespace boost::graph {
template <class Graph, class WeightMap, class MASVisitor, class KeyedUpdatablePriorityQueue>
void maximum_adjacency_search(
const Graph& g, WeightMap weights, MASVisitor vis,
const typename graph_traits<Graph>::vertex_descriptor start);
const Graph& g,
WeightMap weights,
MASVisitor vis,
typename graph_traits<Graph>::vertex_descriptor start,
KeyedUpdatablePriorityQueue pq);
}
----

[cols="1,2,5"]
Expand All @@ -36,7 +48,7 @@ void maximum_adjacency_search(

| IN
| `const Graph& g`
| A connected, directed graph. The graph type must be a model of
| A connected, undirected graph. The graph type must be a model of
xref:concepts/IncidenceGraph.adoc[Incidence Graph] and
xref:concepts/VertexListGraph.adoc[Vertex List Graph].

Expand All @@ -61,11 +73,110 @@ void maximum_adjacency_search(
| This specifies the vertex that the search should originate from. The type
is the type of a vertex descriptor for the given graph.

| IN
| `KeyedUpdatablePriorityQueue pq`
| A max priority queue keyed on the reach counts. It must be a model of
xref:concepts/property_types/KeyedUpdatableQueue.adoc[Keyed Updatable Queue] and a
max link:./UpdatableQueue.html#concept%3AUpdatablePriorityQueue[Updatable
Priority Queue]. The value type must be the graph's vertex descriptor and
the key type must be the weight type. It must be empty when passed in.

|===

==== Example

[source,cpp]
----
include::example$algorithms/utility/maximum_adjacency_search.cpp[]
----

[,text]
----
include::example$algorithms/utility/maximum_adjacency_search.txt[]
----

'''

=== (2) Four arguments overload

Building the priority queue is the cumbersome part, so this form defaults it to a
max `d_ary_heap_indirect` keyed on the reach counts.

[source,cpp]
----
namespace boost::graph {
template <class Graph, class WeightMap, class MASVisitor>
void maximum_adjacency_search(
const Graph& g,
WeightMap weights,
MASVisitor vis,
typename graph_traits<Graph>::vertex_descriptor start);
}
----

==== Example

[source,cpp]
----
include::example$algorithms/utility/maximum_adjacency_search_default_queue.cpp[]
----

[,text]
----
include::example$algorithms/utility/maximum_adjacency_search_default_queue.txt[]
----

'''

=== (2) Named parameter version
=== (3) Three arguments overload

The start vertex rarely matters, this form defaults it to `*vertices(g).first`.

[source,cpp]
----
namespace boost::graph {
template <class Graph, class WeightMap, class MASVisitor>
void maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis);
}
----

'''

=== (4) Six arguments overload (deprecated)

[WARNING]
====
Deprecated: the `assignments` map is unused. Use the fully positional or
convenience `boost::graph::maximum_adjacency_search` overloads instead. Removal
planned for Boost 1.95.
====

[source,cpp]
----
namespace boost {
template <class Graph, class WeightMap, class MASVisitor,
class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
void maximum_adjacency_search(
const Graph& g, WeightMap weights, MASVisitor vis,
typename graph_traits<Graph>::vertex_descriptor start,
VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq);
}
----

Identical to the fully positional overload except for the extra
`VertexAssignmentMap assignments` parameter, which is accepted for backward
compatibility but never read.

'''

=== (5) Named parameter version (deprecated)

[WARNING]
====
Deprecated: the named parameter interface is deprecated. Use the fully
positional or convenience `boost::graph::maximum_adjacency_search` overloads
instead. Removal planned for Boost 1.95.
====

[source,cpp]
----
Expand All @@ -81,7 +192,7 @@ void maximum_adjacency_search(

| IN
| `const Graph& g`
| A connected, directed graph. The graph type must be a model of
| A connected, undirected graph. The graph type must be a model of
xref:concepts/IncidenceGraph.adoc[Incidence Graph] and
xref:concepts/VertexListGraph.adoc[Vertex List Graph].

Expand Down Expand Up @@ -143,7 +254,7 @@ void maximum_adjacency_search(
| `max_priority_queue(MaxPriorityQueue& pq)`
| `MaxPriorityQueue` must be a model of
xref:concepts/property_types/KeyedUpdatableQueue.adoc[Keyed Updatable Queue] and a
max-link:./UpdatableQueue.html#concept%3AUpdatablePriorityQueue[Updatable
max link:./UpdatableQueue.html#concept%3AUpdatablePriorityQueue[Updatable
Priority Queue]. The value type must be the graph's vertex descriptor and
the key type must be the weight type. +
*Default:* A `boost::d_ary_heap_indirect` using a default index-in-heap
Expand Down Expand Up @@ -175,26 +286,7 @@ void maximum_adjacency_search(

|===

== Description

The `maximum_adjacency_search()` function performs a traversal of the
vertices in an undirected graph. The next vertex visited is the vertex
that has the most visited neighbors at any time. In the case of an
unweighted, undirected graph, the number of visited neighbors of the very
last vertex visited in the graph is also the number of edge-disjoint
paths between that vertex and the next-to-last vertex visited. These can
be retrieved from a visitor, an example of which is in the test harness
mas_test.cpp.

The `maximum_adjacency_search()` function invokes user-defined actions at
certain event-points within the algorithm. This provides a mechanism for
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.

=== Pseudo-Code
== Pseudo-Code

[cols="1a,1a"]
|===
Expand All @@ -208,10 +300,10 @@ MAS(G)
reach_count[s] := 1
for each unvisited vertex u in V
call MAS-VISIT(G, u)
remove u from the list on unvisited vertices
remove u from unvisited
for each out edge from u to t
if t has not yet been visited
increment reach_count[t]
reach_count[t] += weight(u, t)
end if
end for each out edge
call MAS-VISIT(G, u)
Expand All @@ -226,7 +318,7 @@ initialize vertex u
.
.
.
examine vertex u
start vertex u
.
examine edge (u,t)
.
Expand All @@ -238,15 +330,6 @@ finish vertex u
----
|===

== Returns

`void`

== 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.

== Visitor Event Points

* *`vis.initialize_vertex(s, g)`* is invoked on every vertex of the
Expand All @@ -259,6 +342,11 @@ finish vertex u
out edges have been examined and the reach counts of the unvisited
targets have been updated.

== 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
Expand Down
Loading
Loading