16 #ifndef PAAL_THORUP_2KMINUS1_HPP
17 #define PAAL_THORUP_2KMINUS1_HPP
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>
31 #include <unordered_map>
46 template <
typename Graph,
47 typename VertexIndexMap,
48 typename EdgeWeightMap,
49 typename Rand=std::default_random_engine
52 using DT =
typename boost::property_traits<EdgeWeightMap>::value_type;
53 using VT =
typename boost::graph_traits<Graph>::vertex_descriptor;
56 using DVect = std::vector< std::pair<int, DT> >;
59 using BunchMap = std::unordered_map<int, DT>;
62 VertexIndexMap m_index;
69 std::vector< int > m_layer_num;
72 std::vector< DVect > m_parent;
75 std::vector< BunchMap > m_bunch;
87 int choose_layers(
const Graph& g,
int k,
long double p, Rand & random_engine) {
88 std::uniform_real_distribution<> dist(0,1);
90 int max_layer_num = 0;
91 long double logp = log(p);
93 for (
int ind:
irange(num_vertices(g))) {
94 m_layer_num[ind] = std::min(k-1, (
int)(log(dist(random_engine)) / logp));
98 return max_layer_num+1;
107 template <
typename NearestMap,
typename Tag>
108 class nearest_recorder : boost::base_visitor< nearest_recorder<NearestMap, Tag> > {
111 NearestMap m_nearest_map;
114 using event_filter = Tag;
117 explicit nearest_recorder(NearestMap
const nearest_map) : m_nearest_map(nearest_map) {}
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);
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};
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;
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{};
155 boost::dijkstra_shortest_paths_no_init(
159 boost::dummy_property_map(),
160 make_iterator_property_map(distance.begin(), m_index, distance[0]),
164 boost::closed_plus<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{})
172 for (
int ind:
irange(num_vertices(g))) {
173 m_parent[ind].push_back(std::make_pair(nearest[ind], distance[ind]));
185 cluster_dist(DT value,
bool unmodified) :
186 m_value(value), m_unmodified(unmodified) {}
190 cluster_dist(DT value = DT{}) :
191 m_value(value), m_unmodified(
false) {}
195 make_limit(DT value = std::numeric_limits<DT>::max()) {
196 return cluster_dist(value,
true);
206 return (a.m_value < b.m_value) && (b.m_unmodified || !a.m_unmodified);
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);
219 const DT value()
const {
230 class cluster_distance_wrapper :
231 public boost::put_get_helper<cluster_dist&, cluster_distance_wrapper>
234 std::vector< cluster_dist > *m_distance;
237 VertexIndexMap m_index;
244 std::vector< DT > *m_limit;
247 std::vector<int> *m_last_accessed;
257 typedef cluster_dist value_type;
258 typedef value_type& reference;
259 typedef boost::lvalue_property_map_tag category;
270 cluster_distance_wrapper(
271 std::vector< cluster_dist > *distance,
272 VertexIndexMap index,
273 std::vector< DT > *limit,
274 std::vector< int > *last_accessed,
276 m_distance(distance),
279 m_last_accessed(last_accessed),
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]);
295 return (*m_distance)[k_ind];
305 template <
typename DistanceMap,
typename Tag>
306 class cluster_recorder : boost::base_visitor< cluster_recorder<DistanceMap, Tag> > {
311 std::vector< BunchMap >* m_bunch;
314 VertexIndexMap m_index;
317 DistanceMap m_distance;
320 using event_filter = Tag;
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) {}
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()));
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};
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) {
367 int w_ind = m_index[w];
368 int w_layer_num = m_layer_num[w_ind];
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{});
375 boost::dijkstra_shortest_paths_no_color_map_no_init(
378 boost::dummy_property_map(),
382 typename cluster_dist::less(),
383 typename cluster_dist::plus(),
384 cluster_dist(std::numeric_limits<DT>::max()),
386 boost::make_dijkstra_visitor(make_cluster_recorder(
387 w_ind, &m_bunch, m_index, distance_wrapper,
388 boost::on_examine_vertex{})
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()));
405 for (
int i:
irange(num_vertices(g))) {
406 limit[l][i] = m_parent[i][l].second;
409 std::vector<cluster_dist> distance(num_vertices(g));
410 std::vector<int> last_accessed(num_vertices(g), -1);
412 for (
auto v: boost::as_array(vertices(g))) {
413 compute_cluster(g, edge_weight, v, k, limit, distance, last_accessed);
429 VertexIndexMap index,
430 EdgeWeightMap edge_weight,
432 Rand && random_engine = Rand(5426u)) :
434 m_layer_num(num_vertices(g)),
435 m_parent(num_vertices(g)),
436 m_bunch(num_vertices(g))
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);
443 compute_bunchs(g, edge_weight, k);
449 int u_ind = m_index[u], v_ind = m_index[v];
450 typename std::unordered_map<int, DT>::const_iterator it;
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()) {
455 middle_vertex = m_parent[v_ind][l];
456 std::swap(u_ind, v_ind);
459 return it->second + middle_vertex.second;
478 template <
typename Graph,
479 typename EdgeWeightMap,
480 typename VertexIndexMap,
481 typename Rand=std::default_random_engine
483 distance_oracle_thorup2kminus1approximation<Graph, VertexIndexMap, EdgeWeightMap, Rand>
487 VertexIndexMap index,
488 EdgeWeightMap edge_weight,
489 Rand && random_engine = Rand(5426u)) {
493 Rand>(g, index, edge_weight, k, std::move(random_engine));
511 template <
typename Graph,
513 typename T = boost::detail::unused_tag_type,
514 typename R = boost::no_property,
515 typename Rand=std::default_random_engine
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)),
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));
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.
A comparator struct adjusted to recognize unmodified values.
auto irange(T begin, T end)
irange
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.
2k-1 approximate distance oracle