diff --git a/include/graph/algorithm/bellman_ford_shortest_paths.hpp b/include/graph/algorithm/bellman_ford_shortest_paths.hpp index e53e45a..ebc0f13 100644 --- a/include/graph/algorithm/bellman_ford_shortest_paths.hpp +++ b/include/graph/algorithm/bellman_ford_shortest_paths.hpp @@ -100,22 +100,24 @@ concept bellman_visitor = //is_arithmetic && * was not minimized, the on_edge_not_minimized event is called. */ template (edge_reference_t)>, class Visitor = bellman_visitor_base, class Compare = less>, class Combine = plus>> -requires is_arithmetic_v> && // +requires convertible_to, vertex_id_t> && // + is_arithmetic_v> && // convertible_to, ranges::range_value_t> && basic_edge_weight_function, Compare, Combine> // && bellman_visitor bool bellman_ford_shortest_paths( - G& g, - const vertex_id_t source, - Distances& distances, - Predecessors& predecessor, - WF&& weight = + G& g, + const Sources& sources, + Distances& distances, + Predecessors& predecessor, + WF&& weight = [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 Visitor&& visitor = bellman_visitor_base(), Compare&& compare = less>(), @@ -146,9 +148,12 @@ bool bellman_ford_shortest_paths( const id_type N = static_cast(num_vertices(g)); - distances[source] = zero; - if (source >= N || source < 0) { - throw out_of_range(fmt::format("bellman_fored_shortest_paths: source vertex id of '{}' is out of range", source)); + // Seed the queue with the initial vertice(s) + for (auto&& source : sources) { + if (source >= N || source < 0) { + throw out_of_range(fmt::format("bellman_ford_shortest_paths: source vertex id '{}' is out of range", source)); + } + distances[static_cast(source)] = zero; // mark source as discovered } for (id_type k = 0; k < N; ++k) { @@ -198,6 +203,32 @@ bool bellman_ford_shortest_paths( return true; } +template (edge_reference_t)>, + class Visitor = bellman_visitor_base, + class Compare = less>, + class Combine = plus>> +requires is_arithmetic_v> && // + convertible_to, ranges::range_value_t> && + basic_edge_weight_function, Compare, Combine> +// && bellman_visitor +bool bellman_ford_shortest_paths( + G& g, + const vertex_id_t source, + Distances& distances, + Predecessors& predecessor, + WF&& weight = + [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 + Visitor&& visitor = bellman_visitor_base(), + Compare&& compare = less>(), + Combine&& combine = plus>()) { + return bellman_ford_shortest_paths(g, ranges::subrange(&source, (&source + 1)), distances, predecessor, weight, + forward(visitor), forward(compare), forward(combine)); +} + + /** * @brief Shortest distnaces from a single source using Bellman-Ford's single-source shortest paths * algorithm with a visitor. @@ -227,6 +258,31 @@ bool bellman_ford_shortest_paths( * @return true if all edges were minimized, false if a negative weight cycle was found. If an edge * was not minimized, the on_edge_not_minimized event is called. */ +template (edge_reference_t)>, + class Visitor = bellman_visitor_base, + class Compare = less>, + class Combine = plus>> +requires convertible_to, vertex_id_t> && // + is_arithmetic_v> && // + basic_edge_weight_function, Compare, Combine> +//&& bellman_visitor +bool bellman_ford_shortest_distances( + G& g, + const Sources& sources, + Distances& distances, + WF&& weight = + [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 + Visitor&& visitor = bellman_visitor_base(), + Compare&& compare = less>(), + Combine&& combine = plus>()) { + return bellman_ford_shortest_paths(g, sources, distances, _null_predecessors, forward(weight), + std::forward(visitor), std::forward(compare), + std::forward(combine)); +} + template (edge_reference_t)>, @@ -245,9 +301,9 @@ bool bellman_ford_shortest_distances( Visitor&& visitor = bellman_visitor_base(), Compare&& compare = less>(), Combine&& combine = plus>()) { - return bellman_ford_shortest_paths(g, source, distances, _null_predecessors, forward(weight), - std::forward(visitor), std::forward(compare), - std::forward(combine)); + return bellman_ford_shortest_paths(g, ranges::subrange(&source, (&source + 1)), distances, _null_predecessors, + forward(weight), std::forward(visitor), + std::forward(compare), std::forward(combine)); } } // namespace std::graph diff --git a/include/graph/algorithm/dijkstra_shortest_paths.hpp b/include/graph/algorithm/dijkstra_shortest_paths.hpp index 1c51554..18451fa 100644 --- a/include/graph/algorithm/dijkstra_shortest_paths.hpp +++ b/include/graph/algorithm/dijkstra_shortest_paths.hpp @@ -90,40 +90,42 @@ concept dijkstra_visitor = //is_arithmetic && * @tparam WF Edge weight function. Defaults to a function that returns 1. * @tparam Visitor Visitor type with functions called for different events in the algorithm. * Function calls are removed by the optimizer if not uesd. - * @tparam Compare Comparison function for Distance values. Defaults to less. + * @tparam Compare Comparison function for Distance values. Defaults to less. * @tparam Combine Combine function for Distance values. Defaults to plus. */ template (edge_reference_t)>, class Visitor = dijkstra_visitor_base, class Compare = less>, class Combine = plus>> -requires is_arithmetic_v> && // +requires convertible_to, vertex_id_t> && // + is_arithmetic_v> && // convertible_to, ranges::range_value_t> && basic_edge_weight_function, Compare, Combine> // && dijkstra_visitor void dijkstra_shortest_paths( - G& g, - const vertex_id_t source, - Distances& distances, - Predecessors& predecessor, - WF&& weight = + G& g, + const Sources& sources, + Distances& distances, + Predecessors& predecessor, + WF&& weight = [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 Visitor&& visitor = dijkstra_visitor_base(), Compare&& compare = less>(), Combine&& combine = plus>()) { using id_type = vertex_id_t; - using DistanceValue = ranges::range_value_t; + using distance_type = ranges::range_value_t; using weight_type = invoke_result_t>; // relxing the target is the function of reducing the distance from the source to the target auto relax_target = [&g, &predecessor, &distances, &compare, &combine] // (edge_reference_t e, vertex_id_t uid, const weight_type& w_e) -> bool { - id_type vid = target_id(g, e); - const DistanceValue d_u = distances[static_cast(uid)]; - const DistanceValue d_v = distances[static_cast(vid)]; + const id_type vid = target_id(g, e); + const distance_type d_u = distances[static_cast(uid)]; + const distance_type d_v = distances[static_cast(vid)]; if (compare(combine(d_u, w_e), d_v)) { distances[static_cast(vid)] = combine(d_u, w_e); @@ -135,8 +137,8 @@ void dijkstra_shortest_paths( return false; }; - constexpr auto zero = shortest_path_zero(); - constexpr auto infinite = shortest_path_invalid_distance(); + constexpr auto zero = shortest_path_zero(); + constexpr auto infinite = shortest_path_invalid_distance(); const id_type N = static_cast(num_vertices(g)); @@ -151,13 +153,15 @@ void dijkstra_shortest_paths( visitor.on_initialize_vertex({uid, *find_vertex(g, uid)}); } - // Seed the queue with the initial vertex - if (source >= N || source < 0) { - throw out_of_range(fmt::format("dijkstra_shortest_paths: source vertex id of '{}' is out of range", source)); + // Seed the queue with the initial vertice(s) + for (auto&& source : sources) { + if (source >= N || source < 0) { + throw out_of_range(fmt::format("dijkstra_shortest_paths: source vertex id '{}' is out of range", source)); + } + queue.push(source); + distances[static_cast(source)] = zero; // mark source as discovered + visitor.on_discover_vertex({source, *find_vertex(g, source)}); } - queue.push(source); - distances[static_cast(source)] = zero; // mark source as discovered - visitor.on_discover_vertex({source, *find_vertex(g, source)}); // Main loop to process the queue while (!queue.empty()) { @@ -208,6 +212,31 @@ void dijkstra_shortest_paths( } // while(!queue.empty()) } +template (edge_reference_t)>, + class Visitor = dijkstra_visitor_base, + class Compare = less>, + class Combine = plus>> +requires is_arithmetic_v> && // + convertible_to, ranges::range_value_t> && + basic_edge_weight_function, Compare, Combine> +// && dijkstra_visitor +void dijkstra_shortest_paths( + G& g, + const vertex_id_t source, + Distances& distances, + Predecessors& predecessor, + WF&& weight = + [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 + Visitor&& visitor = dijkstra_visitor_base(), + Compare&& compare = less>(), + Combine&& combine = plus>()) { + dijkstra_shortest_paths(g, ranges::subrange(&source, (&source + 1)), distances, predecessor, weight, + forward(visitor), forward(compare), forward(combine)); +} + /** * @brief Shortest distnaces from a single source using Dijkstra's single-source shortest paths algorithm * with a visitor. @@ -231,9 +260,34 @@ void dijkstra_shortest_paths( * @tparam WF Edge weight function. Defaults to a function that returns 1. * @tparam Visitor Visitor type with functions called for different events in the algorithm. * Function calls are removed by the optimizer if not uesd. - * @tparam Compare Comparison function for Distance values. Defaults to less. + * @tparam Compare Comparison function for Distance values. Defaults to less. * @tparam Combine Combine function for Distance values. Defaults to plus. */ +template (edge_reference_t)>, + class Visitor = dijkstra_visitor_base, + class Compare = less>, + class Combine = plus>> +requires convertible_to, vertex_id_t> && // + is_arithmetic_v> && // + basic_edge_weight_function, Compare, Combine> +//&& dijkstra_visitor +void dijkstra_shortest_distances( + G& g, + const Sources& sources, + Distances& distances, + WF&& weight = + [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 + Visitor&& visitor = dijkstra_visitor_base(), + Compare&& compare = less>(), + Combine&& combine = plus>()) { + dijkstra_shortest_paths(g, sources, distances, _null_predecessors, forward(weight), + std::forward(visitor), std::forward(compare), + std::forward(combine)); +} + template (edge_reference_t)>, @@ -252,8 +306,9 @@ void dijkstra_shortest_distances( Visitor&& visitor = dijkstra_visitor_base(), Compare&& compare = less>(), Combine&& combine = plus>()) { - dijkstra_shortest_paths(g, source, distances, _null_predecessors, forward(weight), std::forward(visitor), - std::forward(compare), std::forward(combine)); + dijkstra_shortest_paths(g, ranges::subrange(&source, (&source + 1)), distances, _null_predecessors, + forward(weight), std::forward(visitor), std::forward(compare), + std::forward(combine)); } } // namespace std::graph