Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r63334 - in trunk: boost/graph libs/graph/test
From: jewillco_at_[hidden]
Date: 2010-06-25 20:43:34


Author: jewillco
Date: 2010-06-25 20:43:33 EDT (Fri, 25 Jun 2010)
New Revision: 63334
URL: http://svn.boost.org/trac/boost/changeset/63334

Log:
Added (undocumented) functions for loop-erased random walk and random generation of spanning trees
Added:
   trunk/boost/graph/loop_erased_random_walk.hpp (contents, props changed)
   trunk/boost/graph/random_spanning_tree.hpp (contents, props changed)
   trunk/libs/graph/test/random_spanning_tree_test.cpp (contents, props changed)
Text files modified:
   trunk/boost/graph/random.hpp | 41 ++++++++++++++++++++++++++++++++++++++++
   trunk/libs/graph/test/Jamfile.v2 | 1
   2 files changed, 42 insertions(+), 0 deletions(-)

Added: trunk/boost/graph/loop_erased_random_walk.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/loop_erased_random_walk.hpp 2010-06-25 20:43:33 EDT (Fri, 25 Jun 2010)
@@ -0,0 +1,110 @@
+// Copyright 2010 The Trustees of Indiana University.
+
+// 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)
+
+// Authors: Jeremiah Willcock
+// Andrew Lumsdaine
+
+#ifndef BOOST_GRAPH_LOOP_ERASED_RANDOM_WALK_HPP
+#define BOOST_GRAPH_LOOP_ERASED_RANDOM_WALK_HPP
+
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/properties.hpp>
+#include <boost/graph/random.hpp>
+#include <boost/next_prior.hpp>
+#include <vector>
+#include <cassert>
+
+namespace boost {
+
+ // Do a loop-erased random walk from vertex s to any vertex colored black (or
+ // actually any color other than white or gray) in the color map. The color
+ // white is for vertices that are not part of the path, while gray is for
+ // those that are on the path (for cycle detection). The vector path is used
+ // for temporary storage and as the result of the algorithm; while all
+ // elements of the path except the last have their colors set to gray upon
+ // return. Vertex s must start off colored white.
+ //
+ // Useful references:
+ // http://everything2.com/title/loop-erased+random+walk
+ // Wikipedia page on "Loop-Erased Random Walk"
+
+ template <typename Graph, typename ColorMap, typename NextEdge>
+ void loop_erased_random_walk(
+ const Graph& g,
+ typename boost::graph_traits<Graph>::vertex_descriptor s,
+ NextEdge next_edge,
+ ColorMap color,
+ std::vector<typename boost::graph_traits<Graph>::vertex_descriptor>& path
+ ) {
+ typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+ typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
+ typedef typename boost::property_traits<ColorMap>::value_type color_t;
+ typedef boost::color_traits<color_t> color_gen;
+
+ assert (get(color, s) == color_gen::white());
+ path.clear();
+ path.push_back(s);
+ put(color, s, color_gen::gray());
+ while (true) {
+ edge_descriptor e = next_edge(s, g);
+ vertex_descriptor t = target(e, g);
+ color_t t_color = get(color, t);
+ if (t_color == color_gen::white()) {
+ path.push_back(t);
+ put(color, t, color_gen::gray());
+ s = t;
+ } else if (t_color == color_gen::gray()) {
+ // Found a loop; delete from path from the first occurrence of t to the
+ // end, coloring vertices white.
+ typename std::vector<vertex_descriptor>::iterator it = std::find(path.begin(), path.end(), t);
+ assert (it != path.end());
+ ++it;
+ for (typename std::vector<vertex_descriptor>::iterator j = it; j != path.end(); ++j) {
+ put(color, *j, color_gen::white());
+ }
+ path.erase(it, path.end());
+ s = t;
+ } else {
+ // Done
+ path.push_back(t);
+ break;
+ }
+ }
+ }
+
+ template <typename Graph, typename Gen>
+ class unweighted_random_out_edge_gen {
+ Gen& gen;
+
+ typedef boost::graph_traits<Graph> gt;
+
+ public:
+ unweighted_random_out_edge_gen(Gen& gen): gen(gen) {}
+
+ typename gt::edge_descriptor
+ operator()(typename gt::vertex_descriptor src, const Graph& g) const {
+ return boost::random_out_edge(g, src, gen);
+ }
+ };
+
+ template <typename Graph, typename WeightMap, typename Gen>
+ class weighted_random_out_edge_gen {
+ WeightMap weight;
+ Gen& gen;
+
+ typedef boost::graph_traits<Graph> gt;
+
+ public:
+ weighted_random_out_edge_gen(const WeightMap& weight, Gen& gen): weight(weight), gen(gen) {}
+
+ typename gt::edge_descriptor
+ operator()(typename gt::vertex_descriptor src, const Graph& g) const {
+ return boost::weighted_random_out_edge(g, src, weight, gen);
+ }
+ };
+}
+
+#endif // BOOST_GRAPH_LOOP_ERASED_RANDOM_WALK_HPP

Modified: trunk/boost/graph/random.hpp
==============================================================================
--- trunk/boost/graph/random.hpp (original)
+++ trunk/boost/graph/random.hpp 2010-06-25 20:43:33 EDT (Fri, 25 Jun 2010)
@@ -12,10 +12,12 @@
 
 #include <boost/graph/graph_traits.hpp>
 #include <boost/random/uniform_int.hpp>
+#include <boost/random/uniform_real.hpp>
 #include <boost/random/variate_generator.hpp>
 
 #include <boost/pending/property.hpp>
 #include <boost/graph/properties.hpp>
+#include <boost/graph/iteration_macros.hpp>
 #include <boost/next_prior.hpp>
 
 #include <boost/graph/adjacency_list.hpp>
@@ -24,6 +26,7 @@
 #include <boost/type_traits/is_convertible.hpp>
 
 #include <iostream>
+#include <cassert>
 
 namespace boost {
 
@@ -67,6 +70,43 @@
       return *edges(g).first;
   }
 
+ template <typename Graph, typename RandomNumGen>
+ typename graph_traits<Graph>::edge_descriptor
+ random_out_edge(Graph& g, typename graph_traits<Graph>::vertex_descriptor src, RandomNumGen& gen) {
+ typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
+ typedef boost::uniform_int<degree_size_type> ui_type;
+ ui_type ui(0, out_degree(src, g) - 1);
+ boost::variate_generator<RandomNumGen&, ui_type>
+ variate(gen, ui);
+ typename graph_traits<Graph>::out_edge_iterator it = out_edges(src, g).first;
+ std::advance(it, variate());
+ return *it;
+ }
+
+ template <typename Graph, typename WeightMap, typename RandomNumGen>
+ typename graph_traits<Graph>::edge_descriptor
+ weighted_random_out_edge(Graph& g, typename graph_traits<Graph>::vertex_descriptor src, WeightMap weight, RandomNumGen& gen) {
+ typedef graph_traits<Graph> gt;
+ typedef typename gt::vertex_descriptor vertex_descriptor;
+ typedef typename property_traits<WeightMap>::value_type weight_type;
+ weight_type weight_sum(0);
+ BGL_FORALL_OUTEDGES_T(src, e, g, Graph) {weight_sum += get(weight, e);}
+ typedef boost::uniform_real<> ur_type;
+ ur_type ur(0, weight_sum);
+ boost::variate_generator<RandomNumGen&, ur_type>
+ variate(gen, ur);
+ weight_type chosen_weight = variate();
+ BGL_FORALL_OUTEDGES_T(src, e, g, Graph) {
+ weight_type w = get(weight, e);
+ if (chosen_weight < w) {
+ return e;
+ } else {
+ chosen_weight -= w;
+ }
+ }
+ assert (false); // Should not get here
+ }
+
   namespace detail {
     class dummy_property_copier {
     public:
@@ -200,5 +240,6 @@
   
 }
 
+#include <boost/graph/iteration_macros_undef.hpp>
 
 #endif

Added: trunk/boost/graph/random_spanning_tree.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/random_spanning_tree.hpp 2010-06-25 20:43:33 EDT (Fri, 25 Jun 2010)
@@ -0,0 +1,103 @@
+// Copyright 2010 The Trustees of Indiana University.
+
+// 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)
+
+// Authors: Jeremiah Willcock
+// Andrew Lumsdaine
+
+#ifndef BOOST_GRAPH_RANDOM_SPANNING_TREE_HPP
+#define BOOST_GRAPH_RANDOM_SPANNING_TREE_HPP
+
+#include <vector>
+#include <boost/graph/loop_erased_random_walk.hpp>
+#include <boost/graph/random.hpp>
+#include <boost/graph/iteration_macros.hpp>
+#include <boost/property_map/property_map.hpp>
+
+namespace boost {
+
+ namespace detail {
+ // Use Wilson's algorithm (based on loop-free random walks) to generate a
+ // random spanning tree. The distribution of edges used is controlled by
+ // the next_edge() function, so this version allows either weighted or
+ // unweighted selection of trees.
+ // Algorithm is from http://en.wikipedia.org/wiki/Uniform_spanning_tree
+ template <typename Graph, typename PredMap, typename ColorMap, typename NextEdge>
+ void random_spanning_tree_internal(const Graph& g, PredMap pred, ColorMap color, NextEdge next_edge) {
+ typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+ typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
+
+ assert (num_vertices(g) >= 2); // g must also be undirected (or symmetric) and connected
+
+ typedef color_traits<typename property_traits<ColorMap>::value_type> color_gen;
+ BGL_FORALL_VERTICES_T(v, g, Graph) put(color, v, color_gen::white());
+
+ std::vector<vertex_descriptor> path;
+
+ vertex_descriptor s = *vertices(g).first;
+ put(color, s, color_gen::black());
+ put(pred, s, graph_traits<Graph>::null_vertex());
+
+ BGL_FORALL_VERTICES_T(v, g, Graph) {
+ if (get(color, v) != color_gen::white()) continue;
+ loop_erased_random_walk(g, v, next_edge, color, path);
+ for (typename std::vector<vertex_descriptor>::const_reverse_iterator i = path.rbegin();
+ boost::next(i) != path.rend(); ++i) {
+ typename std::vector<vertex_descriptor>::const_reverse_iterator j = i;
+ ++j;
+ assert (get(color, *j) == color_gen::gray());
+ put(color, *j, color_gen::black());
+ put(pred, *j, *i);
+ }
+ }
+ }
+ }
+
+ // Compute a uniformly-distributed spanning tree on a graph.
+ template <typename Graph, typename PredMap, typename ColorMap, typename Gen>
+ void random_spanning_tree(const Graph& g, PredMap pred, Gen& gen, ColorMap color) {
+ unweighted_random_out_edge_gen<Graph, Gen> random_oe(gen);
+ detail::random_spanning_tree_internal(g, pred, color, random_oe);
+ }
+
+ // Compute a uniformly-distributed spanning tree on a graph.
+ template <typename Graph, typename PredMap, typename Gen>
+ void random_spanning_tree(const Graph& g, PredMap pred, Gen& gen) {
+ std::vector<default_color_type> color_data(num_vertices(g));
+ random_spanning_tree(g, pred, gen, make_iterator_property_map(color_data.begin(), get(vertex_index, g)));
+ }
+
+ // Compute a weight-distributed spanning tree on a graph.
+ // Weighting works according to:
+ // @article{Mosbah1999263,
+ // title = "Non-uniform random spanning trees on weighted graphs",
+ // journal = "Theoretical Computer Science",
+ // volume = "218",
+ // number = "2",
+ // pages = "263--271",
+ // year = "1999",
+ // note = "",
+ // issn = "0304-3975",
+ // doi = "DOI: 10.1016/S0304-3975(98)00325-9",
+ // url = "http://www.sciencedirect.com/science/article/B6V1G-3WSV1D9-P/2/06bea092e23163c4884844cde4a5e92c",
+ // author = "M. Mosbah and N. Saheb"
+ // }
+ template <typename Graph, typename PredMap, typename WeightMap, typename ColorMap, typename Gen>
+ void weighted_random_spanning_tree(const Graph& g, PredMap pred, WeightMap weight, Gen& gen, ColorMap color) {
+ weighted_random_out_edge_gen<Graph, WeightMap, Gen> random_oe(weight, gen);
+ detail::random_spanning_tree_internal(g, pred, color, random_oe);
+ }
+
+ // Compute a weight-distributed spanning tree on a graph.
+ template <typename Graph, typename PredMap, typename WeightMap, typename Gen>
+ void weighted_random_spanning_tree(const Graph& g, PredMap pred, WeightMap weight, Gen& gen) {
+ std::vector<default_color_type> color_data(num_vertices(g));
+ weighted_random_spanning_tree(g, pred, weight, gen, make_iterator_property_map(color_data.begin(), get(vertex_index, g)));
+ }
+}
+
+#include <boost/graph/iteration_macros_undef.hpp>
+
+#endif // BOOST_GRAPH_RANDOM_SPANNING_TREE_HPP

Modified: trunk/libs/graph/test/Jamfile.v2
==============================================================================
--- trunk/libs/graph/test/Jamfile.v2 (original)
+++ trunk/libs/graph/test/Jamfile.v2 2010-06-25 20:43:33 EDT (Fri, 25 Jun 2010)
@@ -116,6 +116,7 @@
     [ compile grid_graph_cc.cpp ]
     [ run grid_graph_test.cpp ]
     [ run incremental_components_test.cpp ]
+ [ run random_spanning_tree_test.cpp ../build//boost_graph ]
     [ run graphml_test.cpp ../build//boost_graph : : "graphml_test.xml" ]
     ;
 

Added: trunk/libs/graph/test/random_spanning_tree_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/graph/test/random_spanning_tree_test.cpp 2010-06-25 20:43:33 EDT (Fri, 25 Jun 2010)
@@ -0,0 +1,69 @@
+// Copyright 2010 The Trustees of Indiana University.
+
+// 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)
+
+// Authors: Jeremiah Willcock
+// Andrew Lumsdaine
+
+#include <boost/graph/random_spanning_tree.hpp>
+#include <boost/graph/grid_graph.hpp>
+#include <boost/array.hpp>
+#include <boost/random.hpp>
+#include <boost/property_map/shared_array_property_map.hpp>
+#include <boost/property_map/dynamic_property_map.hpp>
+#include <boost/graph/graphviz.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/graph/property_maps/constant_property_map.hpp>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/graph/iteration_macros.hpp>
+
+using namespace boost;
+using namespace std;
+
+typedef grid_graph<2> graph_type;
+typedef graph_traits<graph_type> gt;
+
+template <typename Graph, typename PredMap, typename WeightMap>
+void write_spanning_tree(const Graph& g, PredMap pred, WeightMap weight, string filename) {
+ shared_array_property_map<string, typename property_map<Graph, edge_index_t>::const_type> edge_style(num_edges(g), get(edge_index, g));
+ shared_array_property_map<string, typename property_map<Graph, vertex_index_t>::const_type> vertex_pos(num_vertices(g), get(vertex_index, g));
+ BGL_FORALL_EDGES_T(e, g, Graph) {
+ put(edge_style, e, (get(pred, target(e, g)) == source(e, g) || get(pred, source(e, g)) == target(e, g)) ? "bold" : "dotted");
+ }
+ BGL_FORALL_VERTICES_T(v, g, Graph) {
+ put(vertex_pos, v, lexical_cast<string>(v[0]) + "," + lexical_cast<string>(v[1]));
+ }
+ dynamic_properties dp;
+ dp.property("style", edge_style);
+ dp.property("pos", vertex_pos);
+ dp.property("len", weight);
+ dp.property("node_id", get(vertex_index, g));
+ ofstream out(filename.c_str());
+ write_graphviz_dp(out, g, dp);
+}
+
+int main(int, char**) {
+
+ array<size_t, 2> sizes = {{ 5, 5 }};
+ graph_type g(sizes);
+
+ shared_array_property_map<gt::vertex_descriptor, property_map<graph_type, vertex_index_t>::const_type> pred(num_vertices(g), get(vertex_index, g));
+ shared_array_property_map<double, property_map<graph_type, edge_index_t>::const_type> weight(num_edges(g), get(edge_index, g));
+
+ BGL_FORALL_EDGES(e, g, graph_type) {put(weight, e, (1. + get(edge_index, g, e)) / num_edges(g));}
+
+ mt19937 gen;
+ random_spanning_tree(g, pred, gen);
+ // write_spanning_tree(g, pred, constant_property_map<gt::edge_descriptor, double>(1.), "unweight_random_st.dot");
+ random_spanning_tree(g, pred, gen);
+ // write_spanning_tree(g, pred, constant_property_map<gt::edge_descriptor, double>(1.), "unweight_random_st2.dot");
+
+ weighted_random_spanning_tree(g, pred, weight, gen);
+ // write_spanning_tree(g, pred, weight, "weight_random_st.dot");
+
+ 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