All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Pages
thorup_2kminus1.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //=======================================================================
16 #ifndef PAAL_THORUP_2KMINUS1_HPP
17 #define PAAL_THORUP_2KMINUS1_HPP
18 
19 #include "paal/utils/functors.hpp"
20 #include "paal/utils/irange.hpp"
22 
23 #include <boost/range/as_array.hpp>
24 #include <boost/range/iterator_range.hpp>
25 #include <boost/property_map/property_map.hpp>
26 #include <boost/graph/named_function_params.hpp>
27 #include <boost/graph/dijkstra_shortest_paths.hpp>
28 #include <boost/graph/dijkstra_shortest_paths_no_color_map.hpp>
29 
30 #include <queue>
31 #include <unordered_map>
32 #include <limits>
33 #include <random>
34 #include <cmath>
35 
36 namespace paal {
37 
46 template < typename Graph,
47  typename VertexIndexMap,
48  typename EdgeWeightMap,
49  typename Rand=std::default_random_engine
50  >
52  using DT = typename boost::property_traits<EdgeWeightMap>::value_type;
53  using VT = typename boost::graph_traits<Graph>::vertex_descriptor;
54 
56  using DVect = std::vector< std::pair<int, DT> >;
57 
59  using BunchMap = std::unordered_map<int, DT>;
60 
62  VertexIndexMap m_index;
63 
65 
69  std::vector< int > m_layer_num;
70 
72  std::vector< DVect > m_parent;
73 
75  std::vector< BunchMap > m_bunch;
76 
87  int choose_layers(const Graph& g, int k, long double p, Rand & random_engine) {
88  std::uniform_real_distribution<> dist(0,1);
89 
90  int max_layer_num = 0;
91  long double logp = log(p);
92 
93  for (int ind: irange(num_vertices(g))) {
94  m_layer_num[ind] = std::min(k-1, (int)(log(dist(random_engine)) / logp));
95  assign_max(max_layer_num, m_layer_num[ind]);
96  }
97 
98  return max_layer_num+1;
99  }
100 
107  template <typename NearestMap, typename Tag>
108  class nearest_recorder : boost::base_visitor< nearest_recorder<NearestMap, Tag> > {
109 
111  NearestMap m_nearest_map;
112 
113  public:
114  using event_filter = Tag;
115 
117  explicit nearest_recorder(NearestMap const nearest_map) : m_nearest_map(nearest_map) {}
118 
120  template <typename Edge>
121  void operator()(Edge const e, Graph const &g) const {
122  auto nearest = get(m_nearest_map, source(e,g));
123  put(m_nearest_map, target(e,g), nearest);
124  }
125 
126  };
127 
129  template <typename NearestMap, typename Tag>
130  nearest_recorder<NearestMap, Tag>
131  make_nearest_recorder(NearestMap nearest_map, Tag) {
132  return nearest_recorder<NearestMap, Tag>{nearest_map};
133  }
134 
141  void compute_parents(const Graph& g, EdgeWeightMap edge_weight, int layer_num) {
142  std::vector<DT> distance(num_vertices(g), std::numeric_limits<DT>::max());
143  std::vector<int> nearest(num_vertices(g), -1);
144  std::vector<VT> roots;
145 
146  for (auto v: boost::as_array(vertices(g))) {
147  int v_ind = m_index[v];
148  if (m_layer_num[v_ind] >= layer_num) {
149  nearest[v_ind] = v_ind;
150  distance[v_ind] = DT{};
151  roots.push_back(v);
152  }
153  }
154 
155  boost::dijkstra_shortest_paths_no_init(
156  g,
157  roots.begin(),
158  roots.end(),
159  boost::dummy_property_map(),
160  make_iterator_property_map(distance.begin(), m_index, distance[0]),
161  edge_weight,
162  m_index,
163  utils::less{},
164  boost::closed_plus<DT>(),
165  DT{},
166  boost::make_dijkstra_visitor(make_nearest_recorder(
167  make_iterator_property_map(nearest.begin(), m_index, nearest[0]),
168  boost::on_edge_relaxed{})
169  )
170  );
171 
172  for (int ind: irange(num_vertices(g))) {
173  m_parent[ind].push_back(std::make_pair(nearest[ind], distance[ind]));
174  }
175  }
176 
178  class cluster_dist {
180  DT m_value;
182  bool m_unmodified;
183 
185  cluster_dist(DT value, bool unmodified) :
186  m_value(value), m_unmodified(unmodified) {}
187 
188  public:
190  cluster_dist(DT value = DT{}) :
191  m_value(value), m_unmodified(false) {}
192 
194  static cluster_dist
195  make_limit(DT value = std::numeric_limits<DT>::max()) {
196  return cluster_dist(value, true);
197  }
198 
200 
203  struct less {
205  bool operator()(cluster_dist a, cluster_dist b) const {
206  return (a.m_value < b.m_value) && (b.m_unmodified || !a.m_unmodified);
207  }
208  };
209 
211  struct plus {
213  cluster_dist operator()(cluster_dist a, cluster_dist b) const {
214  return cluster_dist(a.m_value + b.m_value, a.m_unmodified || b.m_unmodified);
215  }
216  };
217 
219  const DT value() const {
220  return m_value;
221  }
222  };
223 
230  class cluster_distance_wrapper :
231  public boost::put_get_helper<cluster_dist&, cluster_distance_wrapper>
232  {
234  std::vector< cluster_dist > *m_distance;
235 
237  VertexIndexMap m_index;
238 
240 
244  std::vector< DT > *m_limit;
245 
247  std::vector<int> *m_last_accessed;
248 
250 
253  int m_now;
254 
255  public:
256  typedef VT key_type;
257  typedef cluster_dist value_type;
258  typedef value_type& reference;
259  typedef boost::lvalue_property_map_tag category;
260 
270  cluster_distance_wrapper(
271  std::vector< cluster_dist > *distance,
272  VertexIndexMap index,
273  std::vector< DT > *limit,
274  std::vector< int > *last_accessed,
275  int now) :
276  m_distance(distance),
277  m_index(index),
278  m_limit(limit),
279  m_last_accessed(last_accessed),
280  m_now(now) {}
281 
289  reference operator[](const key_type& key) const {
290  int k_ind = m_index[key];
291  if ((*m_last_accessed)[k_ind] != m_now) {
292  (*m_last_accessed)[k_ind] = m_now;
293  (*m_distance)[k_ind] = cluster_dist::make_limit((*m_limit)[k_ind]);
294  }
295  return (*m_distance)[k_ind];
296  }
297  };
298 
305  template <typename DistanceMap, typename Tag>
306  class cluster_recorder : boost::base_visitor< cluster_recorder<DistanceMap, Tag> > {
308  int m_w_ind;
309 
311  std::vector< BunchMap >* m_bunch;
312 
314  VertexIndexMap m_index;
315 
317  DistanceMap m_distance;
318 
319  public:
320  using event_filter = Tag;
321 
322  explicit cluster_recorder(int w_ind, std::vector<BunchMap> *bunch,
323  VertexIndexMap index, DistanceMap distance) :
324  m_w_ind(w_ind), m_bunch(bunch), m_index(index), m_distance(distance) {}
325 
326  template <typename Vertex>
327  void operator()(Vertex const v, Graph const &g) const {
328  (*m_bunch)[m_index[v]].insert(std::make_pair(m_w_ind, m_distance[v].value()));
329  }
330  };
331 
344  template <typename DistanceMap, typename Tag>
345  cluster_recorder<DistanceMap, Tag>
346  make_cluster_recorder(int w_ind, std::vector<BunchMap> *bunch, VertexIndexMap index,
347  DistanceMap distance, Tag) {
348  return cluster_recorder<DistanceMap, Tag>{w_ind, bunch, index, distance};
349  };
350 
363  void compute_cluster(const Graph& g, EdgeWeightMap edge_weight, VT w, int k,
364  std::vector< std::vector<DT> > &limit,
365  std::vector<cluster_dist> &distance, std::vector<int> &last_accessed) {
366  DVect cluster;
367  int w_ind = m_index[w];
368  int w_layer_num = m_layer_num[w_ind];
369 
370  cluster_distance_wrapper distance_wrapper(
371  &distance, m_index, &limit[w_layer_num + 1],
372  &last_accessed, w_ind);
373  distance_wrapper[w] = cluster_dist(DT{});
374 
375  boost::dijkstra_shortest_paths_no_color_map_no_init(
376  g,
377  w,
378  boost::dummy_property_map(),
379  distance_wrapper,
380  edge_weight,
381  m_index,
382  typename cluster_dist::less(),
383  typename cluster_dist::plus(),
384  cluster_dist(std::numeric_limits<DT>::max()),
385  cluster_dist(DT{}),
386  boost::make_dijkstra_visitor(make_cluster_recorder(
387  w_ind, &m_bunch, m_index, distance_wrapper,
388  boost::on_examine_vertex{})
389  )
390  );
391  }
392 
400  void compute_bunchs(const Graph& g, EdgeWeightMap edge_weight, int k) {
402  std::vector< std::vector<DT> > limit(k+1,
403  std::vector<DT>(num_vertices(g), std::numeric_limits<DT>::max()));
404  for (int l: irange(k)) {
405  for (int i: irange(num_vertices(g))) {
406  limit[l][i] = m_parent[i][l].second;
407  }
408  }
409  std::vector<cluster_dist> distance(num_vertices(g));
410  std::vector<int> last_accessed(num_vertices(g), -1);
411 
412  for (auto v: boost::as_array(vertices(g))) {
413  compute_cluster(g, edge_weight, v, k, limit, distance, last_accessed);
414  }
415  }
416 
417 public:
418 
429  VertexIndexMap index,
430  EdgeWeightMap edge_weight,
431  int k,
432  Rand && random_engine = Rand(5426u)) :
433  m_index(index),
434  m_layer_num(num_vertices(g)),
435  m_parent(num_vertices(g)),
436  m_bunch(num_vertices(g))
437  {
438  long double p = powl(num_vertices(g), -1./k);
439  k = choose_layers(g, k, p, random_engine);
440  for (int layer_num: irange(k)) {
441  compute_parents(g, edge_weight, layer_num);
442  }
443  compute_bunchs(g, edge_weight, k);
444  }
445 
447 
448  DT operator()(VT u, VT v) const {
449  int u_ind = m_index[u], v_ind = m_index[v];
450  typename std::unordered_map<int, DT>::const_iterator it;
451  int l = 0;
452  std::pair<int, DT> middle_vertex = m_parent[u_ind][l];
453  while ((it = m_bunch[v_ind].find(middle_vertex.first)) == m_bunch[v_ind].end()) {
454  ++l;
455  middle_vertex = m_parent[v_ind][l];
456  std::swap(u_ind, v_ind);
457  }
459  return it->second + middle_vertex.second;
460  }
461 };
462 
478 template < typename Graph,
479  typename EdgeWeightMap,
480  typename VertexIndexMap,
481  typename Rand=std::default_random_engine
482  >
483 distance_oracle_thorup2kminus1approximation<Graph, VertexIndexMap, EdgeWeightMap, Rand>
485  const Graph &g,
486  const int k,
487  VertexIndexMap index,
488  EdgeWeightMap edge_weight,
489  Rand && random_engine = Rand(5426u)) {
491  VertexIndexMap,
492  EdgeWeightMap,
493  Rand>(g, index, edge_weight, k, std::move(random_engine));
494 }
495 
511 template < typename Graph,
512  typename P = char,
513  typename T = boost::detail::unused_tag_type,
514  typename R = boost::no_property,
515  typename Rand=std::default_random_engine
516  >
517 auto
519  const Graph &g,
520  const int k,
521  const boost::bgl_named_params<P, T, R>& params = boost::no_named_parameters(),
522  Rand && random_engine = Rand(5426u))
524  decltype(choose_const_pmap(get_param(params, boost::vertex_index), g, boost::vertex_index)),
525  decltype(choose_const_pmap(get_param(params, boost::edge_weight), g, boost::edge_weight)),
526  Rand> {
528  k,
529  choose_const_pmap(get_param(params, boost::vertex_index), g, boost::vertex_index),
530  choose_const_pmap(get_param(params, boost::edge_weight), g, boost::edge_weight),
531  std::move(random_engine));
532 }
533 
534 } //paal
535 
536 #endif // PAAL_THORUP_2KMINUS1_HPP
DT operator()(VT u, VT v) const
Returns an 2k-1 approximate distance between two vertices in O(k) time.
less functor
Definition: functors.hpp:497
A comparator struct adjusted to recognize unmodified values.
auto irange(T begin, T end)
irange
Definition: irange.hpp:22
This file contains set of simple useful functors or functor adapters.
void assign_max(T &t, const T &u)
cluster_dist operator()(cluster_dist a, cluster_dist b) const
Sum operator.
bool operator()(cluster_dist a, cluster_dist b) const
A comparison operator.
distance_oracle_thorup2kminus1approximation< Graph, VertexIndexMap, EdgeWeightMap, Rand > make_distance_oracle_thorup2kminus1approximation(const Graph &g, const int k, VertexIndexMap index, EdgeWeightMap edge_weight, Rand &&random_engine=Rand(5426u))
distance_oracle_thorup2kminus1approximation(const Graph &g, VertexIndexMap index, EdgeWeightMap edge_weight, int k, Rand &&random_engine=Rand(5426u))
Constructor.