1 // Copyright 2004-5 The Trustees of Indiana University.
2 // Copyright 2002 Brad King and Douglas Gregor
3 
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 
8 //  Authors: Douglas Gregor
9 //           Andrew Lumsdaine
10 
11 #ifndef BOOST_GRAPH_PAGE_RANK_HPP
12 #define BOOST_GRAPH_PAGE_RANK_HPP
13 
14 #include <boost/property_map/property_map.hpp>
15 #include <boost/graph/graph_traits.hpp>
16 #include <boost/graph/properties.hpp>
17 #include <boost/graph/iteration_macros.hpp>
18 #include <boost/graph/overloading.hpp>
19 #include <boost/graph/detail/mpi_include.hpp>
20 #include <vector>
21 
22 namespace boost { namespace graph {
23 
24 struct n_iterations
25 {
n_iterationsboost::graph::n_iterations26   explicit n_iterations(std::size_t n) : n(n) { }
27 
28   template<typename RankMap, typename Graph>
29   bool
operator ()boost::graph::n_iterations30   operator()(const RankMap&, const Graph&)
31   {
32     return n-- == 0;
33   }
34 
35  private:
36   std::size_t n;
37 };
38 
39 namespace detail {
40   template<typename Graph, typename RankMap, typename RankMap2>
page_rank_step(const Graph & g,RankMap from_rank,RankMap2 to_rank,typename property_traits<RankMap>::value_type damping,incidence_graph_tag)41   void page_rank_step(const Graph& g, RankMap from_rank, RankMap2 to_rank,
42                       typename property_traits<RankMap>::value_type damping,
43                       incidence_graph_tag)
44   {
45     typedef typename property_traits<RankMap>::value_type rank_type;
46 
47     // Set new rank maps
48     BGL_FORALL_VERTICES_T(v, g, Graph) put(to_rank, v, rank_type(1 - damping));
49 
50     BGL_FORALL_VERTICES_T(u, g, Graph) {
51       rank_type u_rank_out = damping * get(from_rank, u) / out_degree(u, g);
52       BGL_FORALL_ADJ_T(u, v, g, Graph)
53         put(to_rank, v, get(to_rank, v) + u_rank_out);
54     }
55   }
56 
57   template<typename Graph, typename RankMap, typename RankMap2>
page_rank_step(const Graph & g,RankMap from_rank,RankMap2 to_rank,typename property_traits<RankMap>::value_type damping,bidirectional_graph_tag)58   void page_rank_step(const Graph& g, RankMap from_rank, RankMap2 to_rank,
59                       typename property_traits<RankMap>::value_type damping,
60                       bidirectional_graph_tag)
61   {
62     typedef typename property_traits<RankMap>::value_type damping_type;
63     BGL_FORALL_VERTICES_T(v, g, Graph) {
64       typename property_traits<RankMap>::value_type rank(0);
65       BGL_FORALL_INEDGES_T(v, e, g, Graph)
66         rank += get(from_rank, source(e, g)) / out_degree(source(e, g), g);
67       put(to_rank, v, (damping_type(1) - damping) + damping * rank);
68     }
69   }
70 } // end namespace detail
71 
72 template<typename Graph, typename RankMap, typename Done, typename RankMap2>
73 void
page_rank(const Graph & g,RankMap rank_map,Done done,typename property_traits<RankMap>::value_type damping,typename graph_traits<Graph>::vertices_size_type n,RankMap2 rank_map2 BOOST_GRAPH_ENABLE_IF_MODELS_PARM (Graph,vertex_list_graph_tag))74 page_rank(const Graph& g, RankMap rank_map, Done done,
75           typename property_traits<RankMap>::value_type damping,
76           typename graph_traits<Graph>::vertices_size_type n,
77           RankMap2 rank_map2
78           BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, vertex_list_graph_tag))
79 {
80   typedef typename property_traits<RankMap>::value_type rank_type;
81 
82   rank_type initial_rank = rank_type(rank_type(1) / n);
83   BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map, v, initial_rank);
84 
85   bool to_map_2 = true;
86   while ((to_map_2 && !done(rank_map, g)) ||
87          (!to_map_2 && !done(rank_map2, g))) {
88     typedef typename graph_traits<Graph>::traversal_category category;
89 
90     if (to_map_2) {
91       detail::page_rank_step(g, rank_map, rank_map2, damping, category());
92     } else {
93       detail::page_rank_step(g, rank_map2, rank_map, damping, category());
94     }
95     to_map_2 = !to_map_2;
96   }
97 
98   if (!to_map_2) {
99     BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map, v, get(rank_map2, v));
100   }
101 }
102 
103 template<typename Graph, typename RankMap, typename Done>
104 void
page_rank(const Graph & g,RankMap rank_map,Done done,typename property_traits<RankMap>::value_type damping,typename graph_traits<Graph>::vertices_size_type n)105 page_rank(const Graph& g, RankMap rank_map, Done done,
106           typename property_traits<RankMap>::value_type damping,
107           typename graph_traits<Graph>::vertices_size_type n)
108 {
109   typedef typename property_traits<RankMap>::value_type rank_type;
110 
111   std::vector<rank_type> ranks2(num_vertices(g));
112   page_rank(g, rank_map, done, damping, n,
113             make_iterator_property_map(ranks2.begin(), get(vertex_index, g)));
114 }
115 
116 template<typename Graph, typename RankMap, typename Done>
117 inline void
page_rank(const Graph & g,RankMap rank_map,Done done,typename property_traits<RankMap>::value_type damping=0.85)118 page_rank(const Graph& g, RankMap rank_map, Done done,
119           typename property_traits<RankMap>::value_type damping = 0.85)
120 {
121   page_rank(g, rank_map, done, damping, num_vertices(g));
122 }
123 
124 template<typename Graph, typename RankMap>
125 inline void
page_rank(const Graph & g,RankMap rank_map)126 page_rank(const Graph& g, RankMap rank_map)
127 {
128   page_rank(g, rank_map, n_iterations(20));
129 }
130 
131 // TBD: this could be _much_ more efficient, using a queue to store
132 // the vertices that should be reprocessed and keeping track of which
133 // vertices are in the queue with a property map. Baah, this only
134 // applies when we have a bidirectional graph.
135 template<typename MutableGraph>
136 void
remove_dangling_links(MutableGraph & g BOOST_GRAPH_ENABLE_IF_MODELS_PARM (MutableGraph,vertex_list_graph_tag))137 remove_dangling_links(MutableGraph& g
138                       BOOST_GRAPH_ENABLE_IF_MODELS_PARM(MutableGraph,
139                                                         vertex_list_graph_tag))
140 {
141   typename graph_traits<MutableGraph>::vertices_size_type old_n;
142   do {
143     old_n = num_vertices(g);
144 
145     typename graph_traits<MutableGraph>::vertex_iterator vi, vi_end;
146     for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; /* in loop */) {
147       typename graph_traits<MutableGraph>::vertex_descriptor v = *vi++;
148       if (out_degree(v, g) == 0) {
149         clear_vertex(v, g);
150         remove_vertex(v, g);
151       }
152     }
153   } while (num_vertices(g) < old_n);
154 }
155 
156 } } // end namespace boost::graph
157 
158 #include BOOST_GRAPH_MPI_INCLUDE(<boost/graph/distributed/page_rank.hpp>)
159 
160 #endif // BOOST_GRAPH_PAGE_RANK_HPP
161