11#include <boost/graph/dijkstra_shortest_paths.hpp>
12#include <boost/graph/bellman_ford_shortest_paths.hpp>
13#include <boost/graph/dag_shortest_paths.hpp>
14#include <boost/graph/floyd_warshall_shortest.hpp>
41template <
typename NodeID,
typename Distance =
double>
50 const auto it =
distance.find(target);
51 return it !=
distance.end() && it->second != std::numeric_limits<Distance>::max();
62 [[nodiscard]] std::vector<NodeID>
path_to(
const NodeID& target)
const {
63 const auto distance_it =
distance.find(target);
65 throw std::runtime_error(
"Path reconstruction failed: target node not found in result.");
67 if (distance_it->second == std::numeric_limits<Distance>::max()) {
68 throw std::runtime_error(
"Path reconstruction failed: target node is unreachable.");
71 std::vector<NodeID> path;
72 NodeID current = target;
77 path.push_back(current);
81 throw std::runtime_error(
"Path reconstruction failed: predecessor map is incomplete.");
83 if (pred_it->second == current) {
87 current = pred_it->second;
89 if (hops > max_hops) {
90 throw std::runtime_error(
"Path reconstruction failed: predecessor cycle detected.");
94 std::reverse(path.begin(), path.end());
99template <
typename Distance>
100Distance normalize_weighted_distance(Distance value) {
101 if constexpr (std::is_integral_v<Distance> && std::is_signed_v<Distance>) {
102 if (value == std::numeric_limits<Distance>::lowest()) {
103 return std::numeric_limits<Distance>::max();
109template <
typename Distance>
110using shortest_path_calc_type = std::conditional_t<std::is_integral_v<Distance>, double, Distance>;
112template <
typename GraphWrapper,
typename VertexDesc>
113std::vector<typename GraphWrapper::NodeType> reconstruct_vertex_path(
114 const GraphWrapper& graph,
117 const std::vector<VertexDesc>& predecessor
119 std::vector<typename GraphWrapper::NodeType> path;
120 const auto max_hops = predecessor.size() + 1;
123 for (VertexDesc current = target;; current = predecessor[graph.get_vertex_index(current)]) {
124 path.push_back(graph.get_node_id(current));
125 if (current == source) {
129 if (hops > max_hops) {
130 throw std::runtime_error(
"Path reconstruction failed: predecessor cycle detected.");
134 std::reverse(path.begin(), path.end());
138template <
typename Distance,
typename CalcDistance>
139Distance convert_shortest_path_distance(CalcDistance value) {
140 if constexpr (std::is_same_v<CalcDistance, Distance>) {
141 return normalize_weighted_distance(value);
143 if constexpr (std::is_integral_v<Distance> && std::is_floating_point_v<CalcDistance>) {
144 if (!std::isfinite(value) || value >=
static_cast<CalcDistance
>(std::numeric_limits<Distance>::max())) {
145 return std::numeric_limits<Distance>::max();
147 if (value <=
static_cast<CalcDistance
>(std::numeric_limits<Distance>::lowest())) {
148 return std::numeric_limits<Distance>::lowest();
151 if (value == std::numeric_limits<CalcDistance>::max()) {
152 return std::numeric_limits<Distance>::max();
154 return static_cast<Distance
>(value);
158inline WeightMode parse_shortest_path_weight_mode(
const std::string& weight) {
159 if (weight.empty()) {
160 return WeightMode::Unweighted;
162 if (weight ==
"weight") {
163 return WeightMode::BuiltIn;
165 throw std::runtime_error(
"Weight lookup failed: only the built-in edge weight property named 'weight' is supported.");
168inline WeightMode parse_builtin_shortest_path_weight_mode(
const std::string& weight) {
169 if (weight.empty() || weight ==
"weight") {
170 return WeightMode::BuiltIn;
172 throw std::runtime_error(
"Weight lookup failed: only the built-in edge weight property named 'weight' is supported.");
177template <
typename GraphWrapper>
186[[deprecated(
"Use G.shortest_path(source, target) instead.")]]
187auto shortest_path(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id) {
188 return G.shortest_path(source_id, target_id);
191template <
typename GraphWrapper>
192requires(GraphWrapper::has_builtin_edge_weight)
201[[deprecated(
"Use G.dijkstra_path(source, target) instead.")]]
202auto dijkstra_path(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id) {
203 return G.dijkstra_path(source_id, target_id);
206template <
typename GraphWrapper>
207requires(GraphWrapper::has_builtin_edge_weight)
216[[deprecated(
"Use G.dijkstra_shortest_paths(source) instead.")]]
217auto dijkstra_shortest_paths(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id) {
218 return G.dijkstra_shortest_paths(source_id);
221template <
typename GraphWrapper>
222requires(GraphWrapper::has_builtin_edge_weight)
231[[deprecated(
"Use G.dijkstra_shortest_paths(source) instead.")]]
232auto single_source_dijkstra(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id) {
233 return G.dijkstra_shortest_paths(source_id);
236template <
typename GraphWrapper>
246[[deprecated(
"Use G.shortest_path(source, target, weight) instead.")]]
247auto shortest_path(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& weight) {
248 return G.shortest_path(source_id, target_id, weight);
251template <
typename GraphWrapper>
252requires(GraphWrapper::has_builtin_edge_weight)
262[[deprecated(
"Use G.dijkstra_path(source, target, weight) instead.")]]
263auto dijkstra_path(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& weight) {
264 return G.dijkstra_path(source_id, target_id, weight);
267template <
typename GraphWrapper>
276[[deprecated(
"Use G.shortest_path_length(source, target) instead.")]]
277double shortest_path_length(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id) {
278 return G.shortest_path_length(source_id, target_id);
281template <
typename GraphWrapper>
291[[deprecated(
"Use G.shortest_path_length(source, target, weight) instead.")]]
292double shortest_path_length(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& weight) {
293 return G.shortest_path_length(source_id, target_id, weight);
296template <
typename GraphWrapper>
297requires(GraphWrapper::has_builtin_edge_weight)
305[[deprecated(
"Use G.dijkstra_path_length(source) instead.")]]
306auto dijkstra_path_length(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id) {
307 return G.dijkstra_path_length(source_id);
310template <
typename GraphWrapper>
311requires(GraphWrapper::has_builtin_edge_weight)
321[[deprecated(
"Use G.dijkstra_path_length(source, target) instead.")]]
322auto dijkstra_path_length(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id) {
323 return G.dijkstra_path_length(source_id, target_id);
326template <
typename GraphWrapper>
327requires(GraphWrapper::has_builtin_edge_weight)
338[[deprecated(
"Use G.dijkstra_path_length(source, target, weight) instead.")]]
339auto dijkstra_path_length(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& weight) {
340 return G.dijkstra_path_length(source_id, target_id, weight);
344template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
346 if (id_to_bgl.find(source_id) == id_to_bgl.end() || id_to_bgl.find(target_id) == id_to_bgl.end()) {
347 throw std::runtime_error(
"Shortest-path lookup failed: source or target node not found.");
350 const VertexDesc source = id_to_bgl.at(source_id);
351 const VertexDesc target = id_to_bgl.at(target_id);
353 if (source == target) {
354 return std::vector<NodeID>{source_id};
357 const size_t n = boost::num_vertices(g);
358 const auto source_index = get_vertex_index(source);
359 const auto target_index = get_vertex_index(target);
360 std::vector<bool> visited(n,
false);
361 std::vector<VertexDesc> pred(n);
362 std::queue<VertexDesc> q;
364 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) {
365 pred[get_vertex_index(*v)] = *v;
368 visited[source_index] =
true;
372 const VertexDesc current = q.front();
375 for (
auto [e, eend] = boost::out_edges(current, g); e != eend; ++e) {
376 const VertexDesc next = boost::target(*e, g);
377 const auto next_index = get_vertex_index(next);
378 if (!visited[next_index]) {
379 visited[next_index] =
true;
380 pred[next_index] = current;
381 if (next == target) {
390 if (!visited[target_index]) {
391 throw std::runtime_error(
"Shortest-path lookup failed: target node is unreachable.");
394 return reconstruct_vertex_path(*
this, source, target, pred);
397template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
399 return shortest_path(source_id, target_id, parse_shortest_path_weight_mode(weight));
402template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
404 if (mode == WeightMode::Unweighted) {
407 if (mode == WeightMode::BuiltIn) {
408 if constexpr (Weighted) {
409 return dijkstra_path(source_id, target_id);
411 throw std::runtime_error(
"Weight lookup failed: only the built-in edge weight property named 'weight' is supported.");
414 throw std::runtime_error(
"Weight lookup failed: unsupported shortest-path weight mode.");
417template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
421 throw std::runtime_error(
"Shortest-path lookup failed: target node is unreachable.");
423 return static_cast<double>(path.size() - 1);
426template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
431template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
433 if (mode == WeightMode::Unweighted) {
436 if (mode == WeightMode::BuiltIn) {
437 if constexpr (Weighted) {
438 return dijkstra_path_length(source_id, target_id);
440 throw std::runtime_error(
"Weight lookup failed: only the built-in edge weight property named 'weight' is supported.");
443 throw std::runtime_error(
"Weight lookup failed: unsupported shortest-path weight mode.");
446template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
450 if (id_to_bgl.find(source_id) == id_to_bgl.end() || id_to_bgl.find(target_id) == id_to_bgl.end()) {
451 throw std::runtime_error(
"Shortest-path lookup failed: source or target node not found.");
454 const VertexDesc source = id_to_bgl.at(source_id);
455 const VertexDesc target = id_to_bgl.at(target_id);
456 const size_t n = boost::num_vertices(g);
457 const auto target_index = get_vertex_index(target);
458 std::vector<EdgeWeight> dist(n);
459 std::vector<VertexDesc> pred(n);
461 boost::dijkstra_shortest_paths(
464 boost::distance_map(boost::make_iterator_property_map(dist.begin(), vertex_index_map))
465 .predecessor_map(boost::make_iterator_property_map(pred.begin(), vertex_index_map))
466 .vertex_index_map(vertex_index_map)
469 if (pred[target_index] == target && source != target) {
470 throw std::runtime_error(
"Shortest-path lookup failed: target node is unreachable.");
473 return reconstruct_vertex_path(*
this, source, target, pred);
476template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
480 return dijkstra_path(source_id, target_id, parse_builtin_shortest_path_weight_mode(weight));
483template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
487 if (mode == WeightMode::Unweighted) {
490 if (mode == WeightMode::BuiltIn) {
491 return dijkstra_path(source_id, target_id);
493 throw std::runtime_error(
"Weight lookup failed: unsupported shortest-path weight mode.");
496template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
500 if (id_to_bgl.find(source_id) == id_to_bgl.end()) {
501 throw std::runtime_error(
"Shortest-path lookup failed: source node not found.");
504 const VertexDesc source = id_to_bgl.at(source_id);
505 const size_t n = boost::num_vertices(g);
506 std::vector<EdgeWeight> dist(n, std::numeric_limits<EdgeWeight>::max());
507 std::vector<VertexDesc> pred(n);
508 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) {
509 pred[get_vertex_index(*v)] = *v;
512 boost::dijkstra_shortest_paths(
515 boost::distance_map(boost::make_iterator_property_map(dist.begin(), vertex_index_map))
516 .predecessor_map(boost::make_iterator_property_map(pred.begin(), vertex_index_map))
517 .vertex_index_map(vertex_index_map)
521 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) {
522 const auto index = get_vertex_index(*v);
523 const auto&
id = get_node_id(*v);
530template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
534 return dijkstra_shortest_paths(source_id).distance;
537template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
541 const auto distances = dijkstra_path_length(source_id);
542 const auto it = distances.find(target_id);
543 if (it == distances.end()) {
544 throw std::runtime_error(
"Shortest-path lookup failed: target node not found.");
549template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
553 return dijkstra_path_length(source_id, target_id, parse_builtin_shortest_path_weight_mode(weight));
556template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
560 if (mode == WeightMode::Unweighted) {
563 if (mode == WeightMode::BuiltIn) {
564 return dijkstra_path_length(source_id, target_id);
566 throw std::runtime_error(
"Weight lookup failed: unsupported shortest-path weight mode.");
569template <
typename GraphWrapper>
570requires(GraphWrapper::has_builtin_edge_weight)
579[[deprecated(
"Use G.bellman_ford_path(source, target) instead.")]]
580auto bellman_ford_path(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id) {
581 return G.bellman_ford_path(source_id, target_id);
584template <
typename GraphWrapper>
585requires(GraphWrapper::has_builtin_edge_weight)
594[[deprecated(
"Use G.bellman_ford_shortest_paths(source) instead.")]]
595auto bellman_ford_shortest_paths(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id) {
596 return G.bellman_ford_shortest_paths(source_id);
599template <
typename GraphWrapper>
600requires(GraphWrapper::has_builtin_edge_weight)
609[[deprecated(
"Use G.bellman_ford_shortest_paths(source) instead.")]]
610auto single_source_bellman_ford(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id) {
611 return G.bellman_ford_shortest_paths(source_id);
614template <
typename GraphWrapper>
615requires(GraphWrapper::has_builtin_edge_weight)
625[[deprecated(
"Use G.bellman_ford_path(source, target, weight) instead.")]]
626auto bellman_ford_path(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& weight) {
627 return G.bellman_ford_path(source_id, target_id, weight);
630template <
typename GraphWrapper>
631requires(GraphWrapper::has_builtin_edge_weight)
641[[deprecated(
"Use G.bellman_ford_path_length(source, target) instead.")]]
642auto bellman_ford_path_length(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id) {
643 return G.bellman_ford_path_length(source_id, target_id);
646template <
typename GraphWrapper>
647requires(GraphWrapper::has_builtin_edge_weight)
658[[deprecated(
"Use G.bellman_ford_path_length(source, target, weight) instead.")]]
659auto bellman_ford_path_length(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id,
const typename GraphWrapper::NodeType& target_id,
const std::string& weight) {
660 return G.bellman_ford_path_length(source_id, target_id, weight);
663template <
typename GraphWrapper>
664requires(GraphWrapper::has_builtin_edge_weight)
673[[deprecated(
"Use G.dag_shortest_paths(source) instead.")]]
674auto dag_shortest_paths(
const GraphWrapper& G,
const typename GraphWrapper::NodeType& source_id) {
675 return G.dag_shortest_paths(source_id);
678template <
typename GraphWrapper>
679requires(GraphWrapper::has_builtin_edge_weight)
687[[deprecated(
"Use G.floyd_warshall_all_pairs_shortest_paths() instead.")]]
688auto floyd_warshall_all_pairs_shortest_paths(
const GraphWrapper& G) {
689 return G.floyd_warshall_all_pairs_shortest_paths();
692template <
typename GraphWrapper>
693requires(GraphWrapper::has_builtin_edge_weight)
701[[deprecated(
"Use G.floyd_warshall_all_pairs_shortest_paths_map() instead.")]]
702auto floyd_warshall_all_pairs_shortest_paths_map(
const GraphWrapper& G) {
703 return G.floyd_warshall_all_pairs_shortest_paths_map();
707template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
711 if (id_to_bgl.find(source_id) == id_to_bgl.end() || id_to_bgl.find(target_id) == id_to_bgl.end()) {
712 throw std::runtime_error(
"Shortest-path lookup failed: source or target node not found.");
715 const VertexDesc source = id_to_bgl.at(source_id);
716 const VertexDesc target = id_to_bgl.at(target_id);
717 const size_t n = boost::num_vertices(g);
718 const auto source_index = get_vertex_index(source);
719 const auto target_index = get_vertex_index(target);
720 std::vector<EdgeWeight> dist(n, std::numeric_limits<EdgeWeight>::max());
721 std::vector<VertexDesc> pred(n);
722 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) pred[get_vertex_index(*v)] = *v;
723 dist[source_index] = EdgeWeight{};
725 const bool ok = boost::bellman_ford_shortest_paths(
728 boost::weight_map(boost::get(boost::edge_weight, g))
729 .distance_map(boost::make_iterator_property_map(dist.begin(), vertex_index_map))
730 .predecessor_map(boost::make_iterator_property_map(pred.begin(), vertex_index_map))
733 if (!ok)
throw std::runtime_error(
"Bellman-Ford failed: negative cycle detected.");
734 if (dist[target_index] == std::numeric_limits<EdgeWeight>::max())
throw std::runtime_error(
"Shortest-path lookup failed: target node is unreachable.");
736 return reconstruct_vertex_path(*
this, source, target, pred);
739template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
743 if (id_to_bgl.find(source_id) == id_to_bgl.end()) {
744 throw std::runtime_error(
"Shortest-path lookup failed: source node not found.");
747 const VertexDesc source = id_to_bgl.at(source_id);
748 const size_t n = boost::num_vertices(g);
749 const auto source_index = get_vertex_index(source);
750 std::vector<EdgeWeight> dist(n, std::numeric_limits<EdgeWeight>::max());
751 std::vector<VertexDesc> pred(n);
752 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) pred[get_vertex_index(*v)] = *v;
753 dist[source_index] = EdgeWeight{};
755 const bool ok = boost::bellman_ford_shortest_paths(
758 boost::weight_map(boost::get(boost::edge_weight, g))
759 .distance_map(boost::make_iterator_property_map(dist.begin(), vertex_index_map))
760 .predecessor_map(boost::make_iterator_property_map(pred.begin(), vertex_index_map))
763 if (!ok)
throw std::runtime_error(
"Bellman-Ford failed: negative cycle detected.");
766 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) {
767 const auto index = get_vertex_index(*v);
768 const auto&
id = get_node_id(*v);
775template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
779 return bellman_ford_path(source_id, target_id, parse_builtin_shortest_path_weight_mode(weight));
782template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
786 if (mode == WeightMode::Unweighted) {
789 if (mode == WeightMode::BuiltIn) {
790 return bellman_ford_path(source_id, target_id);
792 throw std::runtime_error(
"Weight lookup failed: unsupported shortest-path weight mode.");
795template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
800 const auto path = bellman_ford_path(source_id, target_id);
801 for (
size_t i = 0; i + 1 < path.size(); ++i) total += get_edge_weight(path[i], path[i + 1]);
805template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
809 return bellman_ford_path_length(source_id, target_id, parse_builtin_shortest_path_weight_mode(weight));
812template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
816 if (mode == WeightMode::Unweighted) {
819 if (mode == WeightMode::BuiltIn) {
820 return bellman_ford_path_length(source_id, target_id);
822 throw std::runtime_error(
"Weight lookup failed: unsupported shortest-path weight mode.");
825template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
829 using CalcDistance = shortest_path_calc_type<EdgeWeight>;
830 if (id_to_bgl.find(source_id) == id_to_bgl.end())
throw std::runtime_error(
"Shortest-path lookup failed: source node not found.");
832 const VertexDesc source = id_to_bgl.at(source_id);
833 const size_t n = boost::num_vertices(g);
834 std::vector<CalcDistance> dist(n, std::numeric_limits<CalcDistance>::max());
835 std::vector<VertexDesc> pred(n);
836 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) pred[get_vertex_index(*v)] = *v;
838 boost::dag_shortest_paths(
840 boost::distance_map(boost::make_iterator_property_map(dist.begin(), vertex_index_map))
841 .predecessor_map(boost::make_iterator_property_map(pred.begin(), vertex_index_map))
842 .distance_compare(std::less<CalcDistance>())
843 .distance_combine(boost::closed_plus<CalcDistance>(std::numeric_limits<CalcDistance>::max()))
844 .distance_inf(std::numeric_limits<CalcDistance>::max())
845 .distance_zero(CalcDistance{})
848 std::vector<EdgeWeight> normalized_dist(n);
849 for (
size_t i = 0; i < n; ++i) normalized_dist[i] = convert_shortest_path_distance<EdgeWeight>(dist[i]);
852 for (
auto [v, vend] = boost::vertices(g); v != vend; ++v) {
853 const auto index = get_vertex_index(*v);
854 const auto&
id = get_node_id(*v);
855 result.
distance[id] = normalized_dist[index];
861template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
863 using CalcDistance = std::conditional_t<std::is_integral_v<EdgeWeight>,
long long, EdgeWeight>;
864 const size_t n = boost::num_vertices(g);
865 const CalcDistance inf = std::numeric_limits<CalcDistance>::max() / 4;
866 std::vector<std::vector<CalcDistance>> internal_matrix(n, std::vector<CalcDistance>(n, inf));
867 for (
size_t i = 0; i < n; ++i) internal_matrix[i][i] = CalcDistance{};
869 for (
auto [e, eend] = boost::edges(g); e != eend; ++e) {
870 const size_t u = get_vertex_index(boost::source(*e, g));
871 const size_t v = get_vertex_index(boost::target(*e, g));
872 const CalcDistance w =
static_cast<CalcDistance
>(boost::get(boost::edge_weight, g, *e));
873 internal_matrix[u][v] = std::min(internal_matrix[u][v], w);
874 if constexpr (!Directed) internal_matrix[v][u] = std::min(internal_matrix[v][u], w);
877 for (
size_t k = 0; k < n; ++k)
for (
size_t i = 0; i < n; ++i)
if (internal_matrix[i][k] != inf)
878 for (
size_t j = 0; j < n; ++j)
if (internal_matrix[k][j] != inf) {
879 const CalcDistance through_k = internal_matrix[i][k] + internal_matrix[k][j];
880 if (through_k < internal_matrix[i][j]) internal_matrix[i][j] = through_k;
883 std::vector<size_t> order(n);
884 for (
size_t i = 0; i < n; ++i) order[i] = i;
885 if constexpr (std::is_arithmetic_v<NodeID> || std::is_same_v<NodeID, std::string>) {
886 std::sort(order.begin(), order.end(), [&](
size_t lhs,
size_t rhs) { return bgl_to_id[lhs] < bgl_to_id[rhs]; });
889 std::vector<std::vector<EdgeWeight>> matrix(n, std::vector<EdgeWeight>(n));
890 for (
size_t i = 0; i < n; ++i)
for (
size_t j = 0; j < n; ++j)
891 matrix[i][j] = internal_matrix[order[i]][order[j]] == inf ? std::numeric_limits<EdgeWeight>::max() :
static_cast<EdgeWeight
>(internal_matrix[order[i]][order[j]]);
892 return std::pair{std::move(matrix), std::move(order)};
895template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
899 auto [matrix, order] = floyd_warshall_matrix_with_order();
904template <
typename NodeID,
typename EdgeWeight,
bool Directed,
bool Multi,
bool Weighted,
typename OutEdgeSelector,
typename VertexSelector>
908 const auto [matrix, order] = floyd_warshall_matrix_with_order();
909 const size_t n = matrix.size();
910 std::map<NodeID, std::map<NodeID, EdgeWeight>> result;
911 for (
size_t i = 0; i < n; ++i) {
912 for (
size_t j = 0; j < n; ++j) {
913 result[bgl_to_id[order[i]]][bgl_to_id[order[j]]] = matrix[i][j];
Graph wrapper around Boost Graph Library with Python-inspired helpers.
Definition graph.hpp:288
auto shortest_path(const NodeID &source_id, const NodeID &target_id) const
Computes an unweighted shortest path between two nodes.
Definition shortest_paths.hpp:345
double shortest_path_length(const NodeID &source_id, const NodeID &target_id) const
Returns the length of an unweighted shortest path.
Definition shortest_paths.hpp:418
Core graph wrapper, proxy surface, and public alias presets.
WeightMode
Explicit source-target shortest-path weighting mode.
Definition graph.hpp:117
auto shortest_path(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id)
Deprecated free-function alias for G.shortest_path(source, target).
Definition shortest_paths.hpp:187
double shortest_path_length(const GraphWrapper &G, const typename GraphWrapper::NodeType &source_id, const typename GraphWrapper::NodeType &target_id)
Deprecated free-function alias for G.shortest_path_length(source, target).
Definition shortest_paths.hpp:277
Result container for single-source shortest-path routines.
Definition shortest_paths.hpp:42
std::vector< NodeID > path_to(const NodeID &target) const
Reconstructs the path from the original source to target.
Definition shortest_paths.hpp:62
bool has_path_to(const NodeID &target) const
Returns true when the target exists in the result and is reachable.
Definition shortest_paths.hpp:49
std::map< NodeID, NodeID > predecessor
Predecessor tree keyed by target node ID.
Definition shortest_paths.hpp:46
std::map< NodeID, Distance > distance
Final shortest-path distance for each node known to the result.
Definition shortest_paths.hpp:44