Chris@16
|
1 // Copyright 2010 The Trustees of Indiana University.
|
Chris@16
|
2
|
Chris@16
|
3 // Distributed under the Boost Software License, Version 1.0.
|
Chris@16
|
4 // (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
5 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6
|
Chris@16
|
7 // Authors: Jeremiah Willcock
|
Chris@16
|
8 // Andrew Lumsdaine
|
Chris@16
|
9
|
Chris@16
|
10 #ifndef BOOST_GRAPH_LOOP_ERASED_RANDOM_WALK_HPP
|
Chris@16
|
11 #define BOOST_GRAPH_LOOP_ERASED_RANDOM_WALK_HPP
|
Chris@16
|
12
|
Chris@16
|
13 #include <boost/graph/graph_traits.hpp>
|
Chris@16
|
14 #include <boost/graph/properties.hpp>
|
Chris@16
|
15 #include <boost/graph/random.hpp>
|
Chris@16
|
16 #include <boost/next_prior.hpp>
|
Chris@16
|
17 #include <vector>
|
Chris@16
|
18 #include <boost/assert.hpp>
|
Chris@16
|
19
|
Chris@16
|
20 namespace boost {
|
Chris@16
|
21
|
Chris@16
|
22 struct loop_erased_random_walk_stuck : public std::exception {
|
Chris@16
|
23 virtual ~loop_erased_random_walk_stuck() throw() {}
|
Chris@16
|
24 inline virtual const char* what() const throw() {
|
Chris@16
|
25 return "Loop-erased random walk found a vertex with no out-edges";
|
Chris@16
|
26 }
|
Chris@16
|
27 };
|
Chris@16
|
28
|
Chris@16
|
29 // Do a loop-erased random walk from vertex s to any vertex colored black (or
|
Chris@16
|
30 // actually any color other than white or gray) in the color map. The color
|
Chris@16
|
31 // white is for vertices that are not part of the path, while gray is for
|
Chris@16
|
32 // those that are on the path (for cycle detection). The vector path is used
|
Chris@16
|
33 // for temporary storage and as the result of the algorithm; while all
|
Chris@16
|
34 // elements of the path except the last have their colors set to gray upon
|
Chris@16
|
35 // return. Vertex s must start off colored white.
|
Chris@16
|
36 //
|
Chris@16
|
37 // Useful references:
|
Chris@16
|
38 // http://everything2.com/title/loop-erased+random+walk
|
Chris@16
|
39 // Wikipedia page on "Loop-Erased Random Walk"
|
Chris@16
|
40
|
Chris@16
|
41 template <typename Graph, typename ColorMap, typename NextEdge>
|
Chris@16
|
42 void loop_erased_random_walk(
|
Chris@16
|
43 const Graph& g,
|
Chris@16
|
44 typename boost::graph_traits<Graph>::vertex_descriptor s,
|
Chris@16
|
45 NextEdge next_edge,
|
Chris@16
|
46 ColorMap color,
|
Chris@16
|
47 std::vector<typename boost::graph_traits<Graph>::vertex_descriptor>& path
|
Chris@16
|
48 ) {
|
Chris@16
|
49 typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
Chris@16
|
50 typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
|
Chris@16
|
51 typedef typename boost::property_traits<ColorMap>::value_type color_t;
|
Chris@16
|
52 typedef boost::color_traits<color_t> color_gen;
|
Chris@16
|
53
|
Chris@16
|
54 BOOST_ASSERT (get(color, s) == color_gen::white());
|
Chris@16
|
55 path.clear();
|
Chris@16
|
56 path.push_back(s);
|
Chris@16
|
57 put(color, s, color_gen::gray());
|
Chris@16
|
58 while (true) {
|
Chris@16
|
59 edge_descriptor e = next_edge(s, g);
|
Chris@16
|
60 vertex_descriptor t = target(e, g);
|
Chris@16
|
61 color_t t_color = get(color, t);
|
Chris@16
|
62 if (t_color == color_gen::white()) {
|
Chris@16
|
63 path.push_back(t);
|
Chris@16
|
64 put(color, t, color_gen::gray());
|
Chris@16
|
65 s = t;
|
Chris@16
|
66 } else if (t_color == color_gen::gray()) {
|
Chris@16
|
67 // Found a loop; delete from path from the first occurrence of t to the
|
Chris@16
|
68 // end, coloring vertices white.
|
Chris@16
|
69 typename std::vector<vertex_descriptor>::iterator it = std::find(path.begin(), path.end(), t);
|
Chris@16
|
70 BOOST_ASSERT (it != path.end());
|
Chris@16
|
71 ++it;
|
Chris@16
|
72 for (typename std::vector<vertex_descriptor>::iterator j = it; j != path.end(); ++j) {
|
Chris@16
|
73 put(color, *j, color_gen::white());
|
Chris@16
|
74 }
|
Chris@16
|
75 path.erase(it, path.end());
|
Chris@16
|
76 s = t;
|
Chris@16
|
77 } else {
|
Chris@16
|
78 // Done
|
Chris@16
|
79 path.push_back(t);
|
Chris@16
|
80 break;
|
Chris@16
|
81 }
|
Chris@16
|
82 }
|
Chris@16
|
83 }
|
Chris@16
|
84
|
Chris@16
|
85 template <typename Graph, typename Gen>
|
Chris@16
|
86 class unweighted_random_out_edge_gen {
|
Chris@16
|
87 Gen& gen;
|
Chris@16
|
88
|
Chris@16
|
89 typedef boost::graph_traits<Graph> gt;
|
Chris@16
|
90
|
Chris@16
|
91 public:
|
Chris@16
|
92 unweighted_random_out_edge_gen(Gen& gen): gen(gen) {}
|
Chris@16
|
93
|
Chris@16
|
94 typename gt::edge_descriptor
|
Chris@16
|
95 operator()(typename gt::vertex_descriptor src, const Graph& g) const {
|
Chris@16
|
96 if (out_degree(src, g) == 0) throw loop_erased_random_walk_stuck();
|
Chris@16
|
97 return boost::random_out_edge(g, src, gen);
|
Chris@16
|
98 }
|
Chris@16
|
99 };
|
Chris@16
|
100
|
Chris@16
|
101 template <typename Graph, typename WeightMap, typename Gen>
|
Chris@16
|
102 class weighted_random_out_edge_gen {
|
Chris@16
|
103 WeightMap weight;
|
Chris@16
|
104 Gen& gen;
|
Chris@16
|
105
|
Chris@16
|
106 typedef boost::graph_traits<Graph> gt;
|
Chris@16
|
107
|
Chris@16
|
108 public:
|
Chris@16
|
109 weighted_random_out_edge_gen(const WeightMap& weight, Gen& gen): weight(weight), gen(gen) {}
|
Chris@16
|
110
|
Chris@16
|
111 typename gt::edge_descriptor
|
Chris@16
|
112 operator()(typename gt::vertex_descriptor src, const Graph& g) const {
|
Chris@16
|
113 if (out_degree(src, g) == 0) throw loop_erased_random_walk_stuck();
|
Chris@16
|
114 return boost::weighted_random_out_edge(g, src, weight, gen);
|
Chris@16
|
115 }
|
Chris@16
|
116 };
|
Chris@16
|
117 }
|
Chris@16
|
118
|
Chris@16
|
119 #endif // BOOST_GRAPH_LOOP_ERASED_RANDOM_WALK_HPP
|