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
25 log_message(
"Start removing loops and multi arcs from input.");
35 unsigned arc_count = head.size();
40 for(
unsigned in = 0; in < arc_count; ++in){
41 if(
tail[in] != head[in]){
45 input_arc_id[out] = input_arc_id[in];
55 for(
unsigned in = 1; in < arc_count; ++in){
56 if(
tail[in-1] !=
tail[in] || head[in-1] != head[in]){
60 input_arc_id[out] = input_arc_id[in];
65 input_arc_id[out-1] = input_arc_id[in];
73 head.erase(head.begin()+arc_count, head.end());
75 input_arc_id.erase(input_arc_id.begin()+arc_count, input_arc_id.end());
79 log_message(
"Finished removing loops and multi arcs from input. Needed "+std::to_string(timer)+
"musec time.");
87 Graph(
unsigned node_count,
const std::vector<unsigned>&
tail,
const std::vector<unsigned>&head,
const std::vector<unsigned>&
weight):
92 for(
unsigned a=0; a<head.size(); ++a){
112 unsigned x, std::vector<Arc>&x_out,
113 unsigned y, std::vector<Arc>&y_in
117 for(
unsigned out_arc = 0; out_arc < x_out.size(); ++out_arc){
118 if(x_out[out_arc].
node == y){
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;
130 y_in[in_arc].weight =
weight;
136 assert(
false &&
"arc only exists in one direction");
142 if(out_[x].size() <= in_[y].size()){
143 if(reduce_arc_if_exists(x, out_[x], y, in_[y]))
146 if(reduce_arc_if_exists(y, in_[y], x, out_[x]))
155 void remove_all_incident_arcs(
unsigned x){
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){
171 remove_back_arcs(x, out_[x], in_);
172 remove_back_arcs(x, in_[x], out_);
176 in_[x].shrink_to_fit();
177 out_[x].shrink_to_fit();
187 unsigned out_deg(
unsigned node)
const{
192 unsigned in_deg(
unsigned node)
const{
197 Arc out(
unsigned node,
unsigned out_arc)
const{
199 assert(out_arc < out_[
node].size());
203 Arc in(
unsigned node,
unsigned in_arc)
const{
205 assert(in_arc < in_[
node].size());
210 assert(
in_.size() ==
out_.size());
214 unsigned level(
unsigned node)
const{
219 void raise_level(
unsigned node,
unsigned level){
221 if(level >= level_[
node]){
230 class ShorterPathTest{
233 ShorterPathTest(
const Graph&graph,
unsigned max_pop_count):
242 void assert_no_witness_found(
unsigned len)
const{
250 void assert_forward_tentative_distances_correct()
const{
267 void assert_backward_tentative_distances_correct()
const{
284 void assert_witness_found(
unsigned len)
const{
296 template<
class GetOutDeg,
class GetOutArc>
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,
310 unsigned popped_node = p.id;
311 unsigned distance_to_popped_node = p.key;
313 assert(forward_tentative_distance[popped_node] == distance_to_popped_node);
317 if(distance_to_popped_node + backward_tentative_distance[popped_node] <= len){
318 assert_witness_found(len);
323 bool witness_found =
false;
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;
328 if(next_node == bypass)
331 unsigned next_node_distance = distance_to_popped_node + graph_out(popped_node, out_arc).weight;
334 if(next_node_distance < forward_tentative_distance[next_node]){
339 if(next_node_distance + backward_tentative_distance[next_node] <= len){
340 assert_witness_found(len);
341 witness_found =
true;
351 if(next_node_distance + backward_tentative_distance[next_node] <= len){
352 assert_witness_found(len);
353 witness_found =
true;
360 assert_no_witness_found(len);
361 return witness_found;
366 void pin_source(
unsigned s,
unsigned new_bypass_node){
375 bool does_shorter_or_equal_path_to_target_exist(
unsigned t,
unsigned len){
382 unsigned pop_count = 0;
385 if(forward_tentative_distance[t] <= len)
388 assert_no_witness_found(len);
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);},
407 assert_witness_found(len);
410 assert_no_witness_found(len);
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);},
424 assert_witness_found(len);
427 assert_no_witness_found(len);
433 if(pop_count > max_pop_count){
440 bool does_shorter_or_equal_path_exist(
unsigned s,
unsigned t,
unsigned len,
unsigned bypass){
459 unsigned pop_count = 0;
461 assert_no_witness_found(len);
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);},
481 assert_witness_found(len);
484 assert_no_witness_found(len);
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);},
498 assert_witness_found(len);
501 assert_no_witness_found(len);
507 if(pop_count > max_pop_count)
513 unsigned get_max_pop_count()
const{
527 unsigned estimate_node_importance(
const Graph&
graph, ShorterPathTest&shorter_path_test,
unsigned node){
530 unsigned added_arc_count = 0;
531 unsigned added_hop_count = 0;
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){
540 !shorter_path_test.does_shorter_or_equal_path_to_target_exist(
546 added_hop_count +=
graph.in(
node, in_arc).hop_length;
547 added_hop_count +=
graph.out(
node, out_arc).hop_length;
553 unsigned removed_arc_count = 1;
555 removed_arc_count +=
graph.out_deg(
node);
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;
563 return 1 + 1000*level + (1000*added_arc_count) / removed_arc_count + (1000*added_hop_count) / removed_hop_count;
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){
574 !shorter_path_test.does_shorter_or_equal_path_to_target_exist(
576 graph.in(node_being_contracted, in_arc).weight +
graph.out(node_being_contracted, out_arc).weight
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
589 graph.remove_all_incident_arcs(node_being_contracted);
591 assert(
graph.out_deg(node_being_contracted) == 0);
592 assert(
graph.in_deg(node_being_contracted) == 0);
599 struct ContractionHierarchyExtraInfo{
608 void build_ch_and_order(
610 ContractionHierarchy&ch,
611 ContractionHierarchyExtraInfo&ch_extra,
613 const std::function<
void(std::string)>&log_message
616 long long last_log_message_time = 0;
619 timer = -last_log_message_time;
620 log_message(
"Start building queue.");
633 queue.push({i, estimate_node_importance(
graph, shorter_path_test, i)});
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.");
646 log_message(
"Finished building queue. Needed "+std::to_string(timer)+
"musec time.");
647 log_message(
"Start contracting nodes.");
651 std::vector<unsigned>neighbor_list;
652 std::vector<bool>is_neighbor(
node_count,
false);
654 unsigned contracted_node_count = 0;
656 while(!queue.empty()){
657 unsigned node_being_contracted = queue.pop().id;
659 ch.rank[node_being_contracted] = contracted_node_count;
660 ch.order[contracted_node_count] = node_being_contracted;
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);
667 neighbor_list.push_back(x);
668 is_neighbor[x] =
true;
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);
676 neighbor_list.push_back(x);
677 is_neighbor[x] =
true;
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);
686 const auto&a =
graph.out(node_being_contracted, out_arc);
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);
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);
697 const auto&a =
graph.in(node_being_contracted, in_arc);
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);
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);
709 contract_node(
graph, shorter_path_test, node_being_contracted);
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});
723 neighbor_list.clear();
725 ++contracted_node_count;
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.");
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();
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();
748 log_message(
"Finished contracting nodes. Needed "+std::to_string(timer)+
"musec.");
754 void build_ch_given_rank(
756 ContractionHierarchy&ch,
757 ContractionHierarchyExtraInfo&ch_extra,
758 const std::vector<unsigned>&rank,
760 const std::function<
void(std::string)>&log_message
765 long long last_log_message_time = 0;
768 timer = -last_log_message_time;
769 log_message(
"Start building contraction hierarchy with given rank.");
778 unsigned node_being_contracted = ch.order[i];
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);
783 const auto&a =
graph.out(node_being_contracted, out_arc);
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);
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);
794 const auto&a =
graph.in(node_being_contracted, in_arc);
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);
802 unsigned out_deg =
graph.out_deg(node_being_contracted);
803 unsigned in_deg =
graph.in_deg(node_being_contracted);
805 contract_node(
graph, shorter_path_test, node_being_contracted);
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.");
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();
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();
828 log_message(
"Finished contracting nodes. Needed "+std::to_string(timer)+
"musec.");
833 void make_internal_nodes_and_rank_coincide(
834 ContractionHierarchy&ch,
835 ContractionHierarchyExtraInfo&ch_extra,
836 const std::function<
void(std::string)>&log_message
841 log_message(
"Start reordering nodes by rank.");
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]);
860 log_message(
"Finished reordering nodes by rank. Needed "+std::to_string(timer)+
"musec.");
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
872 log_message(
"Start sorting arcs.");
898 log_message(
"Finished sorting arcs. Needed "+std::to_string(timer)+
"musec.");
902 void optimize_order_for_cache(
903 ContractionHierarchy&ch,
904 const ContractionHierarchyExtraInfo&ch_extra,
905 const std::function<
void(std::string)>&log_message
910 log_message(
"Start optimizing order for cache.");
917 std::vector<bool>is_in_bottom_level(
node_count,
true);
919 is_in_bottom_level[ch.forward.head[a]] =
false;
921 is_in_bottom_level[ch.backward.head[a]] =
false;
926 std::vector<bool>is_in_new_order(
node_count,
false);
930 if(is_in_bottom_level[r]){
931 unsigned search_space_end = new_order_end;
933 q.push({r, ch.rank[r]});
934 assert(!is_in_new_order[r]);
935 is_in_new_order[r] =
true;
938 unsigned x = q.pop().id;
941 new_order[new_order_end] = x;
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]});
951 for(
unsigned xy = ch.forward.first_out[x]; xy < ch.forward.first_out[x+1]; ++xy)
952 on_node(ch.forward.head[xy]);
954 for(
unsigned xy = ch.backward.first_out[x]; xy < ch.backward.first_out[x+1]; ++xy)
955 on_node(ch.backward.head[xy]);
957 std::reverse(new_order.begin()+new_order_end, new_order.begin()+search_space_end);
961 assert(new_order_end == 0);
965 ch.order = std::move(new_order);
969 log_message(
"Finished optimizing order for cache. Needed "+std::to_string(timer)+
"musec.");
973 void build_unpacking_information(
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
986 log_message(
"Start building path unpacking information.");
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());
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());
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];
1004 ch.forward.is_shortcut_an_original_arc.set(xy);
1007 ch.forward.shortcut_first_arc[xy] = input_arc_id[a];
1008 ch.forward.shortcut_second_arc[xy] = head[a];
1010 ch.forward.is_shortcut_an_original_arc.reset(xy);
1014 assert(ch.forward.weight[xy] == ch.backward.weight[ch.forward.shortcut_first_arc[xy]] + ch.forward.weight[ch.forward.shortcut_second_arc[xy]]);
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];
1025 ch.backward.is_shortcut_an_original_arc.set(xy);
1027 ch.backward.shortcut_first_arc[xy] = input_arc_id[a];
1028 ch.backward.shortcut_second_arc[xy] = head[a];
1030 ch.backward.is_shortcut_an_original_arc.reset(xy);
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());
1045 assert(ch.forward.shortcut_first_arc[a] < input_arc_count);
1046 assert(ch.forward.shortcut_second_arc[a] <
node_count);
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());
1054 assert(ch.backward.shortcut_first_arc[a] < input_arc_count);
1055 assert(ch.backward.shortcut_second_arc[a] <
node_count);
1063 log_message(
"Finished building path unpacking information. Needed "+std::to_string(timer)+
"musec.");
1064 log_message(
"Contraction Hierarchy is fully constructed.");
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){
1070 log_message(
"Input graph has "+std::to_string(
node_count)+
" nodes and "+std::to_string(
tail.size())+
" arcs.");
1072 for(
unsigned i=0; i<
tail.size(); ++i)
1075 std::fill(deg.begin(), deg.end(), 0);
1076 for(
unsigned i=0; i<
tail.size(); ++i)
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)+
".");
1084 void log_contraction_hierarchy_statistics(
const ContractionHierarchy&ch,
const std::function<
void(std::string)>&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.");
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
1097 assert(
tail.size() == head.size());
1104 ContractionHierarchyExtraInfo ch_extra;
1111 sort_arcs_and_remove_multi_and_loop_arcs(
node_count,
tail, head,
weight, input_arc_id, log_message);
1121 sort_ch_arcs_and_build_first_out_arrays(ch, ch_extra, log_message);
1122 optimize_order_for_cache(ch, ch_extra, log_message);
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);
1130 build_unpacking_information(
node_count,
tail, head, input_arc_id, ch, ch_extra, log_message);
1132 log_contraction_hierarchy_statistics(ch, log_message);
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
1144 assert(
tail.size() == head.size());
1152 ContractionHierarchyExtraInfo ch_extra;
1160 sort_arcs_and_remove_multi_and_loop_arcs(
node_count,
tail, head,
weight, input_arc_id, log_message);
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);
1174 build_unpacking_information(
node_count,
tail, head, input_arc_id, ch, ch_extra, log_message);
1176 log_contraction_hierarchy_statistics(ch, log_message);
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
1193 throw std::runtime_error(
"CH is invalid because: ch.rank != invert_permutation(ch.order)");
1196 throw std::runtime_error(
"CH is invalid because: ch.forward.first_out.size() != node_count+1");
1198 throw std::runtime_error(
"CH is invalid because: ch.backward.first_out.size() != node_count+1");
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)");
1207 throw std::runtime_error(
"CH is invalid because: ch.forward.head.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");
1217 throw std::runtime_error(
"CH is invalid because: !ch.forward.head.empty() && max_element_of(ch.forward.head) >= node_count");
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)");
1226 throw std::runtime_error(
"CH is invalid because: ch.backward.head.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");
1236 throw std::runtime_error(
"CH is invalid because: !ch.backward.head.empty() && max_element_of(ch.backward.head) >= node_count");
1242 throw std::runtime_error(
"CH is invalid because: forward graph contains downward arc "+std::to_string(x)+
" -> "+std::to_string(y));
1247 throw std::runtime_error(
"CH is invalid because: backward graph contains downward arc "+std::to_string(x)+
" -> "+std::to_string(y));
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");
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]]");
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");
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");
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]]");
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");
1291 const unsigned long long ch_magic_number = 0x436f6e7448696572ull;
1293 struct CHFileHeader{
1304 [&](
char*p,
unsigned long long l){
1306 throw std::runtime_error(
"std::istream::read failed while reading a contraction hierarchy");
1313 [&](
char*p,
unsigned long long l){
1315 throw std::runtime_error(
"std::istream::read failed while reading a contraction hierarchy");
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");
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?");
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);
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);
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);
1370 CHFileHeader header = read_value<CHFileHeader>(in);
1371 check_header(header);
1372 unsigned long long expected_file_size = (
1373 sizeof(CHFileHeader)
1374 +
sizeof(
unsigned)*(
1377 header.node_count+1 +
1378 4*header.forward_arc_count
1382 header.node_count+1 +
1383 4*header.backward_arc_count
1387 + ((header.backward_arc_count+511)/512) * 64
1388 + ((header.forward_arc_count+511)/512) * 64
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);
1396 CHFileHeader header = read_value<CHFileHeader>(in);
1397 check_header(header);
1398 return finish_read(in, header);
1402 CHFileHeader header;
1403 header.magic_number = ch_magic_number;
1439 assert(
ch &&
"query object must have an attached CH");
1463 assert(
ch &&
"query object must have an attached CH");
1464 assert(external_s < ch->
node_count() &&
"node out of bounds");
1467 unsigned s =
ch->
rank[external_s];
1485 assert(
ch &&
"query object must have an attached CH");
1486 assert(external_t < ch->
node_count() &&
"node out of bounds");
1489 unsigned t =
ch->
rank[external_t];
1507 template<
class SetPred>
1508 void forward_expand_upward_ch_arcs_of_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,
1517 const SetPred&set_predecessor
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];
1525 set_predecessor(h,
node, arc);
1531 set_predecessor(h,
node, arc);
1536 bool forward_can_stall_at_node(
1538 const std::vector<unsigned>&backward_first_out,
const std::vector<unsigned>&backward_head,
const std::vector<unsigned>&backward_weight,
1542 for(
unsigned arc = backward_first_out[
node]; arc < backward_first_out[
node+1]; ++arc){
1543 unsigned x = backward_head[arc];
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,
1561 std::vector<unsigned>&forward_predecessor_node, std::vector<unsigned>&forward_predecessor_arc
1566 auto popped_node = p.
id;
1567 auto distance_to_popped_node = p.key;
1572 shortest_path_meeting_node = popped_node;
1577 !forward_can_stall_at_node(
1579 backward_first_out, backward_head, backward_weight,
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;
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,
1601 std::vector<unsigned>&forward_predecessor_node, std::vector<unsigned>&forward_predecessor_arc
1605 auto popped_node = p.
id;
1606 auto distance_to_popped_node = p.key;
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;
1627 assert(
ch &&
"query object must have an attached CH");
1635 bool forward_next =
true;
1638 bool forward_finished =
false;
1640 forward_finished =
true;
1642 forward_finished =
true;
1644 bool backward_finished =
false;
1646 backward_finished =
true;
1648 backward_finished =
true;
1650 if(forward_finished && backward_finished)
1653 if(forward_finished)
1654 forward_next =
false;
1655 if(backward_finished)
1656 forward_next =
true;
1659 forward_settle_node(
1668 forward_next =
false;
1670 forward_settle_node(
1679 forward_next =
true;
1688 assert(
ch &&
"query object must have an attached CH");
1701 assert(
ch &&
"query object must have an attached CH");
1719 template<
class OnNewInputArc>
1720 void unpack_forward_arc(
const ContractionHierarchy&ch,
unsigned arc,
const OnNewInputArc&on_new_input_arc);
1722 template<
class OnNewInputArc>
1723 void unpack_backward_arc(
const ContractionHierarchy&ch,
unsigned arc,
const OnNewInputArc&on_new_input_arc);
1725 template<
class OnNewInputArc>
1726 void unpack_forward_arc(
const ContractionHierarchy&ch,
unsigned arc,
const OnNewInputArc&on_new_input_arc){
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]);
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);
1761 assert(
ch &&
"query object must have an attached CH");
1764 std::vector<unsigned>path;
1767 std::vector<unsigned>up_path;
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);});
1795 assert(
ch &&
"query object must have an attached CH");
1798 std::vector<unsigned>path;
1801 std::vector<unsigned>up_path;
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);});
1827 assert(
ch &&
"query object must have an attached CH");
1838 assert(
ch &&
"query object must have an attached CH");
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,
1868 const std::vector<unsigned>&backward_first_out,
1869 const std::vector<unsigned>&backward_head,
1870 const std::vector<unsigned>&backward_weight
1872 target_count = external_target_list.size();
1874 for(
unsigned i=0; i<target_count; ++i){
1875 unsigned t = external_target_list[i];
1876 t = external_node_to_internal_node[t];
1884 auto x = q.
pop().
id;
1885 select_list[select_count++] = x;
1887 for(
unsigned xy=backward_first_out[x]; xy < backward_first_out[x+1]; ++xy){
1888 unsigned y = backward_head[xy];
1895 std::reverse(select_list.begin(), select_list.begin() + select_count);
1910 std::vector<unsigned>&select_list,
1911 unsigned&select_count,
1913 TimestampFlags&has_forward_predecessor,
1915 std::vector<unsigned>&tentative_distance,
1917 std::vector<unsigned>&forward_predecessor_node,
1918 std::vector<unsigned>&predecessor_arc,
1920 const std::vector<unsigned>&forward_first_out,
1921 const std::vector<unsigned>&forward_head,
1922 const std::vector<unsigned>&forward_weight,
1924 const std::vector<unsigned>&backward_first_out,
1925 const std::vector<unsigned>&backward_head,
1926 const std::vector<unsigned>&backward_weight
1928 full_forward_search(
1929 forward_first_out, forward_head, forward_weight,
1930 has_forward_predecessor,
1933 forward_predecessor_node, predecessor_arc
1936 for(
unsigned i=0; i<select_count; ++i){
1941 if(has_forward_predecessor.is_set(x))
1942 dist = tentative_distance[x];
1944 for(
unsigned xy = backward_first_out[x]; xy < backward_first_out[x+1]; ++xy){
1945 unsigned y = backward_head[xy];
1947 unsigned new_dist = tentative_distance[y]+backward_weight[xy];
1948 if(new_dist < dist){
1955 tentative_distance[x] = dist;
1956 predecessor_arc[x] = pred;
1957 has_forward_predecessor.reset_one(x);
1966 const std::vector<unsigned>&target_list,
1967 unsigned target_count,
1971 for(
unsigned i=0; i<target_count; ++i)
1976 const std::vector<unsigned>&target_list,
1977 unsigned target_count,
1980 std::vector<unsigned>dist(target_count);
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");
1992 external_target_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");
2017 external_source_list,
2036 assert(
ch &&
"query object must have an attached CH");
2064 assert(
ch &&
"query object must have an attached CH");
2114 void internal_get_used_sources_to_targets(
2115 const std::vector<unsigned>&target_list,
2116 unsigned target_count,
2119 const std::vector<unsigned>&forward_predecessor_node,
2120 const std::vector<unsigned>&predecessor_arc,
2122 const std::vector<unsigned>&backward_head,
2124 const std::vector<unsigned>&ch_order,
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){
2133 while(!has_forward_predecessor.
is_set(x)){
2134 unsigned y = backward_head[predecessor_arc[x]];
2138 while(forward_predecessor_node[x] !=
invalid_id){
2139 assert(has_forward_predecessor.
is_set(x));
2140 unsigned y = forward_predecessor_node[x];
2144 output[i] = ch_order[x];
2153 internal_get_used_sources_to_targets(
2178 internal_get_used_sources_to_targets(
static constexpr Uninitialized uninitialized
bool is_set(uint64_t x) const
void save_file(const std::string &file_name) const
unsigned node_count() 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
std::vector< unsigned > order
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)
std::vector< unsigned > rank
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)
std::vector< unsigned > get_distances_to_targets()
enum RoutingKit::ContractionHierarchyQuery::InternalState state
ContractionHierarchyQuery()
std::vector< unsigned > backward_predecessor_node
ContractionHierarchyQuery & reset()
std::vector< unsigned > backward_predecessor_arc
unsigned many_to_many_source_or_target_count
std::vector< unsigned > get_distances_to_sources()
ContractionHierarchyQuery & pin_targets(const std::vector< unsigned > &)
std::vector< unsigned > get_node_path()
const ContractionHierarchy * ch
std::vector< unsigned > forward_predecessor_arc
std::vector< unsigned > get_used_sources_to_targets()
ContractionHierarchyQuery & reset_source()
std::vector< unsigned > forward_tentative_distance
ContractionHierarchyQuery & run_to_pinned_targets()
std::vector< unsigned > backward_tentative_distance
std::vector< unsigned > get_arc_path()
unsigned get_used_source()
ContractionHierarchyQuery & run_to_pinned_sources()
ContractionHierarchyQuery & add_source(unsigned s, unsigned dist_to_s=0)
TimestampFlags was_backward_pushed
unsigned get_used_target()
std::vector< unsigned > get_used_targets_to_sources()
ContractionHierarchyQuery & pin_sources(const std::vector< unsigned > &)
ContractionHierarchyQuery & run()
unsigned shortest_path_meeting_node
ContractionHierarchyQuery & add_target(unsigned t, unsigned dist_to_t=0)
std::vector< unsigned > forward_predecessor_node
TimestampFlags was_forward_pushed
ContractionHierarchyQuery & reset_target()
MinIDQueue backward_queue
bool empty() const
Returns whether the queue is empty. Equivalent to checking whether size() returns 0.
IDKeyPair pop()
Returns the smallest element key pair and removes it form the queue.
bool contains_id(unsigned id)
Checks whether an element is in the queue.
bool decrease_key(IDKeyPair p)
void clear()
Removes all elements from the queue.
IDKeyPair peek() const
Returns the smallest element key pair without removing it from the queue.
bool is_set(unsigned id) const
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_
MinIDQueue backward_queue
unsigned backward_arc_count
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)
void write_bit_vector(const std::function< void(const char *, unsigned long long)> &out, const BitVector &v)
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)
void write_value(std::ostream &out, const T &val)
std::vector< T > apply_inverse_permutation(const std::vector< unsigned > &p, const std::vector< T > &v)
long long get_micro_time()
const T & max_element_of(const std::vector< T > &v)
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)
void open_file_for_loading(const std::string &file_name, const F &f)
void write_vector(std::ostream &out, const std::vector< T > &v)
std::vector< unsigned > identity_permutation(unsigned n)
const unsigned invalid_id
void inplace_apply_permutation_to_possibly_invalid_elements_of(const std::vector< unsigned > &p, std::vector< unsigned > &v)
const unsigned inf_weight
BitVector read_bit_vector(const std::function< void(char *, unsigned long long)> &in, unsigned long long size)
void open_file_for_saving(const std::string &file_name, const F &f)
std::vector< unsigned > first_out
std::vector< unsigned > weight
std::vector< unsigned > head
std::vector< unsigned > shortcut_first_arc
BitVector is_shortcut_an_original_arc
std::vector< unsigned > shortcut_second_arc