From c5780e55934283914bce90d05385a54b62e853f5 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Thu, 21 Dec 2023 16:52:54 -0500 Subject: [PATCH] Add dijksta general algorithm implementation Add tests for the general algorithms --- include/graph/algorithm/shortest_paths.hpp | 130 ++++++++- tests/shortest_paths_tests.cpp | 315 +++++++++++++++++++-- 2 files changed, 419 insertions(+), 26 deletions(-) diff --git a/include/graph/algorithm/shortest_paths.hpp b/include/graph/algorithm/shortest_paths.hpp index c60af0e..0439645 100644 --- a/include/graph/algorithm/shortest_paths.hpp +++ b/include/graph/algorithm/shortest_paths.hpp @@ -164,10 +164,11 @@ void dijkstra_shortest_paths( using id_type = vertex_id_t; using weight_type = invoke_result_t>; - size_t N(size(vertices(g))); // Question(Andrew): Do we want a num_vertices(g) CPO? - assert(source < N && source >= 0); + size_t N(num_vertices(g)); + if (source < N || source >= 0) + throw out_of_range("source is outside the vertices range"); - std::ranges::fill(distances, numeric_limits::max()); + //std::ranges::fill(distances, numeric_limits::max()); distances[source] = 0; struct weighted_vertex { @@ -218,17 +219,134 @@ template requires is_arithmetic_v> && // edge_weight_function> +void dijkstra_shortest_distances( + G&& g, // graph + vertex_id_t seed, // starting vertex_id + Distances& distances, // out: Distances[uid] of uid from seed + WF&& weight = + [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 + Allocator alloc = Allocator()) // +{ + dijkstra_shortest_paths(g, seed, distances, _null_predecessors, forward(weight), + alloc); // default weight(uv) -> 1 +} + +/** + * @brief Dijkstra Shortest Paths general algorithm. + * + * @tparam G The graph type. + * @tparam Distances The distance range type. + * @tparam Predecessors The predecessors range type. + * @tparam WF The edge value function that returns the weight of an edge. + * + * @param g The graph. + * @param source The single source vertex to start the search. + * @param distances [inout] The distance[uid] of vertex_id uid from seed. distance[seed] == 0. The caller + * must assure size(distance) >= size(vertices(g)) and set the values to be + * dijkstra_invalid_distance(). + * @param predecessors [inout] The predecessor[uid] of vertex_id uid in path. predecessor[seed] == seed. The + * caller must assure size(predecessor) >= size(vertices(g)). It is only valid when + * distance[uid] != dijkstra_invalid_distance(). + * @param weight The weight function object used to determine the distance between + * vertices on an edge. Return values must be non-negative. The default return value is 1. +*/ +template (edge_reference_t)>, // + class Allocator = allocator> // + > +requires is_arithmetic_v> && // + convertible_to, ranges::range_value_t> && // + basic_edge_weight_function, Compare, Combine> void dijkstra_shortest_paths( + G&& g, // graph + vertex_id_t source, // starting vertex_id + Distances& distances, // out: Distances[uid] of uid from source + Predecessors& predecessors, // out: predecessor[uid] of uid in path + Compare&& compare, + Combine&& combine, + WF&& weight = + [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 + Allocator alloc = Allocator()) // +{ + using id_type = vertex_id_t; + using weight_type = invoke_result_t>; + + size_t N(num_vertices(g)); + if (source < N || source >= 0) + throw out_of_range("source is outside the vertices range"); + + //std::ranges::fill(distances, numeric_limits::max()); + distances[source] = 0; + + struct weighted_vertex { + id_type vertex_id = id_type(); + weight_type weight = weight_type(); + }; + + using q_compare = decltype([](const weighted_vertex& a, const weighted_vertex& b) { return a.weight > b.weight; }); + priority_queue, q_compare> Q(alloc); + + // (CLRS puts all vertices in the queue to start but standard practice seems to be to enqueue source) + Q.push({source, distances[source]}); + + while (!Q.empty()) { + auto uid = Q.top().vertex_id; + Q.pop(); + + for (auto&& [vid, uv, w] : views::incidence(g, uid, weight)) { + if (compare(combine(distances[uid], w), distances[vid])) { + distances[vid] = combine(distances[uid], w); + if constexpr (!is_same_v) + predecessors[vid] = uid; + Q.push({vid, distances[vid]}); + } + } + } +} + +/** + * @brief Dijkstra Shortest Paths common algorithm. + * + * @tparam G The graph type. + * @tparam Distances The distance range type. + * @tparam WF The edge value function that returns the weight of an edge. + * + * @param g The graph. + * @param source The single source vertex to start the search. + * @param distances [inout] The distance[uid] of vertex_id uid from seed. distance[seed] == 0. The caller + * must assure size(distance) >= size(vertices(g)) and set the values to be + * dijkstra_invalid_distance(). + * @param weight The weight function object used to determine the distance between + * vertices on an edge. Return values must be non-negative. The default return value is 1. +*/ +template (edge_reference_t)>, // + class Allocator = allocator> // + > +requires is_arithmetic_v> && // + basic_edge_weight_function, Compare, Combine> +void dijkstra_shortest_distances( G&& g, // graph vertex_id_t seed, // starting vertex_id Distances& distances, // out: Distances[uid] of uid from seed + Compare&& compare, + Combine&& combine, WF&& weight = - [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 - Allocator alloc = Allocator()) // + [](edge_reference_t uv) { return ranges::range_value_t(1); }, // default weight(uv) -> 1 + Allocator alloc = Allocator()) // { - dijkstra_shortest_paths(g, seed, distances, _null_predecessors, forward(weight), alloc); // default weight(uv) -> 1 + dijkstra_shortest_paths(g, seed, distances, _null_predecessors, compare, combine, forward(weight), + alloc); // default weight(uv) -> 1 } + } // namespace std::graph #endif //GRAPH_SHORTEST_PATHS_HPP diff --git a/tests/shortest_paths_tests.cpp b/tests/shortest_paths_tests.cpp index 48b738b..9385f62 100644 --- a/tests/shortest_paths_tests.cpp +++ b/tests/shortest_paths_tests.cpp @@ -4,7 +4,7 @@ #include "graph/algorithm/shortest_paths.hpp" #include "graph/container/dynamic_graph.hpp" #include "graph/views/vertexlist.hpp" -#include +#include #include #ifdef _MSC_VER # include "Windows.h" @@ -55,6 +55,7 @@ using std::graph::views::vertexlist; using std::graph::shortest_path_invalid_distance; using std::graph::init_shortest_paths; using std::graph::dijkstra_shortest_paths; +using std::graph::dijkstra_shortest_distances; using routes_volf_graph_traits = std::graph::container::vofl_graph_traits; using routes_volf_graph_type = std::graph::container::dynamic_adjacency_graph; @@ -82,9 +83,9 @@ auto to_string(G&& g, const Predecessors& predecessors, vertex_id_t uid, vert vertex_id_t pid = predecessors[uid]; vertex_reference_t pref = *find_vertex(g, pid); if (pred.empty()) { - pred += std::format("[{}]{}", pid, vertex_value(g, pref)); + pred += fmt::format("[{}]{}", pid, vertex_value(g, pref)); } else { - pred += std::format(", [{}]{}", pid, vertex_value(g, pref)); + pred += fmt::format(", [{}]{}", pid, vertex_value(g, pref)); } } return pred; @@ -105,15 +106,15 @@ auto to_string(const Predecessors& predecessors) { std::string pred; for (auto& pid : predecessors) { if (pred.empty()) { - pred += std::format("{}", pid); + pred += fmt::format("{}", pid); } else { - pred += std::format(",{}", pid); + pred += fmt::format(",{}", pid); } } return pred; } -TEST_CASE("Dijkstra's Shortest Segments", "[csv][vofl][shortest][segments][dijkstra]") { +TEST_CASE("Dijkstra's Common Shortest Segments", "[csv][vofl][shortest][segments][dijkstra][common]") { init_console(); using G = routes_volf_graph_type; auto&& g = load_graph(TEST_DATA_ROOT_DIR "germany_routes.csv"); @@ -267,7 +268,7 @@ TEST_CASE("Dijkstra's Shortest Segments", "[csv][vofl][shortest][segments][dijks #endif } -TEST_CASE("Dijkstra's Shortest Paths", "[csv][vofl][shortest][paths][dijkstra]") { +TEST_CASE("Dijkstra's Common Shortest Paths", "[csv][vofl][shortest][paths][dijkstra][common]") { init_console(); using G = routes_volf_graph_type; auto&& g = load_graph(TEST_DATA_ROOT_DIR "germany_routes.csv"); @@ -287,22 +288,296 @@ TEST_CASE("Dijkstra's Shortest Paths", "[csv][vofl][shortest][paths][dijkstra]") cout << endl << '[' << frankfurt_id << "] " << vertex_value(g, **frankfurt) << " (source)" << endl; for (auto&& [uid, u, city_name] : vertexlist(g, vname)) { vertex_reference_t pred = *find_vertex(g, predecessors[uid]); - cout << '[' << uid << "] " << city_name << ", segments=" << distance[uid] + cout << '[' << uid << "] " << city_name << ", distance=" << distance[uid] << ", predecessors=" << to_string(g, predecessors, uid, frankfurt_id) << endl; } /* Output: [2] Frankfürt (source) - [0] Augsburg, segments=415, predecessors=[3]Karlsruhe, [5]Mannheim, [2]Frankfürt - [1] Erfurt, segments=403, predecessors=[9]Würzburg, [2]Frankfürt + [0] Augsburg, distance=415, predecessors=[3]Karlsruhe, [5]Mannheim, [2]Frankfürt + [1] Erfurt, distance=403, predecessors=[9]Würzburg, [2]Frankfürt + [2] Frankfürt, distance=0, predecessors= + [3] Karlsruhe, distance=165, predecessors=[5]Mannheim, [2]Frankfürt + [4] Kassel, distance=173, predecessors=[2]Frankfürt + [5] Mannheim, distance=85, predecessors=[2]Frankfürt + [6] München, distance=487, predecessors=[7]Nürnberg, [9]Würzburg, [2]Frankfürt + [7] Nürnberg, distance=320, predecessors=[9]Würzburg, [2]Frankfürt + [8] Stuttgart, distance=503, predecessors=[7]Nürnberg, [9]Würzburg, [2]Frankfürt + [9] Würzburg, distance=217, predecessors=[2]Frankfürt + */ + } +#elif TEST_OPTION == TEST_OPTION_GEN + SECTION("Dijkstra's Shortest Paths generate") { + using namespace std::graph; + using std::cout; + using std::endl; + ostream_indenter indent; + + cout << endl << indent << "for (auto&& [uid, u, city_name] : vertexlist(g, vname)) {" << endl; + ++indent; + cout << indent << "switch (uid) {" << endl; + + for (auto&& [uid, u, city_name] : vertexlist(g, vname)) { + cout << indent << "case " << uid << ": {" << endl; + ++indent; + { + cout << indent << "REQUIRE(\"" << city_name << "\" == vertex_value(g, u));" << endl + << indent << "REQUIRE(" << distance[uid] << " == distance[uid]);" << endl; + + std::string expect = to_string(to_vector(g, predecessors, uid, frankfurt_id)); + cout << indent << "REQUIRE(Predecessors{" << expect << "} == to_vector(g, predecessors, uid, frankfurt_id));" + << endl; + //cout << indent << "} break;" << endl; // case + } + --indent; + cout << indent << "} break;" << endl; // case + } + + cout << indent << "}" << endl; // switch + --indent; + cout << indent << "}" << endl; // for + } +#elif TEST_OPTION == TEST_OPTION_TEST + for (auto&& [uid, u, city_name] : vertexlist(g, vname)) { + switch (uid) { + case 0: { + REQUIRE("Augsburg" == vertex_value(g, u)); + REQUIRE(415 == distance[uid]); + REQUIRE(Predecessors{3, 5, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 1: { + REQUIRE("Erfurt" == vertex_value(g, u)); + REQUIRE(403 == distance[uid]); + REQUIRE(Predecessors{9, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 2: { + REQUIRE("Frankfürt" == vertex_value(g, u)); + REQUIRE(0 == distance[uid]); + REQUIRE(Predecessors{} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 3: { + REQUIRE("Karlsruhe" == vertex_value(g, u)); + REQUIRE(165 == distance[uid]); + REQUIRE(Predecessors{5, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 4: { + REQUIRE("Kassel" == vertex_value(g, u)); + REQUIRE(173 == distance[uid]); + REQUIRE(Predecessors{2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 5: { + REQUIRE("Mannheim" == vertex_value(g, u)); + REQUIRE(85 == distance[uid]); + REQUIRE(Predecessors{2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 6: { + REQUIRE("München" == vertex_value(g, u)); + REQUIRE(487 == distance[uid]); + REQUIRE(Predecessors{7, 9, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 7: { + REQUIRE("Nürnberg" == vertex_value(g, u)); + REQUIRE(320 == distance[uid]); + REQUIRE(Predecessors{9, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 8: { + REQUIRE("Stuttgart" == vertex_value(g, u)); + REQUIRE(503 == distance[uid]); + REQUIRE(Predecessors{7, 9, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 9: { + REQUIRE("Würzburg" == vertex_value(g, u)); + REQUIRE(217 == distance[uid]); + REQUIRE(Predecessors{2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + } + } +#endif +} + +TEST_CASE("Dijkstra's Common Shortest Distances", "[csv][vofl][shortest][distances][dijkstra][common]") { + init_console(); + using G = routes_volf_graph_type; + auto&& g = load_graph(TEST_DATA_ROOT_DIR "germany_routes.csv"); + auto frankfurt = find_frankfurt(g); + vertex_id_t frankfurt_id = find_frankfurt_id(g); + auto vname = [&](vertex_reference_t u) { return vertex_value(g, u); }; + + vector distance(size(vertices(g))); + init_shortest_paths(distance); + auto weight = [&g](edge_reference_t uv) -> double { return edge_value(g, uv); }; + + // This test case just tests that these will compile without error. The distances will be the same as before. + dijkstra_shortest_distances(g, frankfurt_id, distance); + dijkstra_shortest_distances(g, frankfurt_id, distance, weight); +} + +TEST_CASE("Dijkstra's General Shortest Segments", "[csv][vofl][shortest][segments][dijkstra][general]") { + init_console(); + using G = routes_volf_graph_type; + auto&& g = load_graph(TEST_DATA_ROOT_DIR "germany_routes.csv"); + auto frankfurt = find_frankfurt(g); + vertex_id_t frankfurt_id = find_frankfurt_id(g); + auto vname = [&](vertex_reference_t u) { return vertex_value(g, u); }; + + Distances distance(size(vertices(g))); + Predecessors predecessors(size(vertices(g))); + init_shortest_paths(distance, predecessors); + //auto weight = [](edge_reference_t uv) -> double { return 1.0; }; + + dijkstra_shortest_paths(g, frankfurt_id, distance, predecessors, std::less(), std::plus()); + +#if TEST_OPTION == TEST_OPTION_OUTPUT + SECTION("Dijkstra's Shortest Segments output") { + cout << '[' << frankfurt_id << "] " << vertex_value(g, **frankfurt) << " (source)" << endl; + for (auto&& [uid, u, city_name] : vertexlist(g, vname)) { + vertex_reference_t pred = *find_vertex(g, predecessors[uid]); + cout << '[' << uid << "] " << city_name << ", segments=" << distance[uid] + << ", predecessors=" << to_string(g, predecessors, uid, frankfurt_id) << endl; + } + + /* Output: + [2] Frankfürt (seed) + [0] Augsburg, segments=3, predecessors=[3]Karlsruhe, [5]Mannheim, [2]Frankfürt + [1] Erfurt, segments=2, predecessors=[9]Würzburg, [2]Frankfürt [2] Frankfürt, segments=0, predecessors= - [3] Karlsruhe, segments=165, predecessors=[5]Mannheim, [2]Frankfürt - [4] Kassel, segments=173, predecessors=[2]Frankfürt - [5] Mannheim, segments=85, predecessors=[2]Frankfürt - [6] München, segments=487, predecessors=[7]Nürnberg, [9]Würzburg, [2]Frankfürt - [7] Nürnberg, segments=320, predecessors=[9]Würzburg, [2]Frankfürt - [8] Stuttgart, segments=503, predecessors=[7]Nürnberg, [9]Würzburg, [2]Frankfürt - [9] Würzburg, segments=217, predecessors=[2]Frankfürt + [3] Karlsruhe, segments=2, predecessors=[5]Mannheim, [2]Frankfürt + [4] Kassel, segments=1, predecessors=[2]Frankfürt + [5] Mannheim, segments=1, predecessors=[2]Frankfürt + [6] München, segments=2, predecessors=[4]Kassel, [2]Frankfürt + [7] Nürnberg, segments=2, predecessors=[9]Würzburg, [2]Frankfürt + [8] Stuttgart, segments=3, predecessors=[7]Nürnberg, [9]Würzburg, [2]Frankfürt + [9] Würzburg, segments=1, predecessors=[2]Frankfürt + */ + } +#elif TEST_OPTION == TEST_OPTION_GEN + SECTION("Dijkstra's Shortest Segments generate") { + using namespace std::graph; + using std::cout; + using std::endl; + ostream_indenter indent; + + cout << endl << indent << "for (auto&& [uid, u, city_name] : vertexlist(g, vname)) {" << endl; + ++indent; + cout << indent << "switch (uid) {" << endl; + + for (auto&& [uid, u, city_name] : vertexlist(g, vname)) { + cout << indent << "case " << uid << ": {" << endl; + ++indent; + { + cout << indent << "REQUIRE(\"" << city_name << "\" == vertex_value(g, u));" << endl + << indent << "REQUIRE(" << distance[uid] << " == distance[uid]);" << endl; + + std::string expect = to_string(to_vector(g, predecessors, uid, frankfurt_id)); + cout << indent << "REQUIRE(Predecessors{" << expect << "} == to_vector(g, predecessors, uid, frankfurt_id));" + << endl; + //cout << indent << "} break;" << endl; // case + } + --indent; + cout << indent << "} break;" << endl; // case + } + + cout << indent << "}" << endl; // switch + --indent; + cout << indent << "}" << endl; // for + } +#elif TEST_OPTION == TEST_OPTION_TEST + SECTION("Dijkstra's Shortest Segments test content") { + + for (auto&& [uid, u, city_name] : vertexlist(g, vname)) { + switch (uid) { + case 0: { + REQUIRE("Augsburg" == vertex_value(g, u)); + REQUIRE(3 == distance[uid]); + REQUIRE(Predecessors{3, 5, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 1: { + REQUIRE("Erfurt" == vertex_value(g, u)); + REQUIRE(2 == distance[uid]); + REQUIRE(Predecessors{9, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 2: { + REQUIRE("Frankfürt" == vertex_value(g, u)); + REQUIRE(0 == distance[uid]); + REQUIRE(Predecessors{} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 3: { + REQUIRE("Karlsruhe" == vertex_value(g, u)); + REQUIRE(2 == distance[uid]); + REQUIRE(Predecessors{5, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 4: { + REQUIRE("Kassel" == vertex_value(g, u)); + REQUIRE(1 == distance[uid]); + REQUIRE(Predecessors{2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 5: { + REQUIRE("Mannheim" == vertex_value(g, u)); + REQUIRE(1 == distance[uid]); + REQUIRE(Predecessors{2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 6: { + REQUIRE("München" == vertex_value(g, u)); + REQUIRE(2 == distance[uid]); + REQUIRE(Predecessors{4, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 7: { + REQUIRE("Nürnberg" == vertex_value(g, u)); + REQUIRE(2 == distance[uid]); + REQUIRE(Predecessors{9, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 8: { + REQUIRE("Stuttgart" == vertex_value(g, u)); + REQUIRE(3 == distance[uid]); + REQUIRE(Predecessors{7, 9, 2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + case 9: { + REQUIRE("Würzburg" == vertex_value(g, u)); + REQUIRE(1 == distance[uid]); + REQUIRE(Predecessors{2} == to_vector(g, predecessors, uid, frankfurt_id)); + } break; + } + } + } +#endif +} + +TEST_CASE("Dijkstra's General Shortest Paths", "[csv][vofl][shortest][paths][dijkstra][general]") { + init_console(); + using G = routes_volf_graph_type; + auto&& g = load_graph(TEST_DATA_ROOT_DIR "germany_routes.csv"); + auto frankfurt = find_frankfurt(g); + vertex_id_t frankfurt_id = find_frankfurt_id(g); + auto vname = [&](vertex_reference_t u) { return vertex_value(g, u); }; + + vector distance(size(vertices(g))); + vector> predecessors(size(vertices(g))); + init_shortest_paths(distance, predecessors); + auto weight = [&g](edge_reference_t uv) -> double { return edge_value(g, uv); }; + + dijkstra_shortest_paths(g, frankfurt_id, distance, predecessors, std::less(), std::plus(), weight); + +#if TEST_OPTION == TEST_OPTION_OUTPUT + SECTION("Dijkstra's Shortest Paths output") { + cout << endl << '[' << frankfurt_id << "] " << vertex_value(g, **frankfurt) << " (source)" << endl; + for (auto&& [uid, u, city_name] : vertexlist(g, vname)) { + vertex_reference_t pred = *find_vertex(g, predecessors[uid]); + cout << '[' << uid << "] " << city_name << ", distance=" << distance[uid] + << ", predecessors=" << to_string(g, predecessors, uid, frankfurt_id) << endl; + } + + /* Output: + [2] Frankfürt (source) + [0] Augsburg, distance=415, predecessors=[3]Karlsruhe, [5]Mannheim, [2]Frankfürt + [1] Erfurt, distance=403, predecessors=[9]Würzburg, [2]Frankfürt + [2] Frankfürt, distance=0, predecessors= + [3] Karlsruhe, distance=165, predecessors=[5]Mannheim, [2]Frankfürt + [4] Kassel, distance=173, predecessors=[2]Frankfürt + [5] Mannheim, distance=85, predecessors=[2]Frankfürt + [6] München, distance=487, predecessors=[7]Nürnberg, [9]Würzburg, [2]Frankfürt + [7] Nürnberg, distance=320, predecessors=[9]Würzburg, [2]Frankfürt + [8] Stuttgart, distance=503, predecessors=[7]Nürnberg, [9]Würzburg, [2]Frankfürt + [9] Würzburg, distance=217, predecessors=[2]Frankfürt */ } #elif TEST_OPTION == TEST_OPTION_GEN @@ -394,7 +669,7 @@ TEST_CASE("Dijkstra's Shortest Paths", "[csv][vofl][shortest][paths][dijkstra]") #endif } -TEST_CASE("Dijkstra's Shortest Distances", "[csv][vofl][shortest][distances][dijkstra]") { +TEST_CASE("Dijkstra's General Shortest Distances", "[csv][vofl][shortest][distances][dijkstra][general]") { init_console(); using G = routes_volf_graph_type; auto&& g = load_graph(TEST_DATA_ROOT_DIR "germany_routes.csv"); @@ -407,6 +682,6 @@ TEST_CASE("Dijkstra's Shortest Distances", "[csv][vofl][shortest][distances][dij auto weight = [&g](edge_reference_t uv) -> double { return edge_value(g, uv); }; // This test case just tests that these will compile without error. The distances will be the same as before. - dijkstra_shortest_paths(g, frankfurt_id, distance); - dijkstra_shortest_paths(g, frankfurt_id, distance, weight); + dijkstra_shortest_distances(g, frankfurt_id, distance, std::less(), std::plus()); + dijkstra_shortest_distances(g, frankfurt_id, distance, std::less(), std::plus(), weight); }