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