Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
K_Shortest_Paths.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
60# ifndef K_SHORTEST_PATHS_H
61# define K_SHORTEST_PATHS_H
62
63# include <cmath>
64# include <cstddef>
65# include <limits>
66# include <type_traits>
67# include <utility>
68
69# include <Dijkstra.H>
70# include <ah-errors.H>
71# include <cookie_guard.H>
72# include <shortest_path_common.H>
73# include <htlist.H>
74# include <tpl_array.H>
75# include <tpl_dynMapTree.H>
76# include <tpl_dynSetTree.H>
77
78namespace Aleph
79{
86 template <class GT, typename Cost_Type>
92
93
94 namespace k_shortest_paths_detail
95 {
96 template <class GT, typename Cost_Type>
103
104
105 template <class GT, typename Cost_Type>
116
117
118 template <class GT, class SA>
120 {
121 using Node = typename GT::Node;
122 using Arc = typename GT::Arc;
123
124 const GT *g = nullptr;
128
129 bool operator()(Arc *arc) const
130 {
131 if (not base_sa(arc))
132 return false;
133
134 if (forbidden_arcs != nullptr and forbidden_arcs->contains(arc))
135 return false;
136
137 if (forbidden_nodes != nullptr)
138 {
139 Node *src = g->get_src_node(arc);
140 Node *tgt = g->get_tgt_node(arc);
142 return false;
143 }
144
145 return true;
146 }
147 };
148
149
150
151
152
153 template <class GT, class Distance>
155 {
156 using Arc = typename GT::Arc;
158
167 // Context for reverse-graph Dijkstra in build_suffix_index_digraph().
168 // This is intentionally thread-local, but not re-entrant on the same
169 // thread: nested calls can overwrite map_ptr/base_ptr. The
170 // Reset_Reverse_Distance guard below restores this state.
171 inline static thread_local const DynMapTree<Arc *, Arc *> * map_ptr = nullptr;
172 inline static thread_local const Distance * base_ptr = nullptr;
173
175 {
176 ah_runtime_error_if(map_ptr == nullptr)
177 << "Reverse_Arc_Distance: reverse arc map is null";
178 ah_runtime_error_if(base_ptr == nullptr)
179 << "Reverse_Arc_Distance: base distance functor is null";
180
181 auto * pair = map_ptr->search(rev_arc);
182 auto * orig_arc = pair == nullptr ? nullptr : pair->second;
183 ah_runtime_error_if(orig_arc == nullptr)
184 << "Reverse_Arc_Distance: missing reverse-to-original arc map";
185
186 return (*base_ptr)(orig_arc);
187 }
188 };
189
190
191 template <class GT, class Distance, class SA>
193 Distance distance,
194 SA sa)
195 {
196 using Arc = typename GT::Arc;
197 using Cost_Type = typename Distance::Distance_Type;
198
199 static_assert(std::is_arithmetic_v<Cost_Type>,
200 "K shortest paths require arithmetic arc costs");
201
202 for (Arc_Iterator<GT, SA> it(g, sa); it.has_curr(); it.next_ne())
203 {
204 Arc *arc = it.get_curr_ne();
205 const Cost_Type w = distance(arc);
206
207 if constexpr (std::is_floating_point_v<Cost_Type>)
208 ah_domain_error_if(not std::isfinite(w))
209 << "K shortest paths require finite arc weights";
210
212 << "K shortest paths require non-negative arc weights";
213 }
214 }
215
216
217 template <class GT, typename Cost_Type>
223
224
225 template <class GT, typename Cost_Type>
228 {
230 snapshot.nodes.reserve(path.nodes.size());
231 snapshot.arcs.reserve(path.arcs.size());
232
233 for (auto it = path.nodes.get_it(); it.has_curr(); it.next_ne())
234 snapshot.nodes.append(it.get_curr_ne());
235
236 for (auto it = path.arcs.get_it(); it.has_curr(); it.next_ne())
237 snapshot.arcs.append(it.get_curr_ne());
238
239 return snapshot;
240 }
241
242
243 template <class GT, typename Cost_Type>
245 path_to_state(const Path<GT> & path, const Cost_Type total_cost)
246 {
248 state.total_cost = total_cost;
249
250 for (typename Path<GT>::Iterator it(path); it.has_current_node(); it.next_ne())
251 {
252 state.nodes.append(it.get_current_node_ne());
253 if (it.has_current_arc())
254 state.arcs.append(it.get_current_arc_ne());
255 }
256
257 return state;
258 }
259
260
261 template <class GT, typename Cost_Type>
263 {
264 Path<GT> path(g);
265 if (state.nodes.is_empty())
266 return path;
267
268 path.set_graph(g, state.nodes.get_first());
269
270 if (g.is_digraph())
271 {
272 for (typename DynList<typename GT::Arc *>::Iterator it(state.arcs);
273 it.has_curr(); it.next_ne())
274 path.append_directed(it.get_curr_ne());
275 }
276 else
277 {
278 for (typename DynList<typename GT::Arc *>::Iterator it(state.arcs);
279 it.has_curr(); it.next_ne())
280 path.append(it.get_curr_ne());
281 }
282
283 return path;
284 }
285
286
287 template <class GT, typename Cost_Type>
290 {
291 if (a.nodes.size() != b.nodes.size())
292 return false;
293 if (a.arcs.size() != b.arcs.size())
294 return false;
295
296 auto an = a.nodes.get_it();
297 auto bn = b.nodes.get_it();
298 while (an.has_curr())
299 {
300 if (an.get_curr_ne() != bn.get_curr_ne())
301 return false;
302 an.next_ne();
303 bn.next_ne();
304 }
305
306 auto aa = a.arcs.get_it();
307 auto ba = b.arcs.get_it();
308 while (aa.has_curr())
309 {
310 if (aa.get_curr_ne() != ba.get_curr_ne())
311 return false;
312 aa.next_ne();
313 ba.next_ne();
314 }
315
316 return true;
317 }
318
319
320 template <class GT, typename Cost_Type>
323 const size_t spur_index)
324 {
325 if (a.nodes.size() <= spur_index or b.nodes.size() <= spur_index)
326 return false;
327 if (a.arcs.size() <= spur_index or b.arcs.size() <= spur_index)
328 return false;
329
330 for (size_t i = 0; i <= spur_index; ++i)
331 if (a.nodes[i] != b.nodes[i])
332 return false;
333
334 for (size_t i = 0; i < spur_index; ++i)
335 if (a.arcs[i] != b.arcs[i])
336 return false;
337
338 return true;
339 }
340
341
342 template <class GT, typename Cost_Type>
345 {
346 for (const auto & p: container)
348 return true;
349 return false;
350 }
351
352
353 template <class GT, typename Cost_Type>
356 typename GT::Node * node)
357 {
358 auto * p = index.dist_to_target.search(node);
359 if (p == nullptr)
360 return index.inf;
361 return p->second;
362 }
363
364
365 template <class GT, typename Cost_Type>
366 typename GT::Node *
368 typename GT::Node * node)
369 {
370 auto * p = index.tree_next.search(node);
371 return p == nullptr ? nullptr : p->second;
372 }
373
374
375 template <class GT, typename Cost_Type>
376 typename GT::Arc *
378 typename GT::Node * node)
379 {
380 auto * p = index.tree_arc.search(node);
381 return p == nullptr ? nullptr : p->second;
382 }
383
384
385 template <template <class, class> class Itor,
386 class GT, class Distance, class SA>
389 typename GT::Node * target,
390 Distance distance,
391 SA sa)
392 {
393 using Node = typename GT::Node;
394 using Arc = typename GT::Arc;
395 using Cost_Type = typename Distance::Distance_Type;
396
398
399 for (Node_Iterator<GT> it(g); it.has_curr(); it.next_ne())
400 {
401 Node * node = it.get_curr_ne();
402 index.dist_to_target.insert(node, index.inf);
403 index.tree_next.insert(node, nullptr);
404 index.tree_arc.insert(node, nullptr);
405 }
406
407 auto & mg = const_cast<GT &>(g);
408 Cookie_Saver<GT> cookie_saver(mg, true, true);
409 mg.reset_nodes();
410 mg.reset_arcs();
411
413 reverse_dijkstra.paint_min_paths_tree(g, target);
414
415 for (Node_Iterator<GT> it(g); it.has_curr(); it.next_ne())
416 {
417 Node * node = it.get_curr_ne();
419 continue;
420
421 index.dist_to_target.find(node) = reverse_dijkstra.get_distance(node);
422
423 Node * parent = static_cast<Node *>(NODE_COOKIE(node));
424 index.tree_next.find(node) = parent;
425
426 if (parent == nullptr)
427 continue;
428
429 Arc * selected = nullptr;
430 for (Node_Arc_Iterator<GT, SA> ait(node, sa); ait.has_curr(); ait.next_ne())
431 {
432 Arc * arc = ait.get_current_arc_ne();
433 if (ait.get_tgt_node() == parent and IS_ARC_VISITED(arc, Aleph::Spanning_Tree))
434 {
435 selected = arc;
436 break;
437 }
438 }
439
440 if (selected == nullptr)
441 {
442 const Cost_Type dist_node = index.dist_to_target.find(node);
443 const Cost_Type dist_parent = index.dist_to_target.find(parent);
444 bool has_best = false;
446 for (Node_Arc_Iterator<GT, SA> ait(node, sa); ait.has_curr(); ait.next_ne())
447 {
448 Arc * arc = ait.get_current_arc_ne();
449 if (ait.get_tgt_node() != parent)
450 continue;
451
452 const Cost_Type cand =
454 const Cost_Type diff =
457 {
458 best_diff = diff;
459 selected = arc;
460 has_best = true;
461 }
462 }
463 }
464
465 index.tree_arc.find(node) = selected;
466 }
467
468 return index;
469 }
470
471
472 template <class GT, class Distance, class SA>
475 typename GT::Node * target,
476 Distance distance,
477 SA sa)
478 {
479 using Node = typename GT::Node;
480 using Arc = typename GT::Arc;
481 using Cost_Type = typename Distance::Distance_Type;
482
484
486 DynMapTree<Node *, Node *> orig_to_rev;
487 DynMapTree<Node *, Node *> rev_to_orig;
489
490 for (Node_Iterator<GT> it(g); it.has_curr(); it.next_ne())
491 {
492 Node * node = it.get_curr_ne();
493 index.dist_to_target.insert(node, index.inf);
494 index.tree_next.insert(node, nullptr);
495 index.tree_arc.insert(node, nullptr);
496
497 Node * rev_node = reverse_graph.insert_node(node->get_info());
498 orig_to_rev.insert(node, rev_node);
499 rev_to_orig.insert(rev_node, node);
500 }
501
502 for (Arc_Iterator<GT, SA> it(g, sa); it.has_curr(); it.next_ne())
503 {
504 Arc * arc = it.get_curr_ne();
505 Node * src = g.get_src_node(arc);
506 Node * tgt = g.get_tgt_node(arc);
507
508 Arc * rev_arc = reverse_graph.insert_arc(
509 orig_to_rev.find(tgt),
510 orig_to_rev.find(src),
511 arc->get_info());
512 rev_arc_to_orig.insert(rev_arc, arc);
513 }
514
517 Reverse_Distance::map_ptr = &rev_arc_to_orig;
518 Reverse_Distance::base_ptr = &distance;
519 // Restores thread-local reverse-distance context on scope exit.
520 // Nested/re-entrant use on the same thread is not supported.
522 {
524 {
525 Reverse_Distance::map_ptr = nullptr;
526 Reverse_Distance::base_ptr = nullptr;
527 }
529
531 reverse_graph.reset_nodes();
532 reverse_graph.reset_arcs();
533
536
537 Node * rev_target = orig_to_rev.find(target);
538 reverse_dijkstra.paint_min_paths_tree(reverse_graph, rev_target);
539
540 for (Node_Iterator<GT> rit(reverse_graph); rit.has_curr(); rit.next_ne())
541 {
542 Node * rev_node = rit.get_curr_ne();
543 Node * orig_node = rev_to_orig.find(rev_node);
544
546 continue;
547
549
550 Node * rev_parent = static_cast<Node *>(NODE_COOKIE(rev_node));
551 if (rev_parent == nullptr)
552 continue;
553
554 Node * orig_parent = rev_to_orig.find(rev_parent);
556
557 Arc * selected = nullptr;
560 bool has_best = false;
562 for (Node_Arc_Iterator<GT, SA> ait(orig_node, sa); ait.has_curr(); ait.next_ne())
563 {
564 Arc * arc = ait.get_current_arc_ne();
565 if (ait.get_tgt_node() != orig_parent)
566 continue;
567
568 if (selected == nullptr)
569 selected = arc; // fallback: first arc to parent
570
571 if (dist_v != index.inf)
572 {
573 const Cost_Type cand =
575 const Cost_Type diff =
576 cand >= dist_u ? cand - dist_u : dist_u - cand;
578 {
579 best_diff = diff;
580 selected = arc;
581 has_best = true;
582 }
583 }
584 }
585
586 index.tree_arc.find(orig_node) = selected;
587 }
588
589 return index;
590 }
591
592
593 template <class GT, class Distance, class SA>
596 typename GT::Node * target,
597 Distance distance,
598 SA sa)
599 {
600 if (g.is_digraph())
602 g, target, distance, sa);
603
605 g, target, distance, sa);
606 }
607
608
609 template <class GT, typename Cost_Type>
610 bool build_suffix_state(const GT & g,
611 const Suffix_Index<GT, Cost_Type> & index,
612 typename GT::Node * start,
613 typename GT::Node * target,
615 {
617 out_suffix.nodes.append(start);
618 out_suffix.total_cost = get_dist_to_target(index, start);
619 if (out_suffix.total_cost == index.inf)
620 return false;
621
622 typename GT::Node * curr = start;
623 size_t guard = 0;
624 const size_t max_steps = g.get_num_nodes() + 1;
625
626 while (curr != target)
627 {
628 if (++guard > max_steps)
629 return false;
630
631 auto * next = get_tree_next(index, curr);
632 auto * arc = get_tree_arc(index, curr);
633 if (next == nullptr or arc == nullptr)
634 return false;
635
636 out_suffix.arcs.append(arc);
637 out_suffix.nodes.append(next);
638 curr = next;
639 }
640
641 return true;
642 }
643
644
645 template <class GT, class Distance, class SA>
647 typename GT::Node *source,
648 typename GT::Node *target,
649 Distance distance,
650 SA sa,
651 const DynSetTree<typename GT::Node *> *forbidden_nodes,
652 const DynSetTree<typename GT::Arc *> *forbidden_arcs,
654 {
655 using Cost_Type = typename Distance::Distance_Type;
657
658 if (forbidden_nodes != nullptr and
659 (forbidden_nodes->contains(source) or forbidden_nodes->contains(target)))
660 return false;
661
662 if (source == target)
663 {
665 out.total_cost = Cost_Type{0};
666 out.nodes.append(source);
667 return true;
668 }
669
670 Cookie_Saver<GT> cookie_saver(const_cast<GT &>(g), true, true);
671 const_cast<GT &>(g).reset_nodes();
672 const_cast<GT &>(g).reset_arcs();
673
674 Filter filter{&g, sa, forbidden_nodes, forbidden_arcs};
676
678 const Cost_Type dist = dijkstra(g, source, target, shortest);
679 if (dist == std::numeric_limits<Cost_Type>::max() or shortest.is_empty())
680 return false;
681
683 return true;
684 }
685
686
687 template <class GT, class Distance>
690 Distance distance)
691 {
692 using Cost_Type = typename Distance::Distance_Type;
693
696 it.has_curr(); it.next_ne())
697 total = shortest_path_detail::checked_add(total, distance(it.get_curr_ne()));
698 return total;
699 }
700
701
702 template <class GT, typename Cost_Type>
705 const size_t spur_index,
707 {
709
710 for (size_t i = 0; i <= spur_index; ++i)
712
713 for (size_t i = 0; i < spur_index; ++i)
714 candidate.arcs.append(base_path.arcs[i]);
715
716 bool first_spur_node = true;
718 it.has_curr(); it.next_ne())
719 {
720 if (first_spur_node)
721 {
722 first_spur_node = false;
723 continue;
724 }
725
726 candidate.nodes.append(it.get_curr_ne());
727 }
728
730 it.has_curr(); it.next_ne())
731 candidate.arcs.append(it.get_curr_ne());
732
733 return candidate;
734 }
735
736
737 template <class GT, typename Cost_Type>
740 const size_t spur_index,
741 typename GT::Arc * deviation_arc,
742 typename GT::Node * deviation_next_node,
744 {
746
747 for (size_t i = 0; i <= spur_index; ++i)
749
750 for (size_t i = 0; i < spur_index; ++i)
751 candidate.arcs.append(base_path.arcs[i]);
752
753 candidate.arcs.append(deviation_arc);
754 candidate.nodes.append(deviation_next_node);
755
756 bool first_suffix_node = true;
758 it.has_curr(); it.next_ne())
759 {
761 {
762 first_suffix_node = false;
763 continue;
764 }
765
766 candidate.nodes.append(it.get_curr_ne());
767 }
768
770 it.has_curr(); it.next_ne())
771 candidate.arcs.append(it.get_curr_ne());
772
773 return candidate;
774 }
775
776
777 template <class GT, class Distance, class SA, typename Cost_Type>
779 const GT & g,
781 typename GT::Node * target,
782 const Suffix_Index<GT, Cost_Type> & suffix_index,
783 Distance distance,
784 SA sa,
787 {
788 using Node = typename GT::Node;
789 using Arc = typename GT::Arc;
790
791 if (base_path.arcs.is_empty())
792 return;
793
796
798 const size_t arc_count = base_snapshot.arcs.size();
799
800 for (size_t spur_index = 0; spur_index < arc_count; ++spur_index)
801 {
804
805 for (Node_Arc_Iterator<GT, SA> it(spur_node, sa); it.has_curr(); it.next_ne())
806 {
807 Arc * deviation_arc = it.get_current_arc_ne();
808 if (deviation_arc == base_arc)
809 continue;
810
811 Node * deviation_next_node = it.get_tgt_node();
812 const Cost_Type suffix_dist =
814 if (suffix_dist == suffix_index.inf)
815 continue;
816
819 suffix_index,
821 target,
823 continue;
824
832
836 distance(deviation_arc)),
838
841 candidates.append(candidate);
842 }
843
846 distance(base_arc));
847 }
848 }
849 } // namespace k_shortest_paths_detail
850
851
885 template <class GT,
886 class Distance = Dft_Dist<GT>,
887 class SA = Dft_Show_Arc<GT>>
890 typename GT::Node *source,
891 typename GT::Node *target,
892 const size_t k,
893 Distance distance = Distance(),
894 SA sa = SA())
895 {
896 using Node = typename GT::Node;
897 using Arc = typename GT::Arc;
898 using Cost_Type = typename Distance::Distance_Type;
901
902 DynList<Item> result;
903 if (k == 0)
904 return result;
905
906 ah_domain_error_if(source == nullptr) << "yen_k_shortest_paths(): source is null";
907 ah_domain_error_if(target == nullptr) << "yen_k_shortest_paths(): target is null";
908
910
911 if (source == target)
912 {
913 Item item;
914 item.total_cost = Cost_Type{0};
915 item.path = Path<GT>(g, source);
916 result.append(item);
917 return result;
918 }
919
923 candidates.reserve(k * 2 + 1);
924
925 State first;
926 if (not k_shortest_paths_detail::shortest_path_filtered<GT, Distance, SA>(
927 g, source, target, distance, sa, nullptr,
928 nullptr, first))
929 return result;
930
931 accepted.append(first);
932
933 for (size_t kth = 1; kth < k; ++kth)
934 {
935 const State & previous = accepted.get_last();
936 const auto previous_snapshot =
937 k_shortest_paths_detail::make_path_snapshot<GT, Cost_Type>(previous);
938 if (previous_snapshot.nodes.size() < 2)
939 break;
940
944 for (const State & p: accepted)
945 accepted_snapshots.append(
946 k_shortest_paths_detail::make_path_snapshot<GT, Cost_Type>(p));
947
948 for (size_t spur_index = 0; spur_index + 1 < previous_snapshot.nodes.size();
949 ++spur_index)
950 {
952
953 DynSetTree<Node *> forbidden_nodes;
954 DynSetTree<Arc *> forbidden_arcs;
955
956 for (size_t i = 0; i < spur_index; ++i)
957 forbidden_nodes.insert(previous_snapshot.nodes[i]);
958
959 for (size_t p_idx = 0; p_idx < accepted_snapshots.size(); ++p_idx)
960 {
961 const auto & p_snapshot = accepted_snapshots[p_idx];
964 forbidden_arcs.insert(p_snapshot.arcs[spur_index]);
965 }
966
967 State spur_state;
968 if (not k_shortest_paths_detail::shortest_path_filtered<GT, Distance, SA>(
969 g,
970 spur_node,
971 target,
972 distance,
973 sa,
974 &forbidden_nodes,
975 &forbidden_arcs,
976 spur_state))
977 continue;
978
979 State candidate =
982 candidate.total_cost =
983 k_shortest_paths_detail::compute_cost_from_arcs<GT, Distance>(
984 candidate.arcs, distance);
985
988 candidates.append(candidate);
989 }
990
991 if (candidates.is_empty())
992 break;
993
994 size_t best_idx = 0;
995 for (size_t i = 1; i < candidates.size(); ++i)
996 if (candidates[i].total_cost < candidates[best_idx].total_cost)
997 best_idx = i;
998
999 State best = candidates[best_idx];
1000 if (best_idx + 1 < candidates.size())
1001 candidates[best_idx] = candidates.get_last();
1002 const auto removed_candidate = candidates.remove_last();
1004
1005 accepted.append(best);
1006 }
1007
1008 for (const State & state: accepted)
1009 {
1010 Item item;
1011 item.total_cost = state.total_cost;
1012 item.path = k_shortest_paths_detail::state_to_path(g, state);
1013 result.append(item);
1014 }
1015
1016 return result;
1017 }
1018
1019
1062 template <class GT,
1063 class Distance = Dft_Dist<GT>,
1064 class SA = Dft_Show_Arc<GT>>
1067 typename GT::Node *source,
1068 typename GT::Node *target,
1069 const size_t k,
1070 Distance distance = Distance(),
1071 SA sa = SA())
1072 {
1073 using Cost_Type = typename Distance::Distance_Type;
1076
1077 DynList<Item> result;
1078 if (k == 0)
1079 return result;
1080
1081 ah_domain_error_if(source == nullptr) << "eppstein_k_shortest_paths(): source is null";
1082 ah_domain_error_if(target == nullptr) << "eppstein_k_shortest_paths(): target is null";
1083
1085
1086 if (source == target)
1087 {
1088 Item item;
1089 item.total_cost = Cost_Type{0};
1090 item.path = Path<GT>(g, source);
1091 result.append(item);
1092 return result;
1093 }
1094
1098 candidates.reserve(k * 3 + 1);
1099
1100 const auto suffix_index =
1101 k_shortest_paths_detail::build_suffix_index<GT, Distance, SA>(
1102 g, target, distance, sa);
1103
1104 State first;
1105 if (not k_shortest_paths_detail::build_suffix_state<GT, Cost_Type>(
1106 g, suffix_index, source, target, first))
1107 return result;
1108
1109 accepted.append(first);
1110 k_shortest_paths_detail::generate_general_deviation_candidates<GT, Distance, SA, Cost_Type>(
1111 g, first, target, suffix_index, distance, sa, accepted, candidates);
1112
1113 while (accepted.size() < k and not candidates.is_empty())
1114 {
1115 size_t best_idx = 0;
1116 for (size_t i = 1; i < candidates.size(); ++i)
1117 if (candidates[i].total_cost < candidates[best_idx].total_cost)
1118 best_idx = i;
1119
1120 State best = candidates[best_idx];
1121 if (best_idx + 1 < candidates.size())
1122 candidates[best_idx] = candidates.get_last();
1123 const auto removed_candidate = candidates.remove_last();
1125
1127 continue;
1128
1129 accepted.append(best);
1130 k_shortest_paths_detail::generate_general_deviation_candidates<GT, Distance, SA, Cost_Type>(
1131 g, best, target, suffix_index, distance, sa, accepted, candidates);
1132 }
1133
1134 for (const State & state: accepted)
1135 {
1136 Item item;
1137 item.total_cost = state.total_cost;
1138 item.path = k_shortest_paths_detail::state_to_path(g, state);
1139 result.append(item);
1140 }
1141
1142 return result;
1143 }
1144
1145
1159 template <class GT,
1160 class Distance = Dft_Dist<GT>,
1161 class SA = Dft_Show_Arc<GT>>
1163 {
1166
1167 public:
1169 SA sa = SA())
1170 : distance_(std::move(distance)),
1171 sa_(std::move(sa))
1172 {
1173 // empty
1174 }
1175
1203 operator()(const GT & g,
1204 typename GT::Node *source,
1205 typename GT::Node *target,
1206 const size_t k) const
1207 {
1209 g, source, target, k, distance_, sa_);
1210 }
1211 };
1212
1213
1218 template <class GT,
1219 class Distance = Dft_Dist<GT>,
1220 class SA = Dft_Show_Arc<GT>>
1222 {
1225
1226 public:
1228 SA sa = SA())
1229 : distance_(std::move(distance)),
1230 sa_(std::move(sa))
1231 {
1232 // empty
1233 }
1234
1255 operator()(const GT & g,
1256 typename GT::Node *source,
1257 typename GT::Node *target,
1258 const size_t k) const
1259 {
1261 g, source, target, k, distance_, sa_);
1262 }
1263 };
1264} // namespace Aleph
1265
1266# endif // K_SHORTEST_PATHS_H
Dijkstra's shortest path algorithm.
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:266
WeightedDigraph::Node Node
WeightedDigraph::Arc Arc
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
long double w
Definition btreepic.C:153
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:245
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:315
RAII guard that saves and restores graph cookies.
Default distance accessor for arc weights.
Spanning tree calculation of all shortest paths from a given node according to Dijkstra's algorithm.
Definition Dijkstra.H:101
Iterator on the items of list.
Definition htlist.H:1420
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
T & get_first() const
Return the first item of the list.
Definition htlist.H:1375
Generic key-value map implemented on top of a binary search tree.
Pair * search(const Key &key) const noexcept
Collect all keys.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair.
Data & find(const Key &key)
Find the value associated with key.
Dynamic set backed by balanced binary search trees with automatic memory management.
Key * insert(const Key &key)
Inserts a key into the dynamic set.
bool contains(const Key &key) const
Checks if a key exists in the set.
Functor wrapper for Eppstein-style k-shortest paths API.
DynList< K_Shortest_Path_Item< GT, typename Distance::Distance_Type > > operator()(const GT &g, typename GT::Node *source, typename GT::Node *target, const size_t k) const
Compute k shortest general (loopy) paths.
Eppstein_K_Shortest_Paths(Distance distance=Distance(), SA sa=SA())
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
bool has_curr() const noexcept
Definition htlist.H:930
constexpr bool is_empty() const noexcept
Definition htlist.H:419
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
Filtered iterator on the nodes of a graph.
Definition tpl_graph.H:1206
Iterator on nodes and arcs of a path.
Definition tpl_graph.H:3208
bool has_current_node() const noexcept
Return true if the iterator has a current node.
Definition tpl_graph.H:3321
Path on a graph.
Definition tpl_graph.H:2669
void set_graph(const GT &__g, Node *start_node=nullptr)
Set the graph of the path.
Definition tpl_graph.H:2797
void append(Arc *arc)
Append an arc to the path.
Definition tpl_graph.H:2872
void append_directed(Node *p)
Append a node to a directed path.
Definition tpl_graph.H:2944
Functor wrapper for Yen's k-shortest loopless paths algorithm.
DynList< K_Shortest_Path_Item< GT, typename Distance::Distance_Type > > operator()(const GT &g, typename GT::Node *source, typename GT::Node *target, const size_t k) const
Compute k shortest loopless paths.
Yen_K_Shortest_Paths(Distance distance=Distance(), SA sa=SA())
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:737
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:695
bool is_digraph() const noexcept
Return true if the graph this is directed.
Definition graph-dry.H:657
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:743
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:222
RAII guards for graph node/arc cookies.
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
#define IS_NODE_VISITED(p, bit)
Determine whether the control bit is set or not to one.
#define NODE_COOKIE(p)
Return the node cookie
DynList< K_Shortest_Path_Item< GT, typename Distance::Distance_Type > > eppstein_k_shortest_paths(const GT &g, typename GT::Node *source, typename GT::Node *target, const size_t k, Distance distance=Distance(), SA sa=SA())
Compute k shortest general (loopy) paths.
#define IS_ARC_VISITED(p, bit)
Determine whether the bit field is or not set to one.
DynList< K_Shortest_Path_Item< GT, typename Distance::Distance_Type > > yen_k_shortest_paths(const GT &g, typename GT::Node *source, typename GT::Node *target, const size_t k, Distance distance=Distance(), SA sa=SA())
Compute k shortest loopless paths using Yen's algorithm.
@ Spanning_Tree
Definition aleph-graph.H:79
Singly linked list implementations with head-tail access.
Path< GT > state_to_path(const GT &g, const Path_State< GT, Cost_Type > &state)
GT::Node * get_tree_next(const Suffix_Index< GT, Cost_Type > &index, typename GT::Node *node)
Suffix_Index< GT, typename Distance::Distance_Type > build_suffix_index(const GT &g, typename GT::Node *target, Distance distance, SA sa)
Path_State< GT, Cost_Type > compose_general_candidate(const Path_Snapshot< GT, Cost_Type > &base_path, const size_t spur_index, typename GT::Arc *deviation_arc, typename GT::Node *deviation_next_node, const Path_State< GT, Cost_Type > &suffix_state)
bool contains_path(const Array< Path_State< GT, Cost_Type > > &container, const Path_State< GT, Cost_Type > &candidate)
bool shortest_path_filtered(const GT &g, typename GT::Node *source, typename GT::Node *target, Distance distance, SA sa, const DynSetTree< typename GT::Node * > *forbidden_nodes, const DynSetTree< typename GT::Arc * > *forbidden_arcs, Path_State< GT, typename Distance::Distance_Type > &out)
void generate_general_deviation_candidates(const GT &g, const Path_State< GT, Cost_Type > &base_path, typename GT::Node *target, const Suffix_Index< GT, Cost_Type > &suffix_index, Distance distance, SA sa, const Array< Path_State< GT, Cost_Type > > &accepted, Array< Path_State< GT, Cost_Type > > &candidates)
bool same_path_sequence(const Path_State< GT, Cost_Type > &a, const Path_State< GT, Cost_Type > &b)
Cost_Type get_dist_to_target(const Suffix_Index< GT, Cost_Type > &index, typename GT::Node *node)
Path_State< GT, Cost_Type > compose_candidate(const Path_Snapshot< GT, Cost_Type > &base_path, const size_t spur_index, const Path_State< GT, Cost_Type > &spur_state)
bool build_suffix_state(const GT &g, const Suffix_Index< GT, Cost_Type > &index, typename GT::Node *start, typename GT::Node *target, Path_State< GT, Cost_Type > &out_suffix)
Suffix_Index< GT, typename Distance::Distance_Type > build_suffix_index_with_itor(const GT &g, typename GT::Node *target, Distance distance, SA sa)
Path_State< GT, Cost_Type > path_to_state(const Path< GT > &path, const Cost_Type total_cost)
Suffix_Index< GT, typename Distance::Distance_Type > build_suffix_index_digraph(const GT &g, typename GT::Node *target, Distance distance, SA sa)
Distance::Distance_Type compute_cost_from_arcs(const DynList< typename GT::Arc * > &arcs, Distance distance)
void validate_non_negative_weights(const GT &g, Distance distance, SA sa)
Path_Snapshot< GT, Cost_Type > make_path_snapshot(const Path_State< GT, Cost_Type > &path)
bool same_prefix_nodes(const Path_Snapshot< GT, Cost_Type > &a, const Path_Snapshot< GT, Cost_Type > &b, const size_t spur_index)
GT::Arc * get_tree_arc(const Suffix_Index< GT, Cost_Type > &index, typename GT::Node *node)
T checked_add(const T &a, const T &b)
Safely add two distance values with overflow checking.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
Container2< typename Container1::Item_Type > filter(Container1 &container, Operation &operation)
Filter elements that satisfy operation.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
std::pair< First, Second > pair
Alias to std::pair kept for backwards compatibility.
Definition ahPair.H:89
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
STL namespace.
Common utilities and base class for shortest path algorithms.
Filtered iterator on all the arcs of a graph.
Definition tpl_graph.H:1164
Default filter for filtered iterators on arcs.
Definition tpl_graph.H:1000
A shortest-path item returned by k-shortest algorithms.
Cost_Type total_cost
Total path cost.
Path< GT > path
Path from source to target.
Filtered iterator of adjacent arcs of a node.
Definition tpl_graph.H:1119
DynList< typename GT::Node * > nodes
static thread_local const Distance * base_ptr
static thread_local const DynMapTree< Arc *, Arc * > * map_ptr
Context for reverse-graph Dijkstra in build_suffix_index_digraph().
DynMapTree< Node *, Cost_Type > dist_to_target
Distance accessor.
static int * k
Dynamic array container with automatic resizing.
Dynamic key-value map based on balanced binary search trees.
Dynamic set implementations based on balanced binary search trees.