From ab46b3f8934fe6b0201248dfabd756b84b7bd8d3 Mon Sep 17 00:00:00 2001 From: "Cromwell D. Enage" Date: Thu, 8 Apr 2004 01:30:24 +0000 Subject: [PATCH] Initial revision [SVN r2109] --- doc/breadth_first_search.html | 163 +++++ doc/breadth_first_visit.html | 89 +++ doc/ddnw_random_paths.html | 172 +++++ doc/dijkstra_random_paths.html | 121 ++++ doc/loop_erased_random_paths.html | 124 ++++ doc/loop_erased_random_paths0.html | 158 +++++ doc/tarjan_offline_lca.html | 103 +++ example/make_random_paths.cpp | 643 ++++++++++++++++++ example/tarjan_offline_lca.cpp | 77 +++ include/boost/graph/ddnw_random_paths.hpp | 506 ++++++++++++++ include/boost/graph/dijkstra_random_paths.hpp | 222 ++++++ .../boost/graph/loop_erased_random_paths.hpp | 534 +++++++++++++++ include/boost/graph/map_utility.hpp | 76 +++ include/boost/graph/tarjan_offline_lca.hpp | 335 +++++++++ test/make_random_paths.cpp | 548 +++++++++++++++ test/tarjan_offline_lca.cpp | 209 ++++++ 16 files changed, 4080 insertions(+) create mode 100644 doc/breadth_first_search.html create mode 100644 doc/breadth_first_visit.html create mode 100644 doc/ddnw_random_paths.html create mode 100644 doc/dijkstra_random_paths.html create mode 100644 doc/loop_erased_random_paths.html create mode 100644 doc/loop_erased_random_paths0.html create mode 100644 doc/tarjan_offline_lca.html create mode 100644 example/make_random_paths.cpp create mode 100644 example/tarjan_offline_lca.cpp create mode 100644 include/boost/graph/ddnw_random_paths.hpp create mode 100644 include/boost/graph/dijkstra_random_paths.hpp create mode 100644 include/boost/graph/loop_erased_random_paths.hpp create mode 100644 include/boost/graph/map_utility.hpp create mode 100644 include/boost/graph/tarjan_offline_lca.hpp create mode 100644 test/make_random_paths.cpp create mode 100644 test/tarjan_offline_lca.cpp diff --git a/doc/breadth_first_search.html b/doc/breadth_first_search.html new file mode 100644 index 00000000..e5e17e0a --- /dev/null +++ b/doc/breadth_first_search.html @@ -0,0 +1,163 @@ + + + + + Boost Graph Library: Breadth-First Search + + +

C++ Boost
breadth_first_search

+ +
// named paramter version
+template <class Graph, class P, class T, class R>
+void breadth_first_search(Graph& G,
+  typename graph_traits<Graph>::vertex_descriptor s,
+  const bgl_named_params<P, T, R>& params);
+
+// non-named parameter version
+template <class Graph, class Buffer, class BFSVisitor,
+	  class ColorMap>
+void breadth_first_search(const Graph& g,
+   typename graph_traits<Graph>::vertex_descriptor s,
+   Buffer& Q, BFSVisitor vis, ColorMap color);
+ +

The breadth_first_search() function performs a breadth-first traversal [49] of a directed or undirected graph. A breadth-first traversal visits vertices that are closer to the source before visiting vertices that are further away. In this context "distance" is defined as the number of edges in the shortest path from the source vertex. The breadth_first_search() function can be used to compute the shortest path from the source to all reachable vertices and the resulting shortest-path distances. For more definitions related to BFS see section Breadth-First Search.

+

BFS uses two data structures to to implement the traversal: a color marker for each vertex and a queue. White vertices are undiscovered while gray vertices are discovered but have undiscovered adjacent vertices. Black vertices are discovered and are adjacent to only other black or gray vertices. The algorithm proceeds by removing a vertex u from the queue and examining each out-edge (u,v). If an adjacent vertex v is not already discovered, it is colored gray and placed in the queue. After all of the out-edges are examined, vertex u is colored black and the process is repeated. Pseudo-code for the BFS algorithm is a listed below.

+ + + + + + +
+
+BFS(G, s)
+  for each vertex u in V[G]
+    color[u] := WHITE 
+    d[u] := infinity 
+    p[u] := u 
+  end for
+  color[s] := GRAY 
+  d[s] := 0 
+  ENQUEUE(Q, s)
+  while (Q != Ø) 
+    u := DEQUEUE(Q)
+    for each vertex v in Adj[u]
+      if (color[v] = WHITE)
+        color[v] := GRAY 
+        d[v] := d[u] + 1  
+        p[v] := u  
+        ENQUEUE(Q, v)
+      else
+        if (color[v] = GRAY) 
+          ...
+        else 
+          ...
+    end for
+    color[u] := BLACK
+  end while
+  return (d, p)
+
+
+
+
+initialize vertex u 
+
+
+
+
+
+
+discover vertex s 
+
+examine vertex u 
+examine edge (u,v)
+(u,v) is a tree edge 
+
+
+
+discover vertex v 
+(u,v) is a non-tree edge
+
+(u,v) has a gray target 
+
+(u,v) has a black target 
+
+finish vertex u 
+
+
+ +

The breadth_first_search() function can be extended with user-defined actions that will be called a certain event points. The actions must be provided in the form of a visitor object, that is, an object whose type meets the requirements for a BFS Visitor. In the above pseudo-code, the event points are the labels on the right. Also a description of each event point is given below. By default, the breadth_first_search() function does not carry out any actions, not even recording distances or predecessors. However these can be easily added using the distance_recorder and predecessor_recorder event visitors.

+ +

Where Defined

+

boost/graph/breadth_first_search.hpp

+ +

Parameters

+

IN: Graph& g

+
+

A directed or undirected graph. The graph type must be a model of Vertex List Graph and Incidence Graph.

+
+

IN: vertex_descriptor s

+
+

The source vertex where the search is started.

+
+ +

Named Parameters

+

IN: visitor(BFSVisitor vis)

+
+

A visitor object that is invoked inside the algorithm at the event-points specified by the BFS Visitor concept. The visitor object is passed by value [1].

+

Default: bfs_visitor<null_visitor>

+
+

UTIL/OUT: color_map(ColorMap color)

+
+

This is used by the algorithm to keep track of its progress through the graph. The user need not initialize the color map before calling breadth_first_search() since the algorithm initializes the color of every vertex to white at the start of the algorihtm. If you need to perform multiple breadth-first searches on a graph (for example, if there are some disconnected components) then use the breadth_first_visit() function and do your own color initialization.

+

The type ColorMap must be a model of Read/Write Property Map and its key type must be the graph's vertex descriptor type and the value type of the color map must model ColorValue.

+

Default: an iterator_property_map created from a std::vector<default_color_type> of size num_vertices(g) and using the i_map for the index map.

+
+

IN: vertex_index_map(VertexIndexMap i_map)

+
+

This maps each vertex to an integer in the range [0, num_vertices(g)). This parameter is only necessary when the default color property map is used. The type VertexIndexMap must be a model of Readable Property Map. The value type of the map must be an integer type. The vertex descriptor type of the graph needs to be usable as the key type of the map.

+

Default: get(vertex_index, g)

+
+

UTIL: buffer(Buffer& Q)

+
+

The queue used to determine the order in which vertices will be discovered. If a FIFO queue is used, then the traversal will be according to the usual BFS ordering. Other types of queues can be used, but the traversal order will be different. For example, Dijkstra's algorithm can be implemented using a priority queue. The type Buffer must be a model of Buffer.

+

The value_type of the buffer must be the vertex_descriptor type for the graph.

+

Default: boost::queue<vertex_descriptor>

+
+ +

Complexity

+

The time complexity is O(E + V).

+ +

Visitor Event Points

+ + +

Example

+

The example in example/bfs-example.cpp demonstrates using the BGL Breadth-first search algorithm on the graph from Figure 5. The file example/bfs-example2.cpp contains the same example, except that the adacency_list class used has VertexList and EdgeList set to listS.

+ +

See Also

+

bfs_visitor and depth_first_search()

+ +

Notes

+

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

+ +
+ + + + + +
Copyright © 2004Jeremy Siek, Indiana University (jsiek@osl.iu.edu)
+

Use, modification, and distribution are subject to the Boost Software License, Version 1.0 at http://www.boost.org/LICENSE_1_0.txt

+ + + diff --git a/doc/breadth_first_visit.html b/doc/breadth_first_visit.html new file mode 100644 index 00000000..cd7aa3ea --- /dev/null +++ b/doc/breadth_first_visit.html @@ -0,0 +1,89 @@ + + + + + Boost Graph Library: Breadth-First Visit + + +

C++ Boost
breadth_first_visit

+ +
// named paramter version
+  template <class IncidenceGraph, class P, class T, class R>
+  void breadth_first_visit(IncidenceGraph& G, 
+    typename graph_traits<IncidenceGraph>::vertex_descriptor s, 
+    const bgl_named_params<P, T, R>& params);
+
+// non-named parameter version
+  template <class IncidenceGraph, class Buffer, class BFSVisitor, class ColorMap>
+  void breadth_first_visit
+    (const IncidenceGraph& g, 
+     typename graph_traits<IncidenceGraph>::vertex_descriptor s, 
+     Buffer& Q, BFSVisitor vis, ColorMap color);
+ +

This function is basically the same as breadth_first_search() except that the color markers are not initialized in the algorithm. The user is responsible for making sure the color for every vertex is white before calling the algorithm. With this difference, the graph type is only required to be an Incidence Graph instead of a Vertex List Graph. Also, this difference allows for more flexibility in the color property map. For example, one could use a map that only implements a partial function on the vertices, which could be more space efficient when the search only reaches a small portion of the graph.

+ +

Where Defined

+

boost/graph/breadth_first_search.hpp

+ +

Parameters

+

IN: IncidenceGraph& g

+
+

A directed or undirected graph. The graph type must be a model of Incidence Graph.

+
+

IN: vertex_descriptor s

+
+

The source vertex where the search is started.

+
+ +

Named Parameters

+

IN: visitor(BFSVisitor vis)

+
+

A visitor object that is invoked inside the algorithm at the event-points specified by the BFS Visitor concept. The visitor object is passed by value [1].

+

Default: bfs_visitor<null_visitor>

+
+

UTIL/OUT: color_map(ColorMap color)

+
+

This is used by the algorithm to keep track of its progress through the graph. The type ColorMap must be a model of Read/Write Property Map and its key type must be the graph's vertex descriptor type and the value type of the color map must model ColorValue.

+

Default: an iterator_property_map created from a std::vector<default_color_type> of size num_vertices(g) and using the i_map for the index map.

+
+

UTIL: buffer(Buffer& Q)

+
+

The queue used to determine the order in which vertices will be discovered. If a FIFO queue is used, then the traversal will be according to the usual BFS ordering. Other types of queues can be used, but the traversal order will be different. For example, Dijkstra's algorithm can be implemented using a priority queue. The type Buffer must be a model of Buffer.

+

The value_type of the buffer must be the vertex_descriptor type for the graph.

+

Default: boost::queue<vertex_descriptor>

+
+ + +

Complexity

+

The time complexity is O(E).

+ +

Visitor Event Points

+ + +

See Also

+

breadth_first_search(), bfs_visitor, and depth_first_search()

+ +

Notes

+

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

+ +
+ + + + + +
Copyright © 2004Jeremy Siek, Indiana University (jsiek@osl.iu.edu)
+

Use, modification, and distribution are subject to the Boost Software License, Version 1.0 at http://www.boost.org/LICENSE_1_0.txt

+ + + diff --git a/doc/ddnw_random_paths.html b/doc/ddnw_random_paths.html new file mode 100644 index 00000000..aa0adffe --- /dev/null +++ b/doc/ddnw_random_paths.html @@ -0,0 +1,172 @@ + + + + + Boost Graph Library: Dijkstra-DAG Negative-Weighted Random Paths + + +

C++ Boost
Dijkstra-DAG Negative-Weighted Random Paths

+ +
// default version
+template <typename InputGraph, typename RandomNumberGenerator,
+          typename OutputPredecessorMap, typename UtilGraph>
+void ddnw_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomNumberGenerator& random_weight, OutputPredecessorMap out_pred_map,
+    UtilGraph& dag)
+
+ +
// named parameter version
+template <typename InputGraph, typename RandomNumberGenerator,
+          typename IP, typename IT, typename IR,
+          typename UP, typename UT, typename UR>
+void ddnw_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomNumberGenerator& random_weight, UtilGraph& dag,
+    const bgl_named_params<IP, IT, IR>& in_params,
+    const bgl_named_params<UP, UT, UR>& u_params)
+
+ +
// kitchen-sink version
+template <typename InputGraph, typename RandomNumberGenerator,
+          typename OutputPredecessorMap, typename InputDistanceMap,
+          typename InputIndexMap, typename InputColorMap,
+          typename CompareFunctor, typename CombineFunctor,
+          typename DistanceInfinity, typename DistanceZero,
+          typename InputEventVisitorList, typename UtilGraph,
+          typename UtilPredecessorMap, typename UtilDistanceMap,
+          typename UtilIndexMap, typename UtilColorMap,
+          typename UtilEventVisitorList>
+void ddnw_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomNumberGenerator& random_weight, OutputPredecessorMap out_pred_map,
+    InputDistanceMap in_dist_map, InputIndexMap in_index_map,
+    InputColorMap in_color_map, CompareFunctor compare, CombineFunctor combine,
+    DistanceInfinity infinity, DistanceZero zero, InputEventVisitorList in_vis,
+    UtilGraph& dag, UtilPredecessorMap u_pred_map, UtilDistanceMap u_dist_map,
+    UtilIndexMap u_index_map, UtilColorMap u_color_map,
+    UtilEventVisitorList dag_vis)
+
+ +

This algorithm creates random paths in the input graph, all from the specified source vertex, and places them in the output predecessor map.

+

The implementation carries out the following steps:

+
    +
  1. Run Dijkstra's Random Paths algorithm on the input graph.
  2. +
  3. For the utility graph, make copies of only the forward and cross edges with respect to the previous traversal. This ensures that the utility graph is acyclic.
  4. +
  5. Negate the edge weights in the utility graph.
  6. +
  7. Run dag_shortest_paths on the utility graph. Because of the previous negation, this essentially becomes a longest simple path algorithm. In general, the LSP problem is NP-complete, but directed acyclic graphs make up a special case.
  8. +
  9. Put the resulting random paths in the output predecessor map.
  10. +
+

Because the algorithm requires two graphs, the named-parameter function variant requires two named-parameter arguments. Furthermore, a default utility graph cannot be provided without defining a specific graph implementation (e.g. adjacency_list).

+ +

Where Defined

+

boost/graph/ddnw_random_paths.hpp

+ +

Parameters

+

IN: InputGraph& in_g

+
+

The input graph. The type InputGraph must be a model of Vertex And Edge List Graph, and edge_weight_t must be a read/write interior property of the graph.

+
+

IN: graph_traits<InputGraph>::vertex_descriptor source

+
+

The source vertex. The random paths tree will be rooted at this vertex.

+
+

IN: RandomNumberGenerator& random_weight

+
+

The random number generator used to put random weights in the graph's internal weight map. The type RandomNumberGenerator must also be a legal template argument in the randomize_property function.

+
+ +

UTIL: UtilGraph& dag

+
+

The utility graph. The type UtilGraph must be a model of Vertex And Edge List Graph and EdgeMutableGraphConcept, the associated directed_category type must be convertible to directed_tag, and edge_weight_t must be a read/write interior property of the graph. Furthermore, dag must contain no edges, and num_vertices(dag) == num_vertices(in_g); the behavior of this algorithm is undefined otherwise. Upon completion of the algorithm, dag will retain its original state.

+
+ +

InputGraph Named Parameters

+

OUT: predecessor_map(OutputPredecessorMap out_pred_map)

+
+

The predecessor map records the edges in the random paths. Upon completion of the algorithm, the edges (p[u],u) for all u in V are in the random paths. If p[u] = u then u is either the source vertex or a vertex that is not reachable from the source. The PredecessorMap type must be a Read/Write Property Map whose key and value types are graph_traits<InputGraph>::vertex_descriptor.
Default: get(vertex_predecessor_t(), g)

+
+

IN: vertex_index_map(InputIndexMap in_index_map)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

UTIL/OUT: distance_map(InputDistanceMap in_dist_map)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

IN: distance_compare(CompareFunctor compare)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

IN: distance_combine(CombineFunctor combine)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

IN: distance_inf(D infinity)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

IN: distance_zero(D zero)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

UTIL/OUT: color_map(InputColorMap in_color_map)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

OUT: visitor(InputEventVisitorList in_vis)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+ +

UtilGraph Named Parameters

+

OUT: predecessor_map(UtilPredecessorMap u_pred_map)

+
+

The predecessor map records the edges in the random paths. Upon completion of the algorithm, the edges (p[u],u) for all u in V are in the random paths. If p[u] = u then u is either the source vertex or a vertex that is not reachable from the source. The PredecessorMap type must be a Read/Write Property Map whose key and value types are the same as the vertex descriptor type of the graph.
Default: An associative property map built on top of an std::map whose key and value types are graph_traits<UtilGraph>::vertex_descriptor.

+
+

UTIL/OUT: distance_map(UtilDistanceMap u_dist_map)

+
+

Serves the same function, has the same requirements, and uses the same default as in dag_shortest_paths.

+
+

IN: vertex_index_map(UtilIndexMap in_index_map)

+
+

Serves the same function, has the same requirements, and uses the same default as in dag_shortest_paths.

+
+

UTIL/OUT: color_map(UtilColorMap u_color_map)

+
+

Serves the same function, has the same requirements, and uses the same default as in dag_shortest_paths.

+
+

OUT: visitor(UtilEventVisitorList dag_vis)

+
+

Serves the same function, has the same requirements, and uses the same default as in dag_shortest_paths.

+
+ +

Complexity

+

The time complexity is O((V + E) log V), or just O(E log V) if all vertices are reachable from the source.

+ +

Visitor Event Points

+

The visitor event points for the input visitor are the same as in dijkstra_shortest_paths. The visitor event points for the utility visitor are the same as in dag_shortest_paths.

+ +

Example

+

See example/make_random_paths.cpp for an example of using the Dijkstra-DAG Negative-Weighted Random Paths algorithm.

+ +

Performance

+

In terms of randomness, this algorithm fares better than Dijkstra's version, but not as well as the Loop-Erased Random Paths algorithm.

+ +

Test

+

The test program test/make_random_paths.cpp can be used to verify that ddnw_random_paths works as expected.

+ +
+ + + + + +
Copyright © 2004Cromwell D. Enage
+

Covered by the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).

+ + + diff --git a/doc/dijkstra_random_paths.html b/doc/dijkstra_random_paths.html new file mode 100644 index 00000000..7ce2bfff --- /dev/null +++ b/doc/dijkstra_random_paths.html @@ -0,0 +1,121 @@ + + + + + Boost Graph Library: Dijkstra's Random Paths + + +

C++ Boost
dijkstra_random_paths

+ +
// default version
+template <typename Graph, typename RandomNumberGenerator,
+          typename PredecessorMap>
+void dijkstra_random_paths(
+    Graph& g,
+    typename graph_traits<Graph>::vertex_descriptor source,
+    RandomNumberGenerator& random_weight, PredecessorMap pred_map)
+
+ +
// named parameter version
+template <typename Graph, typename RandomNumberGenerator,
+          typename Param, typename Tag, typename Rest>
+void dijkstra_random_paths(
+    Graph& g,
+    typename graph_traits<Graph>::vertex_descriptor source,
+    RandomNumberGenerator& random_weight,
+    const bgl_named_params<Param, Tag, Rest>& params)
+
+ +
// kitchen-sink version
+template <typename Graph, typename RandomNumberGenerator,
+          typename PredecessorMap, typename DistanceMap,
+          typename VertexIndexMap, typename VertexColorMap,
+          typename CompareFunctor, typename CombineFunctor,
+          typename DistanceInfinity, typename DistanceZero,
+          typename EventVisitorList>
+void dijkstra_random_paths(
+    Graph& g,
+    typename graph_traits<Graph>::vertex_descriptor source,
+    RandomNumberGenerator& random_weight, PredecessorMap pred_map,
+    DistanceMap dist_map, VertexIndexMap index_map, VertexColorMap color_map,
+    CompareFunctor compare, CombineFunctor combine, DistanceInfinity infinity,
+    DistanceZero zero, EventVisitorList vis)
+
+ +

This algorithm creates random paths in the input graph, all from the specified source vertex, and places them in the output predecessor map.

+

The implementation runs on top of Dijkstra's shortest-pahts algorithm using random edge weights; the resulting paths tend to be short as well.

+ +

Where Defined

+

boost/graph/dijkstra_random_paths.hpp

+ +

Parameters

+

IN: Graph& g

+
+

The graph object on which the algorithm will be applied. The type Graph must be a model of Vertex And Edge List Graph, and edge_weight_t must be a read/write interior property of the graph.

+
+

IN: graph_traits<Graph>::vertex_descriptor source

+
+

The source vertex. All distances will be calculated from this vertex, and the random paths tree will be rooted at this vertex.

+
+ +

Named Parameters

+

OUT: predecessor_map(PredecessorMap p_map)

+
+

The predecessor map records the edges in the random paths. Upon completion of the algorithm, the edges (p[u],u) for all u in V are in the random paths. If p[u] = u then u is either the source vertex or a vertex that is not reachable from the source. The PredecessorMap type must be a Read/Write Property Map whose key and value types are the same as the vertex descriptor type of the graph.
Default: get(vertex_predecessor_t(), g)

+
+

IN: vertex_index_map(VertexIndexMap i_map)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

UTIL/OUT: distance_map(DistanceMap d_map)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

IN: distance_compare(CompareFunction cmp)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

IN: distance_combine(CombineFunction cmb)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

IN: distance_inf(D inf)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

IN: distance_zero(D zero)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

UTIL/OUT: color_map(ColorMap c_map)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+

OUT: visitor(EventVisitorList vis)

+
+

Serves the same function, has the same requirements, and uses the same default as in dijkstra_shortest_paths.

+
+ +

Complexity

+

The time complexity is O((V + E) log V), or just O(E log V) if all vertices are reachable from the source.

+ +

Visitor Event Points

+

Same as in dijkstra_shortest_paths.

+ +

Example

+

See example/make_random_paths.cpp for an example of using Dijkstra's Random Paths algorithm.

+ +

Test

+

The test program test/make_random_paths.cpp can be used to verify that dijkstra_random_paths works as expected.

+ +
+ + + + + +
Copyright © 2004Cromwell D. Enage
+

Covered by the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).

+ + + diff --git a/doc/loop_erased_random_paths.html b/doc/loop_erased_random_paths.html new file mode 100644 index 00000000..0f784197 --- /dev/null +++ b/doc/loop_erased_random_paths.html @@ -0,0 +1,124 @@ + + + + + Boost Graph Library: Loop-Erased Random Paths + + +

C++ Boost
loop_erased_random_paths

+ +
// default version
+template <typename InputGraph, typename RandomIndexGenerator,
+          typename OutputPredecessorMap, typename UtilGraph>
+bool loop_erased_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map, UtilGraph& u_g)
+
+ +
// named parameter version
+template <typename InputGraph, typename RandomIndexGenerator,
+          typename IP, typename IT, typename IR,
+          typename UP, typename UT, typename UR>
+bool loop_erased_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomIndexGenerator& rig, UtilGraph& u_g,
+    const bgl_named_params<IP, IT, IR>& in_params,
+    const bgl_named_params<UP, UT, UR>& u_params)
+
+ +
// kitchen-sink version
+template <typename InputGraph, typename RandomIndexGenerator,
+          typename OutputPredecessorMap, typename InputIndexMap,
+          typename InputColorMap, typename UtilGraph, typename UtilIndexMap,
+          typename UtilColorMap>
+bool loop_erased_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map,
+    InputIndexMap in_index_map, InputColorMap in_color_map,
+    UtilGraph& u_g, UtilIndexMap u_index_map, UtilColorMap u_color_map)
+
+ +

This algorithm creates random paths in the input graph, all from the specified source vertex, and places them in the output predecessor map. The implementation is based on an algorithm by James Gary Propp and David Bruce Wilson, located at http://dbwilson.com/ja/ja.ps.gz.ps on page 28. (See http://dbwilson.com/ja/ for output formats other than Postscript.)

+

The output predecessor map may form a forest instead of a tree; the implementation returns false in this case. How you deal with the result depends on whether you need all the paths (solved by while(!loop_erased_random_paths(...)){}) or just the path to a particular target vertex (see the example).

+

Because the algorithm requires two graphs, the named-parameter function variant requires two named-parameter arguments.

+ +

Where Defined

+

boost/graph/loop_erased_random_paths.hpp

+ +

Parameters

+

IN: InputGraph& in_g

+
+

The input graph. The type InputGraph must be a model of Vertex List Graph and Adjacency Graph.

+
+

IN: graph_traits<Graph>::vertex_descriptor source

+
+

The source vertex. The random paths tree will be rooted at this vertex.

+
+

IN: RandomIndexGenerator& rig

+
+

The base random number generator used to help choose random predecessors for vertices. The type RandomIndexGenerator must be a model of STL Random Number Generator. (You may use the boost::random_number_generator for this purpose.)

+
+

UTIL: UtilGraph& u_g

+
+

The utility graph, used by the algorithm to create a transposed copy of the input graph in order to efficiently find random predecessors. The type UtilGraph must be a model of Vertex List Graph, Adjacency Graph, and EdgeMutableGraphConcept.

+

Further preconditions: u_g must contain no edges, and num_vertices(u_g) == num_vertices(in_g)

+
+ +

InputGraph Named Parameters

+

OUT: predecessor_map(OutputPredecessorMap out_pred_map)

+
+

The predecessor map records the edges in the random paths. Upon completion of the algorithm, the edges (p[u],u) for all u in V are in the random paths. If p[u] = u then u is either the source vertex or a vertex that is not reachable from the source. The PredecessorMap type must be a Read/Write Property Map whose key and value types are graph_traits<InputGraph>::vertex_descriptor.

+

Default: get(vertex_predecessor_t(), g)

+
+

IN: vertex_index_map(InputIndexMap in_index_map)

+
+

Aids in bidirectional mapping between the graphs' vertex sets.

+

Default: get(vertex_index_t(), in_g)

+
+

UTIL/OUT: color_map(InputColorMap in_color_map)

+
+

Used by the algorithm to mark a vertex as part of the random tree.

+

Default: An iterator_property_map created from a std::vector<typename graph_traits<InputGraph>::vertex_descriptor> of size num_vertices(in_g) and using in_index_map for the index map.

+
+ +

UtilGraph Named Parameters

+

IN: vertex_index_map(UtilIndexMap in_index_map)

+
+

Aids in bidirectional mapping between the graphs' vertex sets.

+

Default: get(vertex_index_t(), u_g)

+
+

UTIL/OUT: color_map(UtilColorMap u_color_map)

+
+

Used by the algorithm to prevent loops from entering the random tree.

+

Default: An iterator_property_map created from a std::vector<typename graph_traits<UtilGraph>::vertex_descriptor> of size num_vertices(in_g) and using u_index_map for the index map.

+
+ +

Complexity

+

The time complexity is O(V + E).

+ +

Visitor Event Points

+

Should there be?

+ +

Example

+

See example/make_random_paths.cpp for an example of using the Loop-Erased Random Paths algorithm.

+ +

Performance

+

In terms of randomness, this is the library's best implementation so far.

+ +

Test

+

The test program test/make_random_paths.cpp can be used to verify that loop_erased_random_paths works as expected.

+ +
+ + + + + +
Copyright © 2004Cromwell D. Enage
+

Covered by the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).

+ + + diff --git a/doc/loop_erased_random_paths0.html b/doc/loop_erased_random_paths0.html new file mode 100644 index 00000000..6c5581f5 --- /dev/null +++ b/doc/loop_erased_random_paths0.html @@ -0,0 +1,158 @@ + + + + + Boost Graph Library: Loop-Erased Random Paths + + +

C++ Boost
loop_erased_random_paths

+ +
// generic default version
+template <typename InputGraph, typename RandomIndexGenerator,
+          typename OutputPredecessorMap, typename UtilGraph>
+bool loop_erased_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map, UtilGraph& u_g)
+
+ +
// generic named parameter version
+template <typename InputGraph, typename RandomIndexGenerator,
+          typename IP, typename IT, typename IR,
+          typename UP, typename UT, typename UR>
+bool loop_erased_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomIndexGenerator& rig, UtilGraph& u_g,
+    const bgl_named_params<IP, IT, IR>& in_params,
+    const bgl_named_params<UP, UT, UR>& u_params)
+
+ +
// generic kitchen-sink version
+template <typename InputGraph, typename RandomIndexGenerator,
+          typename OutputPredecessorMap, typename InputIndexMap,
+          typename InputColorMap, typename UtilGraph, typename UtilIndexMap,
+          typename UtilColorMap>
+bool loop_erased_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map,
+    InputIndexMap in_index_map, InputColorMap in_color_map,
+    UtilGraph& u_g, UtilIndexMap u_index_map, UtilColorMap u_color_map)
+
+ +
// specialized default version
+template <typename InputGraph, typename RandomIndexGenerator,
+          typename OutputPredecessorMap>
+bool loop_erased_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map)
+
+ +
// specialized named parameter version
+template <typename InputGraph, typename RandomIndexGenerator,
+          typename IP, typename IT, typename IR>
+bool loop_erased_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomIndexGenerator& rig,
+    const bgl_named_params<IP, IT, IR>& in_params)
+
+ +
// specialized kitchen-sink version
+template <typename InputGraph, typename RandomIndexGenerator,
+          typename OutputPredecessorMap, typename InputIndexMap,
+          typename InputColorMap>
+bool loop_erased_random_paths(
+    InputGraph& in_g,
+    typename graph_traits<InputGraph>::vertex_descriptor source,
+    RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map,
+    InputIndexMap in_index_map, InputColorMap in_color_map)
+
+ +

This algorithm creates random paths in the input graph, all from the specified source vertex, and places them in the output predecessor map. The implementation is based on an algorithm by James Gary Propp and David Bruce Wilson, located at http://dbwilson.com/ja/ja.ps.gz.ps on page 28. (See http://dbwilson.com/ja/ for output formats other than Postscript.)

+

The output predecessor map may form a forest instead of a tree; the implementation returns false in this case. How you deal with the result depends on whether you need all the paths (solved by while(!loop_erased_random_paths(...)){}) or just the path to a particular target vertex (see the example).

+

The specialized versions of the algorithm (the ones that don't take in a utility graph parameter) will work (i.e. compile) if and only if the input graph is either undirected or bidirectional.

+

Because the generic versions of the algorithm requires two graphs, the named-parameter function variant requires two named-parameter arguments.

+ +

Where Defined

+

boost/graph/loop_erased_random_paths.hpp

+ +

Parameters

+

IN: InputGraph& in_g

+
+

The input graph. The type InputGraph must be a model of Vertex List Graph and Adjacency Graph.

+
+

IN: graph_traits<InputGraph>::vertex_descriptor source source

+
+

The source vertex. The random paths tree will be rooted at this vertex.

+
+

IN: RandomIndexGenerator& rig

+
+

The base random number generator used to help choose random predecessors for vertices. The type RandomIndexGenerator must be a model of STL Random Number Generator. (You may use the boost::random_number_generator for this purpose.)

+
+

UTIL: UtilGraph& u_g

+
+

The utility graph, used by the algorithm to create a transposed copy of the input graph in order to efficiently find random predecessors. The type UtilGraph must be a model of Vertex List Graph, Adjacency Graph, and EdgeMutableGraphConcept.

+

Further preconditions: u_g must contain no edges, and num_vertices(u_g) == num_vertices(in_g)

+

Note: The specialized versions of the algorithm do not take in this parameter.

+
+ +

InputGraph Named Parameters

+

OUT: predecessor_map(OutputPredecessorMap out_pred_map)

+
+

The predecessor map records the edges in the random paths. Upon completion of the algorithm, the edges (p[u],u) for all u in V are in the random paths. If p[u] = u then u is either the source vertex or a vertex that is not reachable from the source. The PredecessorMap type must be a Read/Write Property Map whose key and value types are graph_traits<InputGraph>::vertex_descriptor.

+

Default: get(vertex_predecessor_t(), g)

+
+

IN: vertex_index_map(InputIndexMap in_index_map)

+
+

Aids in bidirectional mapping between the graphs' vertex sets.

+

Default: get(vertex_index_t(), in_g)

+
+

UTIL/OUT: color_map(InputColorMap in_color_map)

+
+

Used by the algorithm to mark a vertex as part of the random tree.

+

Default: An iterator_property_map created from a std::vector<typename graph_traits<InputGraph>::vertex_descriptor> of size num_vertices(in_g) and using in_index_map for the index map.

+
+ +

UtilGraph Named Parameters

+

IN: vertex_index_map(UtilIndexMap in_index_map)

+
+

Aids in bidirectional mapping between the graphs' vertex sets.

+

Default: get(vertex_index_t(), u_g)

+

Note: The specialized versions of the algorithm do not take in this parameter.

+
+

UTIL/OUT: color_map(UtilColorMap u_color_map)

+
+

Used by the algorithm to prevent loops from entering the random tree.

+

Default: An iterator_property_map created from a std::vector<typename graph_traits<UtilGraph>::vertex_descriptor> of size num_vertices(in_g) and using u_index_map for the index map.

+

Note: The specialized versions of the algorithm do not take in this parameter.

+
+ +

Complexity

+

The time complexity is O(V + E).

+ +

Visitor Event Points

+

Should there be?

+ +

Example

+

See example/make_random_paths.cpp for an example of using the Loop-Erased Random Paths algorithm.

+ +

Performance

+

In terms of randomness, this is the library's best implementation so far.

+ +

Test

+

The test program test/make_random_paths.cpp can be used to verify that loop_erased_random_paths works as expected.

+ +
+ + + + + +
Copyright © 2004Cromwell D. Enage
+

Covered by the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).

+ + + diff --git a/doc/tarjan_offline_lca.html b/doc/tarjan_offline_lca.html new file mode 100644 index 00000000..1bc88bb0 --- /dev/null +++ b/doc/tarjan_offline_lca.html @@ -0,0 +1,103 @@ + + + + + Boost Graph Library: Tarjan's Offline Least Common Ancestor Algorithm + + +

C++ Boost
Tarjan's Offline Least Common Ancestor Algorithm

+ +
// default version
+template <typename Graph, typename AncestorMatrix>
+void tarjan_offline_lca(
+    const Graph& in_g, typename graph_traits<Graph>::vertex_descriptor source,
+    AncestorMatrix& ancestor_matrix)
+
+ +
// kitchen-sink version
+template <typename Graph, typename AncestorMatrix, typename DisjointSets,
+          typename PredecessorMap, typename VertexColorMap,
+          typename EventVisitorList>
+void tarjan_offline_lca(
+    const Graph& in_g, typename graph_traits<Graph>::vertex_descriptor source,
+    AncestorMatrix& ancestor_matrix, DisjointSets dsets,
+    PredecessorMap ancestor_map, VertexColorMap color_map, EventVisitorList vis)
+
+ +

The least common ancestor (LCA) of two vertices is the vertex that fulfills the following conditions:

+
    +
  1. Both input vertices are its descendants.
  2. +
  3. None of its descendants fulfill the previous condition.
  4. +
+

This algorithm precalculates the LCA of all pairs of vertices in the graph and stores the results in the output ancestor matrix.

+

TODO: Implement an output format that is more true to the original algorithm (i.e. only calculates the results for a specified set of vertex pairs) but is still generic. The target time complexity is O(N * V log V), where N is the (relatively small) size of the input set of vertex pairs for which the LCA actually needs to be calculated.

+ +

Where Defined

+

boost/graph/tarjan_offline_lca.hpp

+ +

Parameters

+

IN: Graph& g

+
+

The input graph.

+

Preconditions:

+ +
+

IN: graph_traits<Graph>::vertex_descriptor source

+
+

The root of the tree graph.

+
+

OUT: AncestorMatrix& ancestor_matrix

+
+

The output matrix that will store the results of the LCA calculations.

+

Preconditions:

+ +

Postcondition: The LCA of vertices x and y in g is ancestor_matrix(x, y).

+
+

UTIL/OUT: DisjointSets dsets

+
+

The algorithm makes a set for each vertex during its discovery by the depth-first traversal. During post-traversal of a vertex, it unionizes the vertex with all of its children so that, instead of making X2 LCA calculations for X children, at most N LCA calculations will be made. Currently, N = num_vertices(g); see the TODO above.

+
+

UTIL/OUT: predecessor_map(PredecessorMap out_pred_map)

+
+

The predecessor map records the edges in the tree. Upon completion of the algorithm, the edges (p[u],u) for all u in V are in the tree. If p[u] = u then u is either the source vertex or a vertex that is not reachable from the source. The PredecessorMap type must be a Read/Write Property Map whose key and value types are graph_traits<Graph>::vertex_descriptor.

+

Default: A dummy associative_property_map.

+
+

UTIL/OUT: vertex_color_map(VertexColorMap color_map)

+
+

Used by the algorithm to mark a vertex as part of the tree.

+

Default: An iterator_property_map created from a std::vector<typename graph_traits<InputGraph>::vertex_descriptor> of size num_vertices(g) and using get(vertex_index_t(), g) for the index map.

+
+ +

Complexity

+

The current time complexity is O(V2 log V) until a better output format is implemented; see the TODO above.

+ +

Visitor Event Points

+

Same as in depth_first_search.

+ +

Example

+

See example/tarjan_offline_lca.cpp for an example of using Tarjan's Offline Least Common Ancestor Algorithm.

+ +

Performance

+

Recursion could be a problem, but the current absence of a post-traversal event filter (neither on_back_edge nor on_forward_or_cross_edge would fire if this example program had used them) precludes usage of either the depth_first_search or undirected_dfs built-in functions.

+ +

Test

+

The test program test/tarjan_offline_lca.cpp can be used to verify that tarjan_offline_lca works as expected.

+ +
+ + + + + +
Copyright © 2004Cromwell D. Enage
+

Covered by the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).

+ + + diff --git a/example/make_random_paths.cpp b/example/make_random_paths.cpp new file mode 100644 index 00000000..f251b483 --- /dev/null +++ b/example/make_random_paths.cpp @@ -0,0 +1,643 @@ +/* make_random_paths.cpp source file + * + * Copyright 2004 Cromwell D. Enage. Covered by the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +/* + * Defines the std::ios class and std::cout, its global output instance. + */ +#include + +/* + * Defines the std::list class template and its iterators. + */ +#include + +/* + * Defines the std::map class template. + */ +#include + +/* + * Defines the boost::mt19937 class, to be used as a random-number-generating + * engine. + */ +#include + +/* + * Defines the boost::uniform_int class template, to be used as a random-number + * distribution. + */ +#include + +/* + * Defines the boost::variate_generator class template, to be used as the + * front-end random-number generator. + */ +#include + +/* + * Defines the boost::random_number_generator class template, to be used as the + * front-end random-index generator. + */ +#include + +/* + * Defines the boost::property_map and boost::associative_property_map class + * templates and the boost::get and boost::put function templates. + */ +#include + +/* + * Defines the boost::graph_traits class template. + */ +#include + +/* + * Defines the vertex and edge property tags. + */ +#include + +/* + * Defines the boost::directedS and boost::undirectedS selector tags. + */ +#include + +/* + * Defines the boost::adjacency_list class template and its associated + * non-member function templates. + */ +#include + +/* + * Defines the boost::adjacency_matrix class template and its associated + * non-member function templates. + */ +#include + +/* + * Defines the boost::dijkstra_random_paths function template. + */ +#include + +/* + * Defines the boost::ddnw_random_paths function template. + */ +#include + +/* + * Defines the boost::loop_erased_random_paths function template. + */ +#include + +template +void init_graph(Graph& g) +{ + boost::add_edge(boost::vertex(0, g), boost::vertex(7, g), g); + boost::add_edge(boost::vertex(1, g), boost::vertex(2, g), g); + boost::add_edge(boost::vertex(2, g), boost::vertex(10, g), g); + boost::add_edge(boost::vertex(2, g), boost::vertex(5, g), g); + boost::add_edge(boost::vertex(3, g), boost::vertex(10, g), g); + boost::add_edge(boost::vertex(3, g), boost::vertex(0, g), g); + boost::add_edge(boost::vertex(4, g), boost::vertex(5, g), g); + boost::add_edge(boost::vertex(4, g), boost::vertex(0, g), g); + boost::add_edge(boost::vertex(5, g), boost::vertex(14, g), g); + boost::add_edge(boost::vertex(6, g), boost::vertex(3, g), g); + boost::add_edge(boost::vertex(7, g), boost::vertex(17, g), g); + boost::add_edge(boost::vertex(7, g), boost::vertex(11, g), g); + boost::add_edge(boost::vertex(8, g), boost::vertex(17, g), g); + boost::add_edge(boost::vertex(8, g), boost::vertex(1, g), g); + boost::add_edge(boost::vertex(9, g), boost::vertex(11, g), g); + boost::add_edge(boost::vertex(9, g), boost::vertex(1, g), g); + boost::add_edge(boost::vertex(10, g), boost::vertex(19, g), g); + boost::add_edge(boost::vertex(10, g), boost::vertex(15, g), g); + boost::add_edge(boost::vertex(10, g), boost::vertex(8, g), g); + boost::add_edge(boost::vertex(11, g), boost::vertex(19, g), g); + boost::add_edge(boost::vertex(11, g), boost::vertex(15, g), g); + boost::add_edge(boost::vertex(11, g), boost::vertex(4, g), g); + boost::add_edge(boost::vertex(12, g), boost::vertex(19, g), g); + boost::add_edge(boost::vertex(12, g), boost::vertex(8, g), g); + boost::add_edge(boost::vertex(12, g), boost::vertex(4, g), g); + boost::add_edge(boost::vertex(13, g), boost::vertex(15, g), g); + boost::add_edge(boost::vertex(13, g), boost::vertex(8, g), g); + boost::add_edge(boost::vertex(13, g), boost::vertex(4, g), g); + boost::add_edge(boost::vertex(14, g), boost::vertex(22, g), g); + boost::add_edge(boost::vertex(14, g), boost::vertex(12, g), g); + boost::add_edge(boost::vertex(15, g), boost::vertex(22, g), g); + boost::add_edge(boost::vertex(15, g), boost::vertex(6, g), g); + boost::add_edge(boost::vertex(16, g), boost::vertex(12, g), g); + boost::add_edge(boost::vertex(16, g), boost::vertex(6, g), g); + boost::add_edge(boost::vertex(17, g), boost::vertex(20, g), g); + boost::add_edge(boost::vertex(18, g), boost::vertex(9, g), g); + boost::add_edge(boost::vertex(19, g), boost::vertex(23, g), g); + boost::add_edge(boost::vertex(19, g), boost::vertex(18, g), g); + boost::add_edge(boost::vertex(20, g), boost::vertex(23, g), g); + boost::add_edge(boost::vertex(20, g), boost::vertex(13, g), g); + boost::add_edge(boost::vertex(21, g), boost::vertex(18, g), g); + boost::add_edge(boost::vertex(21, g), boost::vertex(13, g), g); + boost::add_edge(boost::vertex(22, g), boost::vertex(21, g), g); + boost::add_edge(boost::vertex(23, g), boost::vertex(16, g), g); +} + +template +void dijkstra_random_paths_example( + const unsigned int start_index, const unsigned int end_index, + const unsigned int max_weight, unsigned int num_runs) +{ + typedef typename boost::graph_traits::vertex_descriptor + Vertex; + typedef std::map + VertexMap; + typedef boost::associative_property_map + PredecessorMap; + typedef typename boost::property_map::type + VertexIndexMap; + typedef std::list + Path; + typedef typename Path::iterator + PathIterator; + typedef boost::uniform_int + RNGDistribution; + typedef boost::variate_generator + RandomNumberGenerator; + + Graph g(24); + Vertex source_vertex = boost::vertex(start_index, g); + Vertex target_vertex = boost::vertex(end_index, g); + Vertex v; + VertexMap v_map; + PredecessorMap pred_map(v_map); + VertexIndexMap index_map = boost::get(boost::vertex_index_t(), g); + Path path; + PathIterator begin, end; + RNGEngine rng_engine; + RNGDistribution rng_distribution(0, max_weight); + RandomNumberGenerator random_weight(rng_engine, rng_distribution); + + for (init_graph(g); num_runs > 0; --num_runs) + { +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 +// According to example code using dijkstra_shortest_paths, +// VC++ has trouble with the named parameters mechanism. + boost::dijkstra_random_paths(g, source_vertex, random_weight, + pred_map); +#else + boost::dijkstra_random_paths(g, source_vertex, random_weight, + boost::predecessor_map(pred_map)); +#endif + + for (v = target_vertex; + v != boost::get(pred_map, v); + v = boost::get(pred_map, v)) + { + path.push_front(v); + } + + path.push_front(v); + begin = path.begin(); + end = path.end(); + + std::cout << "The path: " << boost::get(index_map, *begin); + + while (++begin != end) + { + std::cout << " -> " << boost::get(index_map, *begin); + } + + std::cout << std::endl; + + path.clear(); + } +} + +template +void ddnw_random_paths_example( + const unsigned int start_index, const unsigned int end_index, + const unsigned int max_weight, unsigned int num_runs) +{ + typedef typename boost::graph_traits::vertex_descriptor + InputVertex; + typedef std::map + OutputVertexMap; + typedef boost::associative_property_map + OutputPredecessorMap; + typedef typename boost::property_map::type + VertexIndexMap; + typedef std::list + Path; + typedef typename Path::iterator + PathIterator; + typedef boost::uniform_int + RNGDistribution; + typedef boost::variate_generator + RandomNumberGenerator; + + InputGraph g(24); + UtilGraph dag(24); + InputVertex source_vertex = boost::vertex(start_index, g); + InputVertex target_vertex = boost::vertex(end_index, g); + InputVertex v; + OutputVertexMap out_v_map; + OutputPredecessorMap out_pred_map(out_v_map); + VertexIndexMap index_map = boost::get(boost::vertex_index_t(), g); + Path path; + PathIterator begin, end; + RNGEngine rng_engine; + RNGDistribution rng_distribution(0, max_weight); + RandomNumberGenerator random_weight(rng_engine, rng_distribution); + + for (init_graph(g); num_runs > 0; --num_runs) + { +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 +// According to example code using dijkstra_shortest_paths, +// VC++ has trouble with the named parameters mechanism. + boost::ddnw_random_paths(g, source_vertex, random_weight, + out_pred_map, dag); +#else + boost::ddnw_random_paths( + g, source_vertex, random_weight, dag, + boost::predecessor_map(out_pred_map), + boost::vertex_index_map(boost::get(boost::vertex_index_t(), dag))); +#endif + + for (v = target_vertex; + v != boost::get(out_pred_map, v); + v = boost::get(out_pred_map, v)) + { + path.push_front(v); + } + + path.push_front(v); + begin = path.begin(); + end = path.end(); + + std::cout << "The path: " << boost::get(index_map, *begin); + + while (++begin != end) + { + std::cout << " -> " << boost::get(index_map, *begin); + } + + std::cout << std::endl; + + path.clear(); + } +} + +template +void loop_erased_random_paths_example( + const unsigned int start_index, const unsigned int end_index, + const unsigned int max_weight, unsigned int num_runs) +{ + typedef typename boost::graph_traits::vertex_descriptor + Vertex; + typedef std::map + VertexMap; + typedef boost::associative_property_map + PredecessorMap; + typedef typename boost::property_map::type + VertexIndexMap; + typedef std::list + Path; + typedef typename Path::iterator + PathIterator; + typedef boost::random_number_generator + RandomIndexGenerator; + + Graph g(24); + Graph u_g(24); + Vertex source_vertex = boost::vertex(start_index, g); + Vertex target_vertex = boost::vertex(end_index, g); + Vertex v; + VertexMap v_map; + PredecessorMap pred_map(v_map); + VertexIndexMap index_map = boost::get(boost::vertex_index_t(), g); + Path path; + PathIterator begin, end; + RNGEngine rng_engine; + RandomIndexGenerator rig(rng_engine); + + init_graph(g); + + while (num_runs > 0) + { +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 +// According to example code using dijkstra_shortest_paths, +// VC++ has trouble with the named parameters mechanism. + boost::loop_erased_random_paths(g, source_vertex, rig, pred_map, + u_g); +#else + boost::loop_erased_random_paths( + g, source_vertex, rig, u_g, + boost::predecessor_map(pred_map), + boost::vertex_index_map(get(boost::vertex_index_t(), u_g))); +#endif + + for (v = target_vertex; + v != boost::get(pred_map, v); + v = boost::get(pred_map, v)) + { + path.push_front(v); + } + + if (v == source_vertex) + { + path.push_front(v); + begin = path.begin(); + end = path.end(); + + std::cout << "The path: " << boost::get(index_map, *begin); + + while (++begin != end) + { + std::cout << " -> " << boost::get(index_map, *begin); + } + + std::cout << std::endl; + --num_runs; + } + + path.clear(); + } +} + +#ifdef RandomIndexGenerator +template +void loop_erased_random_paths_specialized_example( + const unsigned int start_index, const unsigned int end_index, + const unsigned int max_weight, unsigned int num_runs) +{ + typedef typename boost::graph_traits::vertex_descriptor + Vertex; + typedef std::map + VertexMap; + typedef boost::associative_property_map + PredecessorMap; + typedef typename boost::property_map::type + VertexIndexMap; + typedef std::list + Path; + typedef typename Path::iterator + PathIterator; + typedef boost::random_number_generator + RandomIndexGenerator; + + Graph g(24); + Vertex source_vertex = boost::vertex(start_index, g); + Vertex target_vertex = boost::vertex(end_index, g); + Vertex v; + VertexMap v_map; + PredecessorMap pred_map(v_map); + VertexIndexMap index_map = boost::get(boost::vertex_index_t(), g); + Path path; + PathIterator begin, end; + RNGEngine rng_engine; + RandomIndexGenerator rig(rng_engine); + + init_graph(g); + + while (num_runs > 0) + { +//#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 +// According to example code using dijkstra_shortest_paths, +// VC++ has trouble with the named parameters mechanism. + boost::loop_erased_random_paths(g, source_vertex, rig, pred_map); +/*#else + boost::loop_erased_random_paths( + g, source_vertex, rig, boost::predecessor_map(pred_map)); +#endif +*/ + for (v = target_vertex; + v != boost::get(pred_map, v); + v = boost::get(pred_map, v)) + { + path.push_front(v); + } + + if (v == source_vertex) + { + path.push_front(v); + begin = path.begin(); + end = path.end(); + + std::cout << "The path: " << boost::get(index_map, *begin); + + while (++begin != end) + { + std::cout << " -> " << boost::get(index_map, *begin); + } + + std::cout << std::endl; + --num_runs; + } + + path.clear(); + } +} +#endif + +template +void example(const unsigned int start_index, const unsigned int end_index, + const unsigned int max_weight, const unsigned int num_runs) +{ + std::cout << "Running dijkstra_random_paths function template on "; + std::cout << "undirected graph." << std::endl; + dijkstra_random_paths_example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; + + std::cout << "Running ddnw_random_paths function template on "; + std::cout << "undirected graph." << std::endl; + ddnw_random_paths_example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; + + std::cout << "Running loop_erased_random_paths function template on "; + std::cout << "undirected graph." << std::endl; + loop_erased_random_paths_example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; + +#ifdef BOOST_SANDBOX_LERP_SPECIAL + std::cout << "Running specialized loop_erased_random_paths function "; + std::cout << "template on undirected graph." << std::endl; + loop_erased_random_paths_specialized_example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; +#endif + + std::cout << "Running dijkstra_random_paths function template on "; + std::cout << "directed graph." << std::endl; + dijkstra_random_paths_example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; + + std::cout << "Running ddnw_random_paths function template on "; + std::cout << "directed graph." << std::endl; + ddnw_random_paths_example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; + + std::cout << "Running loop_erased_random_paths function template on "; + std::cout << "directed graph." << std::endl; + loop_erased_random_paths_example( + start_index, end_index, max_weight, num_runs); +} + +template +void vec_adjacency_list_example(const unsigned int start_index, + const unsigned int end_index, + const unsigned int max_weight, + const unsigned int num_runs) +{ + typedef boost::adjacency_list< + EdgeContainerSelector,boost::vecS,boost::undirectedS, + boost::no_property,boost::property, + boost::no_property> + UndirectedGraph; + typedef boost::adjacency_list< + EdgeContainerSelector,boost::vecS,boost::directedS, + boost::no_property,boost::property, + boost::no_property> + DirectedGraph; + typedef boost::adjacency_list< + EdgeContainerSelector,boost::vecS,boost::bidirectionalS, + boost::no_property,boost::property, + boost::no_property> + BidirectionalGraph; + + example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; + + std::cout << "Running dijkstra_random_paths function template on "; + std::cout << "bidirectional graph." << std::endl; + dijkstra_random_paths_example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; + + std::cout << "Running ddnw_random_paths function template on "; + std::cout << "bidirectional graph." << std::endl; + ddnw_random_paths_example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; + + std::cout << "Running loop_erased_random_paths function template on "; + std::cout << "bidirectional graph." << std::endl; + loop_erased_random_paths_example( + start_index, end_index, max_weight, num_runs); + +#ifdef BOOST_SANDBOX_LERP_SPECIAL + std::cout << "Running specialized loop_erased_random_paths function "; + std::cout << "template on bidirectional graph." << std::endl; + loop_erased_random_paths_specialized_example( + start_index, end_index, max_weight, num_runs); + std::cout << std::endl; +#endif +} + +template +void adjacency_matrix_example(const unsigned int start_index, + const unsigned int end_index, + const unsigned int max_weight, + const unsigned int num_runs) +{ + typedef boost::adjacency_matrix< + boost::undirectedS,boost::no_property, + boost::property,boost::no_property> + UndirectedGraph; + typedef boost::adjacency_matrix< + boost::directedS,boost::no_property, + boost::property,boost::no_property> + DirectedGraph; + + example( + start_index, end_index, max_weight, num_runs); +} + +int usage() +{ + std::cout << "Options:" << std::endl; + std::cout << "-s#, where # is an integer between 0 and 23, inclusive"; + std::cout << " (default is 0)" << std::endl; + std::cout << "-e#, where # is an integer between 0 and 23, inclusive"; + std::cout << " (default is 22)" << std::endl; + std::cout << "-m#, where # is an integer between 0 and 65536, inclusive"; + std::cout << " (default is 16384)" << std::endl; + std::cout << "-n#, where # is a nonnegative integer"; + std::cout << " (default is 256)" << std::endl; + return 0; +} + +int main(int argc, char** argv) +{ + unsigned int start_index = 0; + unsigned int end_index = 22; + unsigned int max_weight = 16384; + unsigned int num_runs = 256; + char* arg; + + while (--argc > 0) + { + arg = argv[argc]; + + if ((std::strlen(arg) > 2) && (arg[0] == '-')) + { + switch (arg[1]) + { + case 's': + start_index = std::atoi(&arg[2]); + + if (start_index > 23) + { + return usage(); + } + + break; + + case 'e': + end_index = std::atoi(&arg[2]); + + if (end_index > 23) + { + return usage(); + } + + break; + + case 'm': + max_weight = std::atoi(&arg[2]); + + if (max_weight > 65536) + { + return usage(); + } + + break; + + case 'n': + num_runs = std::atoi(&arg[2]); + break; + + default: + return usage(); + } + } + else + { + return usage(); + } + } + +// adjacency_matrix_example( +// vec_adjacency_list_example( +// vec_adjacency_list_example( +// vec_adjacency_list_example( + vec_adjacency_list_example( + start_index, end_index, max_weight, num_runs); + + return 0; +} + diff --git a/example/tarjan_offline_lca.cpp b/example/tarjan_offline_lca.cpp new file mode 100644 index 00000000..6c35a401 --- /dev/null +++ b/example/tarjan_offline_lca.cpp @@ -0,0 +1,77 @@ +/* tarjan_offline_lca.cpp source file + * + * Copyright 2004 Cromwell D. Enage. Covered by the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +/* + * Defines the std::ios class and std::cout, its global output instance. + */ +#include + +/* + * Defines the boost::numeric::ublas::matrix class template. + */ +#include + +/* + * Defines the boost::print_graph function template. + */ +#include + +/* + * Defines the boost::adjacency_list class template and its associated nonmember + * function templates. + */ +#include + +/* + * Defines the boost::tarjan_offline_lca function template. + */ +#include + +int main() +{ + typedef boost::adjacency_list<> Graph; + + const int vertex_count = 15; + + Graph g(vertex_count); + + boost::add_edge(0, 1, g); + boost::add_edge(0, 2, g); + boost::add_edge(1, 3, g); + boost::add_edge(1, 4, g); + boost::add_edge(2, 5, g); + boost::add_edge(2, 6, g); + boost::add_edge(3, 7, g); + boost::add_edge(3, 8, g); + boost::add_edge(4, 9, g); + boost::add_edge(4, 10, g); + boost::add_edge(5, 11, g); + boost::add_edge(5, 12, g); + boost::add_edge(6, 13, g); + boost::add_edge(6, 14, g); + + std::cout << "Input graph:" << std::endl; + boost::print_graph(g); + std::cout << std::endl; + + boost::numeric::ublas::matrix + ancestor_matrix(vertex_count, vertex_count); + + boost::tarjan_offline_lca(g, 0, ancestor_matrix); + + for (int i = 0; i < vertex_count; ++i) + { + for (int j = 0; j < vertex_count; ++j) + { + std::cout << "Least common ancestor of " << i << " and " << j; + std::cout << " is " << ancestor_matrix(i, j) << std::endl; + } + } + + return 0; +} + diff --git a/include/boost/graph/ddnw_random_paths.hpp b/include/boost/graph/ddnw_random_paths.hpp new file mode 100644 index 00000000..2c1c8274 --- /dev/null +++ b/include/boost/graph/ddnw_random_paths.hpp @@ -0,0 +1,506 @@ +/* boost/graph/ddnw_random_paths.hpp header file + * + * Copyright 2004 Cromwell D. Enage. Covered by the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef BOOST_GRAPH_DDNW_RANDOM_PATHS_HPP +#define BOOST_GRAPH_DDNW_RANDOM_PATHS_HPP + +/* + * Defines the std::vector class template. + */ +#include + +/* + * Defines the std::map class template. + */ +#include + +/* + * Defines the std::numeric_limits class template. + */ +#include + +/* + * Defines the boost::function_requires function template and the basic concept + * check templates. + */ +#include + +/* + * Defines the boost::property_traits and boost::associative_property_map class + * templates and the boost::get and boost::put function templates. + */ +#include + +/* + * Defines the boost::tie function template. + */ +#include + +/* + * Defines the BGL concept check templates. + */ +#include + +/* + * Defines the boost::graph_traits class template and the boost::directed_tag + * property tag. + */ +#include + +/* + * Defines the vertex and edge property tags. + */ +#include + +/* + * Defines the boost::null_visitor class. + */ +#include + +/* + * Defines the boost::dag_shortest_paths and boost::make_dijkstra_visitor + * function templates. + */ +#include + +/* + * Defines the boost::bgl_named_params class template and its helper function + * templates. + */ +#include + +/* + * The graph type and its associated non-member function templates must be + * defined externally. + */ +//#include + +/* + * Defines the boost::dijkstra_random_paths function template. + */ +#include + +namespace boost { + + namespace detail { + + /* + * This visitor class copies edges that were either relaxed or not relaxed + * as a result dijkstra_shortest_paths (i.e. tree edges and edges + * with gray targets, or forward and cross edges) from the input graph to + * the utility graph, but negates the corresponding weights. + */ + template + class mrp_edge_copier : + public base_visitor< + mrp_edge_copier > + { + public: + typedef EventFilter event_filter; + + private: + UtilGraph& m_dag; + InputIndexMap m_index_map; + NegateFunctor m_negate; + + public: + mrp_edge_copier(UtilGraph& dag, InputIndexMap index_map, + NegateFunctor negate = NegateFunctor()) : + m_dag(dag), m_index_map(index_map), m_negate(negate) + { + } + + ~mrp_edge_copier() + { + } + + template + void operator()( + typename graph_traits::edge_descriptor e, Graph& g) + { + typename graph_traits::edge_descriptor edge; + bool created_edge; + + tie(edge, created_edge) = + add_edge( + vertex(get(m_index_map, source(e, g)), m_dag), + vertex(get(m_index_map, target(e, g)), m_dag), + m_dag); + + if (created_edge) + { + put(get(edge_weight_t(), m_dag), edge, + m_negate(get(get(edge_weight_t(), g), e))); + } + } + }; + } // namespace detail + +/* + * The kitchen-sink variant. + */ +template +void ddnw_random_paths( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, OutputPredecessorMap out_pred_map, + InputDistanceMap in_dist_map, InputIndexMap in_index_map, + InputColorMap in_color_map, CompareFunctor compare, CombineFunctor combine, + DistanceInfinity infinity, DistanceZero zero, InputEventVisitorList in_vis, + UtilGraph& dag, UtilPredecessorMap u_pred_map, UtilDistanceMap u_dist_map, + UtilIndexMap u_index_map, UtilColorMap u_color_map, + UtilEventVisitorList dag_vis) +{ + function_requires< + VertexAndEdgeListGraphConcept >(); + typedef typename graph_traits::vertex_descriptor + InputVertex; + function_requires< + ReadWritePropertyMapConcept >(); + function_requires< + ReadWritePropertyMapConcept >(); + typedef typename property_map::type + InputWeightMap; + typedef typename property_traits::value_type + InputWeight; + typedef typename property_traits::value_type + InputDistance; + function_requires< + ConvertibleConcept >(); + function_requires< + ConvertibleConcept >(); + function_requires< + ConvertibleConcept >(); + function_requires< + ReadablePropertyMapConcept >(); + function_requires< + ReadWritePropertyMapConcept >(); + function_requires< + VertexAndEdgeListGraphConcept >(); + function_requires< + EdgeMutableGraphConcept >(); + typedef typename graph_traits::directed_category + DirectedCategory; + function_requires< + ConvertibleConcept >(); + typedef typename graph_traits::vertex_descriptor + UtilVertex; + function_requires< + ReadWritePropertyMapConcept >(); + function_requires< + ReadWritePropertyMapConcept >(); + typedef typename property_map::type + UtilWeightMap; + typedef typename property_traits::value_type + UtilWeight; + typedef typename property_traits::value_type + UtilDistance; + function_requires< + ConvertibleConcept >(); + function_requires< + ConvertibleConcept >(); + function_requires< + ConvertibleConcept >(); + function_requires< + ReadablePropertyMapConcept >(); + function_requires< + ReadWritePropertyMapConcept >(); + typedef typename property_traits::value_type + IndexValue; + typedef detail::mrp_edge_copier > + RelaxedEdgeVisitor; + typedef detail::mrp_edge_copier > + NonRelaxedEdgeVisitor; + typedef dijkstra_visitor< + std::pair > > + DVisitor; + + /* + * For the utility graph, make copies of only the forward and cross edges + * with respect to a random traversal from the source vertex. + */ + RelaxedEdgeVisitor re_vis(dag, in_index_map); + NonRelaxedEdgeVisitor nre_vis(dag, in_index_map); + DVisitor d_vis(std::make_pair(re_vis, std::make_pair(nre_vis, in_vis))); + + dijkstra_random_paths( + in_g, source, random_weight, out_pred_map, in_dist_map, in_index_map, + in_color_map, compare, combine, infinity, zero, d_vis); + + /* + * The utility graph should now be a directed acyclic graph. + * Run the longest simple path algorithm on it. + */ + dag_shortest_paths( + dag, source, u_dist_map, get(edge_weight_t(), dag), + u_color_map, u_pred_map, make_dijkstra_visitor(dag_vis), + compare, combine, infinity, zero); + + /* + * The resulting paths will be stored in the utility predecessor map. + * Copy its contents into the output predecessor map. + * + * TODO: + * 1. Don't execute this code if in_index_map and u_index_map refer to + * the same object. + */ + typename graph_traits::vertex_descriptor in_source, in_target; + typename graph_traits::vertex_iterator u_vi, u_vend; + + for (tie(u_vi, u_vend) = vertices(dag); u_vi != u_vend; ++u_vi) + { + in_source = vertex(get(u_index_map, *u_vi), in_g); + in_target = vertex(get(u_index_map, get(u_pred_map, *u_vi)), in_g); + put(out_pred_map, in_source, in_target); + clear_vertex(*u_vi, dag); + } +} + + namespace detail { + + template + void ddnw_random_paths_dispatch( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, + OutputPredecessorMap out_pred_map, InputDistanceMap in_d_map, + InputIndexMap in_index_map, InputColorMap in_color_map, UtilGraph& dag, + UtilDistanceMap u_d_map, UtilIndexMap u_index_map, + UtilColorMap u_color_map, const bgl_named_params in_params, + const bgl_named_params& u_params) + { + // Default for utility predecessor map. + typedef typename property_traits::value_type + Distance; + typedef typename graph_traits::vertex_descriptor + UtilVertex; + typedef std::map + UtilVertexMap; + typedef associative_property_map + UtilPredecessorMap; + + UtilVertexMap u_v_map; + UtilPredecessorMap u_pred_map(u_v_map); + null_visitor n_vis; + + ddnw_random_paths( + in_g, source, random_weight, out_pred_map, + in_d_map, in_index_map, in_color_map, + choose_param( + get_param(in_params, distance_compare_t()), + std::less()), + choose_param( + get_param(in_params, distance_combine_t()), + closed_plus()), + choose_param( + get_param(in_params, distance_inf_t()), + std::numeric_limits::max()), + choose_param( + get_param(in_params, distance_zero_t()), + Distance()), + choose_param( + get_param(in_params, graph_visitor_t()), + n_vis), + dag, + choose_param( + get_param(u_params, vertex_predecessor_t()), + u_pred_map), + u_d_map, u_index_map, u_color_map, + choose_param( + get_param(u_params, graph_visitor_t()), + n_vis)); + } + + template + void ddnw_random_paths_dispatch2( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, + OutputPredecessorMap out_pred_map, InputDistanceMap in_d_map, + InputIndexMap in_index_map, InputColorMap in_color_map, UtilGraph& dag, + UtilDistanceMap u_d_map, UtilIndexMap u_index_map, + UtilColorMap u_color_map, const bgl_named_params in_params, + const bgl_named_params& u_params) + { + // Defaults for distance maps. + typedef typename property_map::type + WeightMap; + typedef typename property_traits::value_type + Distance; + + const Distance zero = choose_param( + get_param(in_params, distance_zero_t()), + Distance()); + + std::vector in_dist_map( + is_default_param(in_d_map) ? num_vertices(in_g) : 1); + std::vector u_dist_map( + is_default_param(u_d_map) ? num_vertices(dag) : 1); + + ddnw_random_paths_dispatch( + in_g, source, random_weight, out_pred_map, + choose_param( + in_d_map, + make_iterator_property_map( + in_dist_map.begin(), in_index_map, zero)), + in_index_map, in_color_map, dag, + choose_param( + u_d_map, + make_iterator_property_map( + u_dist_map.begin(), u_index_map, zero)), + u_index_map, u_color_map, in_params, u_params); + } + + template + void ddnw_random_paths_dispatch3( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, + OutputPredecessorMap out_pred_map, InputDistanceMap in_d_map, + InputIndexMap in_index_map, InputColorMap in_c_map, UtilGraph& dag, + UtilDistanceMap u_d_map, UtilIndexMap u_index_map, + UtilColorMap u_c_map, const bgl_named_params in_params, + const bgl_named_params& u_params) + { + // Default for color maps. + std::vector in_color_map(num_vertices(in_g)); + std::vector u_color_map(num_vertices(dag)); + + ddnw_random_paths_dispatch2( + in_g, source, random_weight, out_pred_map, in_d_map, in_index_map, + choose_param( + in_c_map, + make_iterator_property_map( + in_color_map.begin(), in_index_map, white_color)), + dag, u_d_map, u_index_map, + choose_param( + u_c_map, + make_iterator_property_map( + u_color_map.begin(), u_index_map, white_color)), + in_params, u_params); + } + } // namespace detail + +/* + * The named parameter variant. There are two named parameters because + * there are two graph parameters. + */ +template +void ddnw_random_paths( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, UtilGraph& dag, + const bgl_named_params in_params, + const bgl_named_params& u_params) +{ + detail::ddnw_random_paths_dispatch3( + in_g, source, random_weight, + choose_pmap( + get_param(in_params, vertex_predecessor_t()), in_g, + vertex_predecessor_t()), + get_param(in_params, vertex_distance_t()), + choose_const_pmap( + get_param(in_params, vertex_index_t()), in_g, + vertex_index_t()), + get_param(in_params, vertex_color_t()), + dag, + get_param(u_params, vertex_distance_t()), + choose_const_pmap( + get_param(u_params, vertex_index_t()), dag, + vertex_index_t()), + get_param(u_params, vertex_color_t()), + in_params, u_params); +} + +/* + * The default variant. + */ +template +void ddnw_random_paths( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, OutputPredecessorMap out_pred_map, + UtilGraph& dag) +{ + typedef typename property_map::type + InputIndexMap; + typedef typename property_map::type + UtilIndexMap; + typedef typename property_map::type + WeightMap; + typedef typename property_traits::value_type + Distance; + typedef typename graph_traits::vertex_descriptor + UtilVertex; + typedef std::map + UtilVertexMap; + typedef associative_property_map + UtilPredecessorMap; + + const Distance zero = Distance(); + const typename graph_traits::vertices_size_type + n = num_vertices(in_g); + + UtilVertexMap u_v_map; + UtilPredecessorMap u_pred_map(u_v_map); + null_visitor n_vis; + std::vector in_color_map(n); + std::vector u_color_map(n); + std::vector in_dist_map(n); + std::vector u_dist_map(n); + + InputIndexMap in_index_map = get(vertex_index_t(), in_g); + UtilIndexMap u_index_map = get(vertex_index_t(), dag); + + ddnw_random_paths( + in_g, source, random_weight, out_pred_map, + make_iterator_property_map(in_dist_map.begin(), in_index_map, zero), + in_index_map, std::less(), closed_plus(), + std::numeric_limits::max(), zero, n_vis, dag, u_pred_map, + make_iterator_property_map(u_dist_map.begin(), u_index_map, zero), + u_index_map, + make_iterator_property_map(color.begin(), u_index_map, white_color), + n_vis); +} +} // namespace boost + +#endif /* BOOST_GRAPH_DDNW_RANDOM_PATHS_HPP */ + diff --git a/include/boost/graph/dijkstra_random_paths.hpp b/include/boost/graph/dijkstra_random_paths.hpp new file mode 100644 index 00000000..e6f7bef9 --- /dev/null +++ b/include/boost/graph/dijkstra_random_paths.hpp @@ -0,0 +1,222 @@ +/* boost/graph/dijkstra_random_paths.hpp header file + * + * Copyright 2004 Cromwell D. Enage. Covered by the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef BOOST_GRAPH_DIJKSTRA_RANDOM_PATHS +#define BOOST_GRAPH_DIJKSTRA_RANDOM_PATHS + +/* + * Defines the std::vector class template. + */ +#include + +/* + * Defines the std::numeric_limits class template. + */ +#include + +/* + * Defines the boost::property_traits class template and the boost::get and + * boost::put function templates. + */ +#include + +/* + * Defines the boost::graph_traits class template and the boost::is_directed + * function template. + */ +#include + +/* + * Defines the vertex and edge property tags. + */ +#include + +/* + * Defines the boost::randomize_property function template. + */ +#include + +/* + * Defines the boost::dijkstra_shortest_paths and boost::make_dijkstra_visitor + * function templates. + */ +#include + +/* + * Defines the boost::bgl_named_params class template and its helper function + * templates. + */ +#include + +/* + * The graph type and its associated non-member function templates must be + * defined externally. + */ +//#include + +namespace boost { + +/* + * The kitchen-sink variant. + */ +template +void dijkstra_random_paths( + Graph& g, typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, PredecessorMap pred_map, + DistanceMap dist_map, VertexIndexMap index_map, VertexColorMap color_map, + CompareFunctor compare, CombineFunctor combine, DistanceInfinity infinity, + DistanceZero zero, EventVisitorList vis) +{ + randomize_property( + g, random_weight); +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 +// According to example code using dijkstra_shortest_paths, +// VC++ has trouble with the named parameters mechanism. + dijkstra_shortest_paths( + g, source, pred_map, dist_map, get(edge_weight_t(), g), + index_map, compare, combine, infinity, zero, vis); +#else + dijkstra_shortest_paths( + g, source, + weight_map(get(edge_weight_t(), g)). + vertex_index_map(index_map).predecessor_map(pred_map). + distance_map(dist_map).distance_compare(compare). + distance_combine(combine).distance_inf(infinity). + distance_zero(zero).color_map(color_map).visitor(vis)); +#endif +} + + namespace detail { + + template + void dijkstra_random_paths_dispatch( + Graph& g, typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, PredecessorMap pred_map, + DistanceMap d_map, VertexIndexMap index_map, VertexColorMap color_map, + const bgl_named_params& params) + { + // Default for distance map. + typedef typename property_map::type + WeightMap; + typedef typename property_traits::value_type + Distance; + + const Distance zero = choose_param( + get_param(params, distance_zero_t()), + Distance()); + + std::vector distance_map( + is_default_param(d_map) ? num_vertices(g) : 1); + + dijkstra_random_paths( + g, source, random_weight, pred_map, + choose_param( + d_map, + make_iterator_property_map( + distance_map.begin(), index_map, zero)), + index_map, color_map, + choose_param( + get_param(params, distance_compare_t()), + std::less()), + choose_param( + get_param(params, distance_combine_t()), + closed_plus()), + choose_param( + get_param(params, distance_inf_t()), + std::numeric_limits::max()), + zero, + choose_param( + get_param(params, graph_visitor_t()), + default_dijkstra_visitor())); + } + + template + void dijkstra_random_paths_dispatch2( + Graph& g, typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, PredecessorMap pred_map, + DistanceMap d_map, VertexIndexMap index_map, VertexColorMap color_map, + const bgl_named_params& params) + { + // Default for color map. + std::vector color(num_vertices(g)); + + dijkstra_random_paths_dispatch( + g, source, random_weight, pred_map, d_map, index_map, + choose_param( + color_map, + make_iterator_property_map( + color.begin(), index_map, white_color)), + params); + } + } // namespace detail + +/* + * The named parameter variant. + */ +template +void dijkstra_random_paths( + Graph& g, typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, + const bgl_named_params& params) +{ + detail::dijkstra_random_paths_dispatch2( + g, source, random_weight, + choose_pmap( + get_param(params, vertex_predecessor_t()), g, + vertex_predecessor_t()), + get_param(params, vertex_distance_t()), + choose_pmap( + get_param(params, vertex_index_t()), g, + vertex_index_t()), + get_param(params, vertex_color_t()), + params); +} + +/* + * The default variant. + */ +template +void dijkstra_random_paths( + Graph& g, typename graph_traits::vertex_descriptor source, + RandomNumberGenerator& random_weight, PredecessorMap pred_map) +{ + typedef typename property_map::type + WeightMap; + typedef typename property_traits::value_type + Distance; + + const Distance zero = Distance(); + + typename property_map::type + index_map = get(vertex_index_t(), g); + std::vector distance_map(num_vertices(g)); + std::vector color(num_vertices(g)); + + dijkstra_random_paths( + g, source, random_weight, pred_map, + make_iterator_property_map(distance_map.begin(), index_map, zero), + index_map, + make_iterator_property_map(color.begin(), index_map, white_color), + std::less(), closed_plus(), + std::numeric_limits::max(), zero, default_dijkstra_visitor()); +} +} // namespace boost + +#endif /* BOOST_GRAPH_DIJKSTRA_RANDOM_PATHS */ + diff --git a/include/boost/graph/loop_erased_random_paths.hpp b/include/boost/graph/loop_erased_random_paths.hpp new file mode 100644 index 00000000..bf0279eb --- /dev/null +++ b/include/boost/graph/loop_erased_random_paths.hpp @@ -0,0 +1,534 @@ +/* boost/graph/loop_erased_random_paths.hpp header file + * + * Copyright 2004 Cromwell D. Enage. Covered by the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef BOOST_GRAPH_LOOP_ERASED_RANDOM_PATHS_HPP +#define BOOST_GRAPH_LOOP_ERASED_RANDOM_PATHS_HPP + +/* + * Defines the std::vector class template. + */ +#include + +/* + * Defines the boost::function_requires function template and the basic concept + * check templates. + */ +#include + +/* + * Defines the boost::property_traits class template and the boost::get and + * boost::put function templates. + */ +#include + +/* + * Defines the boost::tie function template. + */ +#include + +/* + * Defines the BGL concept check templates. + */ +#include + +/* + * Defines the boost::graph_traits class template and the directed category + * tags. + */ +#include + +/* + * Defines the boost::vertex_index_t property tag. + */ +#include + +/* + * Defines the boost::bgl_named_params class template and its helper function + * templates. + */ +#include + +/* + * The graph type and its associated non-member function templates must be + * defined externally. + */ +//#include + +/* + * Defines the boost::uniform_int class template, to be used as a random-index + * distribution. + */ +#include + +/* + * Defines the boost::variate_generator class template, to be used as the + * front-end random index generator. + */ +#include + +namespace boost { + + namespace detail { + + /* + * The generic RandomSuccessor() function. + */ + template + typename graph_traits::vertex_descriptor get_random_predecessor( + typename graph_traits::vertex_descriptor v, + InputGraph& in_g, RandomIndexGenerator& rig, InputIndexMap in_index_map, + UtilGraph& u_g, UtilIndexMap u_index_map, UtilColorMap u_color_map) + { + typedef typename property_traits::value_type + UtilColorValue; + typedef color_traits + UtilColor; + + std::vector::vertex_descriptor> prev; + typename graph_traits::vertex_descriptor u = + vertex(get(in_index_map, v), u_g); + typename graph_traits::adjacency_iterator ai, aend; + + for (tie(ai, aend) = adjacent_vertices(u, u_g); ai != aend; ++ai) + { + if (get(u_color_map, *ai) == UtilColor::white()) + { + prev.push_back(*ai); + } + } + + if (prev.empty()) + { + return v; + } + + return vertex(get(u_index_map, prev[rig(prev.size())]), in_g); + } + } // namespace detail + +/* + * The generic kitchen-sink variant. + */ +template +bool loop_erased_random_paths( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map, + InputIndexMap in_index_map, InputColorMap in_color_map, UtilGraph& u_g, + UtilIndexMap u_index_map, UtilColorMap u_color_map) +{ + function_requires< + VertexListGraphConcept >(); + function_requires< + AdjacencyGraphConcept >(); + typedef graph_traits + InputGraphTraits; + typedef typename InputGraphTraits::vertex_descriptor + InputVertex; + function_requires< + ReadWritePropertyMapConcept >(); + function_requires< + ReadablePropertyMapConcept >(); + function_requires< + ReadWritePropertyMapConcept >(); + typedef typename property_traits::value_type + InputColorValue; + typedef color_traits + InputColor; + function_requires< + VertexListGraphConcept >(); + function_requires< + AdjacencyGraphConcept >(); + function_requires< + EdgeMutableGraphConcept >(); + typedef graph_traits + UtilGraphTraits; + typedef typename UtilGraphTraits::vertex_descriptor + UtilVertex; + function_requires< + ReadablePropertyMapConcept >(); + function_requires< + ReadWritePropertyMapConcept >(); + typedef typename property_traits::value_type + UtilColorValue; + typedef color_traits + UtilColor; + + typename InputGraphTraits::vertex_iterator vi, vend; + typename InputGraphTraits::adjacency_iterator ai, aend; + UtilVertex w; + + for (tie(vi, vend) = vertices(in_g); vi != vend; ++vi) + { + put(out_pred_map, *vi, *vi); + put(in_color_map, *vi, InputColor::white()); + w = vertex(get(in_index_map, *vi), u_g); + + for (tie(ai, aend) = adjacent_vertices(*vi, in_g); ai != aend; ++ai) + { + add_edge(vertex(get(in_index_map, *ai), u_g), w, u_g); + } + } + + put(in_color_map, source, InputColor::black()); + + InputVertex u, v; + typename UtilGraphTraits::vertex_iterator ui, uend; + bool is_tree = true; + + for (tie(vi, vend) = vertices(in_g); vi != vend; ++vi) + { + for (tie(ui, uend) = vertices(u_g); ui != uend; ++ui) + { + put(u_color_map, *ui, UtilColor::white()); + } + + for (v = *vi; get(in_color_map, v) == InputColor::white(); v = u) + { + put(u_color_map, get(in_index_map, v), UtilColor::black()); + u = detail::get_random_predecessor( + v, in_g, rig, in_index_map, u_g, u_index_map, u_color_map); + + if (u == v) + { + is_tree = false; + } + + put(out_pred_map, v, u); + put(in_color_map, v, InputColor::black()); + } + } + + for (tie(ui, uend) = vertices(u_g); ui != uend; ++ui) + { + clear_vertex(*ui, u_g); + } + + return is_tree; +} + + namespace detail { + + template + bool loop_erased_random_paths_dispatch( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map, + InputIndexMap in_index_map, InputColorMap in_c_map, UtilGraph& u_g, + UtilIndexMap u_index_map, UtilColorMap u_c_map, + const bgl_named_params& in_params, + const bgl_named_params& u_params) + { + // Default for color maps. + std::vector in_color_map(num_vertices(in_g)); + std::vector u_color_map(num_vertices(u_g)); + + return loop_erased_random_paths( + in_g, source, rig, out_pred_map, in_index_map, + choose_param( + in_c_map, + make_iterator_property_map( + in_color_map.begin(), in_index_map, white_color)), + u_g, u_index_map, + choose_param( + u_c_map, + make_iterator_property_map( + u_color_map.begin(), u_index_map, white_color))); + } + } // namespace detail + +/* + * The named parameter variant. + */ +template +bool loop_erased_random_paths( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomIndexGenerator& rig, UtilGraph& u_g, + const bgl_named_params& in_params, + const bgl_named_params& u_params) +{ + return detail::loop_erased_random_paths_dispatch( + in_g, source, rig, + choose_pmap( + get_param(in_params, vertex_predecessor_t()), in_g, + vertex_predecessor_t()), + choose_const_pmap( + get_param(in_params, vertex_index_t()), in_g, + vertex_index_t()), + get_param(in_params, vertex_color_t()), + u_g, + choose_const_pmap( + get_param(u_params, vertex_index_t()), u_g, + vertex_index_t()), + get_param(u_params, vertex_color_t()), + in_params, u_params); +} + +/* + * The generic default variant. + */ +template +bool loop_erased_random_paths( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map, + UtilGraph& u_g) +{ + typedef typename property_map::type + InputIndexMap; + typedef typename property_map::type + UtilIndexMap; + + std::vector in_color_map(num_vertices(in_g)); + std::vector u_color_map(num_vertices(u_g)); + + InputIndexMap in_index_map = get(vertex_index_t(), in_g); + UtilIndexMap u_index_map = get(vertex_index_t(), u_g); + + return loop_erased_random_paths( + in_g, source, rig, out_pred_map, in_index_map, + make_iterator_property_map( + in_color_map.begin(), in_index_map, white_color), + u_g, u_index_map, + make_iterator_property_map( + u_color_map.begin(), u_index_map, white_color)); +} + +#ifdef BOOST_SANDBOX_LERP_SPECIAL + namespace detail { + + /* + * The undirected-graph RandomSuccessor() function. + */ + template + typename graph_traits::vertex_descriptor get_random_predecessor( + typename graph_traits::vertex_descriptor v, + InputGraph& in_g, RandomIndexGenerator& rig, InputIndexMap in_index_map, + InputColorMap in_color_map, undirected_tag) + { + typedef typename property_traits::value_type + InputColorValue; + typedef color_traits + InputColor; + + std::vector::vertex_descriptor> prev; + typename graph_traits::adjacency_iterator ai, aend; + + /* + * In an undirected graph, there is no difference between the in-edges + * and the out-edges of a vertex. + */ + for (tie(ai, aend) = adjacent_vertices(v, in_g); ai != aend; ++ai) + { + if (get(in_color_map, *ai) == InputColor::white()) + { + prev.push_back(*ai); + } + } + + if (prev.empty()) + { + return v; + } + + return prev[rig(prev.size())]; + } + + /* + * The bidirectional-graph RandomSuccessor() function. + */ + template + typename graph_traits::vertex_descriptor get_random_predecessor( + typename graph_traits::vertex_descriptor v, + InputGraph& in_g, RandomIndexGenerator& rig, InputIndexMap in_index_map, + InputColorMap in_color_map, bidirectional_tag) + { + typedef typename property_traits::value_type + InputColorValue; + typedef color_traits + InputColor; + + std::vector::vertex_descriptor> prev; + typename graph_traits::vertex_descriptor u; + typename graph_traits::in_edge_iterator ii, iend; + + /* + * The in_edges free function is not implemented for directed graphs + * which are not bidirectional, hence the need for a utility graph. + */ + for (tie(ii, iend) = in_edges(v, in_g); ii != iend; ++ii) + { + u = source(*ii, in_g); + + if (get(in_color_map, u) == InputColor::white()) + { + prev.push_back(u); + } + } + + if (prev.empty()) + { + return v; + } + + return prev[rig(prev.size())]; + } + } // namespace detail + +/* + * This specialized kitchen-sink variant can only be used if the graph is either + * undirected or bidirectional. + */ +template +bool loop_erased_random_paths( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map, + InputIndexMap in_index_map, InputColorMap in_color_map) +{ + function_requires< + VertexListGraphConcept >(); + function_requires< + AdjacencyGraphConcept >(); + typedef graph_traits + InputGraphTraits; + typedef typename InputGraphTraits::vertex_descriptor + InputVertex; + function_requires< + ReadWritePropertyMapConcept >(); + function_requires< + ReadablePropertyMapConcept >(); + function_requires< + ReadWritePropertyMapConcept >(); + typedef typename property_traits::value_type + InputColorValue; + typedef color_traits + InputColor; + + typename InputGraphTraits::vertex_iterator ui, uend, vi, vend; + + for (tie(vi, vend) = vertices(in_g); vi != vend; ++vi) + { + put(out_pred_map, *vi, *vi); + put(in_color_map, *vi, InputColor::white()); + } + + put(in_color_map, source, InputColor::black()); + + InputVertex u, v; + bool is_tree = true; + + for (tie(vi, vend) = vertices(in_g); vi != vend; ++vi) + { + for (v = *vi; get(in_color_map, v) == InputColor::white(); v = u) + { + u = detail::get_random_predecessor( + v, in_g, rig, in_index_map, in_color_map, + InputGraphTraits::directed_category()); + + if (u == v) + { + is_tree = false; + } + + put(out_pred_map, v, u); + put(in_color_map, v, InputColor::black()); + } + } + +if (!is_tree) std::cout << " non-tree" << std::endl; + return is_tree; +} + + namespace detail { + + template + bool loop_erased_random_paths_dispatch( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map, + InputIndexMap in_index_map, InputColorMap in_c_map, + const bgl_named_params& in_params) + { + // Default for color maps. + std::vector in_color_map(num_vertices(in_g)); + + return loop_erased_random_paths( + in_g, source, rig, out_pred_map, in_index_map, + choose_param( + in_c_map, + make_iterator_property_map( + in_color_map.begin(), in_index_map, white_color))); + } + } // namespace detail + +/* + * This specialized named parameter variant can only be used if the graph is + * either undirected or bidirectional. + */ +template +bool loop_erased_random_paths( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomIndexGenerator& rig, + const bgl_named_params& in_params) +{ + return detail::loop_erased_random_paths_dispatch( + in_g, source, rig, + choose_pmap( + get_param(in_params, vertex_predecessor_t()), in_g, + vertex_predecessor_t()), + choose_const_pmap( + get_param(in_params, vertex_index_t()), in_g, + vertex_index_t()), + get_param(in_params, vertex_color_t())); +} + +/* + * This specialized default variant can only be used if the graph is either + * undirected or bidirectional. + */ +template +bool loop_erased_random_paths( + InputGraph& in_g, + typename graph_traits::vertex_descriptor source, + RandomIndexGenerator& rig, OutputPredecessorMap out_pred_map) +{ + typename property_map::type + in_index_map = get(vertex_index_t(), in_g); + std::vector in_color_map(num_vertices(in_g)); + + return loop_erased_random_paths( + in_g, source, rig, out_pred_map, in_index_map, + make_iterator_property_map( + in_color_map.begin(), in_index_map, white_color)); +} +#endif // BOOST_SANDBOX_LERP_SPECIAL +} // namespace boost + +#endif /* BOOST_GRAPH_LOOP_ERASED_RANDOM_PATHS_HPP */ + diff --git a/include/boost/graph/map_utility.hpp b/include/boost/graph/map_utility.hpp new file mode 100644 index 00000000..f9dce211 --- /dev/null +++ b/include/boost/graph/map_utility.hpp @@ -0,0 +1,76 @@ +/* boost/graph/map_utility.hpp header file + * + * Copyright 2004 Cromwell D. Enage. Covered by the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef BOOST_GRAPH_MAP_UTILITY_HPP +#define BOOST_GRAPH_MAP_UTILITY_HPP + +/* + * Defines the boost::readable_property_map_tag struct. + */ +#include + +/* + * Defines the boost::graph_traits class template. + */ +#include + +namespace boost { + +/* + * This class template encapsulates the boost::vertex() free function in the () + * and [] operators. To do so, it maintains a const reference to the underlying + * graph. + */ +template +class inverse_index_map +{ + public: + /* + * These typedefs help this class model Adaptable Unary Functor. + */ + typedef typename graph_traits::vertices_size_type + argument_type; + typedef typename graph_traits::vertex_descriptor + result_type; + + /* + * These typedefs help this class model Readable Property Map. + */ + typedef argument_type + key_type; + typedef result_type + value_type; + typedef value_type& + reference; + typedef readable_property_map_tag + category; + + private: + const VertexListGraph& m_g; + + public: + explicit inverse_index_map(const VertexListGraph& g) : m_g(g) + { + } + + inverse_index_map(const inverse_index_map& copy) : m_g(copy.m_g) + { + } + + result_type operator[](const argument_type index) const + { + return vertex(index, m_g); + } + + result_type operator()(const argument_type index) const + { + return vertex(index, m_g); + } +}; +} // namespace boost + +#endif /* BOOST_GRAPH_MAP_UTILITY_HPP */ + diff --git a/include/boost/graph/tarjan_offline_lca.hpp b/include/boost/graph/tarjan_offline_lca.hpp new file mode 100644 index 00000000..21900a99 --- /dev/null +++ b/include/boost/graph/tarjan_offline_lca.hpp @@ -0,0 +1,335 @@ +/* boost/graph/tarjan_offline_lca.hpp header file + * + * Copyright 2004 Cromwell D. Enage. Covered by the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef BOOST_GRAPH_TARJAN_OFFLINE_LCA_HPP +#define BOOST_GRAPH_TARJAN_OFFLINE_LCA_HPP + +/* + * Defines the std::pair class template and its associated std::make_pair + * function template. + */ +#include + +/* + * Defines the std::vector class template. + */ +#include + +/* + * Defines the std::map class template. + */ +#include + +/* + * Defines the boost::function_requires function template and the basic concept + * check templates. + */ +#include + +/* + * Defines the boost::associative_property_map and boost::property_traits class + * templates and the boost::get and boost::put function templates. + */ +#include + +/* + * Defines the boost::tie function template. + */ +#include + +/* + * Defines the boost::is_same class template. + */ +#include + +/* + * Defines the boost::disjoint_sets_with_storage class template. + */ +#include + +/* + * Defines the BGL concept check templates. + */ +#include + +/* + * Defines the boost::graph_traits class template. + */ +#include + +/* + * Defines the boost::vertex_index_t property tag. + */ +#include + +/* + * Defines the boost::bgl_named_params class template and its helper function + * templates. + */ +#include + +/* + * Defines the boost::base_visitor class template and the boost::null_visitor + * class. + */ +#include + +/* + * Defines the boost::depth_first_search and boost::make_dfs_visitor function + * templates. + */ +#include + +/* + * The graph type and its associated non-member function templates must be + * defined externally. + */ +//#include + +/* + * Defines the boost::inverse_index_map class template. + */ +#include + +namespace boost { + + namespace detail { + +/* + template + class tarjan_offline_lca_set_maker : + public base_visitor< + tarjan_offline_lca_set_maker > + { + public: + typedef on_discover_vertex event_filter; + + private: + DisjointSets& m_dsets; + PredecessorMap& m_ancestor_map; + + public: + explicit tarjan_offline_lca_set_maker( + DisjointSets& dsets, PredecessorMap& ancestor_map) : + m_dsets(dsets), m_ancestor_map(ancestor_map) + { + } + + template + void operator()( + typename graph_traits::vertex_descriptor u, Graph& g) + { + m_dsets.make_set(u); + put(m_ancestor_map, m_dsets.find_set(u), u); + } + }; + + template + class tarjan_offline_lca_ancestor_mapper : + public base_visitor< + tarjan_offline_lca_ancestor_mapper > + { + public: + typedef on_finish_vertex event_filter; + + private: + typedef typename property_traits::value_type + VertexColorValue; + typedef color_traits + VertexColor; + + AncestorMatrix& m_ancestor_matrix; + DisjointSets& m_dsets; + PredecessorMap& m_ancestor_map; + VertexColorMap& m_color_map; + + public: + tarjan_offline_lca_ancestor_mapper( + AncestorMatrix& ancestor_matrix, DisjointSets& dsets, + PredecessorMap& ancestor_map, VertexColorMap& color_map) : + m_ancestor_matrix(ancestor_matrix), m_dsets(dsets), + m_ancestor_map(ancestor_map), m_color_map(color_map) + { + } + + template + void operator()( + typename graph_traits::vertex_descriptor u, Graph& g) + { + typename graph_traits::adjacency_iterator ai, aend; + + for (tie(ai, aend) = adjacent_vertices(u, g); ai != aend; ++ai) + { + m_dsets.union_set(u, *ai); + put(m_ancestor_map, m_dsets.find_set(u), u); +std::cout << " union(" << u << "," << *ai << ")="; +std::cout << get(m_ancestor_map, m_dsets.find_set(u)) << std::endl; + } + + typename graph_traits::vertex_iterator vi, vend; + VertexColorValue color; + + for (tie(vi, vend) = vertices(g); vi != vend; ++vi) + { + color = get(m_color_map, *vi); + + if (color == VertexColor::gray()) + { +std::cout << " anc(" << u << ")=" << get(m_ancestor_map, m_dsets.find_set(u)); +std::cout << ", anc(" << *vi << ")=" << get(m_ancestor_map, m_dsets.find_set(*vi)) << std::endl; + // *vi == u or is an ancestor of u. + m_ancestor_matrix(u, *vi) = m_ancestor_matrix(*vi, u) = *vi; + } + else if (color == VertexColor::black()) + { +std::cout << " set(" << u << ")=" << m_dsets.find_set(u); +std::cout << ", anc(" << u << ")=" << get(m_ancestor_map, m_dsets.find_set(u)); +std::cout << ", set(" << *vi << ")=" << m_dsets.find_set(*vi); +std::cout << ", anc(" << *vi << ")=" << get(m_ancestor_map, m_dsets.find_set(*vi)) << std::endl; + // *vi and u are in different subtrees. + m_ancestor_matrix(u, *vi) = m_ancestor_matrix(*vi, u) + = get(m_ancestor_map, + m_dsets.find_set(*vi)); + } + } + } + }; +*/ + + template + void tarjan_offline_lca_impl( + const Graph& g, typename graph_traits::vertex_descriptor u, + AncestorMatrix& ancestor_matrix, DisjointSets& dsets, + PredecessorMap ancestor_map, VertexColorMap color_map) + { + typedef typename property_traits::value_type + VertexColorValue; + typedef color_traits + VertexColor; + + dsets.make_set(u); + put(ancestor_map, dsets.find_set(u), u); + + typename graph_traits::adjacency_iterator ai, aend; + + for (tie(ai, aend) = adjacent_vertices(u, g); ai != aend; ++ai) + { + tarjan_offline_lca_impl(g, *ai, ancestor_matrix, dsets, + ancestor_map, color_map); + dsets.union_set(u, *ai); + put(ancestor_map, dsets.find_set(u), u); + } + + put(color_map, u, VertexColor::black()); + + typename graph_traits::vertex_iterator vi, vend; + + for (tie(vi, vend) = vertices(g); vi != vend; ++vi) + { + if (get(color_map, *vi) == VertexColor::black()) + { + ancestor_matrix(u, *vi) = ancestor_matrix(*vi, u) + = get(ancestor_map, + dsets.find_set(*vi)); + } + } + } + } // namespace detail + +/* + * The kitchen-sink variant. + */ +template +void tarjan_offline_lca( + const Graph& g, typename graph_traits::vertex_descriptor source, + AncestorMatrix& ancestor_matrix, DisjointSets dsets, + PredecessorMap ancestor_map, VertexColorMap color_map, EventVisitorList vis) +{ + typedef graph_traits + GraphTraits; + typedef typename property_traits::value_type + VertexColorValue; + typedef color_traits + VertexColor; +/* + typedef detail::tarjan_offline_lca_set_maker + Visitor1; + typedef detail::tarjan_offline_lca_ancestor_mapper< + AncestorMatrix,DisjointSets,PredecessorMap,VertexColorMap> + Visitor2; + typedef dfs_visitor< + std::pair > > + DFSVisitor; +*/ + + typename GraphTraits::vertex_iterator vi, vend; + + for (tie(vi, vend) = vertices(g); vi != vend; ++vi) + { + put(color_map, *vi, VertexColor::white()); + } + +/* + Visitor1 vis1(dsets, ancestor_map); + Visitor2 vis2(ancestor_matrix, dsets, ancestor_map, color_map); + DFSVisitor vis0 = + make_dfs_visitor( + std::make_pair(vis1, std::make_pair(vis2, vis))); + + dsets.make_set(source); + put(ancestor_map, dsets.find_set(source), source); + depth_first_search(g, vis0, color_map, source); +*/ + tarjan_offline_lca_impl(g, source, ancestor_matrix, dsets, ancestor_map, + color_map); +} + +/* + * The default variant. + */ +template +void tarjan_offline_lca( + const Graph& g, typename graph_traits::vertex_descriptor source, + AncestorMatrix& ancestor_matrix) +{ + typedef graph_traits + GraphTraits; + typedef typename GraphTraits::vertex_descriptor + Vertex; + typedef std::map + VertexMap; + typedef boost::associative_property_map + PredecessorMap; + typedef typename property_map::type + IndexMap; + typedef inverse_index_map + InverseIndexMap; + typedef boost::disjoint_sets_with_storage + DisjointSets; + + IndexMap index_map = get(vertex_index_t(), g); + InverseIndexMap inv_index_map(g); + DisjointSets dsets(num_vertices(g), index_map, + inv_index_map); + VertexMap vert_map; + PredecessorMap ancestor_map(vert_map); + std::vector color(num_vertices(g)); + null_visitor n_vis; + + tarjan_offline_lca( + g, source, ancestor_matrix, dsets, ancestor_map, + make_iterator_property_map(color.begin(), index_map, white_color), + n_vis); +} +} // namespace boost + +#endif /* BOOST_GRAPH_TARJAN_OFFLINE_LCA_HPP */ + diff --git a/test/make_random_paths.cpp b/test/make_random_paths.cpp new file mode 100644 index 00000000..c1194237 --- /dev/null +++ b/test/make_random_paths.cpp @@ -0,0 +1,548 @@ +/* make_random_paths.cpp source file + * + * Copyright 2004 Cromwell D. Enage. Covered by the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +/* + * Defines the Boost Unit Test Framework. + */ +#include +#include +#include + +/* + * Defines the std::list class template and its iterators. + */ +#include + +/* + * Defines the std::map class template. + */ +#include + +/* + * Defines the boost::mt19937 class, to be used as a random-number-generating + * engine. + */ +#include + +/* + * Defines the boost::uniform_int class template, to be used as a random-number + * distribution. + */ +#include + +/* + * Defines the boost::variate_generator class template, to be used as the + * front-end random-number generator. + */ +#include + +/* + * Defines the boost::random_number_generator class template, to be used as the + * front-end random-index generator. + */ +#include + +/* + * Defines the boost::property_map and boost::associative_property_map class + * templates and the boost::get and boost::put function templates. + */ +#include + +/* + * Defines the boost::is_adjacent function template. + */ +#include + +/* + * Defines the boost::graph_traits class template. + */ +#include + +/* + * Defines the vertex and edge property tags. + */ +#include + +/* + * Defines the boost::directedS, boost::undirectedS, and boost::bidirectionalS + * selector tags. + */ +#include + +/* + * Defines the boost::adjacency_list class template and its associated + * non-member function templates. + */ +#include + +/* + * Defines the boost::adjacency_matrix class template and its associated + * non-member function templates. + */ +#include + +/* + * Defines the boost::dijkstra_random_paths function template. + */ +#include + +/* + * Defines the boost::ddnw_random_paths function template. + */ +#include + +/* + * Defines the boost::loop_erased_random_paths function template. + */ +#include + +using boost::unit_test_framework::test_suite; +using namespace boost; + +template +bool contains_no_edges(Graph& g) +{ + typename graph_traits::edge_iterator ei, eend; + + tie(ei, eend) = edges(g); + + return ei == eend; +} + +template +void init_graph(Graph& g) +{ + add_edge(vertex(0, g), vertex(7, g), g); + add_edge(vertex(1, g), vertex(2, g), g); + add_edge(vertex(2, g), vertex(10, g), g); + add_edge(vertex(2, g), vertex(5, g), g); + add_edge(vertex(3, g), vertex(10, g), g); + add_edge(vertex(3, g), vertex(0, g), g); + add_edge(vertex(4, g), vertex(5, g), g); + add_edge(vertex(4, g), vertex(0, g), g); + add_edge(vertex(5, g), vertex(14, g), g); + add_edge(vertex(6, g), vertex(3, g), g); + add_edge(vertex(7, g), vertex(17, g), g); + add_edge(vertex(7, g), vertex(11, g), g); + add_edge(vertex(8, g), vertex(17, g), g); + add_edge(vertex(8, g), vertex(1, g), g); + add_edge(vertex(9, g), vertex(11, g), g); + add_edge(vertex(9, g), vertex(1, g), g); + add_edge(vertex(10, g), vertex(19, g), g); + add_edge(vertex(10, g), vertex(15, g), g); + add_edge(vertex(10, g), vertex(8, g), g); + add_edge(vertex(11, g), vertex(19, g), g); + add_edge(vertex(11, g), vertex(15, g), g); + add_edge(vertex(11, g), vertex(4, g), g); + add_edge(vertex(12, g), vertex(19, g), g); + add_edge(vertex(12, g), vertex(8, g), g); + add_edge(vertex(12, g), vertex(4, g), g); + add_edge(vertex(13, g), vertex(15, g), g); + add_edge(vertex(13, g), vertex(8, g), g); + add_edge(vertex(13, g), vertex(4, g), g); + add_edge(vertex(14, g), vertex(22, g), g); + add_edge(vertex(14, g), vertex(12, g), g); + add_edge(vertex(15, g), vertex(22, g), g); + add_edge(vertex(15, g), vertex(6, g), g); + add_edge(vertex(16, g), vertex(12, g), g); + add_edge(vertex(16, g), vertex(6, g), g); + add_edge(vertex(17, g), vertex(20, g), g); + add_edge(vertex(18, g), vertex(9, g), g); + add_edge(vertex(19, g), vertex(23, g), g); + add_edge(vertex(19, g), vertex(18, g), g); + add_edge(vertex(20, g), vertex(23, g), g); + add_edge(vertex(20, g), vertex(13, g), g); + add_edge(vertex(21, g), vertex(18, g), g); + add_edge(vertex(21, g), vertex(13, g), g); + add_edge(vertex(22, g), vertex(21, g), g); + add_edge(vertex(23, g), vertex(16, g), g); +} + +template +void dijkstra_random_paths_test() +{ + typedef typename graph_traits::vertex_descriptor + Vertex; + typedef typename graph_traits::vertex_iterator + VertexIterator; + typedef std::map + VertexMap; + typedef associative_property_map + PredecessorMap; + typedef typename property_map::type + VertexIndexMap; + typedef std::list + Path; + typedef typename Path::iterator + PathIterator; + typedef uniform_int + RNGDistribution; + typedef variate_generator + RandomNumberGenerator; + + Graph g(24); + VertexIterator source_itr, source_end, target_itr, target_end; + Vertex v; + VertexMap v_map; + PredecessorMap pred_map(v_map); + VertexIndexMap index_map = get(vertex_index_t(), g); + Path path; + PathIterator pi, pi_next; + RNGEngine rng_engine; + RNGDistribution rng_distribution(0, 16384); + RandomNumberGenerator random_weight(rng_engine, rng_distribution); + + init_graph(g); + + for (tie(source_itr, source_end) = vertices(g); + source_itr != source_end; + ++source_itr) + { + dijkstra_random_paths( + g, *source_itr, random_weight, + predecessor_map(pred_map)); + + for (tie(target_itr, target_end) = vertices(g); + target_itr != target_end; + ++target_itr) + { + if (source_itr != target_itr) + { + for (v = *target_itr; + v != get(pred_map, v); + v = get(pred_map, v)) + { + path.push_front(v); + } + + path.push_front(v); + + BOOST_CHECK_MESSAGE( + v == *source_itr, + "No path from " << get(index_map, *source_itr) << " to " + << get(index_map, *target_itr)); + + pi_next = path.begin(); + + for (pi = pi_next; ++pi_next != path.end(); pi = pi_next) + { + BOOST_CHECK_MESSAGE( + (is_adjacent(g, *pi, *pi_next)), + "Path edge " << get(index_map, *pi) << "-" + << get(index_map, *pi_next) + << " not part of graph."); + } + + path.clear(); + } + } + } +} + +template +void ddnw_random_paths_test() +{ + typedef typename graph_traits::vertex_descriptor + InputVertex; + typedef typename graph_traits::vertex_iterator + InputVertexIterator; + typedef std::map + OutputVertexMap; + typedef associative_property_map + OutputPredecessorMap; + typedef typename property_map::type + VertexIndexMap; + typedef std::list + Path; + typedef typename Path::iterator + PathIterator; + typedef uniform_int + RNGDistribution; + typedef variate_generator + RandomNumberGenerator; + + InputGraph g(24); + UtilGraph dag(24); + InputVertexIterator source_itr, source_end, target_itr, target_end; + InputVertex v; + OutputVertexMap out_v_map; + OutputPredecessorMap out_pred_map(out_v_map); + VertexIndexMap index_map = get(vertex_index_t(), g); + Path path; + PathIterator pi, pi_next; + RNGEngine rng_engine; + RNGDistribution rng_distribution(0, 16384); + RandomNumberGenerator random_weight(rng_engine, rng_distribution); + + init_graph(g); + + for (tie(source_itr, source_end) = vertices(g); + source_itr != source_end; + ++source_itr) + { + BOOST_CHECK_MESSAGE( + num_vertices(dag) == num_vertices(g), + "Utility graph doesn't have the same vertex count as input graph."); + BOOST_CHECK_MESSAGE( + contains_no_edges(dag), "Utility graph contains an edge."); + + try + { + ddnw_random_paths( + g, *source_itr, random_weight, dag, + predecessor_map(out_pred_map), + vertex_index_map(get(vertex_index_t(), dag))); + } + catch (not_a_dag&) + { + BOOST_ERROR("ddnw_random_paths did not make utility graph a dag."); + continue; + } + + for (tie(target_itr, target_end) = vertices(g); + target_itr != target_end; + ++target_itr) + { + if (source_itr != target_itr) + { + for (v = *target_itr; + v != get(out_pred_map, v); + v = get(out_pred_map, v)) + { + path.push_front(v); + } + + path.push_front(v); + + BOOST_CHECK_MESSAGE( + v == *source_itr, + "No path from " << get(index_map, *source_itr) << " to " + << get(index_map, *target_itr)); + + pi_next = path.begin(); + + for (pi = pi_next; ++pi_next != path.end(); pi = pi_next) + { + BOOST_CHECK_MESSAGE( + (is_adjacent(g, *pi, *pi_next)), + "Path edge " << get(index_map, *pi) << "-" + << get(index_map, *pi_next) + << " not part of graph."); + } + + path.clear(); + } + } + } +} + +template +void loop_erased_random_paths_test() +{ + typedef typename graph_traits::vertex_descriptor + Vertex; + typedef typename graph_traits::vertex_iterator + VertexIterator; + typedef std::map + VertexMap; + typedef associative_property_map + PredecessorMap; + typedef typename property_map::type + VertexIndexMap; + typedef std::list + Path; + typedef typename Path::iterator + PathIterator; + typedef random_number_generator + RandomIndexGenerator; + + Graph g(24); + Graph u_g(24); + VertexIterator source_itr, source_end, target_itr, target_end; + Vertex v; + VertexMap v_map; + PredecessorMap pred_map(v_map); + VertexIndexMap index_map = get(vertex_index_t(), g); + Path path; + PathIterator pi, pi_next; + RNGEngine rng_engine; + RandomIndexGenerator rig(rng_engine); + + init_graph(g); + + for (tie(source_itr, source_end) = vertices(g); + source_itr != source_end; + ++source_itr) + { + BOOST_CHECK_MESSAGE( + num_vertices(u_g) == num_vertices(g), + "Utility graph doesn't have the same vertex count as input graph."); + BOOST_CHECK_MESSAGE( + contains_no_edges(u_g), "Utility graph contains an edge."); +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 +// According to example code using dijkstra_shortest_paths, +// VC++ has trouble with the named parameters mechanism. + while (!loop_erased_random_paths(g, *source_itr, rig, pred_map, u_g)); +#else + while (!loop_erased_random_paths( + g, *source_itr, rig, u_g, + predecessor_map(pred_map), + vertex_index_map(get(vertex_index_t(), u_g)))); +#endif + + for (tie(target_itr, target_end) = vertices(g); + target_itr != target_end; + ++target_itr) + { + if (source_itr != target_itr) + { + for (v = *target_itr; + v != get(pred_map, v); + v = get(pred_map, v)) + { + path.push_front(v); + } + + path.push_front(v); + + BOOST_CHECK_MESSAGE( + v == *source_itr, + "No path from " << get(index_map, *source_itr) << " to " + << get(index_map, *target_itr)); + + pi_next = path.begin(); + + for (pi = pi_next; ++pi_next != path.end(); pi = pi_next) + { + BOOST_CHECK_MESSAGE( + (is_adjacent(g, *pi, *pi_next)), + "Path edge " << get(index_map, *pi) << "-" + << get(index_map, *pi_next) + << " not part of graph."); + } + + path.clear(); + } + } + } +} + +template +void test() +{ + BOOST_MESSAGE( + "Testing dijkstra_random_paths function template on undirected graph."); + dijkstra_random_paths_test(); + + BOOST_MESSAGE( + "Testing ddnw_random_paths function template on undirected graph."); + ddnw_random_paths_test(); + + BOOST_MESSAGE( + "Testing loop_erased_random_paths function template on " << + "undirected graph."); + loop_erased_random_paths_test(); + + BOOST_MESSAGE( + "Testing dijkstra_random_paths function template on directed graph."); + dijkstra_random_paths_test(); + + BOOST_MESSAGE( + "Testing ddnw_random_paths function template on directed graph."); + ddnw_random_paths_test(); + + BOOST_MESSAGE( + "Testing loop_erased_random_paths function template on " << + "directed graph."); + loop_erased_random_paths_test(); +} + +template +void vec_adjacency_list_test() +{ + typedef adjacency_list,no_property> + UndirectedGraph; + typedef adjacency_list,no_property> + DirectedGraph; + typedef adjacency_list,no_property> + BidirectionalGraph; + + test(); + + BOOST_MESSAGE( + "Testing dijkstra_random_paths function template on bidigraph."); + dijkstra_random_paths_test(); + + BOOST_MESSAGE( + "Testing ddnw_random_paths function template on bidigraph."); + ddnw_random_paths_test(); + + BOOST_MESSAGE( + "Testing loop_erased_random_paths function template on " << + "bidigraph."); + loop_erased_random_paths_test(); +} + +template +void adjacency_matrix_test() +{ + typedef adjacency_matrix< + undirectedS,no_property,property,no_property> + UndirectedGraph; + typedef adjacency_matrix< + directedS,no_property,property,no_property> + DirectedGraph; + + test(); +} + +void vec_adjacency_list_vecS_test_case() +{ + BOOST_MESSAGE("vec_adjacency_list_test vecS"); + vec_adjacency_list_test(); +} + +void vec_adjacency_list_listS_test_case() +{ + BOOST_MESSAGE("vec_adjacency_list_test listS"); + vec_adjacency_list_test(); +} + +void vec_adjacency_list_setS_test_case() +{ + BOOST_MESSAGE("vec_adjacency_list_test setS"); + vec_adjacency_list_test(); +} + +void vec_adjacency_list_multisetS_test_case() +{ + BOOST_MESSAGE("vec_adjacency_list_test multisetS"); + vec_adjacency_list_test(); +} + +void adjacency_matrix_test_case() +{ + BOOST_MESSAGE("adjacency_matrix_test"); + adjacency_matrix_test(); +} + +test_suite* init_unit_test_suite(int argc, char** argv) +{ + test_suite* test = BOOST_TEST_SUITE("make_random_paths unit test"); + + test->add(BOOST_TEST_CASE(&vec_adjacency_list_vecS_test_case)); + test->add(BOOST_TEST_CASE(&vec_adjacency_list_listS_test_case)); + test->add(BOOST_TEST_CASE(&vec_adjacency_list_setS_test_case)); + test->add(BOOST_TEST_CASE(&vec_adjacency_list_multisetS_test_case)); + test->add(BOOST_TEST_CASE(&adjacency_matrix_test_case)); + + return test; +} + diff --git a/test/tarjan_offline_lca.cpp b/test/tarjan_offline_lca.cpp new file mode 100644 index 00000000..a7bf4e1e --- /dev/null +++ b/test/tarjan_offline_lca.cpp @@ -0,0 +1,209 @@ +/* tarjan_offline_lca.cpp source file + * + * Copyright 2004 Cromwell D. Enage. Covered by the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +/* + * Defines the Boost Unit Test Framework. + */ +#include +#include +#include + +/* + * Defines the std::map class template. + */ +#include + +/* + * Defines the boost::associative_property_map class template. + */ +#include + +/* + * Defines the boost::numeric::ublas::matrix class template. + */ +#include + +/* + * Defines the boost::graph_traits class template. + */ +#include + +/* + * Defines the graph selector tags. + */ +#include + +/* + * Defines the BGL named parameters. + */ +#include + +/* + * Defines the boost::depth_first_search and boost::make_dfs_visitor function + * templates. + */ +#include + +/* + * Defines the boost::is_descendant function template. + */ +#include + +/* + * Defines the boost::adjacency_list class template and its associated nonmember + * function templates. + */ +#include + +/* + * Defines the boost::tarjan_offline_lca function template. + */ +#include + +using boost::unit_test_framework::test_suite; +using namespace boost; + +template +void check_lca( + typename property_traits::value_type ancestor, + typename property_traits::value_type descendant1, + typename property_traits::value_type descendant2, + PredecessorMap pred_map) +{ + if (ancestor == descendant1) + { + if (ancestor != descendant2) + { + BOOST_CHECK_MESSAGE( + is_descendant(descendant2, ancestor, pred_map), + "Vertex " << descendant2 << " is not reachable from " + << ancestor << "!"); + } + } + else if (ancestor == descendant2) + { + BOOST_CHECK_MESSAGE( + is_descendant(descendant1, ancestor, pred_map), + "Vertex " << descendant1 << " is not reachable from " + << ancestor << "!"); + } + else if (is_descendant(descendant1, ancestor, pred_map)) + { + if (is_descendant(descendant2, ancestor, pred_map)) + { + typename property_traits::value_type + v = get(pred_map, descendant1); + + while (v != ancestor) + { + if (is_descendant(descendant2, v, pred_map)) + { + BOOST_ERROR("Vertex " << v << " is the lca of " + << descendant1 << " and " + << descendant2 << ", not " + << ancestor << "!"); + return; + } + + v = get(pred_map, v); + } + } + else + { + BOOST_ERROR("Vertex " << descendant2 << " is not reachable from " + << ancestor << "!"); + } + } + else + { + BOOST_ERROR("Vertex " << descendant1 << " is not reachable from " + << ancestor << "!"); + } +} + +template +void test() +{ + typedef typename graph_traits::vertex_descriptor + Vertex; + typedef std::map + VertexMap; + typedef associative_property_map + PredecessorMap; + + const int vertex_count = 15; + + Graph g(vertex_count); + + boost::add_edge(0, 1, g); + boost::add_edge(0, 2, g); + boost::add_edge(1, 3, g); + boost::add_edge(1, 4, g); + boost::add_edge(2, 5, g); + boost::add_edge(2, 6, g); + boost::add_edge(3, 7, g); + boost::add_edge(3, 8, g); + boost::add_edge(4, 9, g); + boost::add_edge(4, 10, g); + boost::add_edge(5, 11, g); + boost::add_edge(5, 12, g); + boost::add_edge(6, 13, g); + boost::add_edge(6, 14, g); + + numeric::ublas::matrix + ancestor_matrix(vertex_count, vertex_count); + + tarjan_offline_lca(g, 0, ancestor_matrix); + + VertexMap v_map; + PredecessorMap p_map(v_map); + + depth_first_search( + g, root_vertex(0). + visitor(make_dfs_visitor(record_predecessors(p_map, + on_tree_edge())))); + + for (int i = 0; i < vertex_count; ++i) + { + for (int j = 0; j < vertex_count; ++j) + { + check_lca(ancestor_matrix(i, j), i, j, p_map); + } + } +} + +/* +void undirected_graph_test_case() +{ + BOOST_MESSAGE("Testing tarjan_offline_lca using undirected graph."); + test >(); +} +*/ + +void directed_graph_test_case() +{ + BOOST_MESSAGE("Testing tarjan_offline_lca using directed graph."); + test >(); +} + +void bidirectional_graph_test_case() +{ + BOOST_MESSAGE("Testing tarjan_offline_lca using bidirectional graph."); + test >(); +} + +test_suite* init_unit_test_suite(int argc, char** argv) +{ + test_suite* test = BOOST_TEST_SUITE("tarjan_offline_lca unit test"); + +// test->add(BOOST_TEST_CASE(&undirected_graph_test_case)); + test->add(BOOST_TEST_CASE(&directed_graph_test_case)); + test->add(BOOST_TEST_CASE(&bidirectional_graph_test_case)); + + return test; +} +