loop_erased_random_walk.hpp 4.3 KB

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