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 @@ namespace boost {
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 @@ namespace boost {
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 @@ namespace boost {
undirected_dfs(const Graph& g,
const bgl_named_params& params)
{
- typedef typename get_param_type< bgl_named_params
,
- vertex_color_t>::type C;
+ typedef typename get_param_type< vertex_color_t, bgl_named_params
>::type C;
detail::udfs_dispatch::apply
(g,
choose_param(get_param(params, graph_visitor),
diff --git a/include/boost/graph/visitors.hpp b/include/boost/graph/visitors.hpp
index f986c96c..39314f5a 100644
--- a/include/boost/graph/visitors.hpp
+++ b/include/boost/graph/visitors.hpp
@@ -44,7 +44,7 @@ namespace boost {
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 @@ namespace boost {
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 {
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index fd6e967c..a2612d88 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -43,6 +43,7 @@ test-suite graph_test :
[ run csr_graph_test.cpp : : : : : 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 ]
diff --git a/test/dfs.cpp b/test/dfs.cpp
index fdffd4ef..7f458e0a 100644
--- a/test/dfs.cpp
+++ b/test/dfs.cpp
@@ -68,6 +68,12 @@ public:
using namespace boost;
BOOST_CHECK( get(m_color, target(e, g)) == Color::black() );
}
+ template
+ 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
void finish_vertex(Vertex u, Graph&) {
using namespace boost;
diff --git a/test/undirected_dfs.cpp b/test/undirected_dfs.cpp
new file mode 100644
index 00000000..b9d4285f
--- /dev/null
+++ b/test/undirected_dfs.cpp
@@ -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
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+template
+class dfs_test_visitor {
+ typedef typename boost::property_traits::value_type ColorValue;
+ typedef typename boost::color_traits 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
+ void initialize_vertex(Vertex u, Graph&) {
+ BOOST_CHECK( boost::get(m_color, u) == Color::white() );
+ }
+ template
+ void start_vertex(Vertex u, Graph&) {
+ BOOST_CHECK( boost::get(m_color, u) == Color::white() );
+ }
+ template
+ 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
+ void examine_edge(Edge e, Graph& g) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, source(e, g)) == Color::gray() );
+ }
+ template
+ 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
+ void back_edge(Edge e, Graph& g) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, target(e, g)) == Color::gray() );
+ }
+ template
+ void forward_or_cross_edge(Edge e, Graph& g) {
+ using namespace boost;
+ BOOST_CHECK( get(m_color, target(e, g)) == Color::black() );
+ }
+ template
+ 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
+ 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::value_type m_time;
+};
+
+template
+struct dfs_test
+{
+ typedef boost::graph_traits 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::type ColorMap;
+ typedef typename boost::property_traits::value_type ColorValue;
+ typedef typename boost::color_traits Color;
+ typedef typename boost::property_map::type EColorMap;
+ typedef typename boost::property_traits::value_type EColorValue;
+ typedef typename boost::color_traits 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 parent(num_vertices(g));
+ for (k = 0; k < num_vertices(g); ++k)
+ parent[k] = k;
+ std::vector discover_time(num_vertices(g)),
+ finish_time(num_vertices(g));
+
+ dfs_test_visitor 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::property >
+ >::go(max_V);
+
+ return 0;
+}
+