Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
contraction_hierarchy.cpp
Go to the documentation of this file.
3#include <routingkit/sort.h>
5#include <routingkit/timer.h>
8
9#include <vector>
10#include <fstream>
11#include <stdexcept>
12
13namespace RoutingKit{
14
15namespace{
16
17 void sort_arcs_and_remove_multi_and_loop_arcs(
18 unsigned node_count, std::vector<unsigned>&tail, std::vector<unsigned>&head, std::vector<unsigned>&weight, std::vector<unsigned>&input_arc_id,
19 const std::function<void(std::string)>&log_message
20 ){
21
22 long long timer = 0; // initialize to avoid warning, not needed
23 if(log_message){
24 timer = -get_micro_time();
25 log_message("Start removing loops and multi arcs from input.");
26 }
27
28 {
30 head = apply_inverse_permutation(p, std::move(head));
32 input_arc_id = apply_inverse_permutation(p, std::move(input_arc_id));
33 }
34
35 unsigned arc_count = head.size();
36
37 if(arc_count != 0){
38
39 unsigned out = 0;
40 for(unsigned in = 0; in < arc_count; ++in){
41 if(tail[in] != head[in]){
42 tail[out] = tail[in];
43 head[out] = head[in];
44 weight[out] = weight[in];
45 input_arc_id[out] = input_arc_id[in];
46 ++out;
47 }
48 }
49 arc_count = out;
50 }
51
52 if(arc_count != 0)
53 {
54 unsigned out = 1;
55 for(unsigned in = 1; in < arc_count; ++in){
56 if(tail[in-1] != tail[in] || head[in-1] != head[in]){
57 tail[out] = tail[in];
58 head[out] = head[in];
59 weight[out] = weight[in];
60 input_arc_id[out] = input_arc_id[in];
61 ++out;
62 }else{
63 if(weight[in] < weight[out-1]){
64 weight[out-1] = weight[in];
65 input_arc_id[out-1] = input_arc_id[in];
66 }
67 }
68 }
69 arc_count = out;
70 }
71
72 tail.erase(tail.begin()+arc_count, tail.end());
73 head.erase(head.begin()+arc_count, head.end());
74 weight.erase(weight.begin()+arc_count, weight.end());
75 input_arc_id.erase(input_arc_id.begin()+arc_count, input_arc_id.end());
76
77 if(log_message){
78 timer += get_micro_time();
79 log_message("Finished removing loops and multi arcs from input. Needed "+std::to_string(timer)+"musec time.");
80 }
81 }
82
83 class Graph{
84 public:
85 Graph(){}
86
87 Graph(unsigned node_count, const std::vector<unsigned>&tail, const std::vector<unsigned>&head, const std::vector<unsigned>&weight):
91
92 for(unsigned a=0; a<head.size(); ++a){
93 unsigned x = tail[a];
94 unsigned y = head[a];
95 unsigned w = weight[a];
96
97
98 if(x != y){
99 out_[x].push_back({y, w, 1, invalid_id});
100 in_[y].push_back({x, w, 1, invalid_id});
101 }
102 }
103 }
104
105 void add_arc_or_reduce_arc_weight(unsigned x, unsigned mid_node, unsigned y, unsigned weight, unsigned hop_length){
106 assert(x != y);
107
108 assert(x < node_count());
109 assert(y < node_count());
110
111 auto reduce_arc_if_exists = [weight, hop_length, mid_node](
112 unsigned x, std::vector<Arc>&x_out,
113 unsigned y, std::vector<Arc>&y_in
114 ){
115
116 // Does arc exist?
117 for(unsigned out_arc = 0; out_arc < x_out.size(); ++out_arc){
118 if(x_out[out_arc].node == y){
119
120 // Is the existing arc longer?
121 if(x_out[out_arc].weight <= weight)
122 return true;
123
124 // We need to adjust the weights
125 for(unsigned in_arc = 0; in_arc < y_in.size(); ++in_arc){
126 if(y_in[in_arc].node == x){
127 x_out[out_arc].weight = weight;
128 x_out[out_arc].hop_length = hop_length;
129 x_out[out_arc].mid_node = mid_node;
130 y_in[in_arc].weight = weight;
131 y_in[in_arc].hop_length = hop_length;
132 y_in[in_arc].mid_node = mid_node;
133 return true;
134 }
135 }
136 assert(false && "arc only exists in one direction");
137 }
138 }
139 return false;
140 };
141
142 if(out_[x].size() <= in_[y].size()){
143 if(reduce_arc_if_exists(x, out_[x], y, in_[y]))
144 return;
145 } else {
146 if(reduce_arc_if_exists(y, in_[y], x, out_[x]))
147 return;
148 }
149
150 // The edges does not exist -> add the edge
151 out_[x].push_back({y,weight,hop_length,mid_node});
152 in_[y].push_back({x,weight,hop_length,mid_node});
153 }
154
155 void remove_all_incident_arcs(unsigned x){
156 assert(x < node_count());
157
158 auto remove_back_arcs = [&](unsigned x, const std::vector<Arc>&x_out, std::vector<std::vector<Arc>>&in){
159 for(unsigned out_arc = 0; out_arc < x_out.size(); ++out_arc){
160 unsigned y = x_out[out_arc].node;
161 for(auto in_arc = in[y].begin(); ; ++in_arc){
162 assert(in_arc != in[y].end());
163 if(in_arc->node == x){
164 in[y].erase(in_arc);
165 break;
166 }
167 }
168 }
169 };
170
171 remove_back_arcs(x, out_[x], in_);
172 remove_back_arcs(x, in_[x], out_);
173
174 in_[x].clear();
175 out_[x].clear();
176 in_[x].shrink_to_fit();
177 out_[x].shrink_to_fit();
178 }
179
180 struct Arc{
181 unsigned node;
182 unsigned weight;
183 unsigned hop_length;
184 unsigned mid_node;
185 };
186
187 unsigned out_deg(unsigned node)const{
188 assert(node < node_count());
189 return out_[node].size();
190 }
191
192 unsigned in_deg(unsigned node)const{
193 assert(node < node_count());
194 return in_[node].size();
195 }
196
197 Arc out(unsigned node, unsigned out_arc)const{
198 assert(node < node_count());
199 assert(out_arc < out_[node].size());
200 return out_[node][out_arc];
201 }
202
203 Arc in(unsigned node, unsigned in_arc)const{
204 assert(node < node_count());
205 assert(in_arc < in_[node].size());
206 return in_[node][in_arc];
207 }
208
209 unsigned node_count()const{
210 assert(in_.size() == out_.size());
211 return out_.size();
212 }
213
214 unsigned level(unsigned node)const{
215 assert(node < node_count());
216 return level_[node];
217 }
218
219 void raise_level(unsigned node, unsigned level){
220 assert(node < node_count());
221 if(level >= level_[node]){
222 level_[node] = level;
223 }
224 }
225 private:
226 std::vector<std::vector<Arc>>out_, in_;
227 std::vector<unsigned>level_;
228 };
229
230 class ShorterPathTest{
231 public:
232 ShorterPathTest(){}
233 ShorterPathTest(const Graph&graph, unsigned max_pop_count):
238 {}
239
240 private:
241// Uncomment the following lines to get some very expensive but very detailed asserts
242 void assert_no_witness_found(unsigned len)const{
243// for(unsigned x = 0; x<graph->node_count(); ++x){
244// if(was_forward_pushed.is_set(x) && was_backward_pushed.is_set(x)){
245// assert(forward_tentative_distance[x] + backward_tentative_distance[x] > len);
246// }
247// }
248 }
249
250 void assert_forward_tentative_distances_correct()const{
251// for(unsigned x = 0; x<graph->node_count(); ++x){
252// if(was_forward_pushed.is_set(x)){
253// if(forward_tentative_distance[x] != 0){
254// bool witness_found = false;
255// for(unsigned yx = 0; yx < graph->in_deg(x); ++yx){
256// unsigned y = graph->in(x, yx).node;
257// unsigned w = graph->in(x, yx).weight;
258// if(forward_tentative_distance[y] + w == forward_tentative_distance[x])
259// witness_found = true;
260// }
261// assert(witness_found && "forward_tentative_distance array contains garbage");
262// }
263// }
264// }
265 }
266
267 void assert_backward_tentative_distances_correct()const{
268// for(unsigned x = 0; x<graph->node_count(); ++x){
269// if(was_backward_pushed.is_set(x)){
270// if(backward_tentative_distance[x] != 0){
271// bool witness_found = false;
272// for(unsigned xy = 0; xy < graph->out_deg(x); ++xy){
273// unsigned y = graph->out(x, xy).node;
274// unsigned w = graph->out(x, xy).weight;
275// if(backward_tentative_distance[y] + w == backward_tentative_distance[x])
276// witness_found = true;
277// }
278// assert(witness_found && "backward_tentative_distance array contains garbage");
279// }
280// }
281// }
282 }
283
284 void assert_witness_found(unsigned len)const{
285// assert_forward_tentative_distances_correct();
286// assert_backward_tentative_distances_correct();
287// for(unsigned x = 0; x<graph->node_count(); ++x){
288// if(was_forward_pushed.is_set(x) && was_backward_pushed.is_set(x)){
289// if(forward_tentative_distance[x] + backward_tentative_distance[x] <= len)
290// return;
291// }
292// }
293// assert(false && "no witness exists but algorithm claimed that there is one");
294 }
295
296 template<class GetOutDeg, class GetOutArc>
297 bool forward_settle(
298 MinIDQueue&forward_queue,
299 TimestampFlags&was_forward_pushed,
300 const TimestampFlags&was_backward_pushed,
301 std::vector<unsigned>&forward_tentative_distance,
302 const std::vector<unsigned>&backward_tentative_distance,
303 const GetOutDeg&graph_out_deg,
304 const GetOutArc&graph_out,
305 unsigned bypass,
306 unsigned len
307 ){
308 auto p = forward_queue.pop();
309
310 unsigned popped_node = p.id;
311 unsigned distance_to_popped_node = p.key;
312
313 assert(forward_tentative_distance[popped_node] == distance_to_popped_node);
314 assert(was_forward_pushed.is_set(popped_node));
315
316 if(was_backward_pushed.is_set(popped_node)){
317 if(distance_to_popped_node + backward_tentative_distance[popped_node] <= len){
318 assert_witness_found(len);
319 return true;
320 }
321 }
322
323 bool witness_found = false;
324
325 for(unsigned out_arc = 0; out_arc < graph_out_deg(popped_node); ++out_arc){
326 unsigned next_node = graph_out(popped_node, out_arc).node;
327
328 if(next_node == bypass)
329 continue;
330
331 unsigned next_node_distance = distance_to_popped_node + graph_out(popped_node, out_arc).weight;
332
333 if(was_forward_pushed.is_set(next_node)){
334 if(next_node_distance < forward_tentative_distance[next_node]){
335 forward_queue.decrease_key({next_node, next_node_distance});
336 forward_tentative_distance[next_node] = next_node_distance;
337
338 if(was_backward_pushed.is_set(next_node)){
339 if(next_node_distance + backward_tentative_distance[next_node] <= len){
340 assert_witness_found(len);
341 witness_found = true;
342 }
343 }
344 }
345 } else {
346 was_forward_pushed.set(next_node);
347 forward_tentative_distance[next_node] = next_node_distance;
348 forward_queue.push({next_node, next_node_distance});
349
350 if(was_backward_pushed.is_set(next_node)){
351 if(next_node_distance + backward_tentative_distance[next_node] <= len){
352 assert_witness_found(len);
353 witness_found = true;
354 }
355 }
356
357 }
358 }
359 if(!witness_found)
360 assert_no_witness_found(len);
361 return witness_found;
362 }
363
364 unsigned bypass_node;
365 public:
366 void pin_source(unsigned s, unsigned new_bypass_node){
367 was_forward_pushed.reset_all();
368 forward_queue.clear();
369 forward_queue.push({s, 0});
371 was_forward_pushed.set(s);
372 bypass_node = new_bypass_node;
373 }
374
375 bool does_shorter_or_equal_path_to_target_exist(unsigned t, unsigned len){
376 was_backward_pushed.reset_all();
377 backward_queue.clear();
378 backward_queue.push({t, 0});
380 was_backward_pushed.set(t);
381
382 unsigned pop_count = 0;
383
384 if(was_forward_pushed.is_set(t))
385 if(forward_tentative_distance[t] <= len)
386 return true;
387
388 assert_no_witness_found(len);
389
390 while(!forward_queue.empty() && !backward_queue.empty()){
391 if(forward_queue.peek().key + backward_queue.peek().key > len){
392 return false;
393 }
394
395 if(forward_queue.peek().key <= backward_queue.peek().key){
396 if(
397 forward_settle(
398 forward_queue,
399 was_forward_pushed, was_backward_pushed,
400 forward_tentative_distance, backward_tentative_distance,
401 [&](unsigned x){return graph->out_deg(x);},
402 [&](unsigned x, unsigned a){return graph->out(x, a);},
404 len
405 )
406 ){
407 assert_witness_found(len);
408 return true;
409 } else {
410 assert_no_witness_found(len);
411 }
412 } else {
413 if(
414 forward_settle(
415 backward_queue,
416 was_backward_pushed, was_forward_pushed,
417 backward_tentative_distance, forward_tentative_distance,
418 [&](unsigned x){return graph->in_deg(x);},
419 [&](unsigned x, unsigned a){return graph->in(x, a);},
421 len
422 )
423 ){
424 assert_witness_found(len);
425 return true;
426 } else {
427 assert_no_witness_found(len);
428 }
429 }
430
431 ++pop_count;
432
433 if(pop_count > max_pop_count){
434 return false;
435 }
436 }
437 return false;
438 }
439
440 bool does_shorter_or_equal_path_exist(unsigned s, unsigned t, unsigned len, unsigned bypass){
441 if(s == t)
442 return true;
443
444 was_forward_pushed.reset_all();
445 was_backward_pushed.reset_all();
446
447 forward_queue.clear();
448 backward_queue.clear();
449
450 forward_queue.push({s, 0});
451 backward_queue.push({t, 0});
452
455
456 was_forward_pushed.set(s);
457 was_backward_pushed.set(t);
458
459 unsigned pop_count = 0;
460
461 assert_no_witness_found(len);
462
463 while(!forward_queue.empty() && !backward_queue.empty()){
464
465 if(forward_queue.peek().key + backward_queue.peek().key > len){
466 return false;
467 }
468
469 if(forward_queue.peek().key <= backward_queue.peek().key){
470 if(
471 forward_settle(
472 forward_queue,
473 was_forward_pushed, was_backward_pushed,
474 forward_tentative_distance, backward_tentative_distance,
475 [&](unsigned x){return graph->out_deg(x);},
476 [&](unsigned x, unsigned a){return graph->out(x, a);},
477 bypass,
478 len
479 )
480 ){
481 assert_witness_found(len);
482 return true;
483 } else {
484 assert_no_witness_found(len);
485 }
486 } else {
487 if(
488 forward_settle(
489 backward_queue,
490 was_backward_pushed, was_forward_pushed,
491 backward_tentative_distance, forward_tentative_distance,
492 [&](unsigned x){return graph->in_deg(x);},
493 [&](unsigned x, unsigned a){return graph->in(x, a);},
494 bypass,
495 len
496 )
497 ){
498 assert_witness_found(len);
499 return true;
500 } else {
501 assert_no_witness_found(len);
502 }
503 }
504
505 ++pop_count;
506
507 if(pop_count > max_pop_count)
508 return false;
509 }
510 return false;
511 }
512
513 unsigned get_max_pop_count()const{
514 return max_pop_count;
515 }
516 private:
518 const Graph*graph;
519 std::vector<unsigned>forward_tentative_distance;
520 std::vector<unsigned>backward_tentative_distance;
521 MinIDQueue forward_queue;
522 MinIDQueue backward_queue;
523 TimestampFlags was_forward_pushed;
524 TimestampFlags was_backward_pushed;
525 };
526
527 unsigned estimate_node_importance(const Graph&graph, ShorterPathTest&shorter_path_test, unsigned node){
528 unsigned level = graph.level(node);
529
530 unsigned added_arc_count = 0;
531 unsigned added_hop_count = 0;
532
533 for(unsigned in_arc = 0; in_arc < graph.in_deg(node); ++in_arc){
534 unsigned in_node = graph.in(node, in_arc).node;
535 shorter_path_test.pin_source(in_node, node);
536 for(unsigned out_arc = 0; out_arc < graph.out_deg(node); ++out_arc){
537 unsigned out_node = graph.out(node, out_arc).node;
538 if(in_node != out_node){
539 if(
540 !shorter_path_test.does_shorter_or_equal_path_to_target_exist(
541 out_node,
542 graph.in(node, in_arc).weight + graph.out(node, out_arc).weight
543 )
544 ){
545 ++added_arc_count;
546 added_hop_count += graph.in(node, in_arc).hop_length;
547 added_hop_count += graph.out(node, out_arc).hop_length;
548 }
549 }
550 }
551 }
552
553 unsigned removed_arc_count = 1;
554 removed_arc_count += graph.in_deg(node);
555 removed_arc_count += graph.out_deg(node);
556
557 unsigned removed_hop_count = 1;
558 for(unsigned in_arc = 0; in_arc < graph.in_deg(node); ++in_arc)
559 removed_hop_count += graph.in(node, in_arc).hop_length;
560 for(unsigned out_arc = 0; out_arc < graph.out_deg(node); ++out_arc)
561 removed_hop_count += graph.out(node, out_arc).hop_length;
562
563 return 1 + 1000*level + (1000*added_arc_count) / removed_arc_count + (1000*added_hop_count) / removed_hop_count;
564 }
565
566 void contract_node(Graph&graph, ShorterPathTest&shorter_path_test, unsigned node_being_contracted){
567 for(unsigned in_arc = 0; in_arc < graph.in_deg(node_being_contracted); ++in_arc){
568 unsigned in_node = graph.in(node_being_contracted, in_arc).node;
569 shorter_path_test.pin_source(in_node, node_being_contracted);
570 for(unsigned out_arc = 0; out_arc < graph.out_deg(node_being_contracted); ++out_arc){
571 unsigned out_node = graph.out(node_being_contracted, out_arc).node;
572 if(in_node != out_node){
573 if(
574 !shorter_path_test.does_shorter_or_equal_path_to_target_exist(
575 out_node,
576 graph.in(node_being_contracted, in_arc).weight + graph.out(node_being_contracted, out_arc).weight
577 )
578 ){
579 graph.add_arc_or_reduce_arc_weight(
580 in_node, node_being_contracted, out_node,
581 graph.in(node_being_contracted, in_arc).weight + graph.out(node_being_contracted, out_arc).weight,
582 graph.in(node_being_contracted, in_arc).hop_length + graph.out(node_being_contracted, out_arc).hop_length
583 );
584 }
585 }
586 }
587 }
588
589 graph.remove_all_incident_arcs(node_being_contracted);
590
591 assert(graph.out_deg(node_being_contracted) == 0);
592 assert(graph.in_deg(node_being_contracted) == 0);
593 }
594
595}
596
597namespace {
598
599 struct ContractionHierarchyExtraInfo{
600 struct Side{
601 std::vector<unsigned>mid_node;
602 std::vector<unsigned>tail;
603 };
604
606 };
607
608 void build_ch_and_order(
609 Graph&graph,
610 ContractionHierarchy&ch,
611 ContractionHierarchyExtraInfo&ch_extra,
612 unsigned max_pop_count,
613 const std::function<void(std::string)>&log_message
614 ){
615 long long timer = 0; // initialize to avoid warning, not needed
616 long long last_log_message_time = 0; // initialize to avoid warning, not needed
617 if(log_message){
618 last_log_message_time = get_micro_time();
619 timer = -last_log_message_time;
620 log_message("Start building queue.");
621 }
622
623 const unsigned node_count = graph.node_count();
624
625 ShorterPathTest shorter_path_test(graph, max_pop_count);
626
627 ch.rank.resize(node_count);
628 ch.order.resize(node_count);
629 MinIDQueue queue(node_count);
630
631
632 for(unsigned i=0; i<node_count; ++i){
633 queue.push({i, estimate_node_importance(graph, shorter_path_test, i)});
634
635 if(log_message){
636 long long current_time = get_micro_time();
637 if(current_time - last_log_message_time > 1000000){
638 last_log_message_time = current_time;
639 log_message("Added "+std::to_string(i+1) + " of " + std::to_string(node_count) + " nodes to the queue. Running for "+std::to_string(timer+current_time)+"musec.");
640 }
641 }
642 }
643
644 if(log_message){
645 timer += get_micro_time();
646 log_message("Finished building queue. Needed "+std::to_string(timer)+"musec time.");
647 log_message("Start contracting nodes.");
648 timer = -get_micro_time();
649 }
650
651 std::vector<unsigned>neighbor_list;
652 std::vector<bool>is_neighbor(node_count, false);
653
654 unsigned contracted_node_count = 0;
655
656 while(!queue.empty()){
657 unsigned node_being_contracted = queue.pop().id;
658
659 ch.rank[node_being_contracted] = contracted_node_count;
660 ch.order[contracted_node_count] = node_being_contracted;
661
662 // Mark the neighbors
663 for(unsigned in_arc = 0; in_arc < graph.in_deg(node_being_contracted); ++in_arc){
664 unsigned x = graph.in(node_being_contracted, in_arc).node;
665 assert(node_being_contracted != x);
666 if(!is_neighbor[x]){
667 neighbor_list.push_back(x);
668 is_neighbor[x] = true;
669 }
670 }
671
672 for(unsigned out_arc = 0; out_arc < graph.out_deg(node_being_contracted); ++out_arc){
673 unsigned x = graph.out(node_being_contracted, out_arc).node;
674 assert(node_being_contracted != x);
675 if(!is_neighbor[x]){
676 neighbor_list.push_back(x);
677 is_neighbor[x] = true;
678 }
679 }
680
681 // Add the arcs to the search graph
682
683 for(unsigned out_arc = 0; out_arc < graph.out_deg(node_being_contracted); ++out_arc){
684 ch_extra.forward.tail.push_back(node_being_contracted);
685
686 const auto&a = graph.out(node_being_contracted, out_arc);
687 if(ch.forward.head.size() == invalid_id)
688 throw std::runtime_error("CH may contain at most 2^32-1 shortcuts per direction");
689 ch.forward.head.push_back(a.node);
690 ch.forward.weight.push_back(a.weight);
691 ch_extra.forward.mid_node.push_back(a.mid_node);
692 }
693
694 for(unsigned in_arc = 0; in_arc < graph.in_deg(node_being_contracted); ++in_arc){
695 ch_extra.backward.tail.push_back(node_being_contracted);
696
697 const auto&a = graph.in(node_being_contracted, in_arc);
698 if(ch.backward.head.size() == invalid_id)
699 throw std::runtime_error("CH may contain at most 2^32-1 shortcuts per direction");
700 ch.backward.head.push_back(a.node);
701 ch.backward.weight.push_back(a.weight);
702 ch_extra.backward.mid_node.push_back(a.mid_node);
703 }
704
705 unsigned neighbor_level = graph.level(node_being_contracted)+1;
706 unsigned out_deg = graph.out_deg(node_being_contracted);
707 unsigned in_deg = graph.in_deg(node_being_contracted);
708
709 contract_node(graph, shorter_path_test, node_being_contracted);
710
711 for(auto x:neighbor_list){
712 is_neighbor[x] = false;
713 graph.raise_level(x, neighbor_level);
714 unsigned new_key = estimate_node_importance(graph, shorter_path_test, x);
715 assert(queue.contains_id(x));
716 unsigned old_key = queue.get_key(x);
717 if(old_key < new_key)
718 queue.increase_key({x, new_key});
719 else if(old_key > new_key)
720 queue.decrease_key({x, new_key});
721 }
722
723 neighbor_list.clear();
724
725 ++contracted_node_count;
726
727 if(log_message){
728 long long current_time = get_micro_time();
729 if(current_time - last_log_message_time > 1000000){
730 last_log_message_time = current_time;
731 log_message("Contracted "+std::to_string(contracted_node_count) + " of " + std::to_string(node_count) + ". The in degree of last node was " + std::to_string(in_deg)+ " and out degree was " + std::to_string(out_deg)+". Running for "+std::to_string(timer+current_time)+"musec.");
732 }
733 }
734 }
735
736 ch.forward.head.shrink_to_fit();
737 ch.forward.weight.shrink_to_fit();
738 ch_extra.forward.mid_node.shrink_to_fit();
739 ch_extra.forward.tail.shrink_to_fit();
740
741 ch.backward.head.shrink_to_fit();
742 ch.backward.weight.shrink_to_fit();
743 ch_extra.backward.mid_node.shrink_to_fit();
744 ch_extra.backward.tail.shrink_to_fit();
745
746 if(log_message){
747 timer += get_micro_time();
748 log_message("Finished contracting nodes. Needed "+std::to_string(timer)+"musec.");
749 }
750
751 }
752
753
754 void build_ch_given_rank(
755 Graph&graph,
756 ContractionHierarchy&ch,
757 ContractionHierarchyExtraInfo&ch_extra,
758 const std::vector<unsigned>&rank,
759 unsigned max_pop_count,
760 const std::function<void(std::string)>&log_message
761 ){
762 unsigned node_count = graph.node_count();
763
764 long long timer = 0; // initialize to avoid warning, not needed
765 long long last_log_message_time = 0; // initialize to avoid warning, not needed
766 if(log_message){
767 last_log_message_time = get_micro_time();
768 timer = -last_log_message_time;
769 log_message("Start building contraction hierarchy with given rank.");
770 }
771
772 ShorterPathTest shorter_path_test(graph, max_pop_count);
773 ch.rank = rank;
774
775 ch.order = invert_permutation(rank);
776
777 for(unsigned i=0; i < node_count; ++i){
778 unsigned node_being_contracted = ch.order[i];
779
780 for(unsigned out_arc = 0; out_arc < graph.out_deg(node_being_contracted); ++out_arc){
781 ch_extra.forward.tail.push_back(node_being_contracted);
782
783 const auto&a = graph.out(node_being_contracted, out_arc);
784 if(ch.forward.head.size() == invalid_id)
785 throw std::runtime_error("CH may contain at most 2^32-1 shortcuts per direction");
786 ch.forward.head.push_back(a.node);
787 ch.forward.weight.push_back(a.weight);
788 ch_extra.forward.mid_node.push_back(a.mid_node);
789 }
790
791 for(unsigned in_arc = 0; in_arc < graph.in_deg(node_being_contracted); ++in_arc){
792 ch_extra.backward.tail.push_back(node_being_contracted);
793
794 const auto&a = graph.in(node_being_contracted, in_arc);
795 if(ch.backward.head.size() == invalid_id)
796 throw std::runtime_error("CH may contain at most 2^32-1 shortcuts per direction");
797 ch.backward.head.push_back(a.node);
798 ch.backward.weight.push_back(a.weight);
799 ch_extra.backward.mid_node.push_back(a.mid_node);
800 }
801
802 unsigned out_deg = graph.out_deg(node_being_contracted);
803 unsigned in_deg = graph.in_deg(node_being_contracted);
804
805 contract_node(graph, shorter_path_test, node_being_contracted);
806
807 if(log_message){
808 long long current_time = get_micro_time();
809 if(current_time - last_log_message_time > 1000000){
810 last_log_message_time = current_time;
811 log_message("Contracted "+std::to_string(i+1) + " of " + std::to_string(node_count) + ". The in degree of last node was " + std::to_string(in_deg)+ " and out degree was " + std::to_string(out_deg)+". Running for "+std::to_string(timer+current_time)+"musec.");
812 }
813 }
814 }
815
816 ch.forward.head.shrink_to_fit();
817 ch.forward.weight.shrink_to_fit();
818 ch_extra.forward.mid_node.shrink_to_fit();
819 ch_extra.forward.tail.shrink_to_fit();
820
821 ch.backward.head.shrink_to_fit();
822 ch.backward.weight.shrink_to_fit();
823 ch_extra.backward.mid_node.shrink_to_fit();
824 ch_extra.backward.tail.shrink_to_fit();
825
826 if(log_message){
827 timer += get_micro_time();
828 log_message("Finished contracting nodes. Needed "+std::to_string(timer)+"musec.");
829 }
830 }
831
832
833 void make_internal_nodes_and_rank_coincide(
834 ContractionHierarchy&ch,
835 ContractionHierarchyExtraInfo&ch_extra,
836 const std::function<void(std::string)>&log_message
837 ){
838 long long timer = 0; // initialize to avoid warning, not needed
839 if(log_message){
840 timer = -get_micro_time();
841 log_message("Start reordering nodes by rank.");
842 }
843
844 inplace_apply_permutation_to_elements_of(ch.rank, ch.forward.head);
845 inplace_apply_permutation_to_elements_of(ch.rank, ch_extra.forward.tail);
846 inplace_apply_permutation_to_possibly_invalid_elements_of(ch.rank, ch_extra.forward.mid_node);
847 inplace_apply_permutation_to_elements_of(ch.rank, ch.backward.head);
848 inplace_apply_permutation_to_elements_of(ch.rank, ch_extra.backward.tail);
849 inplace_apply_permutation_to_possibly_invalid_elements_of(ch.rank, ch_extra.backward.mid_node);
850
851 #ifndef NDEBUG
852 for(unsigned i=0; i<ch_extra.forward.tail.size(); ++i)
853 assert(ch_extra.forward.tail[i] < ch.forward.head[i]);
854 for(unsigned i=0; i<ch_extra.backward.tail.size(); ++i)
855 assert(ch_extra.backward.tail[i] < ch.backward.head[i]);
856 #endif
857
858 if(log_message){
859 timer += get_micro_time();
860 log_message("Finished reordering nodes by rank. Needed "+std::to_string(timer)+"musec.");
861 }
862 }
863
864 void sort_ch_arcs_and_build_first_out_arrays(
865 ContractionHierarchy&ch,
866 ContractionHierarchyExtraInfo&ch_extra,
867 const std::function<void(std::string)>&log_message
868 ){
869 long long timer = 0; // initialize to avoid warning, not needed
870 if(log_message){
871 timer = -get_micro_time();
872 log_message("Start sorting arcs.");
873 }
874
875 unsigned node_count = ch.rank.size();
876
877 {
879
880 ch.forward.head = apply_inverse_permutation(r, ch.forward.head);
881 ch.forward.weight = apply_inverse_permutation(r, ch.forward.weight);
882 ch_extra.forward.mid_node = apply_inverse_permutation(r, ch_extra.forward.mid_node);
883
884 ch.forward.first_out = invert_vector(ch_extra.forward.tail, node_count);
885 }
886
887 {
889 ch.backward.head = apply_inverse_permutation(r, ch.backward.head);
890 ch.backward.weight = apply_inverse_permutation(r, ch.backward.weight);
891 ch_extra.backward.mid_node = apply_inverse_permutation(r,ch_extra.backward.mid_node);
892
893 ch.backward.first_out = invert_vector(ch_extra.backward.tail, node_count);
894 }
895
896 if(log_message){
897 timer += get_micro_time();
898 log_message("Finished sorting arcs. Needed "+std::to_string(timer)+"musec.");
899 }
900 }
901
902 void optimize_order_for_cache(
903 ContractionHierarchy&ch,
904 const ContractionHierarchyExtraInfo&ch_extra,
905 const std::function<void(std::string)>&log_message
906 ){
907 long long timer = 0; // initialize to avoid warning, not needed
908 if(log_message){
909 timer = -get_micro_time();
910 log_message("Start optimizing order for cache.");
911 }
912
913 unsigned node_count = ch.rank.size();
914 unsigned forward_arc_count = ch.forward.head.size();
915 unsigned backward_arc_count = ch.backward.head.size();
916
917 std::vector<bool>is_in_bottom_level(node_count, true);
918 for(unsigned a=0; a<forward_arc_count; ++a)
919 is_in_bottom_level[ch.forward.head[a]] = false;
920 for(unsigned a=0; a<backward_arc_count; ++a)
921 is_in_bottom_level[ch.backward.head[a]] = false;
922 std::vector<unsigned>new_order(node_count);
923
924 unsigned new_order_end = node_count;
925
926 std::vector<bool>is_in_new_order(node_count, false);
927
928 MinIDQueue q(node_count);
929 for(unsigned r=0; r<node_count; ++r){
930 if(is_in_bottom_level[r]){
931 unsigned search_space_end = new_order_end;
932
933 q.push({r, ch.rank[r]});
934 assert(!is_in_new_order[r]);
935 is_in_new_order[r] = true;
936
937 while(!q.empty()){
938 unsigned x = q.pop().id;
939
940 --new_order_end;
941 new_order[new_order_end] = x;
942
943 auto on_node = [&](unsigned y){
944 assert(!is_in_bottom_level[y]);
945 if(!is_in_new_order[y]){
946 is_in_new_order[y] = true;
947 q.push({y, ch.rank[y]});
948 }
949 };
950
951 for(unsigned xy = ch.forward.first_out[x]; xy < ch.forward.first_out[x+1]; ++xy)
952 on_node(ch.forward.head[xy]);
953
954 for(unsigned xy = ch.backward.first_out[x]; xy < ch.backward.first_out[x+1]; ++xy)
955 on_node(ch.backward.head[xy]);
956 }
957 std::reverse(new_order.begin()+new_order_end, new_order.begin()+search_space_end);
958 }
959 }
960
961 assert(new_order_end == 0);
962 assert(is_permutation(new_order));
963
964 ch.rank = invert_permutation(new_order);
965 ch.order = std::move(new_order);
966
967 if(log_message){
968 timer += get_micro_time();
969 log_message("Finished optimizing order for cache. Needed "+std::to_string(timer)+"musec.");
970 }
971 }
972
973 void build_unpacking_information(
974 unsigned node_count,
975 const std::vector<unsigned>&tail,
976 const std::vector<unsigned>&head,
977 const std::vector<unsigned>&input_arc_id,
978 ContractionHierarchy&ch,
979 const ContractionHierarchyExtraInfo&ch_extra,
980 const std::function<void(std::string)>&log_message
981 ){
982 assert(is_sorted_using_less(tail));
983
984 long long timer = 0; // initialize to avoid warning, not needed
985 if(log_message){
986 log_message("Start building path unpacking information.");
987 timer = -get_micro_time();
988 }
989
990 ch.forward.shortcut_first_arc = std::vector<unsigned>(ch.forward.head.size());
991 ch.forward.shortcut_second_arc = std::vector<unsigned>(ch.forward.head.size());
992 ch.forward.is_shortcut_an_original_arc = BitVector(ch.forward.head.size(), BitVector::uninitialized);
993 ch.backward.shortcut_first_arc = std::vector<unsigned>(ch.backward.head.size());
994 ch.backward.shortcut_second_arc = std::vector<unsigned>(ch.backward.head.size());
995 ch.backward.is_shortcut_an_original_arc = BitVector(ch.backward.head.size(), BitVector::uninitialized);
996
997 auto first_out = invert_vector(tail, node_count);
998
999 for(unsigned x=0; x<node_count; ++x){
1000 for(unsigned xy=ch.forward.first_out[x]; xy<ch.forward.first_out[x+1]; ++xy){
1001 unsigned y=ch.forward.head[xy];
1002 unsigned z=ch_extra.forward.mid_node[xy];
1003 if(z == invalid_id){
1004 ch.forward.is_shortcut_an_original_arc.set(xy);
1005
1006 auto a = find_arc_given_sorted_head(first_out, head, ch.order[x], ch.order[y]);
1007 ch.forward.shortcut_first_arc[xy] = input_arc_id[a];
1008 ch.forward.shortcut_second_arc[xy] = head[a];
1009 }else{
1010 ch.forward.is_shortcut_an_original_arc.reset(xy);
1011 ch.forward.shortcut_first_arc[xy] = find_arc_given_sorted_head(ch.backward.first_out, ch.backward.head, z, x);
1012 ch.forward.shortcut_second_arc[xy] = find_arc_given_sorted_head(ch.forward.first_out, ch.forward.head, z, y);
1013
1014 assert(ch.forward.weight[xy] == ch.backward.weight[ch.forward.shortcut_first_arc[xy]] + ch.forward.weight[ch.forward.shortcut_second_arc[xy]]);
1015
1016 }
1017 }
1018 }
1019
1020 for(unsigned x=0; x<node_count; ++x){
1021 for(unsigned xy=ch.backward.first_out[x]; xy<ch.backward.first_out[x+1]; ++xy){
1022 unsigned y=ch.backward.head[xy];
1023 unsigned z=ch_extra.backward.mid_node[xy];
1024 if(z == invalid_id){
1025 ch.backward.is_shortcut_an_original_arc.set(xy);
1026 auto a = find_arc_given_sorted_head(first_out, head, ch.order[y], ch.order[x]);
1027 ch.backward.shortcut_first_arc[xy] = input_arc_id[a];
1028 ch.backward.shortcut_second_arc[xy] = head[a];
1029 }else{
1030 ch.backward.is_shortcut_an_original_arc.reset(xy);
1031 ch.backward.shortcut_first_arc[xy] = find_arc_given_sorted_head(ch.backward.first_out, ch.backward.head, z, y);
1032 ch.backward.shortcut_second_arc[xy] = find_arc_given_sorted_head(ch.forward.first_out, ch.forward.head, z, x);
1033 }
1034 }
1035 }
1036
1037 #ifndef NDEBUG
1038 unsigned input_arc_count = max_element_of(input_arc_id, 0u)+1;
1039
1040 for(unsigned a=0; a<ch.forward.head.size(); ++a){
1041 if(!ch.forward.is_shortcut_an_original_arc.is_set(a)){
1042 assert(ch.forward.shortcut_first_arc[a] < ch.backward.head.size());
1043 assert(ch.forward.shortcut_second_arc[a] < ch.forward.head.size());
1044 }else{
1045 assert(ch.forward.shortcut_first_arc[a] < input_arc_count);
1046 assert(ch.forward.shortcut_second_arc[a] < node_count);
1047 }
1048 }
1049 for(unsigned a=0; a<ch.backward.head.size(); ++a){
1050 if(!ch.backward.is_shortcut_an_original_arc.is_set(a)){
1051 assert(ch.backward.shortcut_first_arc[a] < ch.backward.head.size());
1052 assert(ch.backward.shortcut_second_arc[a] < ch.forward.head.size());
1053 }else{
1054 assert(ch.backward.shortcut_first_arc[a] < input_arc_count);
1055 assert(ch.backward.shortcut_second_arc[a] < node_count);
1056 }
1057 }
1058 #endif
1059
1060
1061 if(log_message){
1062 timer += get_micro_time();
1063 log_message("Finished building path unpacking information. Needed "+std::to_string(timer)+"musec.");
1064 log_message("Contraction Hierarchy is fully constructed.");
1065 }
1066 }
1067
1068 void log_input_graph_statistics(unsigned node_count, const std::vector<unsigned>&tail, const std::vector<unsigned>&head, const std::function<void(std::string)>&log_message){
1069 if(log_message){
1070 log_message("Input graph has "+std::to_string(node_count)+" nodes and "+std::to_string(tail.size())+" arcs.");
1071 std::vector<unsigned>deg(node_count, 0);
1072 for(unsigned i=0; i<tail.size(); ++i)
1073 ++deg[tail[i]];
1074 unsigned max_out_degree = max_element_of(deg);
1075 std::fill(deg.begin(), deg.end(), 0);
1076 for(unsigned i=0; i<tail.size(); ++i)
1077 ++deg[head[i]];
1078 unsigned max_in_degree = max_element_of(deg);
1079 log_message("The input's maximum in-degree is "+std::to_string(max_in_degree)+" and its maximum out-degree is "+std::to_string(max_out_degree)+".");
1080
1081 }
1082 }
1083
1084 void log_contraction_hierarchy_statistics(const ContractionHierarchy&ch, const std::function<void(std::string)>&log_message){
1085 if(log_message){
1086 log_message("CH has "+std::to_string(ch.forward.head.size())+" forward arcs.");
1087 log_message("CH has "+std::to_string(ch.backward.head.size())+" backward arcs.");
1088 }
1089 }
1090}
1091
1092
1094 unsigned node_count, std::vector<unsigned>tail, std::vector<unsigned>head, std::vector<unsigned>weight,
1095 const std::function<void(std::string)>&log_message, unsigned max_pop_count
1096){
1097 assert(tail.size() == head.size());
1098 assert(tail.size() == weight.size());
1099 assert(max_element_of(tail) < node_count);
1100 assert(max_element_of(head) < node_count);
1101
1102
1104 ContractionHierarchyExtraInfo ch_extra;
1105
1106 log_input_graph_statistics(node_count, tail, head, log_message);
1107
1108 std::vector<unsigned>input_arc_id = identity_permutation(head.size());
1109
1110 {
1111 sort_arcs_and_remove_multi_and_loop_arcs(node_count, tail, head, weight, input_arc_id, log_message);
1112 }
1113
1114 {
1115 Graph graph(node_count, tail, head, weight);
1116 build_ch_and_order(graph, ch, ch_extra, max_pop_count, log_message);
1117 }
1118
1119 {
1120 // This optimizes the order in a postprocessing step
1121 sort_ch_arcs_and_build_first_out_arrays(ch, ch_extra, log_message);
1122 optimize_order_for_cache(ch, ch_extra, log_message);
1123 }
1124
1125 {
1126 make_internal_nodes_and_rank_coincide(ch, ch_extra, log_message);
1127 sort_ch_arcs_and_build_first_out_arrays(ch, ch_extra, log_message);
1128 }
1129
1130 build_unpacking_information(node_count, tail, head, input_arc_id, ch, ch_extra, log_message);
1131
1132 log_contraction_hierarchy_statistics(ch, log_message);
1133
1134 return ch;
1135}
1136
1138 std::vector<unsigned>rank,
1139 std::vector<unsigned>tail, std::vector<unsigned>head, std::vector<unsigned>weight,
1140 const std::function<void(std::string)>&log_message, unsigned max_pop_count
1141){
1142 unsigned node_count = rank.size();
1143
1144 assert(tail.size() == head.size());
1145 assert(tail.size() == weight.size());
1146 assert(max_element_of(tail) < node_count);
1147 assert(max_element_of(head) < node_count);
1148
1149
1150
1152 ContractionHierarchyExtraInfo ch_extra;
1153
1154
1155 log_input_graph_statistics(node_count, tail, head, log_message);
1156
1157 std::vector<unsigned>input_arc_id = identity_permutation(head.size());
1158
1159 {
1160 sort_arcs_and_remove_multi_and_loop_arcs(node_count, tail, head, weight, input_arc_id, log_message);
1161 }
1162
1163
1164 {
1165 Graph graph(node_count, tail, head, weight);
1166 build_ch_given_rank(graph, ch, ch_extra, rank, max_pop_count, log_message);
1167 }
1168
1169 {
1170 make_internal_nodes_and_rank_coincide(ch, ch_extra, log_message);
1171 sort_ch_arcs_and_build_first_out_arrays(ch, ch_extra, log_message);
1172 }
1173
1174 build_unpacking_information(node_count, tail, head, input_arc_id, ch, ch_extra, log_message);
1175
1176 log_contraction_hierarchy_statistics(ch, log_message);
1177
1178 return ch; // NVRO
1179}
1180
1182 std::vector<unsigned>order,
1183 std::vector<unsigned>tail, std::vector<unsigned>head, std::vector<unsigned>weight,
1184 const std::function<void(std::string)>&log_message, unsigned max_pop_count
1185){
1186 return build_given_rank(invert_permutation(order), tail, head, weight, log_message, max_pop_count);
1187}
1188
1190 unsigned node_count = ch.rank.size();
1191
1192 if(ch.rank != invert_permutation(ch.order))
1193 throw std::runtime_error("CH is invalid because: ch.rank != invert_permutation(ch.order)");
1194
1195 if(ch.forward.first_out.size() != node_count+1)
1196 throw std::runtime_error("CH is invalid because: ch.forward.first_out.size() != node_count+1");
1197 if(ch.backward.first_out.size() != node_count+1)
1198 throw std::runtime_error("CH is invalid because: ch.backward.first_out.size() != node_count+1");
1199
1200 unsigned forward_arc_count = ch.forward.first_out.back();
1201
1202 if(ch.forward.first_out.front() != 0)
1203 throw std::runtime_error("CH is invalid because: ch.forward.first_out.front() != 0");
1205 throw std::runtime_error("CH is invalid because: !is_sorted_using_less(ch.forward.first_out)");
1206 if(ch.forward.head.size() != forward_arc_count)
1207 throw std::runtime_error("CH is invalid because: ch.forward.head.size() != forward_arc_count");
1208 if(ch.forward.weight.size() != forward_arc_count)
1209 throw std::runtime_error("CH is invalid because: ch.forward.weight.size() != forward_arc_count");
1211 throw std::runtime_error("CH is invalid because: ch.forward.shortcut_first_arc.size() != forward_arc_count");
1213 throw std::runtime_error("CH is invalid because: ch.forward.shortcut_second_arc.size() != forward_arc_count");
1215 throw std::runtime_error("CH is invalid because: ch.forward.is_shortcut_an_original_arc.size() != forward_arc_count");
1216 if(!ch.forward.head.empty() && max_element_of(ch.forward.head) >= node_count)
1217 throw std::runtime_error("CH is invalid because: !ch.forward.head.empty() && max_element_of(ch.forward.head) >= node_count");
1218
1219 unsigned backward_arc_count = ch.backward.first_out.back();
1220
1221 if(ch.backward.first_out.front() != 0)
1222 throw std::runtime_error("CH is invalid because: ch.backward.first_out.front() != 0");
1224 throw std::runtime_error("CH is invalid because: !is_sorted_using_less(ch.backward.first_out)");
1225 if(ch.backward.head.size() != backward_arc_count)
1226 throw std::runtime_error("CH is invalid because: ch.backward.head.size() != backward_arc_count");
1227 if(ch.backward.weight.size() != backward_arc_count)
1228 throw std::runtime_error("CH is invalid because: ch.backward.weight.size() != backward_arc_count");
1230 throw std::runtime_error("CH is invalid because: ch.backward.shortcut_first_arc.size() != backward_arc_count");
1232 throw std::runtime_error("CH is invalid because: ch.backward.shortcut_second_arc.size() != backward_arc_count");
1234 throw std::runtime_error("CH is invalid because: ch.backward.is_shortcut_an_original_arc.size() != backward_arc_count");
1235 if(!ch.backward.head.empty() && max_element_of(ch.backward.head) >= node_count)
1236 throw std::runtime_error("CH is invalid because: !ch.backward.head.empty() && max_element_of(ch.backward.head) >= node_count");
1237
1238 for(unsigned x=0; x<node_count; ++x){
1239 for(unsigned xy=ch.forward.first_out[x]; xy<ch.forward.first_out[x+1]; ++xy){
1240 unsigned y=ch.forward.head[xy];
1241 if(y <= x)
1242 throw std::runtime_error("CH is invalid because: forward graph contains downward arc "+std::to_string(x)+" -> "+std::to_string(y));
1243 }
1244 for(unsigned xy=ch.backward.first_out[x]; xy<ch.backward.first_out[x+1]; ++xy){
1245 unsigned y=ch.backward.head[xy];
1246 if(y <= x)
1247 throw std::runtime_error("CH is invalid because: backward graph contains downward arc "+std::to_string(x)+" -> "+std::to_string(y));
1248 }
1249 }
1250
1251 for(unsigned xy=0; xy<forward_arc_count; ++xy){
1254 throw std::runtime_error("CH is invalid because: ch.forward.shortcut_first_arc["+std::to_string(xy)+"] >= backward_arc_count");
1256 throw std::runtime_error("CH is invalid because: ch.forward.shortcut_second_arc["+std::to_string(xy)+"] >= forward_arc_count");
1257 if(ch.forward.shortcut_second_arc[xy] >= xy)
1258 throw std::runtime_error("CH is invalid because: ch.forward.shortcut_second_arc["+std::to_string(xy)+"] >= "+std::to_string(xy));
1260 throw std::runtime_error("CH is invalid because: ch.forward.weight[xy] != ch.backward.weight[ch.forward.shortcut_first_arc[xy]] + ch.forward.weight[ch.forward.shortcut_second_arc[xy]]");
1261 } else {
1263 throw std::runtime_error("CH is invalid because: ch.forward.shortcut_first_arc["+std::to_string(xy)+"] == invalid_id for an original arc");
1265 throw std::runtime_error("CH is invalid because: ch.forward.shortcut_second_arc["+std::to_string(xy)+"] >= node_count for an original arc");
1266 }
1267 }
1268
1269 for(unsigned xy=0; xy<backward_arc_count; ++xy){
1272 throw std::runtime_error("CH is invalid because: ch.backward.shortcut_first_arc["+std::to_string(xy)+"] >= backward_arc_count");
1274 throw std::runtime_error("CH is invalid because: ch.backward.shortcut_second_arc["+std::to_string(xy)+"] >= forward_arc_count");
1275 if(ch.backward.shortcut_first_arc[xy] >= xy)
1276 throw std::runtime_error("CH is invalid because: ch.backward.shortcut_first_arc["+std::to_string(xy)+"] >= "+std::to_string(xy));
1278 throw std::runtime_error("CH is invalid because: ch.backward.weight[xy] != ch.backward.weight[ch.backward.shortcut_first_arc[xy]] + ch.forward.weight[ch.backward.shortcut_second_arc[xy]]");
1279 } else {
1281 throw std::runtime_error("CH is invalid because: ch.backward.shortcut_first_arc["+std::to_string(xy)+"] == invalid_id for an original arc");
1283 throw std::runtime_error("CH is invalid because: ch.backward.shortcut_second_arc["+std::to_string(xy)+"] >= node_count for an original arc");
1284 }
1285 }
1286
1287}
1288
1289
1290namespace {
1291 const unsigned long long ch_magic_number = 0x436f6e7448696572ull;
1292
1293 struct CHFileHeader{
1294 unsigned long long magic_number;
1295 unsigned node_count;
1298 };
1299}
1300
1301
1303 return read(
1304 [&](char*p, unsigned long long l){
1305 if(!in.read(p, l))
1306 throw std::runtime_error("std::istream::read failed while reading a contraction hierarchy");
1307 }
1308 );
1309}
1310
1311ContractionHierarchy ContractionHierarchy::read(std::istream&in, unsigned long long file_size){
1312 return read(
1313 [&](char*p, unsigned long long l){
1314 if(!in.read(p, l))
1315 throw std::runtime_error("std::istream::read failed while reading a contraction hierarchy");
1316 },
1317 file_size
1318 );
1319}
1320
1321void ContractionHierarchy::write(std::ostream&out) const {
1322 write(
1323 [&](const char*p, unsigned long long l){
1324 if(!out.write(p, l))
1325 throw std::runtime_error("std::ostream::write failed while reading a contraction hierarchy");
1326 }
1327 );
1328}
1329
1332 open_file_for_loading(file_name, [&](std::istream&in, unsigned long long file_size){ch = read(in, file_size);});
1333 return ch;
1334}
1335
1336void ContractionHierarchy::save_file(const std::string&file_name) const {
1337 open_file_for_saving(file_name, [&](std::ostream&out){write(out);});
1338}
1339
1340namespace{
1341 void check_header(CHFileHeader header){
1342 if(header.magic_number != ch_magic_number)
1343 throw std::runtime_error("CH file magic number broken. Is this really a CH file?");
1344 }
1345
1346 ContractionHierarchy finish_read(std::function<void(char*, unsigned long long)>in, CHFileHeader header){
1347 ContractionHierarchy ch;
1348 ch.rank = read_vector<unsigned>(in, header.node_count);
1349 ch.order = invert_permutation(ch.rank);
1350
1351 ch.forward.first_out = read_vector<unsigned>(in, header.node_count+1);
1352 ch.forward.head = read_vector<unsigned>(in, header.forward_arc_count);
1353 ch.forward.weight = read_vector<unsigned>(in, header.forward_arc_count);
1354 ch.forward.is_shortcut_an_original_arc = read_bit_vector(in, header.forward_arc_count);
1355 ch.forward.shortcut_first_arc = read_vector<unsigned>(in, header.forward_arc_count);
1356 ch.forward.shortcut_second_arc = read_vector<unsigned>(in, header.forward_arc_count);
1357
1358 ch.backward.first_out = read_vector<unsigned>(in, header.node_count+1);
1359 ch.backward.head = read_vector<unsigned>(in, header.backward_arc_count);
1360 ch.backward.weight = read_vector<unsigned>(in, header.backward_arc_count);
1361 ch.backward.is_shortcut_an_original_arc = read_bit_vector(in, header.backward_arc_count);
1362 ch.backward.shortcut_first_arc = read_vector<unsigned>(in, header.backward_arc_count);
1363 ch.backward.shortcut_second_arc = read_vector<unsigned>(in, header.backward_arc_count);
1364
1365 return ch; // NVRO
1366 }
1367}
1368
1369ContractionHierarchy ContractionHierarchy::read(std::function<void(char*, unsigned long long)>in, unsigned long long file_size){
1370 CHFileHeader header = read_value<CHFileHeader>(in);
1371 check_header(header);
1372 unsigned long long expected_file_size = (
1373 sizeof(CHFileHeader)
1374 + sizeof(unsigned)*(
1375 header.node_count
1376 + (
1377 header.node_count+1 +
1378 4*header.forward_arc_count
1379
1380 )
1381 + (
1382 header.node_count+1 +
1383 4*header.backward_arc_count
1384
1385 )
1386 )
1387 + ((header.backward_arc_count+511)/512) * 64
1388 + ((header.forward_arc_count+511)/512) * 64
1389 );
1390 if(expected_file_size != file_size)
1391 throw std::runtime_error("CH file has a different size than specified in the header. This file is corrupt.");
1392 return finish_read(in, header);
1393}
1394
1395ContractionHierarchy ContractionHierarchy::read(std::function<void(char*, unsigned long long)>in){
1396 CHFileHeader header = read_value<CHFileHeader>(in);
1397 check_header(header);
1398 return finish_read(in, header);
1399}
1400
1401void ContractionHierarchy::write(std::function<void(const char*, unsigned long long)>out) const {
1402 CHFileHeader header;
1403 header.magic_number = ch_magic_number;
1404 header.node_count = forward.first_out.size()-1;
1405 header.forward_arc_count = forward.head.size();
1406 header.backward_arc_count = backward.head.size();
1407
1408 write_value(out, header);
1409 write_vector(out, rank);
1410
1417
1424}
1425
1427 ch(&ch),
1431 forward_predecessor_node(ch.node_count()), backward_predecessor_node(ch.node_count()),
1432 forward_predecessor_arc(ch.node_count()), backward_predecessor_arc(ch.node_count()),
1433 shortest_path_meeting_node(invalid_id),
1434 state(ContractionHierarchyQuery::InternalState::initialized)
1435
1436{}
1437
1451
1453 if(forward_tentative_distance.size() == new_ch.node_count()){
1454 reset();
1455 ch = &new_ch;
1456 } else {
1457 *this = ContractionHierarchyQuery(new_ch);
1458 }
1459 return *this;
1460}
1461
1463 assert(ch && "query object must have an attached CH");
1464 assert(external_s < ch->node_count() && "node out of bounds");
1466
1467 unsigned s = ch->rank[external_s];
1468
1469 if(!forward_queue.contains_id(s)){
1470 forward_queue.push({s, dist_to_s});
1471 forward_tentative_distance[s] = dist_to_s;
1473 }else{
1474 if(dist_to_s < forward_tentative_distance[s]){
1475 forward_tentative_distance[s] = dist_to_s;
1476 forward_queue.decrease_key({s, dist_to_s});
1477 }
1478 }
1479
1481 return *this;
1482}
1483
1485 assert(ch && "query object must have an attached CH");
1486 assert(external_t < ch->node_count() && "node out of bounds");
1488
1489 unsigned t = ch->rank[external_t];
1491 backward_queue.push({t, dist_to_t});
1492 backward_tentative_distance[t] = dist_to_t;
1494 }else{
1495 if(dist_to_t < backward_tentative_distance[t]){
1496 backward_tentative_distance[t] = dist_to_t;
1497 backward_queue.decrease_key({t, dist_to_t});
1498 }
1499 }
1500
1502 return *this;
1503}
1504
1505namespace{
1506
1507 template<class SetPred>
1508 void forward_expand_upward_ch_arcs_of_node(
1509 unsigned node,
1510 unsigned distance_to_node,
1511 const std::vector<unsigned>&forward_first_out,
1512 const std::vector<unsigned>&forward_head,
1513 const std::vector<unsigned>&forward_weight,
1516 std::vector<unsigned>&forward_tentative_distance,
1517 const SetPred&set_predecessor
1518 ){
1519 for(unsigned arc = forward_first_out[node]; arc < forward_first_out[node+1]; ++arc){
1520 unsigned h = forward_head[arc], d = distance_to_node + forward_weight[arc];
1522 if(d < forward_tentative_distance[h]){
1525 set_predecessor(h, node, arc);
1526 }
1527 } else if(d < inf_weight){
1528 forward_queue.push({h, d});
1531 set_predecessor(h, node, arc);
1532 }
1533 }
1534 }
1535
1536 bool forward_can_stall_at_node(
1537 unsigned node,
1538 const std::vector<unsigned>&backward_first_out, const std::vector<unsigned>&backward_head, const std::vector<unsigned>&backward_weight,
1539 const TimestampFlags&was_forward_pushed,
1540 std::vector<unsigned>&forward_tentative_distance, const std::vector<unsigned>&backward_tentative_distance
1541 ){
1542 for(unsigned arc = backward_first_out[node]; arc < backward_first_out[node+1]; ++arc){
1543 unsigned x = backward_head[arc];
1545 if(forward_tentative_distance[x] + backward_weight[arc] <= forward_tentative_distance[node])
1546 return true;
1547 }
1548 }
1549 return false;
1550 }
1551
1552
1553 void forward_settle_node(
1554 unsigned&shortest_path_length,
1555 unsigned&shortest_path_meeting_node,
1556 const std::vector<unsigned>&forward_first_out, const std::vector<unsigned>&forward_head, const std::vector<unsigned>&forward_weight,
1557 const std::vector<unsigned>&backward_first_out, const std::vector<unsigned>&backward_head, const std::vector<unsigned>&backward_weight,
1558 TimestampFlags&was_forward_pushed, const TimestampFlags&was_backward_pushed,
1559 MinIDQueue&forward_queue,
1560 std::vector<unsigned>&forward_tentative_distance, const std::vector<unsigned>&backward_tentative_distance,
1561 std::vector<unsigned>&forward_predecessor_node, std::vector<unsigned>&forward_predecessor_arc
1562 ){
1563
1564
1565 auto p = forward_queue.pop();
1566 auto popped_node = p.id;
1567 auto distance_to_popped_node = p.key;
1568
1569 if(was_backward_pushed.is_set(popped_node)){
1570 if(shortest_path_length > distance_to_popped_node + backward_tentative_distance[popped_node]){
1571 shortest_path_length = distance_to_popped_node + backward_tentative_distance[popped_node];
1572 shortest_path_meeting_node = popped_node;
1573 }
1574 }
1575
1576 if(
1577 !forward_can_stall_at_node(
1578 popped_node,
1579 backward_first_out, backward_head, backward_weight,
1582 )
1583 )
1584 forward_expand_upward_ch_arcs_of_node(
1585 popped_node, distance_to_popped_node,
1586 forward_first_out, forward_head, forward_weight,
1589 [&](unsigned x, unsigned pred_node, unsigned pred_arc){
1590 forward_predecessor_node[x] = pred_node;
1591 forward_predecessor_arc[x] = pred_arc;
1592 }
1593 );
1594 }
1595
1596 void full_forward_search(
1597 const std::vector<unsigned>&forward_first_out, const std::vector<unsigned>&forward_head, const std::vector<unsigned>&forward_weight,
1598 TimestampFlags&was_forward_pushed,
1599 MinIDQueue&forward_queue,
1600 std::vector<unsigned>&forward_tentative_distance,
1601 std::vector<unsigned>&forward_predecessor_node, std::vector<unsigned>&forward_predecessor_arc
1602 ){
1603 while(!forward_queue.empty()){
1604 auto p = forward_queue.pop();
1605 auto popped_node = p.id;
1606 auto distance_to_popped_node = p.key;
1607
1608 forward_expand_upward_ch_arcs_of_node(
1609 popped_node, distance_to_popped_node,
1610 forward_first_out, forward_head, forward_weight,
1613 [&](unsigned x, unsigned pred_node, unsigned pred_arc){
1614 forward_predecessor_node[x] = pred_node;
1615 forward_predecessor_arc[x] = pred_arc;
1616 }
1617 );
1618 }
1619 }
1620
1621
1622
1623
1624}
1625
1627 assert(ch && "query object must have an attached CH");
1628 assert(!forward_queue.empty() && "must add at least one source before calling run");
1629 assert(!backward_queue.empty() && "must add at least one target before calling run");
1631
1632 unsigned shortest_path_length = inf_weight;
1634
1635 bool forward_next = true;
1636
1637 for(;;){
1638 bool forward_finished = false;
1639 if(forward_queue.empty())
1640 forward_finished = true;
1641 else if(forward_queue.peek().key >= shortest_path_length)
1642 forward_finished = true;
1643
1644 bool backward_finished = false;
1645 if(backward_queue.empty())
1646 backward_finished = true;
1647 else if(backward_queue.peek().key >= shortest_path_length)
1648 backward_finished = true;
1649
1650 if(forward_finished && backward_finished)
1651 break;
1652
1653 if(forward_finished)
1654 forward_next = false;
1655 if(backward_finished)
1656 forward_next = true;
1657
1658 if(forward_next){
1659 forward_settle_node(
1660 shortest_path_length, shortest_path_meeting_node,
1667 );
1668 forward_next = false;
1669 } else {
1670 forward_settle_node(
1671 shortest_path_length, shortest_path_meeting_node,
1678 );
1679 forward_next = true;
1680 }
1681 }
1682
1684 return *this;
1685}
1686
1688 assert(ch && "query object must have an attached CH");
1690
1692 return invalid_id;
1693 unsigned x = shortest_path_meeting_node;
1696
1697 return ch->order[x];
1698}
1699
1701 assert(ch && "query object must have an attached CH");
1703
1705 return invalid_id;
1706 unsigned x = shortest_path_meeting_node;
1709 return ch->order[x];
1710}
1711
1712namespace{
1713
1714 // OnNewInputArc has the signature
1715 // on_new_arc(unsigned xy, unsigned y)
1716 // It is called for every arc xy of the path. y is the head of xy.
1717 // The source node of the path must be obtained by some other mean
1718
1719 template<class OnNewInputArc>
1720 void unpack_forward_arc(const ContractionHierarchy&ch, unsigned arc, const OnNewInputArc&on_new_input_arc);
1721
1722 template<class OnNewInputArc>
1723 void unpack_backward_arc(const ContractionHierarchy&ch, unsigned arc, const OnNewInputArc&on_new_input_arc);
1724
1725 template<class OnNewInputArc>
1726 void unpack_forward_arc(const ContractionHierarchy&ch, unsigned arc, const OnNewInputArc&on_new_input_arc){
1728 on_new_input_arc(ch.forward.shortcut_first_arc[arc], ch.forward.shortcut_second_arc[arc]);
1729 } else {
1730 assert(ch.forward.shortcut_first_arc[arc] < ch.backward.head.size());
1731 assert(ch.forward.shortcut_second_arc[arc] < ch.forward.head.size());
1732 unpack_backward_arc(ch, ch.forward.shortcut_first_arc[arc], on_new_input_arc);
1733 unpack_forward_arc(ch, ch.forward.shortcut_second_arc[arc], on_new_input_arc);
1734 }
1735 }
1736
1737 template<class OnNewInputArc>
1738 void unpack_backward_arc(const ContractionHierarchy&ch, unsigned arc, const OnNewInputArc&on_new_input_arc){
1739 if(ch.backward.is_shortcut_an_original_arc.is_set(arc)){
1740 on_new_input_arc(ch.backward.shortcut_first_arc[arc], ch.backward.shortcut_second_arc[arc]);
1741 } else {
1742 assert(ch.backward.shortcut_first_arc[arc] < ch.backward.head.size());
1743 assert(ch.backward.shortcut_second_arc[arc] < ch.forward.head.size());
1744 unpack_backward_arc(ch, ch.backward.shortcut_first_arc[arc], on_new_input_arc);
1745 unpack_forward_arc(ch, ch.backward.shortcut_second_arc[arc], on_new_input_arc);
1746 }
1747 }
1748}
1749
1758
1759
1761 assert(ch && "query object must have an attached CH");
1763
1764 std::vector<unsigned>path;
1766 {
1767 std::vector<unsigned>up_path;
1768 {
1769 unsigned x = shortest_path_meeting_node;
1771 assert(was_forward_pushed.is_set(x));
1772 up_path.push_back(forward_predecessor_arc[x]);
1773 //up_path.push_back(find_arc_given_sorted_head(ch->forward.first_out, ch->forward.head, forward_predecessor_node[x], x));
1775 }
1776 }
1777 for(unsigned i=up_path.size(); i>0; --i){
1778 unpack_forward_arc(*ch, up_path[i-1], [&](unsigned xy, unsigned y){path.push_back(xy);});
1779 }
1780 {
1781 unsigned x = shortest_path_meeting_node;
1783 assert(was_backward_pushed.is_set(x));
1784 unpack_backward_arc(*ch, backward_predecessor_arc[x], [&](unsigned xy, unsigned y){path.push_back(xy);});
1785 //unpack_backward_arc(*ch, find_arc_given_sorted_head(ch->backward.first_out, ch->backward.head, backward_predecessor_node[x], x), [&](unsigned xy, unsigned y){path.push_back(xy);});
1787 }
1788 }
1789 }
1790 return path; // NVRO
1791}
1792
1793
1795 assert(ch && "query object must have an attached CH");
1797
1798 std::vector<unsigned>path;
1800 {
1801 std::vector<unsigned>up_path;
1802 {
1803 unsigned x = shortest_path_meeting_node;
1805 assert(was_forward_pushed.is_set(x));
1806 up_path.push_back(forward_predecessor_arc[x]);
1808 }
1809 path.push_back(ch->order[x]);
1810 }
1811 for(unsigned i=up_path.size(); i>0; --i){
1812 unpack_forward_arc(*ch, up_path[i-1], [&](unsigned xy, unsigned y){path.push_back(y);});
1813 }
1814 {
1815 unsigned x = shortest_path_meeting_node;
1817 assert(was_backward_pushed.is_set(x));
1818 unpack_backward_arc(*ch, backward_predecessor_arc[x], [&](unsigned xy, unsigned y){path.push_back(y);});
1820 }
1821 }
1822 }
1823 return path; // NVRO
1824}
1825
1836
1847
1848namespace{
1849
1850 // target_list[0] ... target_list[target_count-1] are the target nodes.
1851 // The IDs are with repect to the CH and not with respect to the input.
1852 // The nodes are ordered the same way as in the input.
1853
1854 // select_list[0] ... select_list[select_count-1] are the nodes reachable from a target node in the CH.
1855 // For a forward search, the nodes in select_list are the ones reachable in the backward CH.
1856 // For a backward search, the nodes in select_list are the ones reachable in the forward CH.
1857 // The IDs are with repect to the CH and not with respect to the input.
1858 // select_list is ordered decreasing by rank.
1859
1860 void pin(
1861 const std::vector<unsigned>&external_target_list,
1862 const std::vector<unsigned>&external_node_to_internal_node,
1863 std::vector<unsigned>&target_list,
1864 unsigned&target_count,
1865 std::vector<unsigned>&select_list,
1866 unsigned&select_count,
1867 MinIDQueue&q,
1868 const std::vector<unsigned>&backward_first_out,
1869 const std::vector<unsigned>&backward_head,
1870 const std::vector<unsigned>&backward_weight
1871 ){
1872 target_count = external_target_list.size();
1873
1874 for(unsigned i=0; i<target_count; ++i){
1875 unsigned t = external_target_list[i];
1876 t = external_node_to_internal_node[t];
1877 target_list[i] = t;
1878 if(!q.contains_id(t))
1879 q.push({t,t});
1880 }
1881
1882 select_count = 0;
1883 while(!q.empty()){
1884 auto x = q.pop().id;
1885 select_list[select_count++] = x;
1886
1887 for(unsigned xy=backward_first_out[x]; xy < backward_first_out[x+1]; ++xy){
1888 unsigned y = backward_head[xy];
1889 assert(x < y);
1890 if(!q.contains_id(y))
1891 q.push({y,y});
1892 }
1893 }
1894
1895 std::reverse(select_list.begin(), select_list.begin() + select_count);
1896 }
1897
1898 //
1899 // After pinned_run is finished, there are three types of nodes:
1900 // 1) a source node
1901 // 2) a node that was reached in the forward CH
1902 // 3) a node that was reached in the backward CH
1903 // A node x is categorizes as follows:
1904 // 1) forward_predecessor_node[x] == invalid_id && has_forward_predecessor.is_set(x)
1905 // 2) forward_predecessor_node[x] != invalid_id && has_forward_predecessor.is_set(x)
1906 // 2) !has_forward_predecessor.is_set(x)
1907 //
1908
1909 void pinned_run(
1910 std::vector<unsigned>&select_list,
1911 unsigned&select_count,
1912
1913 TimestampFlags&has_forward_predecessor,
1914 MinIDQueue&forward_queue,
1915 std::vector<unsigned>&tentative_distance,
1916
1917 std::vector<unsigned>&forward_predecessor_node,
1918 std::vector<unsigned>&predecessor_arc,
1919
1920 const std::vector<unsigned>&forward_first_out,
1921 const std::vector<unsigned>&forward_head,
1922 const std::vector<unsigned>&forward_weight,
1923
1924 const std::vector<unsigned>&backward_first_out,
1925 const std::vector<unsigned>&backward_head,
1926 const std::vector<unsigned>&backward_weight
1927 ){
1928 full_forward_search(
1929 forward_first_out, forward_head, forward_weight,
1930 has_forward_predecessor,
1932 tentative_distance,
1933 forward_predecessor_node, predecessor_arc
1934 );
1935
1936 for(unsigned i=0; i<select_count; ++i){
1937 unsigned
1938 x = select_list[i],
1939 dist = inf_weight,
1940 pred = invalid_id;
1941 if(has_forward_predecessor.is_set(x))
1942 dist = tentative_distance[x];
1943
1944 for(unsigned xy = backward_first_out[x]; xy < backward_first_out[x+1]; ++xy){
1945 unsigned y = backward_head[xy];
1946
1947 unsigned new_dist = tentative_distance[y]+backward_weight[xy];
1948 if(new_dist < dist){
1949 dist = new_dist;
1950 pred = xy;
1951 }
1952 }
1953
1954 if(pred != invalid_id){
1955 tentative_distance[x] = dist;
1956 predecessor_arc[x] = pred;
1957 has_forward_predecessor.reset_one(x);
1958 }else if(dist == inf_weight){
1959 tentative_distance[x] = inf_weight;
1960 predecessor_arc[x] = invalid_id;
1961 }
1962 }
1963 }
1964
1966 const std::vector<unsigned>&target_list,
1967 unsigned target_count,
1968 const std::vector<unsigned>&forward_tentative_distance,
1969 unsigned*dist
1970 ){
1971 for(unsigned i=0; i<target_count; ++i)
1972 dist[i] = forward_tentative_distance[target_list[i]];
1973 }
1974
1975 std::vector<unsigned> extract_distances_to_targets(
1976 const std::vector<unsigned>&target_list,
1977 unsigned target_count,
1978 const std::vector<unsigned>&forward_tentative_distance
1979 ){
1980 std::vector<unsigned>dist(target_count);
1981 extract_distances_to_targets(target_list, target_count, forward_tentative_distance, &dist[0]);
1982 return dist; // NVRO
1983 }
1984}
1985
1986ContractionHierarchyQuery&ContractionHierarchyQuery::pin_targets(const std::vector<unsigned>&external_target_list){
1987 assert(ch && "query object must have an attached CH");
1988 assert((external_target_list.empty() || max_element_of(external_target_list) < ch->node_count()) && "node id out of bounds");
1990
1991 pin(
1992 external_target_list,
1993 ch->rank,
1994
1995 // the following 4 variables happen to be unused and of the
1996 // required size -> use them to avoid allocating unnecessary
1997 // memory. Warning: Usage must be consistent over all pinning functions
1999
2001
2003 ch->backward.head,
2005 );
2006
2008 return *this;
2009}
2010
2011ContractionHierarchyQuery& ContractionHierarchyQuery::pin_sources(const std::vector<unsigned>&external_source_list){
2012 assert(ch && "query object must have an attached CH");
2013 assert((external_source_list.empty() || max_element_of(external_source_list) < ch->node_count()) && "node id out of bounds");
2015
2016 pin(
2017 external_source_list,
2018 ch->rank,
2019
2021
2024 ch->forward.head,
2026 );
2027
2029 return *this;
2030}
2031
2032
2033
2034
2036 assert(ch && "query object must have an attached CH");
2037 assert(!forward_queue.empty() && "must add at least one source before calling run");
2039
2040 pinned_run(
2042
2046
2048
2050 ch->forward.head,
2051 ch->forward.weight,
2052
2054 ch->backward.head,
2056 );
2057
2059 return *this;
2060}
2061
2062
2064 assert(ch && "query object must have an attached CH");
2065 assert(!backward_queue.empty() && "must add at least one target before calling run");
2067
2068 pinned_run(
2070
2074
2076
2078 ch->backward.head,
2080
2082 ch->forward.head,
2084 );
2086 return *this;
2087}
2088
2089
2095
2100
2101
2107
2112
2113namespace{
2114 void internal_get_used_sources_to_targets(
2115 const std::vector<unsigned>&target_list,
2116 unsigned target_count,
2117
2118 const TimestampFlags&has_forward_predecessor,
2119 const std::vector<unsigned>&forward_predecessor_node,
2120 const std::vector<unsigned>&predecessor_arc,
2121
2122 const std::vector<unsigned>&backward_head,
2123
2124 const std::vector<unsigned>&ch_order,
2125
2126 unsigned*output
2127 ){
2128 for(unsigned i=0; i<target_count; ++i){
2129 unsigned x = target_list[i];
2130 if(!has_forward_predecessor.is_set(x) && predecessor_arc[x] == invalid_id){
2131 output[i] = invalid_id;
2132 }else{
2133 while(!has_forward_predecessor.is_set(x)){
2134 unsigned y = backward_head[predecessor_arc[x]];
2135 assert(y > x);
2136 x = y;
2137 }
2138 while(forward_predecessor_node[x] != invalid_id){
2139 assert(has_forward_predecessor.is_set(x));
2140 unsigned y = forward_predecessor_node[x];
2141 assert(y < x);
2142 x = y;
2143 }
2144 output[i] = ch_order[x];
2145 }
2146 }
2147 }
2148}
2149
2152
2153 internal_get_used_sources_to_targets(
2155
2158
2159 ch->backward.head,
2160 ch->order,
2161
2162 output
2163 );
2164
2165 return *this;
2166}
2167
2170 std::vector<unsigned>ret(many_to_many_source_or_target_count);
2172 return ret; // NVRO
2173}
2174
2177
2178 internal_get_used_sources_to_targets(
2180
2183
2184 ch->forward.head,
2185 ch->order,
2186
2187 output
2188 );
2189
2190 return *this;
2191}
2192
2195 std::vector<unsigned>ret(many_to_many_source_or_target_count);
2197 return ret; // NVRO
2198}
2199
2202template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_targets<std::vector<int>, SaturatedWeightAddition, std::vector<int>, std::vector<int>>(const std::vector<int>&, const SaturatedWeightAddition&, std::vector<int>&, std::vector<int>&);
2203template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_sources<std::vector<int>, SaturatedWeightAddition, std::vector<int>, std::vector<int>>(const std::vector<int>&, const SaturatedWeightAddition&, std::vector<int>&, std::vector<int>&);
2204template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_targets<std::vector<unsigned>, SaturatedWeightAddition, std::vector<unsigned>, std::vector<unsigned>>(const std::vector<unsigned>&, const SaturatedWeightAddition&, std::vector<unsigned>&, std::vector<unsigned>&);
2205template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_sources<std::vector<unsigned>, SaturatedWeightAddition, std::vector<unsigned>, std::vector<unsigned>>(const std::vector<unsigned>&, const SaturatedWeightAddition&, std::vector<unsigned>&, std::vector<unsigned>&);
2206template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_targets<ContractionHierarchyExtraWeight<int>, SaturatedWeightAddition, std::vector<int>, std::vector<int>>(const ContractionHierarchyExtraWeight<int>&, const SaturatedWeightAddition&, std::vector<int>&, std::vector<int>&);
2207template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_sources<ContractionHierarchyExtraWeight<int>, SaturatedWeightAddition, std::vector<int>, std::vector<int>>(const ContractionHierarchyExtraWeight<int>&, const SaturatedWeightAddition&, std::vector<int>&, std::vector<int>&);
2208template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_targets<ContractionHierarchyExtraWeight<unsigned>, SaturatedWeightAddition, std::vector<unsigned>, std::vector<unsigned>>(const ContractionHierarchyExtraWeight<unsigned>&, const SaturatedWeightAddition&, std::vector<unsigned>&, std::vector<unsigned>&);
2209template ContractionHierarchyQuery& ContractionHierarchyQuery::get_extra_weight_distances_to_sources<ContractionHierarchyExtraWeight<unsigned>, SaturatedWeightAddition, std::vector<unsigned>, std::vector<unsigned>>(const ContractionHierarchyExtraWeight<unsigned>&, const SaturatedWeightAddition&, std::vector<unsigned>&, std::vector<unsigned>&);
2212template unsigned ContractionHierarchyQuery::get_extra_weight_distance<std::vector<unsigned>,SaturatedWeightAddition>(const std::vector<unsigned>&, const SaturatedWeightAddition&);
2213template int ContractionHierarchyQuery::get_extra_weight_distance<std::vector<int>,SaturatedWeightAddition>(const std::vector<int>&, const SaturatedWeightAddition&);
2214template unsigned ContractionHierarchyQuery::get_extra_weight_distance<ContractionHierarchyExtraWeight<unsigned>,SaturatedWeightAddition>(const ContractionHierarchyExtraWeight<unsigned>&, const SaturatedWeightAddition&);
2215template int ContractionHierarchyQuery::get_extra_weight_distance<ContractionHierarchyExtraWeight<int>,SaturatedWeightAddition>(const ContractionHierarchyExtraWeight<int>&, const SaturatedWeightAddition&);
2216
2217} // namespace RoutingKit
static constexpr Uninitialized uninitialized
Definition bit_vector.h:13
uint64_t size() const
Definition bit_vector.h:26
bool is_set(uint64_t x) const
Definition bit_vector.h:34
void save_file(const std::string &file_name) const
static ContractionHierarchy build_given_rank(std::vector< unsigned >rank, std::vector< unsigned >tail, std::vector< unsigned >head, std::vector< unsigned >weight, const std::function< void(std::string)> &log_message=std::function< void(std::string)>(), unsigned max_pop_count=default_max_pop_count)
void write(std::function< void(const char *, unsigned long long)>data_sink) const
static ContractionHierarchy read(std::function< void(char *, unsigned long long)>data_source)
static ContractionHierarchy load_file(const std::string &file_name)
static ContractionHierarchy build(unsigned node_count, std::vector< unsigned >tail, std::vector< unsigned >head, std::vector< unsigned >weight, const std::function< void(std::string)> &log_message=std::function< void(std::string)>(), unsigned max_pop_count=default_max_pop_count)
static ContractionHierarchy build_given_order(std::vector< unsigned >order, std::vector< unsigned >tail, std::vector< unsigned >head, std::vector< unsigned >weight, const std::function< void(std::string)> &log_message=std::function< void(std::string)>(), unsigned max_pop_count=default_max_pop_count)
enum RoutingKit::ContractionHierarchyQuery::InternalState state
ContractionHierarchyQuery & pin_targets(const std::vector< unsigned > &)
std::vector< unsigned > get_used_sources_to_targets()
ContractionHierarchyQuery & run_to_pinned_targets()
std::vector< unsigned > backward_tentative_distance
ContractionHierarchyQuery & run_to_pinned_sources()
ContractionHierarchyQuery & add_source(unsigned s, unsigned dist_to_s=0)
std::vector< unsigned > get_used_targets_to_sources()
ContractionHierarchyQuery & pin_sources(const std::vector< unsigned > &)
ContractionHierarchyQuery & add_target(unsigned t, unsigned dist_to_t=0)
bool empty() const
Returns whether the queue is empty. Equivalent to checking whether size() returns 0.
Definition id_queue.h:30
IDKeyPair pop()
Returns the smallest element key pair and removes it form the queue.
Definition id_queue.h:79
bool contains_id(unsigned id)
Checks whether an element is in the queue.
Definition id_queue.h:45
bool decrease_key(IDKeyPair p)
Definition id_queue.h:107
void clear()
Removes all elements from the queue.
Definition id_queue.h:51
void push(IDKeyPair p)
Definition id_queue.h:93
IDKeyPair peek() const
Returns the smallest element key pair without removing it from the queue.
Definition id_queue.h:73
bool is_set(unsigned id) const
unsigned max_pop_count
unsigned node
MinIDQueue forward_queue
unsigned hop_length
std::vector< unsigned > level_
std::vector< unsigned > tail
std::vector< std::vector< Arc > > out_
std::vector< unsigned > forward_tentative_distance
std::vector< unsigned > backward_tentative_distance
TimestampFlags was_forward_pushed
unsigned long long magic_number
std::vector< std::vector< Arc > > in_
unsigned weight
MinIDQueue backward_queue
unsigned mid_node
unsigned backward_arc_count
unsigned bypass_node
unsigned node_count
const Graph * graph
TimestampFlags was_backward_pushed
unsigned forward_arc_count
void extract_distances_to_targets(const std::vector< unsigned > &target_list, unsigned target_count, const TimestampFlags &has_forward_predecessor, const std::vector< unsigned > &forward_predecessor_node, const std::vector< unsigned > &predecessor_arc, const ExtraWeight &extra_weight, const std::vector< unsigned > &forward_first_out, const std::vector< unsigned > &forward_head, const std::vector< unsigned > &backward_first_out, const std::vector< unsigned > &backward_head, TmpContainer &source_to_node_distance, TimestampFlags &has_source_to_node_distance, DistContainer &output, std::vector< unsigned > &stack, const LinkFunction &link)
bool is_sorted_using_less(const std::vector< T > &v)
Definition sort.h:374
void write_bit_vector(const std::function< void(const char *, unsigned long long)> &out, const BitVector &v)
Definition vector_io.h:149
void check_contraction_hierarchy_for_errors(const ContractionHierarchy &ch)
unsigned find_arc_given_sorted_head(const std::vector< unsigned > &first_out, const std::vector< unsigned > &head, unsigned x, unsigned y)
void inplace_apply_permutation_to_elements_of(const std::vector< unsigned > &p, std::vector< unsigned > &v)
Definition permutation.h:96
void write_value(std::ostream &out, const T &val)
Definition vector_io.h:71
std::vector< T > apply_inverse_permutation(const std::vector< unsigned > &p, const std::vector< T > &v)
Definition permutation.h:72
long long get_micro_time()
Definition timer.cpp:14
const T & max_element_of(const std::vector< T > &v)
Definition min_max.h:56
std::vector< unsigned > invert_vector(const std::vector< unsigned > &v, unsigned element_count)
std::vector< unsigned > invert_permutation(const std::vector< unsigned > &p)
std::vector< unsigned > compute_inverse_sort_permutation_first_by_tail_then_by_head_and_apply_sort_to_tail(unsigned node_count, std::vector< unsigned > &tail, const std::vector< unsigned > &head)
bool is_permutation(const std::vector< unsigned > &p)
Definition permutation.h:19
void open_file_for_loading(const std::string &file_name, const F &f)
Definition vector_io.h:164
void write_vector(std::ostream &out, const std::vector< T > &v)
Definition vector_io.h:89
std::vector< unsigned > identity_permutation(unsigned n)
void inplace_apply_permutation_to_possibly_invalid_elements_of(const std::vector< unsigned > &p, std::vector< unsigned > &v)
BitVector read_bit_vector(const std::function< void(char *, unsigned long long)> &in, unsigned long long size)
Definition vector_io.h:142
void open_file_for_saving(const std::string &file_name, const F &f)
Definition vector_io.h:156