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
65# ifndef K_SHORTEST_PATHS_H
66# define K_SHORTEST_PATHS_H
67
68# include <ah-graph-concepts.H>
69
70# include <cmath>
71# include <cstddef>
72# include <limits>
73# include <type_traits>
74# include <utility>
75
76# include <Dijkstra.H>
77# include <ah-errors.H>
78# include <cookie_guard.H>
79# include <shortest_path_common.H>
80# include <htlist.H>
81# include <tpl_array.H>
82# include <tpl_dynMapTree.H>
83# include <tpl_dynSetTree.H>
84
85namespace Aleph
86{
93 template <AlephGraph GT, typename Cost_Type>
99
100
101 namespace k_shortest_paths_detail
102 {
103 template <AlephGraph GT, typename Cost_Type>
110
111
112 template <AlephGraph GT, typename Cost_Type>
123
124
125 template <AlephGraph GT, ArcFilter<GT> SA>
127 {
128 using Node = typename GT::Node;
129 using Arc = typename GT::Arc;
130
131 const GT *g = nullptr;
135
136 bool operator()(Arc *arc) const
137 {
138 if (not base_sa(arc))
139 return false;
140
141 if (forbidden_arcs != nullptr and forbidden_arcs->contains(arc))
142 return false;
143
144 if (forbidden_nodes != nullptr)
145 {
146 Node *src = g->get_src_node(arc);
147 Node *tgt = g->get_tgt_node(arc);
149 return false;
150 }
151
152 return true;
153 }
154 };
155
156
157
158
159
160 template <AlephGraph GT, ArcDistance<GT> Distance>
162 {
163 using Arc = typename GT::Arc;
165
174 // Context for reverse-graph Dijkstra in build_suffix_index_digraph().
175 // This is intentionally thread-local, but not re-entrant on the same
176 // thread: nested calls can overwrite map_ptr/base_ptr. The
177 // Reset_Reverse_Distance guard below restores this state.
178 inline static thread_local const DynMapTree<Arc *, Arc *> * map_ptr = nullptr;
179 inline static thread_local const Distance * base_ptr = nullptr;
180
182 {
183 ah_runtime_error_if(map_ptr == nullptr)
184 << "Reverse_Arc_Distance: reverse arc map is null";
185 ah_runtime_error_if(base_ptr == nullptr)
186 << "Reverse_Arc_Distance: base distance functor is null";
187
188 auto * pair = map_ptr->search(rev_arc);
189 auto * orig_arc = pair == nullptr ? nullptr : pair->second;
190 ah_runtime_error_if(orig_arc == nullptr)
191 << "Reverse_Arc_Distance: missing reverse-to-original arc map";
192
193 return (*base_ptr)(orig_arc);
194 }
195 };
196
197
198 template <AlephGraph GT, ArcDistance<GT> Distance, ArcFilter<GT> SA>
199 requires std::is_arithmetic_v<typename Distance::Distance_Type>
201 Distance distance,
202 SA sa)
203 {
204 using Arc = typename GT::Arc;
205 using Cost_Type = typename Distance::Distance_Type;
206
207 for (Arc_Iterator<GT, SA> it(g, sa); it.has_curr(); it.next_ne())
208 {
209 Arc *arc = it.get_curr_ne();
210 const Cost_Type w = distance(arc);
211
212 if constexpr (std::is_floating_point_v<Cost_Type>)
213 ah_domain_error_if(not std::isfinite(w))
214 << "K shortest paths require finite arc weights";
215
217 << "K shortest paths require non-negative arc weights";
218 }
219 }
220
221
222 template <AlephGraph GT, typename Cost_Type>
228
229
230 template <AlephGraph GT, typename Cost_Type>
233 {
235 snapshot.nodes.reserve(path.nodes.size());
236 snapshot.arcs.reserve(path.arcs.size());
237
238 for (auto it = path.nodes.get_it(); it.has_curr(); it.next_ne())
239 snapshot.nodes.append(it.get_curr_ne());
240
241 for (auto it = path.arcs.get_it(); it.has_curr(); it.next_ne())
242 snapshot.arcs.append(it.get_curr_ne());
243
244 return snapshot;
245 }
246
247
248 template <AlephGraph GT, typename Cost_Type>
250 path_to_state(const Path<GT> & path, const Cost_Type total_cost)
251 {
253 state.total_cost = total_cost;
254
255 for (typename Path<GT>::Iterator it(path); it.has_current_node(); it.next_ne())
256 {
257 state.nodes.append(it.get_current_node_ne());
258 if (it.has_current_arc())
259 state.arcs.append(it.get_current_arc_ne());
260 }
261
262 return state;
263 }
264
265
266 template <AlephGraph GT, typename Cost_Type>
268 {
269 Path<GT> path(g);
270 if (state.nodes.is_empty())
271 return path;
272
273 path.set_graph(g, state.nodes.get_first());
274
275 if (g.is_digraph())
276 {
277 for (typename DynList<typename GT::Arc *>::Iterator it(state.arcs);
278 it.has_curr(); it.next_ne())
279 path.append_directed(it.get_curr_ne());
280 }
281 else
282 {
283 for (typename DynList<typename GT::Arc *>::Iterator it(state.arcs);
284 it.has_curr(); it.next_ne())
285 path.append(it.get_curr_ne());
286 }
287
288 return path;
289 }
290
291
292 template <AlephGraph GT, typename Cost_Type>
295 {
296 if (a.nodes.size() != b.nodes.size())
297 return false;
298 if (a.arcs.size() != b.arcs.size())
299 return false;
300
301 auto an = a.nodes.get_it();
302 auto bn = b.nodes.get_it();
303 while (an.has_curr())
304 {
305 if (an.get_curr_ne() != bn.get_curr_ne())
306 return false;
307 an.next_ne();
308 bn.next_ne();
309 }
310
311 auto aa = a.arcs.get_it();
312 auto ba = b.arcs.get_it();
313 while (aa.has_curr())
314 {
315 if (aa.get_curr_ne() != ba.get_curr_ne())
316 return false;
317 aa.next_ne();
318 ba.next_ne();
319 }
320
321 return true;
322 }
323
324
325 template <AlephGraph GT, typename Cost_Type>
328 const size_t spur_index)
329 {
330 if (a.nodes.size() <= spur_index or b.nodes.size() <= spur_index)
331 return false;
332 if (a.arcs.size() <= spur_index or b.arcs.size() <= spur_index)
333 return false;
334
335 for (size_t i = 0; i <= spur_index; ++i)
336 if (a.nodes[i] != b.nodes[i])
337 return false;
338
339 for (size_t i = 0; i < spur_index; ++i)
340 if (a.arcs[i] != b.arcs[i])
341 return false;
342
343 return true;
344 }
345
346
347 template <AlephGraph GT, typename Cost_Type>
350 {
351 for (const auto & p: container)
353 return true;
354 return false;
355 }
356
357
358 template <AlephGraph GT, typename Cost_Type>
361 typename GT::Node * node)
362 {
363 auto * p = index.dist_to_target.search(node);
364 if (p == nullptr)
365 return index.inf;
366 return p->second;
367 }
368
369
370 template <AlephGraph GT, typename Cost_Type>
371 typename GT::Node *
373 typename GT::Node * node)
374 {
375 auto * p = index.tree_next.search(node);
376 return p == nullptr ? nullptr : p->second;
377 }
378
379
380 template <AlephGraph GT, typename Cost_Type>
381 typename GT::Arc *
383 typename GT::Node * node)
384 {
385 auto * p = index.tree_arc.search(node);
386 return p == nullptr ? nullptr : p->second;
387 }
388
389
390 template <template <class, class> class Itor,
394 typename GT::Node * target,
395 Distance distance,
396 SA sa)
397 {
398 using Node = typename GT::Node;
399 using Arc = typename GT::Arc;
400 using Cost_Type = typename Distance::Distance_Type;
401
403
404 for (Node_Iterator<GT> it(g); it.has_curr(); it.next_ne())
405 {
406 Node * node = it.get_curr_ne();
407 index.dist_to_target.insert(node, index.inf);
408 index.tree_next.insert(node, nullptr);
409 index.tree_arc.insert(node, nullptr);
410 }
411
412 auto & mg = const_cast<GT &>(g);
413 Cookie_Saver<GT> cookie_saver(mg, true, true);
414 mg.reset_nodes();
415 mg.reset_arcs();
416
418 reverse_dijkstra.paint_min_paths_tree(g, target);
419
420 for (Node_Iterator<GT> it(g); it.has_curr(); it.next_ne())
421 {
422 Node * node = it.get_curr_ne();
424 continue;
425
426 index.dist_to_target.find(node) = reverse_dijkstra.get_distance(node);
427
428 Node * parent = static_cast<Node *>(NODE_COOKIE(node));
429 index.tree_next.find(node) = parent;
430
431 if (parent == nullptr)
432 continue;
433
434 Arc * selected = nullptr;
435 for (Node_Arc_Iterator<GT, SA> ait(node, sa); ait.has_curr(); ait.next_ne())
436 {
437 Arc * arc = ait.get_current_arc_ne();
438 if (ait.get_tgt_node() == parent and IS_ARC_VISITED(arc, Aleph::Spanning_Tree))
439 {
440 selected = arc;
441 break;
442 }
443 }
444
445 if (selected == nullptr)
446 {
447 const Cost_Type dist_node = index.dist_to_target.find(node);
448 const Cost_Type dist_parent = index.dist_to_target.find(parent);
449 bool has_best = false;
451 for (Node_Arc_Iterator<GT, SA> ait(node, sa); ait.has_curr(); ait.next_ne())
452 {
453 Arc * arc = ait.get_current_arc_ne();
454 if (ait.get_tgt_node() != parent)
455 continue;
456
457 const Cost_Type cand =
459 const Cost_Type diff =
462 {
463 best_diff = diff;
464 selected = arc;
465 has_best = true;
466 }
467 }
468 }
469
470 index.tree_arc.find(node) = selected;
471 }
472
473 return index;
474 }
475
476
477 template <AlephGraph GT, ArcDistance<GT> Distance, ArcFilter<GT> SA>
480 typename GT::Node * target,
481 Distance distance,
482 SA sa)
483 {
484 using Node = typename GT::Node;
485 using Arc = typename GT::Arc;
486 using Cost_Type = typename Distance::Distance_Type;
487
489
491 DynMapTree<Node *, Node *> orig_to_rev;
492 DynMapTree<Node *, Node *> rev_to_orig;
494
495 for (Node_Iterator<GT> it(g); it.has_curr(); it.next_ne())
496 {
497 Node * node = it.get_curr_ne();
498 index.dist_to_target.insert(node, index.inf);
499 index.tree_next.insert(node, nullptr);
500 index.tree_arc.insert(node, nullptr);
501
502 Node * rev_node = reverse_graph.insert_node(node->get_info());
503 orig_to_rev.insert(node, rev_node);
504 rev_to_orig.insert(rev_node, node);
505 }
506
507 for (Arc_Iterator<GT, SA> it(g, sa); it.has_curr(); it.next_ne())
508 {
509 Arc * arc = it.get_curr_ne();
510 Node * src = g.get_src_node(arc);
511 Node * tgt = g.get_tgt_node(arc);
512
513 Arc * rev_arc = reverse_graph.insert_arc(
514 orig_to_rev.find(tgt),
515 orig_to_rev.find(src),
516 arc->get_info());
517 rev_arc_to_orig.insert(rev_arc, arc);
518 }
519
522 Reverse_Distance::map_ptr = &rev_arc_to_orig;
523 Reverse_Distance::base_ptr = &distance;
524 // Restores thread-local reverse-distance context on scope exit.
525 // Nested/re-entrant use on the same thread is not supported.
527 {
529 {
530 Reverse_Distance::map_ptr = nullptr;
531 Reverse_Distance::base_ptr = nullptr;
532 }
534
536 reverse_graph.reset_nodes();
537 reverse_graph.reset_arcs();
538
541
542 Node * rev_target = orig_to_rev.find(target);
543 reverse_dijkstra.paint_min_paths_tree(reverse_graph, rev_target);
544
545 for (Node_Iterator<GT> rit(reverse_graph); rit.has_curr(); rit.next_ne())
546 {
547 Node * rev_node = rit.get_curr_ne();
548 Node * orig_node = rev_to_orig.find(rev_node);
549
551 continue;
552
554
555 Node * rev_parent = static_cast<Node *>(NODE_COOKIE(rev_node));
556 if (rev_parent == nullptr)
557 continue;
558
559 Node * orig_parent = rev_to_orig.find(rev_parent);
561
562 Arc * selected = nullptr;
565 bool has_best = false;
567 for (Node_Arc_Iterator<GT, SA> ait(orig_node, sa); ait.has_curr(); ait.next_ne())
568 {
569 Arc * arc = ait.get_current_arc_ne();
570 if (ait.get_tgt_node() != orig_parent)
571 continue;
572
573 if (selected == nullptr)
574 selected = arc; // fallback: first arc to parent
575
576 if (dist_v != index.inf)
577 {
578 const Cost_Type cand =
580 const Cost_Type diff =
581 cand >= dist_u ? cand - dist_u : dist_u - cand;
583 {
584 best_diff = diff;
585 selected = arc;
586 has_best = true;
587 }
588 }
589 }
590
591 index.tree_arc.find(orig_node) = selected;
592 }
593
594 return index;
595 }
596
597
598 template <AlephGraph GT, ArcDistance<GT> Distance, ArcFilter<GT> SA>
601 typename GT::Node * target,
602 Distance distance,
603 SA sa)
604 {
605 if (g.is_digraph())
607 g, target, distance, sa);
608
610 g, target, distance, sa);
611 }
612
613
614 template <AlephGraph GT, typename Cost_Type>
615 bool build_suffix_state(const GT & g,
616 const Suffix_Index<GT, Cost_Type> & index,
617 typename GT::Node * start,
618 typename GT::Node * target,
620 {
622 out_suffix.nodes.append(start);
623 out_suffix.total_cost = get_dist_to_target(index, start);
624 if (out_suffix.total_cost == index.inf)
625 return false;
626
627 typename GT::Node * curr = start;
628 size_t guard = 0;
629 const size_t max_steps = g.get_num_nodes() + 1;
630
631 while (curr != target)
632 {
633 if (++guard > max_steps)
634 return false;
635
636 auto * next = get_tree_next(index, curr);
637 auto * arc = get_tree_arc(index, curr);
638 if (next == nullptr or arc == nullptr)
639 return false;
640
641 out_suffix.arcs.append(arc);
642 out_suffix.nodes.append(next);
643 curr = next;
644 }
645
646 return true;
647 }
648
649
650 template <AlephGraph GT, ArcDistance<GT> Distance, ArcFilter<GT> SA>
652 typename GT::Node *source,
653 typename GT::Node *target,
654 Distance distance,
655 SA sa,
656 const DynSetTree<typename GT::Node *> *forbidden_nodes,
657 const DynSetTree<typename GT::Arc *> *forbidden_arcs,
659 {
660 using Cost_Type = typename Distance::Distance_Type;
662
663 if (forbidden_nodes != nullptr and
664 (forbidden_nodes->contains(source) or forbidden_nodes->contains(target)))
665 return false;
666
667 if (source == target)
668 {
670 out.total_cost = Cost_Type{0};
671 out.nodes.append(source);
672 return true;
673 }
674
675 Cookie_Saver<GT> cookie_saver(const_cast<GT &>(g), true, true);
676 const_cast<GT &>(g).reset_nodes();
677 const_cast<GT &>(g).reset_arcs();
678
679 Filter filter{&g, sa, forbidden_nodes, forbidden_arcs};
681
683 const Cost_Type dist = dijkstra(g, source, target, shortest);
684 if (dist == std::numeric_limits<Cost_Type>::max() or shortest.is_empty())
685 return false;
686
688 return true;
689 }
690
691
692 template <AlephGraph GT, ArcDistance<GT> Distance>
695 Distance distance)
696 {
697 using Cost_Type = typename Distance::Distance_Type;
698
701 it.has_curr(); it.next_ne())
702 total = shortest_path_detail::checked_add(total, distance(it.get_curr_ne()));
703 return total;
704 }
705
706
707 template <AlephGraph GT, typename Cost_Type>
710 const size_t spur_index,
712 {
714
715 for (size_t i = 0; i <= spur_index; ++i)
717
718 for (size_t i = 0; i < spur_index; ++i)
719 candidate.arcs.append(base_path.arcs[i]);
720
721 bool first_spur_node = true;
723 it.has_curr(); it.next_ne())
724 {
725 if (first_spur_node)
726 {
727 first_spur_node = false;
728 continue;
729 }
730
731 candidate.nodes.append(it.get_curr_ne());
732 }
733
735 it.has_curr(); it.next_ne())
736 candidate.arcs.append(it.get_curr_ne());
737
738 return candidate;
739 }
740
741
742 template <AlephGraph GT, typename Cost_Type>
745 const size_t spur_index,
746 typename GT::Arc * deviation_arc,
747 typename GT::Node * deviation_next_node,
749 {
751
752 for (size_t i = 0; i <= spur_index; ++i)
754
755 for (size_t i = 0; i < spur_index; ++i)
756 candidate.arcs.append(base_path.arcs[i]);
757
758 candidate.arcs.append(deviation_arc);
759 candidate.nodes.append(deviation_next_node);
760
761 bool first_suffix_node = true;
763 it.has_curr(); it.next_ne())
764 {
766 {
767 first_suffix_node = false;
768 continue;
769 }
770
771 candidate.nodes.append(it.get_curr_ne());
772 }
773
775 it.has_curr(); it.next_ne())
776 candidate.arcs.append(it.get_curr_ne());
777
778 return candidate;
779 }
780
781
782 template <AlephGraph GT, ArcDistance<GT> Distance, ArcFilter<GT> SA, typename Cost_Type>
784 const GT & g,
786 typename GT::Node * target,
787 const Suffix_Index<GT, Cost_Type> & suffix_index,
788 Distance distance,
789 SA sa,
792 {
793 using Node = typename GT::Node;
794 using Arc = typename GT::Arc;
795
796 if (base_path.arcs.is_empty())
797 return;
798
801
803 const size_t arc_count = base_snapshot.arcs.size();
804
805 for (size_t spur_index = 0; spur_index < arc_count; ++spur_index)
806 {
809
810 for (Node_Arc_Iterator<GT, SA> it(spur_node, sa); it.has_curr(); it.next_ne())
811 {
812 Arc * deviation_arc = it.get_current_arc_ne();
813 if (deviation_arc == base_arc)
814 continue;
815
816 Node * deviation_next_node = it.get_tgt_node();
817 const Cost_Type suffix_dist =
819 if (suffix_dist == suffix_index.inf)
820 continue;
821
824 suffix_index,
826 target,
828 continue;
829
837
841 distance(deviation_arc)),
843
846 candidates.append(candidate);
847 }
848
851 distance(base_arc));
852 }
853 }
854 } // namespace k_shortest_paths_detail
855
856
890 template <AlephGraph GT,
893 requires std::is_arithmetic_v<typename Distance::Distance_Type>
896 typename GT::Node *source,
897 typename GT::Node *target,
898 const size_t k,
899 Distance distance = Distance(),
900 SA sa = SA())
901 {
902 using Node = typename GT::Node;
903 using Arc = typename GT::Arc;
904 using Cost_Type = typename Distance::Distance_Type;
907
908 DynList<Item> result;
909 if (k == 0)
910 return result;
911
912 ah_domain_error_if(source == nullptr) << "yen_k_shortest_paths(): source is null";
913 ah_domain_error_if(target == nullptr) << "yen_k_shortest_paths(): target is null";
914
916
917 if (source == target)
918 {
919 Item item;
920 item.total_cost = Cost_Type{0};
921 item.path = Path<GT>(g, source);
922 result.append(item);
923 return result;
924 }
925
929 candidates.reserve(k * 2 + 1);
930
931 State first;
932 if (not k_shortest_paths_detail::shortest_path_filtered<GT, Distance, SA>(
933 g, source, target, distance, sa, nullptr,
934 nullptr, first))
935 return result;
936
937 accepted.append(first);
938
939 for (size_t kth = 1; kth < k; ++kth)
940 {
941 const State & previous = accepted.get_last();
942 const auto previous_snapshot =
943 k_shortest_paths_detail::make_path_snapshot<GT, Cost_Type>(previous);
944 if (previous_snapshot.nodes.size() < 2)
945 break;
946
950 for (const State & p: accepted)
951 accepted_snapshots.append(
952 k_shortest_paths_detail::make_path_snapshot<GT, Cost_Type>(p));
953
954 for (size_t spur_index = 0; spur_index + 1 < previous_snapshot.nodes.size();
955 ++spur_index)
956 {
958
959 DynSetTree<Node *> forbidden_nodes;
960 DynSetTree<Arc *> forbidden_arcs;
961
962 for (size_t i = 0; i < spur_index; ++i)
963 forbidden_nodes.insert(previous_snapshot.nodes[i]);
964
965 for (size_t p_idx = 0; p_idx < accepted_snapshots.size(); ++p_idx)
966 {
967 const auto & p_snapshot = accepted_snapshots[p_idx];
970 forbidden_arcs.insert(p_snapshot.arcs[spur_index]);
971 }
972
973 State spur_state;
974 if (not k_shortest_paths_detail::shortest_path_filtered<GT, Distance, SA>(
975 g,
976 spur_node,
977 target,
978 distance,
979 sa,
980 &forbidden_nodes,
981 &forbidden_arcs,
982 spur_state))
983 continue;
984
985 State candidate =
988 candidate.total_cost =
989 k_shortest_paths_detail::compute_cost_from_arcs<GT, Distance>(
990 candidate.arcs, distance);
991
994 candidates.append(candidate);
995 }
996
997 if (candidates.is_empty())
998 break;
999
1000 size_t best_idx = 0;
1001 for (size_t i = 1; i < candidates.size(); ++i)
1002 if (candidates[i].total_cost < candidates[best_idx].total_cost)
1003 best_idx = i;
1004
1005 State best = candidates[best_idx];
1006 if (best_idx + 1 < candidates.size())
1007 candidates[best_idx] = candidates.get_last();
1008 const auto removed_candidate = candidates.remove_last();
1010
1011 accepted.append(best);
1012 }
1013
1014 for (const State & state: accepted)
1015 {
1016 Item item;
1017 item.total_cost = state.total_cost;
1018 item.path = k_shortest_paths_detail::state_to_path(g, state);
1019 result.append(item);
1020 }
1021
1022 return result;
1023 }
1024
1025
1068 template <AlephGraph GT,
1071 requires std::is_arithmetic_v<typename Distance::Distance_Type>
1074 typename GT::Node *source,
1075 typename GT::Node *target,
1076 const size_t k,
1077 Distance distance = Distance(),
1078 SA sa = SA())
1079 {
1080 using Cost_Type = typename Distance::Distance_Type;
1083
1084 DynList<Item> result;
1085 if (k == 0)
1086 return result;
1087
1088 ah_domain_error_if(source == nullptr) << "eppstein_k_shortest_paths(): source is null";
1089 ah_domain_error_if(target == nullptr) << "eppstein_k_shortest_paths(): target is null";
1090
1092
1093 if (source == target)
1094 {
1095 Item item;
1096 item.total_cost = Cost_Type{0};
1097 item.path = Path<GT>(g, source);
1098 result.append(item);
1099 return result;
1100 }
1101
1105 candidates.reserve(k * 3 + 1);
1106
1107 const auto suffix_index =
1108 k_shortest_paths_detail::build_suffix_index<GT, Distance, SA>(
1109 g, target, distance, sa);
1110
1111 State first;
1112 if (not k_shortest_paths_detail::build_suffix_state<GT, Cost_Type>(
1113 g, suffix_index, source, target, first))
1114 return result;
1115
1116 accepted.append(first);
1117 k_shortest_paths_detail::generate_general_deviation_candidates<GT, Distance, SA, Cost_Type>(
1118 g, first, target, suffix_index, distance, sa, accepted, candidates);
1119
1120 while (accepted.size() < k and not candidates.is_empty())
1121 {
1122 size_t best_idx = 0;
1123 for (size_t i = 1; i < candidates.size(); ++i)
1124 if (candidates[i].total_cost < candidates[best_idx].total_cost)
1125 best_idx = i;
1126
1127 State best = candidates[best_idx];
1128 if (best_idx + 1 < candidates.size())
1129 candidates[best_idx] = candidates.get_last();
1130 const auto removed_candidate = candidates.remove_last();
1132
1134 continue;
1135
1136 accepted.append(best);
1137 k_shortest_paths_detail::generate_general_deviation_candidates<GT, Distance, SA, Cost_Type>(
1138 g, best, target, suffix_index, distance, sa, accepted, candidates);
1139 }
1140
1141 for (const State & state: accepted)
1142 {
1143 Item item;
1144 item.total_cost = state.total_cost;
1145 item.path = k_shortest_paths_detail::state_to_path(g, state);
1146 result.append(item);
1147 }
1148
1149 return result;
1150 }
1151
1152
1166 template <AlephGraph GT,
1170 {
1173
1174 public:
1176 SA sa = SA())
1177 : distance_(std::move(distance)),
1178 sa_(std::move(sa))
1179 {
1180 // empty
1181 }
1182
1210 operator()(const GT & g,
1211 typename GT::Node *source,
1212 typename GT::Node *target,
1213 const size_t k) const
1214 requires std::is_arithmetic_v<typename Distance::Distance_Type>
1215 {
1217 g, source, target, k, distance_, sa_);
1218 }
1219 };
1220
1221
1226 template <AlephGraph GT,
1230 {
1233
1234 public:
1236 SA sa = SA())
1237 : distance_(std::move(distance)),
1238 sa_(std::move(sa))
1239 {
1240 // empty
1241 }
1242
1263 operator()(const GT & g,
1264 typename GT::Node *source,
1265 typename GT::Node *target,
1266 const size_t k) const
1267 requires std::is_arithmetic_v<typename Distance::Distance_Type>
1268 {
1270 g, source, target, k, distance_, sa_);
1271 }
1272 };
1273} // namespace Aleph
1274
1275# 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:527
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:271
C++20 concepts for the protocol shared by graph algorithms.
WeightedDigraph::Node Node
WeightedDigraph::Arc Arc
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
long double w
Definition btreepic.C:153
size_t size_t int32_t * out
Definition ca-c-api.h:120
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:250
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:320
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:103
Iterator on the items of list.
Definition htlist.H:1420
Doubly-linked list (defined in tpl_dynList.H).
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:1207
Iterator on nodes and arcs of a path.
Definition tpl_graph.H:3311
bool has_current_node() const noexcept
Return true if the iterator has a current node.
Definition tpl_graph.H:3424
Path on a graph.
Definition tpl_graph.H:2772
void set_graph(const GT &__g, Node *start_node=nullptr)
Set the graph of the path.
Definition tpl_graph.H:2900
void append(Arc *arc)
Append an arc to the path.
Definition tpl_graph.H:2975
void append_directed(Node *p)
Append a node to a directed path.
Definition tpl_graph.H:3047
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:779
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:737
bool is_digraph() const noexcept
Return true if the graph this is directed.
Definition graph-dry.H:699
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
A graph usable by the graph algorithms.
An arc distance (Distance) for graph GT.
An arc filter (SA) for graph GT.
RAII guards for graph node/arc cookies.
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
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.
#define IS_NODE_VISITED(p, bit)
Determine whether the control bit is set or not to one.
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 NODE_COOKIE(p)
Return the node cookie
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
#define IS_ARC_VISITED(p, bit)
Determine whether the bit field is or not set to one.
@ 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
Container2< typename Container1::Item_Type > filter(Container1 &container, Operation &operation)
Filter elements that satisfy operation.
and
Check uniqueness with explicit hash + equality functors.
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:1165
Default filter for filtered iterators on arcs.
Definition tpl_graph.H:1001
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:1120
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.