Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r78030 - in trunk: boost/graph libs/graph/doc libs/graph/example libs/graph/test
From: jewillco_at_[hidden]
Date: 2012-04-16 19:12:52


Author: jewillco
Date: 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
New Revision: 78030
URL: http://svn.boost.org/trac/boost/changeset/78030

Log:
Added code and docs from #5269 (some code heavily rewritten) and removed old workarounds; fixes #5269
Added:
   trunk/libs/graph/test/undirected_dfs.cpp (contents, props changed)
Text files modified:
   trunk/boost/graph/depth_first_search.hpp | 66 ++++++++++++++++++++++++++++-----------
   trunk/boost/graph/undirected_dfs.hpp | 18 ++++++----
   trunk/boost/graph/visitors.hpp | 3 +
   trunk/libs/graph/doc/DFSVisitor.html | 9 +++++
   trunk/libs/graph/doc/depth_first_search.html | 6 +++
   trunk/libs/graph/doc/undirected_dfs.html | 8 ++++
   trunk/libs/graph/example/dfs.cpp | 12 +++++++
   trunk/libs/graph/example/dfs.expected | 6 +++
   trunk/libs/graph/test/Jamfile.v2 | 1
   trunk/libs/graph/test/dfs.cpp | 6 +++
   10 files changed, 107 insertions(+), 28 deletions(-)

Modified: trunk/boost/graph/depth_first_search.hpp
==============================================================================
--- trunk/boost/graph/depth_first_search.hpp (original)
+++ trunk/boost/graph/depth_first_search.hpp 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -21,8 +21,10 @@
 #include <boost/graph/named_function_params.hpp>
 #include <boost/ref.hpp>
 #include <boost/implicit_cast.hpp>
+#include <boost/optional.hpp>
 #include <boost/parameter.hpp>
 #include <boost/concept/assert.hpp>
+#include <boost/tti/has_member_function.hpp>
 
 #include <vector>
 #include <utility>
@@ -41,6 +43,7 @@
       vis.tree_edge(e, g);
       vis.back_edge(e, g);
       vis.forward_or_cross_edge(e, g);
+ // vis.finish_edge(e, g); // Optional for user
       vis.finish_vertex(u, g);
     }
   private:
@@ -57,6 +60,25 @@
       bool operator()(const T&, const T2&) const { return false; }
     };
 
+ BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge)
+
+ template <bool IsCallable> struct do_call_finish_edge {
+ template <typename E, typename G, typename Vis>
+ static void call_finish_edge(Vis& vis, const E& e, const G& g) {
+ vis.finish_edge(e, g);
+ }
+ };
+
+ template <> struct do_call_finish_edge<false> {
+ template <typename E, typename G, typename Vis>
+ static void call_finish_edge(Vis&, const E&, const G&) {}
+ };
+
+ template <typename E, typename G, typename Vis>
+ void call_finish_edge(Vis& vis, const E& e, const G& g) { // Only call if method exists
+ do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g);
+ }
+
 
 // Define BOOST_RECURSIVE_DFS to use older, recursive version.
 // It is retained for a while in order to perform performance
@@ -85,36 +107,35 @@
       BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<IncidenceGraph> ));
       BOOST_CONCEPT_ASSERT(( DFSVisitorConcept<DFSVisitor, IncidenceGraph> ));
       typedef typename graph_traits<IncidenceGraph>::vertex_descriptor Vertex;
+ typedef typename graph_traits<IncidenceGraph>::edge_descriptor Edge;
       BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, Vertex> ));
       typedef typename property_traits<ColorMap>::value_type ColorValue;
       BOOST_CONCEPT_ASSERT(( ColorValueConcept<ColorValue> ));
       typedef color_traits<ColorValue> Color;
       typedef typename graph_traits<IncidenceGraph>::out_edge_iterator Iter;
- typedef std::pair<Vertex, std::pair<Iter, Iter> > VertexInfo;
+ typedef std::pair<Vertex, std::pair<boost::optional<Edge>, std::pair<Iter, Iter> > > VertexInfo;
 
+ boost::optional<Edge> src_e;
       Iter ei, ei_end;
       std::vector<VertexInfo> stack;
 
       // Possible optimization for vector
       //stack.reserve(num_vertices(g));
 
- typedef typename unwrap_reference<TerminatorFunc>::type TF;
-
       put(color, u, Color::gray());
       vis.discover_vertex(u, g);
       boost::tie(ei, ei_end) = out_edges(u, g);
- // Variable is needed to workaround a borland bug.
- TF& fn = static_cast<TF&>(func);
- if (fn(u, g)) {
+ if (func(u, g)) {
           // If this vertex terminates the search, we push empty range
- stack.push_back(std::make_pair(u, std::make_pair(ei_end, ei_end)));
+ stack.push_back(std::make_pair(u, std::make_pair(boost::optional<Edge>(), std::make_pair(ei_end, ei_end))));
       } else {
- stack.push_back(std::make_pair(u, std::make_pair(ei, ei_end)));
+ stack.push_back(std::make_pair(u, std::make_pair(boost::optional<Edge>(), std::make_pair(ei, ei_end))));
       }
       while (!stack.empty()) {
         VertexInfo& back = stack.back();
         u = back.first;
- boost::tie(ei, ei_end) = back.second;
+ src_e = back.second.first;
+ boost::tie(ei, ei_end) = back.second.second;
         stack.pop_back();
         while (ei != ei_end) {
           Vertex v = target(*ei, g);
@@ -122,24 +143,28 @@
           ColorValue v_color = get(color, v);
           if (v_color == Color::white()) {
             vis.tree_edge(*ei, g);
- stack.push_back(std::make_pair(u, std::make_pair(++ei, ei_end)));
+ src_e = *ei;
+ stack.push_back(std::make_pair(u, std::make_pair(src_e, std::make_pair(++ei, ei_end))));
             u = v;
             put(color, u, Color::gray());
             vis.discover_vertex(u, g);
             boost::tie(ei, ei_end) = out_edges(u, g);
- if (fn(u, g)) {
+ if (func(u, g)) {
                 ei = ei_end;
             }
- } else if (v_color == Color::gray()) {
- vis.back_edge(*ei, g);
- ++ei;
           } else {
- vis.forward_or_cross_edge(*ei, g);
+ if (v_color == Color::gray()) {
+ vis.back_edge(*ei, g);
+ } else {
+ vis.forward_or_cross_edge(*ei, g);
+ }
+ call_finish_edge(vis, *ei, g);
             ++ei;
           }
         }
         put(color, u, Color::black());
         vis.finish_vertex(u, g);
+ if (src_e) call_finish_edge(vis, src_e.get(), g);
       }
     }
 
@@ -164,10 +189,7 @@
 
       put(color, u, Color::gray()); vis.discover_vertex(u, g);
 
- typedef typename unwrap_reference<TerminatorFunc>::type TF;
- // Variable is needed to workaround a borland bug.
- TF& fn = static_cast<TF&>(func);
- if (!fn(u, g))
+ if (!func(u, g))
         for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
           Vertex v = target(*ei, g); vis.examine_edge(*ei, g);
           ColorValue v_color = get(color, v);
@@ -175,6 +197,7 @@
           depth_first_visit_impl(g, v, vis, color, func);
           } else if (v_color == Color::gray()) vis.back_edge(*ei, g);
           else vis.forward_or_cross_edge(*ei, g);
+ call_finish_edge(vis, *ei, g);
         }
       put(color, u, Color::black()); vis.finish_vertex(u, g);
     }
@@ -259,6 +282,10 @@
     void forward_or_cross_edge(Edge u, const Graph& g) {
       invoke_visitors(m_vis, u, g, ::boost::on_forward_or_cross_edge());
     }
+ template <class Edge, class Graph>
+ void finish_edge(Edge u, const Graph& g) {
+ invoke_visitors(m_vis, u, g, ::boost::on_finish_edge());
+ }
     template <class Vertex, class Graph>
     void finish_vertex(Vertex u, const Graph& g) {
       invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
@@ -271,6 +298,7 @@
     BOOST_GRAPH_EVENT_STUB(on_tree_edge,dfs)
     BOOST_GRAPH_EVENT_STUB(on_back_edge,dfs)
     BOOST_GRAPH_EVENT_STUB(on_forward_or_cross_edge,dfs)
+ BOOST_GRAPH_EVENT_STUB(on_finish_edge,dfs)
     BOOST_GRAPH_EVENT_STUB(on_finish_vertex,dfs)
 
   protected:

Modified: trunk/boost/graph/undirected_dfs.hpp
==============================================================================
--- trunk/boost/graph/undirected_dfs.hpp (original)
+++ trunk/boost/graph/undirected_dfs.hpp 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -46,18 +46,18 @@
       typedef color_traits<ColorValue> Color;
       typedef color_traits<EColorValue> EColor;
       typedef typename graph_traits<IncidenceGraph>::out_edge_iterator Iter;
- typedef std::pair<Vertex, std::pair<Iter, Iter> > VertexInfo;
+ typedef std::pair<Vertex, std::pair<boost::optional<Edge>, std::pair<Iter, Iter> > > VertexInfo;
 
       std::vector<VertexInfo> stack;
 
       put(vertex_color, u, Color::gray());
       vis.discover_vertex(u, g);
- stack.push_back(std::make_pair(u, out_edges(u, g)));
+ stack.push_back(std::make_pair(u, std::make_pair(boost::optional<Edge>(), out_edges(u, g))));
       while (!stack.empty()) {
         VertexInfo& back = stack.back();
         u = back.first;
- Iter ei, ei_end;
- boost::tie(ei, ei_end) = back.second;
+ boost::optional<Edge> src_e = back.second.first;
+ Iter ei = back.second.second.first, ei_end = back.second.second.second;
         stack.pop_back();
         while (ei != ei_end) {
           Vertex v = target(*ei, g);
@@ -67,20 +67,24 @@
           put(edge_color, *ei, EColor::black());
           if (v_color == Color::white()) {
             vis.tree_edge(*ei, g);
- stack.push_back(std::make_pair(u, std::make_pair(++ei, ei_end)));
+ src_e = *ei;
+ stack.push_back(std::make_pair(u, std::make_pair(src_e, std::make_pair(++ei, ei_end))));
             u = v;
             put(vertex_color, u, Color::gray());
             vis.discover_vertex(u, g);
             boost::tie(ei, ei_end) = out_edges(u, g);
           } else if (v_color == Color::gray()) {
             if (uv_color == EColor::white()) vis.back_edge(*ei, g);
+ call_finish_edge(vis, *ei, g);
             ++ei;
           } else { // if (v_color == Color::black())
+ call_finish_edge(vis, *ei, g);
             ++ei;
           }
         }
         put(vertex_color, u, Color::black());
         vis.finish_vertex(u, g);
+ if (src_e) call_finish_edge(vis, src_e.get(), g);
       }
     }
 
@@ -119,6 +123,7 @@
           undir_dfv_impl(g, v, vis, vertex_color, edge_color);
         } else if (v_color == Color::gray() && uv_color == EColor::white())
                                              vis.back_edge(*ei, g);
+ call_finish_edge(vis, *ei, g);
       }
       put(vertex_color, u, Color::black()); vis.finish_vertex(u, g);
     }
@@ -219,8 +224,7 @@
   undirected_dfs(const Graph& g,
                  const bgl_named_params<P, T, R>& params)
   {
- typedef typename get_param_type< bgl_named_params<P, T, R>,
- vertex_color_t>::type C;
+ typedef typename get_param_type< vertex_color_t, bgl_named_params<P, T, R> >::type C;
     detail::udfs_dispatch<C>::apply
       (g,
        choose_param(get_param(params, graph_visitor),

Modified: trunk/boost/graph/visitors.hpp
==============================================================================
--- trunk/boost/graph/visitors.hpp (original)
+++ trunk/boost/graph/visitors.hpp 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -44,7 +44,7 @@
       on_discover_vertex_num, on_finish_vertex_num, on_examine_vertex_num,
       on_examine_edge_num, on_tree_edge_num, on_non_tree_edge_num,
       on_gray_target_num, on_black_target_num,
- on_forward_or_cross_edge_num, on_back_edge_num,
+ on_forward_or_cross_edge_num, on_back_edge_num, on_finish_edge_num,
       on_edge_relaxed_num, on_edge_not_relaxed_num,
       on_edge_minimized_num, on_edge_not_minimized_num
     };
@@ -75,6 +75,7 @@
   struct on_forward_or_cross_edge {
     enum { num = detail::on_forward_or_cross_edge_num }; };
   struct on_back_edge { enum { num = detail::on_back_edge_num }; };
+ struct on_finish_edge { enum { num = detail::on_finish_edge_num }; };
 
   struct on_edge_relaxed { enum { num = detail::on_edge_relaxed_num }; };
   struct on_edge_not_relaxed {

Modified: trunk/libs/graph/doc/DFSVisitor.html
==============================================================================
--- trunk/libs/graph/doc/DFSVisitor.html (original)
+++ trunk/libs/graph/doc/DFSVisitor.html 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -150,6 +150,15 @@
 </tr>
 
 <tr>
+<td>Finish Edge</td>
+<td><tt>vis.finish_edge(e, g)</tt></td>
+<td><tt>void</tt></td>
+<td>
+This is invoked on each non-tree edge as well as on each tree edge after
+<tt>finish_vertex</tt> has been called on its target vertex.</td>
+</tr>
+
+<tr>
 <td>Finish Vertex</td>
 <td><tt>vis.finish_vertex(u, g)</tt></td>
 <td><tt>void</tt></td>

Modified: trunk/libs/graph/doc/depth_first_search.html
==============================================================================
--- trunk/libs/graph/doc/depth_first_search.html (original)
+++ trunk/libs/graph/doc/depth_first_search.html 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -107,6 +107,7 @@
       <i>...</i>
     <b>else if</b> (<i>color[v] =</i> BLACK)
       <i>...</i>
+ <i>...</i>
   <b>end for</b>
   <i>color[u] :=</i> BLACK
   <i>f_time[u] := time := time + 1</i>
@@ -140,6 +141,8 @@
 -
 <i>(u,v)</i> is a cross or forward edge
 -
+finish edge <i>(u,v)</i>
+-
 finish vertex <i>u</i>
 -
 </pre>
@@ -266,6 +269,9 @@
 <li><b><tt>vis.forward_or_cross_edge(e, g)</tt></b> is invoked on
   forward or cross edges in the graph. In an undirected graph this
   method is never called.
+
+<li><b><tt>vis.finish_edge(e, g)</tt></b> is invoked on the non-tree edges in
+ the graph as well as on each tree edge after its target vertex is finished.
   
 <li><b><tt>vis.finish_vertex(u, g)</tt></b> is invoked on a vertex after
   all of its out edges have been added to the search tree and all of

Modified: trunk/libs/graph/doc/undirected_dfs.html
==============================================================================
--- trunk/libs/graph/doc/undirected_dfs.html (original)
+++ trunk/libs/graph/doc/undirected_dfs.html 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -7,7 +7,7 @@
      http://www.boost.org/LICENSE_1_0.txt)
   -->
 <Head>
-<Title>Boost Graph Library: Depth-First Search</Title>
+<Title>Boost Graph Library: Undirected Depth-First Search</Title>
 <BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
         ALINK="#ff0000">
 <IMG SRC="../../../boost.png"
@@ -116,6 +116,7 @@
       <b>call</b> DFS-VISIT(<i>G</i>, <i>v</i>)
     <b>else if</b> (<i>vcolor[v] =</i> GRAY and <i>ec =</i> WHITE)
       <i>...</i>
+ <i>...</i>
   <b>end for</b>
   <i>vcolor[u] :=</i> BLACK
   <i>f_time[u] := time := time + 1</i>
@@ -152,6 +153,8 @@
 <i>(u,v)</i> is a back edge
 -
 -
+finish edge <i>(u,v)</i>
+-
 finish vertex <i>u</i>
 -
 </pre>
@@ -291,6 +294,9 @@
 <li><b><tt>vis.back_edge(e, g)</tt></b> is invoked on the back edges in
   the graph.
 
+<li><b><tt>vis.finish_edge(e, g)</tt></b> is invoked on the back edges in
+ the graph as well as on each tree edge after its target vertex is finished.
+
 <li><b><tt>vis.finish_vertex(u, g)</tt></b> is invoked on a vertex after
   all of its out edges have been added to the search tree and all of
   the adjacent vertices have been discovered (but before their

Modified: trunk/libs/graph/example/dfs.cpp
==============================================================================
--- trunk/libs/graph/example/dfs.cpp (original)
+++ trunk/libs/graph/example/dfs.cpp 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -27,12 +27,18 @@
   Tree edge: 0 --> 2
   Tree edge: 2 --> 1
   Back edge: 1 --> 1
+ Finish edge: 1 --> 1
   Tree edge: 1 --> 3
   Back edge: 3 --> 1
+ Finish edge: 3 --> 1
   Tree edge: 3 --> 4
   Back edge: 4 --> 0
+ Finish edge: 4 --> 0
   Back edge: 4 --> 1
+ Finish edge: 4 --> 1
   Forward or cross edge: 2 --> 3
+ Finish edge: 2 --> 3
+ Finish edge: 0 --> 2
   1 10
   3 8
   2 9
@@ -69,6 +75,12 @@
          << " --> " << target(e, G) << endl;
     Base::forward_or_cross_edge(e, G);
   }
+ template <class Edge, class Graph>
+ void finish_edge(Edge e, Graph& G) {
+ cout << "Finish edge: " << source(e, G) <<
+ " --> " << target(e, G) << endl;
+ Base::finish_edge(e, G);
+ }
 };
 template <class VisitorList>
 edge_categorizer<VisitorList>

Modified: trunk/libs/graph/example/dfs.expected
==============================================================================
--- trunk/libs/graph/example/dfs.expected (original)
+++ trunk/libs/graph/example/dfs.expected 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -1,12 +1,18 @@
 Tree edge: 0 --> 2
 Tree edge: 2 --> 1
 Back edge: 1 --> 1
+Finish edge: 1 --> 1
 Tree edge: 1 --> 3
 Back edge: 3 --> 1
+Finish edge: 3 --> 1
 Tree edge: 3 --> 4
 Back edge: 4 --> 0
+Finish edge: 4 --> 0
 Back edge: 4 --> 1
+Finish edge: 4 --> 1
 Forward or cross edge: 2 --> 3
+Finish edge: 2 --> 3
+Finish edge: 0 --> 2
 1 10
 3 8
 2 9

Modified: trunk/libs/graph/test/Jamfile.v2
==============================================================================
--- trunk/libs/graph/test/Jamfile.v2 (original)
+++ trunk/libs/graph/test/Jamfile.v2 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -43,6 +43,7 @@
     [ run csr_graph_test.cpp : : : : : <variant>release ]
     [ run dag_longest_paths.cpp ]
     [ run dfs.cpp ../../test/build//boost_test_exec_monitor ]
+ [ run undirected_dfs.cpp ../../test/build//boost_test_exec_monitor ]
     [ compile dfs_cc.cpp ]
     [ compile dijkstra_cc.cpp ]
     [ run dijkstra_heap_performance.cpp : 10000 ]

Modified: trunk/libs/graph/test/dfs.cpp
==============================================================================
--- trunk/libs/graph/test/dfs.cpp (original)
+++ trunk/libs/graph/test/dfs.cpp 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -68,6 +68,12 @@
     using namespace boost;
     BOOST_CHECK( get(m_color, target(e, g)) == Color::black() );
   }
+ template <class Edge, class Graph>
+ void finish_edge(Edge e, Graph& g) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, target(e, g)) == Color::gray() ||
+ get(m_color, target(e, g)) == Color::black() );
+ }
   template <class Vertex, class Graph>
   void finish_vertex(Vertex u, Graph&) {
     using namespace boost;

Added: trunk/libs/graph/test/undirected_dfs.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/graph/test/undirected_dfs.cpp 2012-04-16 19:12:50 EDT (Mon, 16 Apr 2012)
@@ -0,0 +1,187 @@
+//=======================================================================
+// Copyright 2001 University of Notre Dame.
+// Author: Jeremy G. Siek
+//
+// Distributed under 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)
+//=======================================================================
+
+#include <boost/config.hpp>
+#include <boost/test/minimal.hpp>
+#include <stdlib.h>
+
+#include <boost/graph/undirected_dfs.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/graph_archetypes.hpp>
+#include <boost/graph/graph_utility.hpp>
+#include <boost/graph/random.hpp>
+
+#include <boost/random/mersenne_twister.hpp>
+
+template <typename ColorMap, typename ParentMap,
+ typename DiscoverTimeMap, typename FinishTimeMap>
+class dfs_test_visitor {
+ typedef typename boost::property_traits<ColorMap>::value_type ColorValue;
+ typedef typename boost::color_traits<ColorValue> Color;
+public:
+ dfs_test_visitor(ColorMap color, ParentMap p, DiscoverTimeMap d,
+ FinishTimeMap f)
+ : m_color(color), m_parent(p),
+ m_discover_time(d), m_finish_time(f), m_time(0) { }
+
+ template <class Vertex, class Graph>
+ void initialize_vertex(Vertex u, Graph&) {
+ BOOST_CHECK( boost::get(m_color, u) == Color::white() );
+ }
+ template <class Vertex, class Graph>
+ void start_vertex(Vertex u, Graph&) {
+ BOOST_CHECK( boost::get(m_color, u) == Color::white() );
+ }
+ template <class Vertex, class Graph>
+ void discover_vertex(Vertex u, Graph&) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, u) == Color::gray() );
+ BOOST_CHECK( get(m_color, get(m_parent, u)) == Color::gray() );
+
+ put(m_discover_time, u, m_time++);
+ }
+ template <class Edge, class Graph>
+ void examine_edge(Edge e, Graph& g) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, source(e, g)) == Color::gray() );
+ }
+ template <class Edge, class Graph>
+ void tree_edge(Edge e, Graph& g) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, target(e, g)) == Color::white() );
+
+ put(m_parent, target(e, g), source(e, g));
+ }
+ template <class Edge, class Graph>
+ void back_edge(Edge e, Graph& g) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, target(e, g)) == Color::gray() );
+ }
+ template <class Edge, class Graph>
+ void forward_or_cross_edge(Edge e, Graph& g) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, target(e, g)) == Color::black() );
+ }
+ template <class Edge, class Graph>
+ void finish_edge(Edge e, Graph& g) {
+ using namespace boost;
+ BOOST_CHECK(
+ (get(m_color, target(e, g)) == Color::gray())
+ || (get(m_color, target(e, g)) == Color::black())
+ );
+ }
+ template <class Vertex, class Graph>
+ void finish_vertex(Vertex u, Graph&) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, u) == Color::black() );
+
+ put(m_finish_time, u, m_time++);
+ }
+private:
+ ColorMap m_color;
+ ParentMap m_parent;
+ DiscoverTimeMap m_discover_time;
+ FinishTimeMap m_finish_time;
+ typename boost::property_traits<DiscoverTimeMap>::value_type m_time;
+};
+
+template <typename Graph>
+struct dfs_test
+{
+ typedef boost::graph_traits<Graph> Traits;
+ typedef typename Traits::vertices_size_type
+ vertices_size_type;
+
+ static void go(vertices_size_type max_V) {
+ using namespace boost;
+ typedef typename Traits::vertex_descriptor vertex_descriptor;
+ typedef typename boost::property_map<Graph,
+ boost::vertex_color_t>::type ColorMap;
+ typedef typename boost::property_traits<ColorMap>::value_type ColorValue;
+ typedef typename boost::color_traits<ColorValue> Color;
+ typedef typename boost::property_map<Graph,
+ boost::edge_color_t>::type EColorMap;
+ typedef typename boost::property_traits<EColorMap>::value_type EColorValue;
+ typedef typename boost::color_traits<EColorValue> EColor;
+
+ vertices_size_type i, k;
+ typename Traits::edges_size_type j;
+ typename Traits::vertex_iterator vi, vi_end, ui, ui_end;
+ typename Traits::edge_iterator ei, ei_end;
+
+ boost::mt19937 gen;
+
+ for (i = 0; i < max_V; ++i)
+ for (j = 0; j < i*i; ++j) {
+ Graph g;
+ generate_random_graph(g, i, j, gen);
+
+ ColorMap color = get(boost::vertex_color, g);
+ EColorMap e_color = get(boost::edge_color, g);
+ std::vector<vertex_descriptor> parent(num_vertices(g));
+ for (k = 0; k < num_vertices(g); ++k)
+ parent[k] = k;
+ std::vector<int> discover_time(num_vertices(g)),
+ finish_time(num_vertices(g));
+
+ dfs_test_visitor<ColorMap, vertex_descriptor*,
+ int*, int*> vis(color, &parent[0],
+ &discover_time[0], &finish_time[0]);
+
+ boost::undirected_dfs(g, visitor(vis).color_map(color)
+ .edge_color_map(e_color));
+
+ // all vertices should be black
+ for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
+ BOOST_CHECK(get(color, *vi) == Color::black());
+
+ // all edges should be black
+ for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
+ BOOST_CHECK(get(e_color, *ei) == EColor::black());
+
+ // check parenthesis structure of discover/finish times
+ // See CLR p.480
+ for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui)
+ for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
+ vertex_descriptor u = *ui, v = *vi;
+ if (u != v) {
+ BOOST_CHECK( finish_time[u] < discover_time[v]
+ || finish_time[v] < discover_time[u]
+ || (discover_time[v] < discover_time[u]
+ && finish_time[u] < finish_time[v]
+ && boost::is_descendant(u, v, &parent[0]))
+ || (discover_time[u] < discover_time[v]
+ && finish_time[v] < finish_time[u]
+ && boost::is_descendant(v, u, &parent[0]))
+ );
+ }
+ }
+ }
+
+ }
+};
+
+
+// usage: undirected_dfs.exe [max-vertices=15]
+
+int test_main(int argc, char* argv[])
+{
+ int max_V = 7;
+ if (argc > 1)
+ max_V = atoi(argv[1]);
+
+ // Test undirected graphs.
+ dfs_test< boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
+ boost::property<boost::vertex_color_t, boost::default_color_type>,
+ boost::property<boost::edge_color_t, boost::default_color_type> >
+ >::go(max_V);
+
+ return 0;
+}
+


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk