Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
customizable_contraction_hierarchy.cpp
Go to the documentation of this file.
3#include <routingkit/sort.h>
7#include <routingkit/filter.h>
10#include <routingkit/timer.h>
11
12#include "emulate_gcc_builtin.h"
13
14#include <vector>
15#include <assert.h>
16#include <algorithm>
17#include <stdexcept>
18#ifdef _OPENMP
19#include <omp.h>
20#endif
21
22namespace RoutingKit{
23
24namespace{
25 template<class OnNewArc>
26 unsigned compute_chordal_supergraph(unsigned node_count, const std::vector<unsigned>&tail, const std::vector<unsigned>&head, const OnNewArc&on_new_arc){
27 std::vector<std::vector<unsigned>> nodes(node_count);
28 for(unsigned i = 0; i < tail.size(); ++i){
29 if(tail[i] < head[i]) {
30 nodes[tail[i]].push_back(head[i]);
31 }
32 }
33
34 for(unsigned n = 0; n < node_count; ++n){
35 std::sort(nodes[n].begin(), nodes[n].end());
36 auto it = std::unique(nodes[n].begin(), nodes[n].end());
37 nodes[n].resize(std::distance(nodes[n].begin(), it));
38 }
39
40 size_t max_upward_degree = 0;
41 for(unsigned n = 0; n < node_count; ++n){
42 if(nodes[n].size() == 0){ continue; }
43 const unsigned lowest_neighbor = nodes[n][0];
44
45 std::vector<unsigned> merged(nodes[n].size() + nodes[lowest_neighbor].size() - 1);
46 std::merge(++nodes[n].begin(), nodes[n].end(), nodes[lowest_neighbor].begin(), nodes[lowest_neighbor].end(), merged.begin());
47 auto it = std::unique(merged.begin(), merged.end());
48 merged.resize(std::distance(merged.begin(), it));
49 nodes[lowest_neighbor] = std::move(merged);
50
51 for(unsigned neighbor : nodes[n]){
52 on_new_arc(n, neighbor);
53 }
54 max_to(max_upward_degree, nodes[n].size());
55 }
56 return max_upward_degree;
57 }
58
59 // Let {x,y,z} be a triangle with ranks x<y<z. The bottom arc of this triangle is x,y and the mid arc is x,z and the top arc is y,z.
60 // This triangle is a lower triangle of its top arc, i.e., y,z. x is the bottom node, y is the top node, and z is the top node.
61
62 // Callback has signature
63 // f(bottom_arc, mid_arc, top_arc, bottom_node, mid_node, top_node)
64 // and should return false to abort the enumeration, and true to continue
65
66 // Return value forall_*_triangle_of_arc is false if and only if the enumeration was aborted by the callback.
67
68 template<class F>
69 bool forall_upper_triangles_of_arc(const CustomizableContractionHierarchy&cch, unsigned x, unsigned y, unsigned xy, const F&f){
70 unsigned x_up_arc = xy+1;
71 unsigned x_up_arc_end = cch.up_first_out[x+1];
72
73 unsigned y_up_arc = cch.up_first_out[y];
74 unsigned y_up_arc_end = cch.up_first_out[y+1];
75
76 while(x_up_arc != x_up_arc_end && y_up_arc != y_up_arc_end){
77 if(cch.up_head[x_up_arc] < cch.up_head[y_up_arc]){
78 ++x_up_arc;
79 }else if(cch.up_head[x_up_arc] > cch.up_head[y_up_arc]){
80 ++y_up_arc;
81 }else{
82 unsigned z = cch.up_head[x_up_arc];
83 if(!f(xy, x_up_arc, y_up_arc, x, y, z))
84 return false;
85 ++x_up_arc;
86 ++y_up_arc;
87 }
88 }
89 return true;
90 }
91
92 template<class F>
93 bool forall_upper_triangles_of_arc(const CustomizableContractionHierarchy&cch, unsigned xy, const F&f){
94 return forall_upper_triangles_of_arc(cch, cch.up_tail[xy], cch.up_head[xy], xy, f);
95 }
96
97 template<class F>
98 bool forall_intermediate_triangles_of_arc(const CustomizableContractionHierarchy&cch, unsigned x, unsigned y, unsigned xy, const F&f){
99 unsigned x_up_arc = cch.up_first_out[x];
100 unsigned x_up_arc_end = xy;
101
102 unsigned y_down_arc = cch.down_first_out[y];
103 unsigned y_down_arc_end = cch.down_first_out[y+1];
104
105 while(x_up_arc != x_up_arc_end && y_down_arc != y_down_arc_end){
106 if(cch.up_head[x_up_arc] < cch.down_head[y_down_arc]){
107 ++x_up_arc;
108 }else if(cch.up_head[x_up_arc] > cch.down_head[y_down_arc]){
109 ++y_down_arc;
110 }else{
111 unsigned z = cch.up_head[x_up_arc];
112 if(!f(x_up_arc, xy, cch.down_to_up[y_down_arc], x, z, y))
113 return false;
114 ++x_up_arc;
115 ++y_down_arc;
116 }
117 }
118 return true;
119 }
120
121 template<class F>
122 bool forall_intermediate_triangles_of_arc(const CustomizableContractionHierarchy&cch, unsigned xy, const F&f){
123 return forall_intermediate_triangles_of_arc(cch, cch.up_tail[xy], cch.up_head[xy], xy, f);
124 }
125
126 template<class F>
127 bool forall_lower_triangles_of_arc(const CustomizableContractionHierarchy&cch, unsigned x, unsigned y, unsigned xy, const F&f){
128 unsigned x_down_arc = cch.down_first_out[x];
129 unsigned x_down_arc_end = cch.down_first_out[x+1];
130
131 unsigned y_down_arc = cch.down_first_out[y];
132 unsigned y_down_arc_end = cch.down_first_out[y+1];
133
134 while(x_down_arc != x_down_arc_end && y_down_arc != y_down_arc_end){
135 if(cch.down_head[x_down_arc] < cch.down_head[y_down_arc]){
136 ++x_down_arc;
137 }else if(cch.down_head[x_down_arc] > cch.down_head[y_down_arc]){
138 ++y_down_arc;
139 }else{
140 unsigned z = cch.down_head[x_down_arc];
141 if(!f(cch.down_to_up[x_down_arc], cch.down_to_up[y_down_arc], xy, z, x, y))
142 return false;
143 ++x_down_arc;
144 ++y_down_arc;
145 }
146 }
147 return true;
148 }
149
150 template<class F>
151 bool forall_lower_triangles_of_arc(const CustomizableContractionHierarchy&cch, unsigned xy, const F&f){
152 return forall_lower_triangles_of_arc(cch, cch.up_tail[xy], cch.up_head[xy], xy, f);
153 }
154
155 #ifndef NDEBUG
156 struct TriangleVerifier{
157
158 TriangleVerifier(){}
159 explicit TriangleVerifier(const CustomizableContractionHierarchy&cch):cch(&cch){}
160
161 bool operator()(
162 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
163 unsigned bottom_node, unsigned mid_node, unsigned top_node
164 ) const {
165 assert(bottom_node != mid_node);
166 assert(bottom_node != top_node);
167 assert(mid_node != top_node);
168
169 assert(bottom_arc != mid_arc);
170 assert(bottom_arc != top_arc);
171 assert(mid_arc != top_arc);
172
173 assert(bottom_node < mid_node);
174 assert(mid_node < top_node);
175
176 assert(bottom_arc < mid_arc);
177 assert(mid_arc < top_arc);
178
179 assert(cch->up_tail[bottom_arc] == bottom_node);
180 assert(cch->up_head[bottom_arc] == mid_node);
181
182 assert(cch->up_tail[mid_arc] == bottom_node);
183 assert(cch->up_head[mid_arc] == top_node);
184
185 assert(cch->up_tail[top_arc] == mid_node);
186 assert(cch->up_head[top_arc] == top_node);
187
188 return true;
189 }
190
191 const CustomizableContractionHierarchy*cch;
192 };
193 #endif
194}
195
197 std::vector<unsigned>arg_order,
198 std::vector<unsigned>input_tail,
199 std::vector<unsigned>input_head,
200 std::function<void(const std::string&)>log_message,
201 bool filter_always_inf_arcs
202):
203 order(std::move(arg_order))
204{
205 unsigned node_count = order.size();
206 unsigned input_arc_count = input_tail.size();
207
208 long long timer = 0;
209
210 if(log_message){
211 log_message("Building CCH");
212 log_message("Input graph has "+std::to_string(node_count) + " nodes and "+std::to_string(input_arc_count)+" arcs");
213 }
214
216
217 #ifndef NDEBUG
218 std::vector<unsigned> raw_input_tail = input_tail;
219 std::vector<unsigned> raw_input_head = input_head;
220 #endif
221
222
223 if(log_message){
224 log_message("Start reordering nodes according to order");
225 timer = -get_micro_time();
226 }
227
228 input_tail = apply_permutation_to_elements_of(rank, std::move(input_tail));
229 input_head = apply_permutation_to_elements_of(rank, std::move(input_head));
230
231 if(log_message){
232 timer += get_micro_time();
233 log_message("Finished reordering nodes, needed "+std::to_string(timer)+"musec");
234 }
235
236 std::vector<unsigned>input_arc_id;
237
238 if(log_message){
239 log_message("Start sorting arcs");
240 timer = -get_micro_time();
241 }
242
243 {
245 input_head = apply_permutation(input_arc_id, input_head);
246 }
247
248 if(log_message){
249 timer += get_micro_time();
250 log_message("Finished sorting arcs, needed "+std::to_string(timer)+"musec");
251 }
252
253 #ifndef NDEBUG
254 for(unsigned input_arc=0; input_arc<input_arc_count; ++input_arc){
255 assert(rank[raw_input_head[input_arc_id[input_arc]]] == input_head[input_arc]);
256 assert(rank[raw_input_tail[input_arc_id[input_arc]]] == input_tail[input_arc]);
257 }
258 #endif
259
260 // Compute up graph
261
262 if(log_message){
263 log_message("Start building chordal supergraph");
264 timer = -get_micro_time();
265 }
266 {
267 // Make graph symmetric & remove multi edges
268 std::vector<unsigned>symmetric_tail(2*input_arc_count);
269 std::vector<unsigned>symmetric_head(2*input_arc_count);
270 std::copy(input_tail.begin(), input_tail.end(), symmetric_tail.begin());
271 std::copy(input_head.begin(), input_head.end(), symmetric_head.begin());
272 std::copy(input_tail.begin(), input_tail.end(), symmetric_head.begin()+input_arc_count);
273 std::copy(input_head.begin(), input_head.end(), symmetric_tail.begin()+input_arc_count);
274
275 {
277 symmetric_head = apply_inverse_permutation(p, std::move(symmetric_head));
278 }
279
281 if(input_arc_count != 0)
282 filter.set(0, symmetric_tail[0] != symmetric_head[0]);
283 for(unsigned i=1; i<2*input_arc_count; ++i)
284 filter.set(i, (symmetric_head[i] != symmetric_head[i-1] || symmetric_tail[i] != symmetric_tail[i-1]) && (symmetric_tail[i] != symmetric_head[i]));
285
286 inplace_keep_element_of_vector_if(filter, symmetric_tail);
287 inplace_keep_element_of_vector_if(filter, symmetric_head);
288
289 unsigned upper_treewidth_bound = compute_chordal_supergraph(
290 node_count, symmetric_tail, symmetric_head,
291 [&](unsigned x, unsigned y){
292 if(up_tail.size() == invalid_id){
293 if(log_message)
294 log_message("CCH Construction aborted because chordal supergraph contains 2^32 or more arcs");
295 throw std::runtime_error("CCH must contain at most 2^32-1 arcs");
296 }
297 up_tail.push_back(x);
298 up_head.push_back(y);
299 }
300 );
301
302 if(log_message){
303 log_message("The treewidth of the input graph is bounded by "+std::to_string(upper_treewidth_bound));
304 }
305
306 up_head.shrink_to_fit();
307 up_tail.shrink_to_fit();
308
309 {
312 }
313
315 }
316
317 unsigned cch_arc_count = up_tail.size();
318
319 if(log_message){
320 timer += get_micro_time();
321 log_message("Finished building chordal supergraph, needed "+std::to_string(timer)+"musec");
322 log_message("Chordal supergraph contains "+std::to_string(cch_arc_count)+" arcs");
323 }
324
325 // Compute input -> ch mapping
326
327 if(log_message){
328 log_message("Start computing mapping from input arcs to CCH arcs");
329 timer = -get_micro_time();
330 }
331
332 if(cch_arc_count == 0){
335 }else{
338
339 {
340 unsigned cch_up_arc = 0;
341 for(unsigned input_arc=0; input_arc<input_arc_count; ++input_arc){
342 if(input_tail[input_arc] < input_head[input_arc]){
343 while(input_tail[input_arc] != up_tail[cch_up_arc] || input_head[input_arc] != up_head[cch_up_arc]){
344 assert(cch_up_arc < cch_arc_count);
345 ++cch_up_arc;
346 }
347 assert(input_tail[input_arc] == up_tail[cch_up_arc]);
348 assert(input_head[input_arc] == up_head[cch_up_arc]);
349 input_arc_to_cch_arc[input_arc_id[input_arc]] = cch_up_arc;
350 is_input_arc_upward.set(input_arc_id[input_arc]);
351 }else if(input_tail[input_arc] == input_head[input_arc]){
352 input_arc_to_cch_arc[input_arc_id[input_arc]] = invalid_id; // input arc is a loop
353 }
354 }
355 }
356
357 {
358 std::swap(input_tail, input_head);
360 input_head = apply_inverse_permutation(p, input_head);
361 input_arc_id = apply_inverse_permutation(p, input_arc_id);
362 }
363
364 {
365 unsigned cch_up_arc = 0;
366 for(unsigned input_arc=0; input_arc<input_arc_count; ++input_arc){
367 if(input_tail[input_arc] < input_head[input_arc]){
368 while(input_tail[input_arc] != up_tail[cch_up_arc] || input_head[input_arc] != up_head[cch_up_arc]){
369 assert(cch_up_arc < cch_arc_count);
370 ++cch_up_arc;
371 }
372 input_arc_to_cch_arc[input_arc_id[input_arc]] = cch_up_arc;
373 }
374 }
375 }
376 }
377
378 if(log_message){
379 timer += get_micro_time();
380 log_message("Finished computing mapping, needed "+std::to_string(timer)+"musec");
381 }
382
383 if(log_message){
384 log_message("Start computing elimination tree");
385 timer = -get_micro_time();
386 }
387
388 // Compute elimination tree
389 {
391 for(unsigned x=0; x<node_count; ++x){
392 if(up_first_out[x] != up_first_out[x+1])
394 else
396 }
397
398 #ifndef NDEBUG
399 for(unsigned x=0; x<node_count-1; ++x){
401 assert(x < elimination_tree_parent[x]);
402 for(unsigned xy=up_first_out[x]; xy<up_first_out[x+1]; ++xy){
403 unsigned y = up_head[xy];
404 assert(elimination_tree_parent[x] <= y);
405 }
406 }else{
407 assert(up_first_out[x] == up_first_out[x+1]);
408 }
409 }
410 #endif
411 }
412
413
414 if(log_message){
415 timer += get_micro_time();
416 log_message("Finished computing elimination tree, needed "+std::to_string(timer)+"musec");
417 }
418
419 if(log_message){
420 std::vector<unsigned>
421 nodes_in_search_space(node_count, 0),
422 arcs_in_search_space(node_count, 0);
423
424 for(unsigned x=node_count-1; x!=(unsigned)-1; --x){
426 nodes_in_search_space[x] = 1 + nodes_in_search_space[elimination_tree_parent[x]];
427 arcs_in_search_space[x] = up_first_out[x+1] - up_first_out[x] + arcs_in_search_space[elimination_tree_parent[x]];
428 }else{
429 nodes_in_search_space[x] = 1;
430 arcs_in_search_space[x] = 0;
431 }
432 }
433
434 unsigned max_nodes_in_search_space = 0;
435 unsigned max_arcs_in_search_space = 0;
436 unsigned long long nodes_in_search_space_sum = 0;
437 unsigned long long arcs_in_search_space_sum = 0;
438
439 for(unsigned x=0; x<node_count; ++x){
440 max_to(max_nodes_in_search_space, nodes_in_search_space[x]);
441 max_to(max_arcs_in_search_space, arcs_in_search_space[x]);
442 nodes_in_search_space_sum += nodes_in_search_space[x];
443 arcs_in_search_space_sum += arcs_in_search_space[x];
444 }
445 log_message("The average number of nodes in a search space is "+std::to_string(nodes_in_search_space_sum/node_count));
446 log_message("The maximum number of nodes in a search space is "+std::to_string(max_nodes_in_search_space));
447 log_message("The average number of arcs in a search space is "+std::to_string(arcs_in_search_space_sum/node_count));
448 log_message("The maximum number of arcs in a search space is "+std::to_string(max_arcs_in_search_space));
449 }
450
451 // filter up graph
452 if(!filter_always_inf_arcs)
453 log_message("Not filtering upward arcs");
454 else
455 {
456 if(log_message){
457 log_message("Start filtering upward arcs");
458 timer = -get_micro_time();
459 }
460
461 // assert that these have not yet been generated because they would be invalidated by this step
462 assert(down_head.empty());
464
466 can_forward_weight_be_non_inf(cch_arc_count, false),
467 can_backward_weight_be_non_inf(cch_arc_count, false);
468
469 for(unsigned input_arc=0; input_arc<input_arc_count; ++input_arc){
470 unsigned cch_arc=input_arc_to_cch_arc[input_arc];
471 if(cch_arc != invalid_id){
472 if(is_input_arc_upward.is_set(input_arc))
473 can_forward_weight_be_non_inf.set(cch_arc);
474 else
475 can_backward_weight_be_non_inf.set(cch_arc);
476 }
477 }
478
479
480 unsigned long long triangle_count = 0;
481
482 for(unsigned a=0; a<cch_arc_count; ++a){
483 forall_upper_triangles_of_arc(
484 *this, a,
485 [&](
486 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
487 unsigned bottom_node, unsigned mid_node, unsigned top_node
488 ){
489 (void) bottom_node; (void) mid_node; (void) top_node;
490
491 // TODO: Micro-optimizing this code could decrease 1% to 10% of the whole CCH build process.
492
493 if(!can_forward_weight_be_non_inf.is_set(top_arc)){
494 if(can_backward_weight_be_non_inf.is_set(bottom_arc) && can_forward_weight_be_non_inf.is_set(mid_arc))
495 can_forward_weight_be_non_inf.set(top_arc);
496 }
497
498 if(!can_backward_weight_be_non_inf.is_set(top_arc)){
499 if(can_forward_weight_be_non_inf.is_set(bottom_arc) && can_backward_weight_be_non_inf.is_set(mid_arc))
500 can_backward_weight_be_non_inf.set(top_arc);
501 }
502
503 ++triangle_count;
504 return true;
505 }
506 );
507 }
508
509 BitVector must_keep_arc = can_forward_weight_be_non_inf | can_backward_weight_be_non_inf;
510
511 up_head = keep_element_of_vector_if(must_keep_arc, std::move(up_head));
512 up_tail = keep_element_of_vector_if(must_keep_arc, std::move(up_tail));
514
515 LocalIDMapper map(must_keep_arc);
516 for(auto&x:input_arc_to_cch_arc)
517 if(x != invalid_id)
518 x = map.to_local(x);
519
520 if(log_message){
521 timer += get_micro_time();
522 log_message("Finished filtering upward arcs, needed "+std::to_string(timer)+"musec");
523 log_message("The number of arcs decreased from "+std::to_string(cch_arc_count)+" to "+std::to_string(map.local_id_count()));
524 log_message("The number of triangles before filtering was "+std::to_string(triangle_count)+". (The value after filtering was not determined.)");
525 }
526
528 }
529
530 if(log_message){
531 log_message("Start computing downward arcs");
532 timer = -get_micro_time();
533 }
534
535 // compute down graph
536 auto down_tail = up_head;
538
539 {
542 }
544
545 if(log_message){
546 timer += get_micro_time();
547 log_message("Finished computing downward arcs, needed "+std::to_string(timer)+"musec");
548 }
549
550 if(log_message){
551 log_message("Start computing mapping from CCH arcs to input arcs");
552 timer = -get_micro_time();
553 }
554
555 // Compute ch mapping -> input
556 {
559
560 for(unsigned i=0; i<input_arc_count; ++i)
563
565
568
571
574
575 for(unsigned input_arc=0; input_arc<input_arc_count; ++input_arc){
576 unsigned cch_arc = input_arc_to_cch_arc[input_arc];
577 if(cch_arc != invalid_id){
578 unsigned i = does_cch_arc_have_input_arc_mapper.to_local(cch_arc);
579 if(is_input_arc_upward.is_set(input_arc)){
581 forward_input_arc_of_cch[i] = input_arc;
582 }else{
584
585 first_extra_forward_input_arc_of_cch.push_back(cch_arc);
586 extra_forward_input_arc_of_cch.push_back(input_arc);
587 }
588 }else{
590 backward_input_arc_of_cch[i] = input_arc;
591 }else{
593
594 first_extra_backward_input_arc_of_cch.push_back(cch_arc);
595 extra_backward_input_arc_of_cch.push_back(input_arc);
596 }
597 }
598 }
599 }
600
602
607
608 {
612 [](unsigned x){return x;}
613 );
618 )
619 ;
621 }
622
623
624 {
628 [](unsigned x){return x;}
629 );
634 )
635 ;
637 }
638
639 }
640
641 if(log_message){
642 timer += get_micro_time();
643 log_message("Finished computing mapping, needed "+std::to_string(timer)+"musec");
644 log_message(std::to_string(does_cch_arc_have_input_arc_mapper.local_id_count())+" cch arcs have an input arc");
645 log_message(std::to_string(does_cch_arc_have_extra_input_arc_mapper.local_id_count())+" cch arcs have two or more input arcs");
646 }
647
648
649// for(unsigned a=0; a<cch_arc_count; ++a)
650// forall_upper_triangles_of_arc(*this, a, TriangleVerifier(*this));
651// for(unsigned a=0; a<cch_arc_count; ++a)
652// forall_intermediate_triangles_of_arc(*this, a, TriangleVerifier(*this));
653// for(unsigned a=0; a<cch_arc_count; ++a)
654// forall_lower_triangles_of_arc(*this, a, TriangleVerifier(*this));
655}
656
657namespace{
658
659 void extract_initial_metric_of_cch_arc(const CustomizableContractionHierarchy&cch, CustomizableContractionHierarchyMetric&metric, unsigned cch_arc){
660 if(__builtin_expect(!cch.does_cch_arc_have_input_arc.is_set(cch_arc), true)){
661 metric.forward[cch_arc] = inf_weight;
662 metric.backward[cch_arc] = inf_weight;
663 } else {
664 {
665 unsigned i = cch.does_cch_arc_have_input_arc_mapper.to_local(cch_arc);
668 else
669 metric.forward[cch_arc] = inf_weight;
670
673 else
674 metric.backward[cch_arc] = inf_weight;
675 }
682 }
683 }
684 }
685
686 void extract_initial_metric(const CustomizableContractionHierarchy&cch, CustomizableContractionHierarchyMetric&metric){
687 for(unsigned cch_arc=0; cch_arc<cch.cch_arc_count(); ++cch_arc){
688 extract_initial_metric_of_cch_arc(cch, metric, cch_arc);
689 }
690 }
691
692 struct LowerTriangleRelaxer{
693
694 LowerTriangleRelaxer(){}
695 explicit LowerTriangleRelaxer(CustomizableContractionHierarchyMetric&metric):metric(&metric){}
696
697 bool operator()(
698 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
699 unsigned bottom_node, unsigned mid_node, unsigned top_node
700 ) const {
701 (void)bottom_node;
702 (void)mid_node;
703 (void)top_node;
704 min_to(metric->forward[top_arc], metric->backward[bottom_arc] + metric->forward[mid_arc] );
705 min_to(metric->backward[top_arc], metric->forward[bottom_arc] + metric->backward[mid_arc]);
706 return true;
707 }
708
709 CustomizableContractionHierarchyMetric*metric;
710 };
711
712 #ifndef NDEBUG
713 struct LowerTriangleInequalityVerifier{
714
715 LowerTriangleInequalityVerifier(){}
716 explicit LowerTriangleInequalityVerifier(CustomizableContractionHierarchyMetric&metric):metric(&metric){}
717
718 bool operator()(
719 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
720 unsigned bottom_node, unsigned mid_node, unsigned top_node
721 ) const {
722 (void)bottom_node;
723 (void)mid_node;
724 (void)top_node;
725 assert(metric->forward[top_arc] <= metric->backward[bottom_arc] + metric->forward[mid_arc]);
726 assert(metric->backward[top_arc] <= metric->forward[bottom_arc] + metric->backward[mid_arc]);
727 return true;
728 }
729
730 CustomizableContractionHierarchyMetric*metric;
731 };
732 #endif
733}
734
736 forward(cch.cch_arc_count()), backward(cch.cch_arc_count()), cch(&cch), input_weight(&input_weight[0]){
737}
738
740 forward(cch.cch_arc_count()), backward(cch.cch_arc_count()), cch(&cch), input_weight(input_weight){
741}
742
744 assert(input_weight.size() == cch.input_arc_count() && "Input weight vector has the wrong size");
745 reset(cch, &input_weight[0]);
746 return *this;
747}
748
750 assert(cch && "Need to be attached to a CCH");
751 assert(input_weight.size() == cch->input_arc_count() && "Input weight vector has the wrong size");
752 reset(&input_weight[0]);
753 return *this;
754}
755
757 assert(input_weight_ != nullptr && "Input weight pointer must not be null");
758 if(cch_.cch_arc_count() != forward.size()){
759 *this = CustomizableContractionHierarchyMetric(cch_, input_weight_);
760 }else{
761 cch = &cch_;
762 input_weight = input_weight_;
763 }
764 return *this;
765}
766
768 assert(input_weight_ != nullptr && "Input weight pointer must not be null");
769 input_weight = input_weight_;
770 return *this;
771}
772
774 assert(input_weight != nullptr && "Metric must be connected to a weight vector");
775
776 extract_initial_metric(*cch, *this);
777
778 std::vector<unsigned> arc_id_cache(cch->node_count());
779
780 for(unsigned x=0; x<cch->node_count(); ++x){
781 const unsigned xz_up_end = cch->up_first_out[x+1];
782 for(unsigned xz_up = cch->up_first_out[x]; xz_up < xz_up_end; ++xz_up){
783 arc_id_cache[cch->up_head[xz_up]] = xz_up;
784 }
785
786 const unsigned xy_down_end = cch->down_first_out[x+1];
787 for(unsigned xy_down = cch->down_first_out[x]; xy_down < xy_down_end; ++xy_down){
788 const unsigned yx_up = cch->down_to_up[xy_down];
789 const unsigned y = cch->down_head[xy_down];
790 const unsigned yz_up_end_reversed = cch->up_first_out[y];
791 for(unsigned yz_up_reversed = cch->up_first_out[y+1]; yz_up_reversed > yz_up_end_reversed; --yz_up_reversed){
792 const unsigned yz_up = yz_up_reversed-1;
793 const unsigned z = cch->up_head[yz_up];
794 if (z <= x) { break; }
795 LowerTriangleRelaxer(*this)(yx_up, yz_up, arc_id_cache[z], y, x, z);
796 }
797 }
798 }
799
800 #ifndef NDEBUG
801 for(unsigned a=0; a<cch->cch_arc_count(); ++a)
802 forall_upper_triangles_of_arc(*cch, a, LowerTriangleInequalityVerifier(*this));
803 #endif
804 return *this;
805}
806
807namespace{
808 template<class T>
809 void atomic_min_to(T&x, const T&y){
810 T z = x;
811 while(y < z && !__sync_bool_compare_and_swap(&x, z, y))
812 z = x;
813 }
814
815 struct AtomicLowerTriangleRelaxer{
816
817 AtomicLowerTriangleRelaxer(){}
818 explicit AtomicLowerTriangleRelaxer(CustomizableContractionHierarchyMetric&metric):metric(&metric){}
819
820 bool operator()(
821 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
822 unsigned bottom_node, unsigned mid_node, unsigned top_node
823 ) const {
824 (void)bottom_node;
825 (void)mid_node;
826 (void)top_node;
827 atomic_min_to(metric->forward[top_arc], metric->backward[bottom_arc] + metric->forward[mid_arc] );
828 atomic_min_to(metric->backward[top_arc], metric->forward[bottom_arc] + metric->backward[mid_arc]);
829 return true;
830 }
831
832 CustomizableContractionHierarchyMetric*metric;
833 };
834}
835
837 const unsigned node_count = cch.node_count();
838
839 std::vector<unsigned>node_level(node_count);
840 unsigned level_count;
841 {
842 std::vector<unsigned>lock(node_count);
843 std::vector<unsigned>zero_lock_list(node_count);
844 unsigned zero_lock_count = 0;
845 for(unsigned x=0; x<node_count; ++x){
846 lock[x] = cch.down_first_out[x+1] - cch.down_first_out[x];
847 if(lock[x] == 0){
848 zero_lock_list[zero_lock_count] = x;
849 ++zero_lock_count;
850 }
851 }
852
853 level_count = 0;
854 std::vector<unsigned>next_zero_lock_list(node_count);
855 while(zero_lock_count != 0){
856 unsigned next_zero_lock_count = 0;
857 for(unsigned i=0; i<zero_lock_count; ++i){
858 unsigned x = zero_lock_list[i];
859 node_level[x] = level_count;
860 for(unsigned xy=cch.up_first_out[x]; xy < cch.up_first_out[x+1]; ++xy){
861 unsigned y = cch.up_head[xy];
862 --lock[y];
863 if(lock[y] == 0){
864 next_zero_lock_list[next_zero_lock_count] = y;
865 ++next_zero_lock_count;
866 }
867 }
868 }
869 ++level_count;
870 std::swap(next_zero_lock_list, zero_lock_list);
871 zero_lock_count = next_zero_lock_count;
872 }
873 }
874
875 const unsigned arc_count = cch.cch_arc_count();
876
877 std::vector<unsigned>arc_level(arc_count);
878 arcs_ordered_by_level.resize(arc_count);
879
880 auto p = compute_stable_sort_permutation_using_key(node_level, level_count, [&](unsigned x){ return x; });
881
882 unsigned j = 0;
883 for(unsigned i=0; i<node_count; ++i){
884 unsigned x = p[i];
885 for(unsigned xy=cch.up_first_out[x]; xy<cch.up_first_out[x+1]; ++xy){
886 arc_level[j] = node_level[x];
887 arcs_ordered_by_level[j] = xy;
888 ++j;
889 }
890 }
891
892 first_arc_of_level = invert_vector(arc_level, level_count);
893
894 this->cch = &cch;
895}
896
897
899 // If OpenMP is enabled, it is used to parallelize the code. If OpenMP is disabled, the code will compile but will run sequentially.
900 #ifdef _OPENMP
901 customize(metric, omp_get_num_procs());
902 #else
903 customize(metric, 1);
904 #endif
905 return *this;
906}
907
909 assert(cch == metric.cch);
910 assert(thread_count != 0);
911 assert(metric.input_weight != nullptr && "Metric must be connected to a weight vector");
912
913 if(thread_count == 1){
914 metric.customize();
915 } else {
916 #ifdef _OPENMP
917 #pragma omp parallel num_threads(thread_count)
918 #endif
919 {
920 #ifdef _OPENMP
921 #pragma omp for
922 #endif
923 for(unsigned cch_arc=0; cch_arc<cch->cch_arc_count(); ++cch_arc){
924 extract_initial_metric_of_cch_arc(*cch, metric, cch_arc);
925 }
926
927 for(unsigned l=0; l<first_arc_of_level.size()-1; ++l){
928 #ifdef _OPENMP
929 #pragma omp for schedule(dynamic,256)
930 #endif
931 for(unsigned i=first_arc_of_level[l]; i<first_arc_of_level[l+1]; ++i){
932 forall_upper_triangles_of_arc(*cch, arcs_ordered_by_level[i], AtomicLowerTriangleRelaxer(metric));
933 }
934 }
935 }
936
937
938
939 #ifndef NDEBUG
940 for(unsigned a=0; a<cch->cch_arc_count(); ++a)
941 forall_upper_triangles_of_arc(*cch, a, LowerTriangleInequalityVerifier(metric));
942 #endif
943 }
944 return *this;
945}
946
951
956
966
973
975 assert(cch == metric.cch);
976 assert(metric.input_weight != nullptr && "Metric must be connected to a weight vector");
977
978 while(!q.empty()){
979 unsigned xy = q.pop();
980
981 unsigned old_forward = metric.forward[xy];
982 unsigned old_backward = metric.backward[xy];
983
984 metric.forward[xy] = inf_weight;
985 metric.backward[xy] = inf_weight;
986
987 extract_initial_metric_of_cch_arc(*cch, metric, xy);
988
989 forall_lower_triangles_of_arc(
990 *cch, xy,
991 LowerTriangleRelaxer(metric)
992 );
993
994 unsigned new_forward = metric.forward[xy];
995 unsigned new_backward = metric.backward[xy];
996
997 if(old_forward != new_forward || old_backward != new_backward){
998 forall_intermediate_triangles_of_arc(
999 *cch, xy,
1000 [&](
1001 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
1002 unsigned bottom_node, unsigned mid_node, unsigned top_node
1003 ){
1004 assert(mid_arc == xy);
1005 if(
1006 metric.backward[bottom_arc] + old_forward == metric.forward[top_arc] ||
1007 metric.forward[bottom_arc] + old_backward == metric.backward[top_arc] ||
1008 metric.backward[bottom_arc] + new_forward < metric.forward[top_arc] ||
1009 metric.forward[bottom_arc] + new_backward < metric.backward[top_arc]
1010 ){
1011 q.push(top_arc);
1012 }
1013 return true;
1014 }
1015 );
1016 forall_upper_triangles_of_arc(
1017 *cch, xy,
1018 [&](
1019 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
1020 unsigned bottom_node, unsigned mid_node, unsigned top_node
1021 ){
1022 assert(bottom_arc == xy);
1023 if(
1024 metric.forward[mid_arc] + old_backward == metric.forward[top_arc] ||
1025 metric.backward[mid_arc] + old_forward == metric.backward[top_arc] ||
1026 metric.forward[mid_arc] + new_backward < metric.forward[top_arc] ||
1027 metric.backward[mid_arc] + new_forward < metric.backward[top_arc]
1028 ){
1029 q.push(top_arc);
1030 }
1031 return true;
1032 }
1033 );
1034 }
1035 }
1036 #ifndef NDEBUG
1037 for(unsigned a=0; a<cch->cch_arc_count(); ++a)
1038 forall_upper_triangles_of_arc(*cch, a, LowerTriangleInequalityVerifier(metric));
1039 #endif
1040 return *this;
1041}
1042
1043namespace{
1044 const unsigned query_state_initialized = 0;
1045 const unsigned query_state_run = 1;
1046 const unsigned query_state_source_pinned = 2;
1047 const unsigned query_state_source_run = 3;
1048 const unsigned query_state_target_pinned = 4;
1049 const unsigned query_state_target_run = 5;
1050}
1051
1052namespace{
1053
1054 template<class F>
1055 void forall_ancestors(const std::vector<unsigned>&parent, unsigned x, unsigned stop_at, const F&f){
1056 assert(x < parent.size());
1057 assert(stop_at < parent.size() || stop_at == invalid_id);
1058
1059 while(x != stop_at){
1060 assert(x < parent.size() && "stop_at is not an ancestor of x");
1061 if(!f(x))
1062 return;
1063 assert(parent[x] > x);
1064 x = parent[x];
1065 }
1066 }
1067
1068 template<class F>
1069 void forall_ancestors(const std::vector<unsigned>&parent, unsigned x, const F&f){
1070 forall_ancestors(parent, x, invalid_id, f);
1071 }
1072
1073
1074 void reset_source_list(
1075 const std::vector<unsigned>&elimination_tree_parent,
1076 std::vector<unsigned>&source_node, std::vector<unsigned>&source_elimination_tree_end,
1077 std::vector<bool>&in_forward_search_space, std::vector<unsigned>&forward_tentative_distance
1078 ){
1079 for(unsigned i=0; i<source_node.size(); ++i){
1080 forall_ancestors(
1081 elimination_tree_parent,
1082 source_node[i], source_elimination_tree_end[i],
1083 [&](unsigned x){
1084 in_forward_search_space[x] = false;
1086 return true;
1087 }
1088 );
1089 }
1090 source_node.clear();
1091 source_elimination_tree_end.clear();
1092 }
1093}
1094
1098 forward_predecessor_node(metric.cch->node_count()),
1099 backward_predecessor_node(metric.cch->node_count()),
1100 in_forward_search_space(metric.cch->node_count(), false),
1101 in_backward_search_space(metric.cch->node_count(), false),
1102 shortest_path_meeting_node(invalid_id),
1103 cch(metric.cch),
1104 metric(&metric),
1105 state(query_state_initialized){}
1106
1107namespace{
1108 void internal_add_source(
1109 unsigned external_s, unsigned dist_to_s,
1110 const std::vector<unsigned>&rank,
1111 const std::vector<unsigned>&elimination_tree_parent,
1112 std::vector<unsigned>&forward_tentative_distance,
1113 std::vector<unsigned>&forward_predecessor_node,
1114 std::vector<bool>&in_forward_search_space,
1115 std::vector<unsigned>&source_node,
1116 std::vector<unsigned>&source_elimination_tree_end
1117 ){
1118 unsigned s = rank[external_s];
1119
1121
1122 source_node.push_back(s);
1123 forward_tentative_distance[s] = dist_to_s;
1124 forward_predecessor_node[s] = invalid_id;
1125
1126 forall_ancestors(
1127 elimination_tree_parent, s,
1128 [&](unsigned x){
1129 if(!in_forward_search_space[x]){
1130 in_forward_search_space[x] = true;
1131 return true;
1132 } else {
1133 source_elimination_tree_end.push_back(x);
1134 return false;
1135 }
1136 }
1137 );
1138 if(source_elimination_tree_end.size() != source_node.size())
1139 source_elimination_tree_end.push_back(invalid_id);
1140 }else{
1141 min_to(forward_tentative_distance[s], dist_to_s);
1142 }
1143 }
1144}
1145
1146
1147
1148
1150 assert(external_s < cch->node_count());
1151 assert(state == query_state_initialized || state == query_state_target_pinned);
1152 internal_add_source(
1153 external_s, dist_to_s,
1154 cch->rank,
1161 );
1162 return *this;
1163}
1164
1166 assert(external_t < cch->node_count());
1167 assert(state == query_state_initialized || state == query_state_source_pinned);
1168 internal_add_source(
1169 external_t, dist_to_t,
1170 cch->rank,
1177 );
1178 return *this;
1179}
1180
1181namespace{
1182 template<class SetPred>
1183 void relax_outgoing_arcs(
1184 const std::vector<unsigned>&first_out,
1185 const std::vector<unsigned>&head,
1186 const std::vector<unsigned>&weight,
1187 std::vector<unsigned>&tentative_distance,
1188 const SetPred&set_node_predecessor,
1189 unsigned x
1190 ){
1191
1192 for(unsigned xy=first_out[x]; xy<first_out[x+1]; ++xy){
1193 unsigned y=head[xy];
1194 if(tentative_distance[x] + weight[xy] < tentative_distance[y]){
1195 tentative_distance[y] = tentative_distance[x] + weight[xy];
1196 set_node_predecessor(y, x);
1197 }
1198 }
1199 }
1200
1201 template<class SetPred>
1202 void relax_incoming_arcs(
1203 const std::vector<unsigned>&first_out,
1204 const std::vector<unsigned>&head,
1205 const std::vector<unsigned>&weight,
1206 std::vector<unsigned>&tentative_distance,
1207 const SetPred&set_node_predecessor,
1208 unsigned x
1209 ){
1210 for(unsigned xy=first_out[x]; xy<first_out[x+1]; ++xy){
1211 unsigned y=head[xy];
1212 if(tentative_distance[y] + weight[xy] < tentative_distance[x]){
1213 tentative_distance[x] = tentative_distance[y] + weight[xy];
1214 set_node_predecessor(x, y);
1215 }
1216 }
1217 }
1218}
1219
1220
1222 assert(state == query_state_initialized);
1223
1224 for(unsigned i = source_node.size()-1; i!=(unsigned)-1; --i){
1225 forall_ancestors(
1228 [&](unsigned x){
1229
1230 relax_outgoing_arcs(
1231 cch->up_first_out, cch->up_head, metric->forward,
1232 forward_tentative_distance, [&](unsigned a, unsigned b){forward_predecessor_node[a] = b;},
1233 x
1234 );
1235 return true;
1236 }
1237 );
1238 }
1239
1240// for(unsigned x=0; x<cch->node_count(); ++x){
1241// for(unsigned xy=cch->up_first_out[x]; xy < cch->up_first_out[x+1]; ++xy){
1242// unsigned y = cch->up_head[xy];
1243// assert(forward_tentative_distance[y] <= forward_tentative_distance[x] + metric->forward[xy] && "not all forward arcs relaxed");
1244// }
1245// }
1246
1247 shortest_path_meeting_node = invalid_id;
1248 unsigned shortest_path_length = inf_weight;
1249
1250 for(unsigned i = target_node.size()-1; i!=(unsigned)-1; --i){
1251 forall_ancestors(
1253 target_node[i], target_elimination_tree_end[i],
1254 [&](unsigned x){
1255 relax_outgoing_arcs(
1256 cch->up_first_out, cch->up_head, metric->backward,
1257 backward_tentative_distance, [&](unsigned a, unsigned b){backward_predecessor_node[a] = b;},
1258 x
1259 );
1260 if(in_forward_search_space[x]){
1262 if(l < shortest_path_length){
1263 shortest_path_length = l;
1264 shortest_path_meeting_node = x;
1265 }
1266 }
1267 return true;
1268 }
1269 );
1270 }
1271
1272// for(unsigned x=0; x < cch->node_count(); ++x){
1273// unsigned l = forward_tentative_distance[x] + backward_tentative_distance[x];
1274// assert(l >= shortest_path_length);
1275// }
1276
1277 state = query_state_run;
1278 return *this;
1279}
1280
1281unsigned CustomizableContractionHierarchyQuery::get_distance(){
1282 assert(state == query_state_run);
1283 if(shortest_path_meeting_node == invalid_id)
1284 return inf_weight;
1285 else
1286 return forward_tentative_distance[shortest_path_meeting_node] + backward_tentative_distance[shortest_path_meeting_node];
1287}
1288
1289unsigned CustomizableContractionHierarchyQuery::get_used_source(){
1290 assert(state == query_state_run);
1291 if(shortest_path_meeting_node == invalid_id) {
1292 return invalid_id;
1293 } else {
1294 unsigned x = shortest_path_meeting_node;
1295 while(forward_predecessor_node[x] != invalid_id){
1296 x = forward_predecessor_node[x];
1297 }
1298 return cch->order[x];
1299 }
1300}
1301
1302unsigned CustomizableContractionHierarchyQuery::get_used_target(){
1303 assert(state == query_state_run);
1304 if(shortest_path_meeting_node == invalid_id) {
1305 return invalid_id;
1306 } else {
1307 unsigned x = shortest_path_meeting_node;
1308 while(backward_predecessor_node[x] != invalid_id){
1309 x = backward_predecessor_node[x];
1310 }
1311 return cch->order[x];
1312 }
1313}
1314
1315namespace{
1316 struct TriangleUnpacker{
1317 TriangleUnpacker(){}
1318 TriangleUnpacker(unsigned&bottom_node, unsigned&bottom_arc, unsigned&mid_arc):
1319 bottom_node_(&bottom_node), bottom_arc_(&bottom_arc), mid_arc_(&mid_arc){}
1320 bool operator()(
1321 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
1322 unsigned bottom_node, unsigned mid_node, unsigned top_node
1323 ) const {
1324 (void)top_node; (void)mid_node;
1325 if((*forward)[top_arc] == (*backward)[bottom_arc] + (*forward)[mid_arc]){
1326 *bottom_node_ = bottom_node;
1327 *bottom_arc_ = bottom_arc;
1328 *mid_arc_ = mid_arc;
1329
1330 return false;
1331 }else{
1332 return true;
1333 }
1334 }
1335
1336 const std::vector<unsigned>*forward;
1337 const std::vector<unsigned>*backward;
1338
1340 };
1341
1342 template<class OnNewSegment>
1343 void unpack_arc(
1344 const CustomizableContractionHierarchy&cch, const CustomizableContractionHierarchyMetric&metric,
1345 bool is_forward,
1346 unsigned x, unsigned y, unsigned xy,
1347 const OnNewSegment&on_new_segment
1348 ){
1349 assert(x == cch.up_tail[xy]);
1350 assert(y == cch.up_head[xy]);
1351
1352 unsigned
1353 bottom_node = invalid_id,
1354 bottom_arc,
1355 mid_arc;
1356
1357 auto unpacker = [&](
1358 unsigned bottom_arc_, unsigned mid_arc_, unsigned top_arc_,
1359 unsigned bottom_node_, unsigned mid_node_, unsigned top_node_
1360 ){
1361 (void)top_node_; (void)mid_node_;
1362
1363 bool fits;
1364 if(is_forward)
1365 fits = metric.forward[top_arc_] == metric.backward[bottom_arc_] + metric.forward[mid_arc_];
1366 else
1367 fits = metric.backward[top_arc_] == metric.forward[bottom_arc_] + metric.backward[mid_arc_];
1368 if(fits){
1369 bottom_node = bottom_node_;
1370 bottom_arc = bottom_arc_;
1371 mid_arc = mid_arc_;
1372 return false;
1373 }else{
1374 return true;
1375 }
1376 };
1377 forall_lower_triangles_of_arc(cch, x, y, xy, unpacker);
1378 if(bottom_node == invalid_id){
1379 if(is_forward)
1380 on_new_segment(x, xy, true);
1381 else
1382 on_new_segment(y, xy, false);
1383 } else {
1384 if(is_forward){
1385 unpack_arc(cch, metric, false, bottom_node, x, bottom_arc, on_new_segment);
1386 unpack_arc(cch, metric, true, bottom_node, y, mid_arc, on_new_segment);
1387 }else{
1388 unpack_arc(cch, metric, false, bottom_node, y, mid_arc, on_new_segment);
1389 unpack_arc(cch, metric, true, bottom_node, x, bottom_arc, on_new_segment);
1390 }
1391 }
1392 }
1393
1394 template<class OnNewSegment>
1395 unsigned unpack_shortest_path(
1396 const CustomizableContractionHierarchy&cch, const CustomizableContractionHierarchyMetric&metric, const CustomizableContractionHierarchyQuery&query,
1397 const OnNewSegment&on_new_segment
1398 ){
1399 if(query.shortest_path_meeting_node == invalid_id)
1400 return invalid_id;
1401
1402 {
1403 std::vector<unsigned>up_path = {query.shortest_path_meeting_node};
1404
1405 unsigned x = query.shortest_path_meeting_node;
1406 while(query.forward_predecessor_node[x] != invalid_id){
1407 x = query.forward_predecessor_node[x];
1408 up_path.push_back(x);
1409 }
1410
1411 for(unsigned i=up_path.size()-1; i!=0; --i){
1412 unpack_arc(
1413 cch, metric,
1414 true,
1415 up_path[i], up_path[i-1], find_arc_given_sorted_head(cch.up_first_out, cch.up_head, up_path[i], up_path[i-1]),
1416 on_new_segment
1417 );
1418 }
1419 }
1420 {
1421 unsigned x = query.shortest_path_meeting_node;
1422 unsigned y = query.backward_predecessor_node[x];
1423 while(y != invalid_id){
1424 unpack_arc(
1425 cch, metric,
1426 false,
1427 y, x, find_arc_given_sorted_head(cch.up_first_out, cch.up_head, y, x),
1428 on_new_segment
1429 );
1430 x = y;
1431 y = query.backward_predecessor_node[y];
1432 }
1433 return x;
1434 }
1435 }
1436}
1437
1438std::vector<unsigned>CustomizableContractionHierarchyQuery::get_node_path(){
1439 assert(state == query_state_run);
1440 std::vector<unsigned>path;
1441 unsigned last = unpack_shortest_path(
1442 *cch, *metric, *this,
1443 [&](unsigned cch_node, unsigned cch_arc, bool forward){
1444 path.push_back(cch->order[cch_node]);
1445 (void)forward;
1446 (void)cch_arc;
1447 }
1448 );
1449 if(last != invalid_id)
1450 path.push_back(cch->order[last]);
1451 return path; // NVRO
1452}
1453
1454namespace{
1455 // unpack_original_*_arc returns the input arc id corresponding to a cch arc if such an arc
1456 // exists and has the same length as the cch_arc
1457
1458 unsigned unpack_original_forward_arc(
1460 unsigned cch_arc
1461 ){
1462 if(cch.does_cch_arc_have_input_arc.is_set(cch_arc)){
1463 unsigned i = cch.does_cch_arc_have_input_arc_mapper.to_local(cch_arc);
1464 if(cch.forward_input_arc_of_cch[i] != invalid_id){
1465 unsigned original_arc = cch.forward_input_arc_of_cch[i];
1466 if(metric.forward[cch_arc] == metric.input_weight[original_arc])
1467 return original_arc;
1468
1469 if(cch.does_cch_arc_have_extra_input_arc.is_set(cch_arc)){
1470 unsigned j = cch.does_cch_arc_have_extra_input_arc_mapper.to_local(cch_arc);
1471 for(unsigned k = cch.first_extra_forward_input_arc_of_cch[j]; k < cch.first_extra_forward_input_arc_of_cch[j+1]; ++k){
1472 unsigned original_arc = cch.extra_forward_input_arc_of_cch[k];
1473 if(metric.forward[cch_arc] == metric.input_weight[original_arc])
1474 return original_arc;
1475 }
1476 }
1477 }
1478 }
1479 return invalid_id;
1480 }
1481
1482 unsigned unpack_original_backward_arc(
1483 const CustomizableContractionHierarchy&cch, const CustomizableContractionHierarchyMetric&metric,
1484 unsigned cch_arc
1485 ){
1486 if(cch.does_cch_arc_have_input_arc.is_set(cch_arc)){
1487 unsigned i = cch.does_cch_arc_have_input_arc_mapper.to_local(cch_arc);
1488 if(cch.backward_input_arc_of_cch[i] != invalid_id){
1489 unsigned original_arc = cch.backward_input_arc_of_cch[i];
1490 if(metric.backward[cch_arc] == metric.input_weight[original_arc])
1491 return original_arc;
1492 if(cch.does_cch_arc_have_extra_input_arc.is_set(cch_arc)){
1493 unsigned j = cch.does_cch_arc_have_extra_input_arc_mapper.to_local(cch_arc);
1494 for(unsigned k = cch.first_extra_backward_input_arc_of_cch[j]; k < cch.first_extra_backward_input_arc_of_cch[j+1]; ++k){
1495 unsigned original_arc = cch.extra_backward_input_arc_of_cch[k];
1496 if(metric.backward[cch_arc] == metric.input_weight[original_arc])
1497 return original_arc;
1498 }
1499 }
1500 }
1501 }
1502 return invalid_id;
1503 }
1504
1505
1506 unsigned unpack_original_arc(
1507 const CustomizableContractionHierarchy&cch, const CustomizableContractionHierarchyMetric&metric,
1508 unsigned cch_arc, bool is_forward
1509 ){
1510 if(is_forward)
1511 return unpack_original_forward_arc(cch, metric, cch_arc);
1512 else
1513 return unpack_original_backward_arc(cch, metric, cch_arc);
1514 }
1515}
1516
1517std::vector<unsigned>CustomizableContractionHierarchyQuery::get_arc_path(){
1518 assert(state == query_state_run);
1519 std::vector<unsigned>path;
1520 unpack_shortest_path(
1521 *cch, *metric, *this,
1522 [&](unsigned cch_node, unsigned cch_arc, bool is_forward){
1523
1524 if(is_forward)
1525 assert(cch_node == cch->up_tail[cch_arc]);
1526 else
1527 assert(cch_node == cch->up_head[cch_arc]);
1528
1529 (void)cch_node;
1530
1531 unsigned arc = unpack_original_arc(*cch, *metric, cch_arc, is_forward);
1532 assert(arc != invalid_id);
1533 path.push_back(arc);
1534 }
1535 );
1536 return path; // NVRO
1537}
1538
1539namespace{
1540 void internal_pin_targets(
1541 std::vector<unsigned>&target_node,
1542 std::vector<unsigned>&target_elimination_tree_end,
1543 std::vector<bool>&in_backward_search_space,
1544 const std::vector<unsigned>&elimination_tree_parent,
1545 const std::vector<unsigned>&rank,
1546 const std::vector<unsigned>&target_list
1547 ){
1548 target_node.resize(target_list.size());
1549 target_elimination_tree_end.resize(target_list.size());
1550
1551 for(unsigned i=0; i<target_list.size(); ++i){
1552 target_node[i] = rank[target_list[i]];
1553 target_elimination_tree_end[i] = invalid_id;
1554 forall_ancestors(
1555 elimination_tree_parent, target_node[i],
1556 [&](unsigned x){
1557 if(!in_backward_search_space[x]){
1558 in_backward_search_space[x] = true;
1559 return true;
1560 } else {
1561 target_elimination_tree_end[i] = x;
1562 return false;
1563 }
1564 }
1565 );
1566 }
1567 }
1568}
1569
1570CustomizableContractionHierarchyQuery& CustomizableContractionHierarchyQuery::pin_targets(const std::vector<unsigned>&target_list){
1571 assert(state == query_state_initialized);
1572 internal_pin_targets(target_node, target_elimination_tree_end, in_backward_search_space, cch->elimination_tree_parent, cch->rank, target_list);
1573 state = query_state_target_pinned;
1574 return *this;
1575}
1576
1577CustomizableContractionHierarchyQuery& CustomizableContractionHierarchyQuery::pin_sources(const std::vector<unsigned>&source_list){
1578 assert(state == query_state_initialized);
1579 internal_pin_targets(source_node, source_elimination_tree_end, in_forward_search_space, cch->elimination_tree_parent, cch->rank, source_list);
1580 state = query_state_source_pinned;
1581 return *this;
1582}
1583
1584namespace{
1585 void reset_target_distances(
1586 const std::vector<unsigned>&elimination_tree_parent,
1587 const std::vector<unsigned>&target_node,
1588 const std::vector<unsigned>&target_elimination_tree_end,
1589 std::vector<unsigned>&forward_tentative_distance
1590 ){
1591 for(unsigned i = target_node.size()-1; i!=(unsigned)-1; --i){
1592 forall_ancestors(
1593 elimination_tree_parent,
1594 target_node[i], target_elimination_tree_end[i],
1595 [&](unsigned x){
1597 return true;
1598 }
1599 );
1600 }
1601 }
1602}
1603
1604CustomizableContractionHierarchyQuery& CustomizableContractionHierarchyQuery::reset_source(){
1605 assert(state == query_state_target_pinned || state == query_state_target_run);
1606
1607 reset_source_list(cch->elimination_tree_parent, source_node, source_elimination_tree_end, in_forward_search_space, forward_tentative_distance);
1608 reset_target_distances(cch->elimination_tree_parent, target_node, target_elimination_tree_end, forward_tentative_distance);
1609
1610 state = query_state_target_pinned;
1611 return *this;
1612}
1613
1614CustomizableContractionHierarchyQuery& CustomizableContractionHierarchyQuery::reset_target(){
1615 assert(state == query_state_source_pinned || state == query_state_source_run);
1616
1617 reset_source_list(cch->elimination_tree_parent, target_node, target_elimination_tree_end, in_backward_search_space, backward_tentative_distance);
1618 reset_target_distances(cch->elimination_tree_parent, source_node, source_elimination_tree_end, backward_tentative_distance);
1619
1620 state = query_state_source_pinned;
1621 return *this;
1622}
1623
1624namespace{
1625 void internal_run_to_pinned_targets(
1627 const std::vector<unsigned>&forward_weight, const std::vector<unsigned>&backward_weight,
1628 std::vector<unsigned>&forward_tentative_distance, std::vector<unsigned>&backward_tentative_distance,
1629 const std::vector<unsigned>&source_node, const std::vector<unsigned>&source_elimination_tree_end,
1630 const std::vector<unsigned>&target_node, const std::vector<unsigned>&target_elimination_tree_end
1631 ){
1632 for(unsigned i = source_node.size()-1; i!=(unsigned)-1; --i){
1633 forall_ancestors(
1634 cch.elimination_tree_parent,
1635 source_node[i], source_elimination_tree_end[i],
1636 [&](unsigned x){
1637 relax_outgoing_arcs(
1638 cch.up_first_out, cch.up_head, forward_weight,
1639 forward_tentative_distance, [](unsigned,unsigned){},
1640 x
1641 );
1642 return true;
1643 }
1644 );
1645 }
1646
1647 auto&stack = backward_tentative_distance; // backward_tentative_distance is currently not used
1648 unsigned stack_end = 0;
1649 for(unsigned i = target_node.size()-1; i!=(unsigned)-1; --i){
1650 forall_ancestors(
1651 cch.elimination_tree_parent,
1652 target_node[i], target_elimination_tree_end[i],
1653 [&](unsigned x){
1654 stack[stack_end++] = x;
1655 return true;
1656 }
1657 );
1658 }
1659
1660 while(stack_end != 0){
1661 --stack_end;
1662 unsigned x = stack[stack_end];
1663 stack[stack_end] = inf_weight;
1664 relax_incoming_arcs(
1665 cch.up_first_out, cch.up_head, backward_weight,
1666 forward_tentative_distance, [](unsigned,unsigned){},
1667 x
1668 );
1669 }
1670 }
1671}
1672
1673CustomizableContractionHierarchyQuery& CustomizableContractionHierarchyQuery::run_to_pinned_targets(){
1674 assert(state == query_state_target_pinned);
1675 internal_run_to_pinned_targets(
1676 *cch,
1677 metric->forward, metric->backward,
1679 source_node, source_elimination_tree_end,
1680 target_node, target_elimination_tree_end
1681 );
1682 state = query_state_target_run;
1683 return *this;
1684}
1685
1686CustomizableContractionHierarchyQuery& CustomizableContractionHierarchyQuery::run_to_pinned_sources(){
1687 assert(state == query_state_source_pinned);
1688 internal_run_to_pinned_targets(
1689 *cch,
1690 metric->backward, metric->forward,
1692 target_node, target_elimination_tree_end,
1693 source_node, source_elimination_tree_end
1694 );
1695 state = query_state_source_run;
1696 return *this;
1697}
1698
1699CustomizableContractionHierarchyQuery& CustomizableContractionHierarchyQuery::get_distances_to_targets(unsigned*dist){
1700 assert(state == query_state_target_run);
1701 for(unsigned i=0; i<target_node.size(); ++i)
1702 dist[i] = forward_tentative_distance[target_node[i]];
1703 return *this;
1704}
1705
1706std::vector<unsigned> CustomizableContractionHierarchyQuery::get_distances_to_targets(){
1707 assert(state == query_state_target_run);
1708 std::vector<unsigned>v(target_node.size());
1709 get_distances_to_targets(&v[0]);
1710 return v;
1711}
1712
1713CustomizableContractionHierarchyQuery& CustomizableContractionHierarchyQuery::get_distances_to_sources(unsigned*dist){
1714 assert(state == query_state_source_run);
1715 for(unsigned i=0; i<source_node.size(); ++i)
1716 dist[i] = backward_tentative_distance[source_node[i]];
1717 return *this;
1718}
1719
1720std::vector<unsigned> CustomizableContractionHierarchyQuery::get_distances_to_sources(){
1721 assert(state == query_state_source_run);
1722 std::vector<unsigned>v(source_node.size());
1723 get_distances_to_sources(&v[0]);
1724 return v;
1725}
1726
1727ContractionHierarchy CustomizableContractionHierarchyMetric::build_contraction_hierarchy_using_perfect_witness_search(){
1728 customize();
1729
1730 BitVector
1731 keep_forward_arc(cch->cch_arc_count(), true),
1732 keep_backward_arc(cch->cch_arc_count(), true);
1733
1734 for(unsigned a=0; a<cch->cch_arc_count(); ++a)
1735 if(forward[a] == inf_weight)
1736 keep_forward_arc.reset(a);
1737
1738 for(unsigned a=0; a<cch->cch_arc_count(); ++a)
1739 if(backward[a] == inf_weight)
1740 keep_backward_arc.reset(a);
1741
1742 for(unsigned a=cch->cch_arc_count()-1; a!=(unsigned)-1; --a){
1743 forall_upper_triangles_of_arc(
1744 *cch, a,
1745 [&](
1746 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
1747 unsigned bottom_node, unsigned mid_node, unsigned top_node
1748 ){
1749 if(forward[bottom_arc] > forward[mid_arc] + backward[top_arc] ){
1750 forward[bottom_arc] = forward[mid_arc] + backward[top_arc];
1751 keep_forward_arc.reset(bottom_arc);
1752 }
1753
1754 if(backward[bottom_arc] > backward[mid_arc] + forward[top_arc]){
1755 backward[bottom_arc] = backward[mid_arc] + forward[top_arc];
1756 keep_backward_arc.reset(bottom_arc);
1757 }
1758
1759 if(forward[mid_arc] > forward[bottom_arc] + forward[top_arc]){
1760 forward[mid_arc] = forward[bottom_arc] + forward[top_arc];
1761 keep_forward_arc.reset(mid_arc);
1762 }
1763
1764 if(backward[mid_arc] > backward[bottom_arc] + backward[top_arc]){
1765 backward[mid_arc] = backward[bottom_arc] + backward[top_arc];
1766 keep_backward_arc.reset(mid_arc);
1767 }
1768 return true;
1769 }
1770 );
1771 }
1772
1773 #ifndef NDEBUG
1774 for(unsigned a=0; a<cch->cch_arc_count(); ++a)
1775 forall_upper_triangles_of_arc(
1776 *cch, a,
1777 [&](
1778 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
1779 unsigned bottom_node, unsigned mid_node, unsigned top_node
1780 ){
1781 (void)bottom_node;
1782 (void)mid_node;
1783 (void)top_node;
1784
1785 assert(forward[top_arc] <= backward[bottom_arc] + forward[mid_arc]);
1786 assert(backward[top_arc] <= forward[bottom_arc] + backward[mid_arc]);
1787
1788 assert(forward[bottom_arc] <= forward[mid_arc] + backward[top_arc]);
1789 assert(backward[bottom_arc] <= backward[mid_arc] + forward[top_arc]);
1790
1791 assert(forward[mid_arc] <= forward[bottom_arc] + forward[top_arc]);
1792 assert(backward[mid_arc] <= backward[mid_arc] + backward[top_arc]);
1793
1794 return true;
1795 }
1796 );
1797 #endif
1798
1800
1801 ch.rank = cch->rank;
1802 ch.order = cch->order;
1803
1804 LocalIDMapper forward_map(keep_forward_arc);
1805 LocalIDMapper backward_map(keep_backward_arc);
1806
1807 ch.forward.head = keep_element_of_vector_if(keep_forward_arc, cch->up_head);
1808 ch.forward.first_out = invert_vector(keep_element_of_vector_if(keep_forward_arc, cch->up_tail), cch->node_count());
1809 ch.forward.weight = keep_element_of_vector_if(keep_forward_arc, forward);
1811 ch.forward.shortcut_first_arc = std::vector<unsigned>(forward_map.local_id_count());
1812 ch.forward.shortcut_second_arc = std::vector<unsigned>(forward_map.local_id_count());
1813
1814 ch.backward.head = keep_element_of_vector_if(keep_backward_arc, cch->up_head);
1815 ch.backward.first_out = invert_vector(keep_element_of_vector_if(keep_backward_arc, cch->up_tail), cch->node_count());
1816 ch.backward.weight = keep_element_of_vector_if(keep_backward_arc, backward);
1818 ch.backward.shortcut_first_arc = std::vector<unsigned>(backward_map.local_id_count());
1819 ch.backward.shortcut_second_arc = std::vector<unsigned>(backward_map.local_id_count());
1820
1821 for(unsigned cch_arc=0; cch_arc<cch->cch_arc_count(); ++cch_arc){
1822 if(keep_forward_arc.is_set(cch_arc)){
1823 unsigned forward_ch_arc = forward_map.to_local(cch_arc);
1824 unsigned forward_original_arc = unpack_original_forward_arc(*cch, *this, cch_arc);
1825 if(forward_original_arc != invalid_id){
1826 ch.forward.is_shortcut_an_original_arc.set(forward_ch_arc);
1827 ch.forward.shortcut_first_arc[forward_ch_arc] = forward_original_arc;
1828 ch.forward.shortcut_second_arc[forward_ch_arc] = cch->order[cch->up_head[cch_arc]];
1829 }else{
1830 bool was_forward_not_found = forall_lower_triangles_of_arc(
1831 *cch, cch_arc,
1832 [&](
1833 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
1834 unsigned bottom_node, unsigned mid_node, unsigned top_node
1835 ){
1836 (void)bottom_node;
1837 (void)mid_node;
1838 (void)top_node;
1839
1840 if(keep_backward_arc.is_set(bottom_arc) && keep_forward_arc.is_set(mid_arc)){
1841 if(backward[bottom_arc] + forward[mid_arc] == forward[top_arc]){
1842 ch.forward.shortcut_first_arc[forward_ch_arc] = backward_map.to_local(bottom_arc);
1843 ch.forward.shortcut_second_arc[forward_ch_arc] = forward_map.to_local(mid_arc);
1844 return false;
1845 }
1846 }
1847 return true;
1848 }
1849 );
1850 (void) was_forward_not_found;
1851 assert(!was_forward_not_found);
1852 }
1853 }
1854 if(keep_backward_arc.is_set(cch_arc)){
1855 unsigned backward_ch_arc = backward_map.to_local(cch_arc);
1856 unsigned backward_original_arc = unpack_original_backward_arc(*cch, *this, cch_arc);
1857 if(backward_original_arc != invalid_id){
1858 ch.backward.is_shortcut_an_original_arc.set(backward_ch_arc);
1859 ch.backward.shortcut_first_arc[backward_ch_arc] = backward_original_arc;
1860 ch.backward.shortcut_second_arc[backward_ch_arc] = cch->order[cch->up_tail[cch_arc]];
1861 }else{
1862 bool was_backward_not_found = forall_lower_triangles_of_arc(
1863 *cch, cch_arc,
1864 [&](
1865 unsigned bottom_arc, unsigned mid_arc, unsigned top_arc,
1866 unsigned bottom_node, unsigned mid_node, unsigned top_node
1867 ){
1868 (void)bottom_node;
1869 (void)mid_node;
1870 (void)top_node;
1871
1872 if(keep_backward_arc.is_set(mid_arc) && keep_forward_arc.is_set(bottom_arc)){
1873 if(backward[mid_arc] + forward[bottom_arc] == backward[top_arc]){
1874 ch.backward.shortcut_first_arc[backward_ch_arc] = backward_map.to_local(mid_arc);
1875 ch.backward.shortcut_second_arc[backward_ch_arc] = forward_map.to_local(bottom_arc);
1876 return false;
1877 }
1878 }
1879 return true;
1880 }
1881 );
1882 (void) was_backward_not_found;
1883 assert(!was_backward_not_found);
1884 }
1885 }
1886 }
1887
1889
1890 return ch;
1891}
1892
1893
1894CustomizableContractionHierarchyQuery& CustomizableContractionHierarchyQuery::reset(){
1895 if(state == query_state_target_pinned || state == query_state_target_run){
1896 reset_target_distances(cch->elimination_tree_parent, target_node, target_elimination_tree_end, forward_tentative_distance);
1897 }else if(state == query_state_source_pinned || state == query_state_source_run){
1898 reset_target_distances(cch->elimination_tree_parent, source_node, source_elimination_tree_end, backward_tentative_distance);
1899 }
1900 reset_source_list(cch->elimination_tree_parent, source_node, source_elimination_tree_end, in_forward_search_space, forward_tentative_distance);
1901 reset_source_list(cch->elimination_tree_parent, target_node, target_elimination_tree_end, in_backward_search_space, backward_tentative_distance);
1902 state = query_state_initialized;
1903 return *this;
1904}
1905
1907 if(this->cch == metric.cch) {
1908 this->metric = &metric;
1909 reset();
1910 } else {
1912 }
1913 state = query_state_initialized;
1914 return *this;
1915}
1916
1917
1918} // namespace RoutingKit
1919
1920
void reset(uint64_t x)
Definition bit_vector.h:70
static constexpr Uninitialized uninitialized
Definition bit_vector.h:13
bool empty() const
Definition bit_vector.h:25
void set(uint64_t x)
Definition bit_vector.h:42
void resize(uint64_t size, Uninitialized)
bool is_set(uint64_t x) const
Definition bit_vector.h:34
unsigned id_count() const
void push(unsigned id)
bool empty() const
Checks whether the queue contains any element.
void clear()
Removes all elements from the queue.
uint64_t local_id_count() const
Definition id_mapper.h:26
uint64_t to_local(uint64_t global_id) const
Definition id_mapper.cpp:86
std::vector< unsigned > tail
std::vector< unsigned > forward_tentative_distance
std::vector< unsigned > backward_tentative_distance
unsigned weight
unsigned mid_node
unsigned node_count
const std::vector< unsigned > * backward
CustomizableContractionHierarchyMetric * metric
const CustomizableContractionHierarchy * cch
const std::vector< unsigned > * forward
std::vector< unsigned > compute_stable_sort_permutation_using_key(const std::vector< T > &v, unsigned key_count, const K &get_key)
Definition sort.h:218
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_keep_element_of_vector_if(const BitVector &keep_filter, std::vector< T > &vec)
Definition filter.h:13
std::vector< unsigned > compute_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)
std::vector< T > apply_permutation(const std::vector< unsigned > &p, const std::vector< T > &v)
Definition permutation.h:48
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
void min_to(T &x, const T &y)
Definition min_max.h:10
std::vector< T > keep_element_of_vector_if(const BitVector &keep_filter, std::vector< T >vec)
Definition filter.h:43
std::vector< unsigned > invert_vector(const std::vector< unsigned > &v, unsigned element_count)
void max_to(T &x, const T &y)
Definition min_max.h:16
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)
std::vector< unsigned > compute_inverse_stable_sort_permutation_using_key(const std::vector< T > &v, unsigned key_count, const K &get_key)
Definition sort.h:250
std::vector< unsigned > apply_permutation_to_elements_of(const std::vector< unsigned > &p, const std::vector< unsigned > &v)
Definition json.hpp:4471
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.hpp:21884
CustomizableContractionHierarchyMetric & reset(const CustomizableContractionHierarchy &cch, const unsigned *input_weight)
CustomizableContractionHierarchyParallelization & customize(CustomizableContractionHierarchyMetric &metric)
CustomizableContractionHierarchyPartialCustomization & customize(CustomizableContractionHierarchyMetric &metric)
CustomizableContractionHierarchyPartialCustomization & update_arc(unsigned xy)
CustomizableContractionHierarchyQuery & add_source(unsigned s, unsigned dist_to_s=0)
CustomizableContractionHierarchyQuery & add_target(unsigned t, unsigned dist_to_t=0)