diff --git a/include/graph/algorithm/bellman_ford_shortest_paths.hpp b/include/graph/algorithm/bellman_ford_shortest_paths.hpp index 292056d..e043e77 100644 --- a/include/graph/algorithm/bellman_ford_shortest_paths.hpp +++ b/include/graph/algorithm/bellman_ford_shortest_paths.hpp @@ -27,41 +27,6 @@ namespace graph { -template -class bellman_visitor_base { - // Types -public: - using graph_type = G; - using vertex_desc_type = vertex_descriptor, vertex_reference_t, void>; - using sourced_edge_desc_type = edge_descriptor, true, edge_reference_t, void>; - - // Visitor Functions -public: - // edge visitor functions - constexpr void on_examine_edge(const sourced_edge_desc_type& edesc) {} - constexpr void on_edge_relaxed(const sourced_edge_desc_type& edesc) {} - constexpr void on_edge_not_relaxed(const sourced_edge_desc_type& edesc) {} - constexpr void on_edge_minimized(const sourced_edge_desc_type& edesc) {} - constexpr void on_edge_not_minimized(const sourced_edge_desc_type& edesc) {} -}; - -template -concept bellman_visitor = //is_arithmetic && - requires(Visitor& v, Visitor::vertex_desc_type& vdesc, Visitor::sourced_edge_desc_type& edesc) { - //typename Visitor::distance_type; - - //{ v.on_initialize_vertex(vdesc) }; - //{ v.on_discover_vertex(vdesc) }; - //{ v.on_examine_vertex(vdesc) }; - //{ v.on_finish_vertex(vdesc) }; - - { v.on_examine_edge(edesc) }; - { v.on_edge_relaxed(edesc) }; - { v.on_edge_not_relaxed(edesc) }; - { v.on_edge_minimized(edesc) }; - { v.on_edge_not_minimized(edesc) }; - }; - /** * @brief Get the vertex ids in a negative weight cycle. * @@ -132,7 +97,7 @@ template (edge_reference_t)>, - class Visitor = bellman_visitor_base, + class Visitor = empty_visitor, class Compare = less>, class Combine = plus>> requires convertible_to, vertex_id_t> && // @@ -141,14 +106,13 @@ requires convertible_to, vertex_id_t> && // sized_range && // sized_range && // basic_edge_weight_function, Compare, Combine> -// && bellman_visitor -[[nodiscard]] optional> bellman_ford_shortest_paths( - G& g, +[[nodiscard]] constexpr optional> bellman_ford_shortest_paths( + G&& g, const Sources& sources, Distances& distances, Predecessors& predecessor, WF&& weight = [](edge_reference_t uv) { return range_value_t(1); }, // default weight(uv) -> 1 - Visitor&& visitor = bellman_visitor_base(), + Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), Combine&& combine = plus>()) { using id_type = vertex_id_t; @@ -199,32 +163,48 @@ requires convertible_to, vertex_id_t> && // fmt::format("bellman_ford_shortest_paths: source vertex id '{}' is out of range", source)); } distances[static_cast(source)] = zero; // mark source as discovered + if constexpr (has_on_discover_vertex) { + visitor.on_discover_vertex({source, vertex_value(g, source)}); + } } + // Evalute the shortest paths + bool at_least_one_edge_relaxed = false; for (id_type k = 0; k < N; ++k) { - bool at_least_one_edge_relaxed = false; + at_least_one_edge_relaxed = false; for (auto&& [uid, vid, uv, w] : views::edgelist(g, weight)) { - visitor.on_examine_edge({uid, vid, uv}); + if constexpr (has_on_examine_edge) { + visitor.on_examine_edge({uid, vid, uv}); + } if (relax_target(uv, uid, w)) { at_least_one_edge_relaxed = true; - visitor.on_edge_relaxed({uid, vid, uv}); - } else + if constexpr (has_on_edge_relaxed) { + visitor.on_edge_relaxed({uid, vid, uv}); + } + } else if constexpr (has_on_edge_not_relaxed) { visitor.on_edge_not_relaxed({uid, vid, uv}); + } } if (!at_least_one_edge_relaxed) break; } // Check for negative weight cycles - for (auto&& [uid, vid, uv, w] : views::edgelist(g, weight)) { - if (compare(combine(distances[uid], w), distances[vid])) { - visitor.on_edge_not_minimized({uid, vid, uv}); - if constexpr (!is_same_v) { - predecessor[vid] = uid; // close the cycle + if (at_least_one_edge_relaxed) { + for (auto&& [uid, vid, uv, w] : views::edgelist(g, weight)) { + if (compare(combine(distances[uid], w), distances[vid])) { + if constexpr (!is_same_v) { + predecessor[vid] = uid; // close the cycle + } + if constexpr (has_on_edge_not_minimized) { + visitor.on_edge_not_minimized({uid, vid, uv}); + } + return return_type(uid); + } else { + if constexpr (has_on_edge_minimized) { + visitor.on_edge_minimized({uid, vid, uv}); + } } - return return_type(uid); - } else { - visitor.on_edge_minimized({uid, vid, uv}); } } @@ -235,7 +215,7 @@ template (edge_reference_t)>, - class Visitor = bellman_visitor_base, + class Visitor = empty_visitor, class Compare = less>, class Combine = plus>> requires is_arithmetic_v> && // @@ -243,18 +223,18 @@ requires is_arithmetic_v> && // sized_range && // sized_range && // basic_edge_weight_function, Compare, Combine> -// && bellman_visitor -[[nodiscard]] optional> bellman_ford_shortest_paths( - G& g, +[[nodiscard]] constexpr optional> bellman_ford_shortest_paths( + G&& g, const vertex_id_t source, Distances& distances, Predecessors& predecessor, WF&& weight = [](edge_reference_t uv) { return range_value_t(1); }, // default weight(uv) -> 1 - Visitor&& visitor = bellman_visitor_base(), + Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), Combine&& combine = plus>()) { return bellman_ford_shortest_paths(g, subrange(&source, (&source + 1)), distances, predecessor, weight, - forward(visitor), forward(compare), forward(combine)); + forward(visitor), forward(compare), + forward(combine)); } @@ -292,42 +272,41 @@ template (edge_reference_t)>, - class Visitor = bellman_visitor_base, + class Visitor = empty_visitor, class Compare = less>, class Combine = plus>> requires convertible_to, vertex_id_t> && // is_arithmetic_v> && // sized_range && // basic_edge_weight_function, Compare, Combine> -//&& bellman_visitor -[[nodiscard]] optional> bellman_ford_shortest_distances( - G& g, +[[nodiscard]] constexpr optional> bellman_ford_shortest_distances( + G&& g, const Sources& sources, Distances& distances, WF&& weight = [](edge_reference_t uv) { return range_value_t(1); }, // default weight(uv) -> 1 - Visitor&& visitor = bellman_visitor_base(), + Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), Combine&& combine = plus>()) { return bellman_ford_shortest_paths(g, sources, distances, _null_predecessors, forward(weight), - forward(visitor), forward(compare), forward(combine)); + forward(visitor), forward(compare), + forward(combine)); } template (edge_reference_t)>, - class Visitor = bellman_visitor_base, + class Visitor = empty_visitor, class Compare = less>, class Combine = plus>> requires is_arithmetic_v> && // sized_range && // basic_edge_weight_function, Compare, Combine> -//&& bellman_visitor -[[nodiscard]] optional> bellman_ford_shortest_distances( - G& g, +[[nodiscard]] constexpr optional> bellman_ford_shortest_distances( + G&& g, const vertex_id_t source, Distances& distances, WF&& weight = [](edge_reference_t uv) { return range_value_t(1); }, // default weight(uv) -> 1 - Visitor&& visitor = bellman_visitor_base(), + Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), Combine&& combine = plus>()) { return bellman_ford_shortest_paths(g, subrange(&source, (&source + 1)), distances, _null_predecessors, diff --git a/include/graph/algorithm/common_shortest_paths.hpp b/include/graph/algorithm/common_shortest_paths.hpp index 0521ef9..e39817e 100644 --- a/include/graph/algorithm/common_shortest_paths.hpp +++ b/include/graph/algorithm/common_shortest_paths.hpp @@ -74,13 +74,71 @@ constexpr void init_shortest_paths(Distances& distances, Predecessors& predecess iota(predecessors.begin(), predecessors.end(), 0); } +// +// Visitor concepts and classes +// + +// Vertex visitor concepts +template +concept has_on_initialize_vertex = // + requires(Visitor& v, vertex_descriptor, vertex_reference_t, void> vdesc) { + { v.on_initialize_vertex(vdesc) }; + }; +template +concept has_on_discover_vertex = // + requires(Visitor& v, vertex_descriptor, vertex_reference_t, void> vdesc) { + { v.on_discover_vertex(vdesc) }; + }; +template +concept has_on_examine_vertex = // + requires(Visitor& v, vertex_descriptor, vertex_reference_t, void> vdesc) { + { v.on_examine_vertex(vdesc) }; + }; +template +concept has_on_finish_vertex = // + requires(Visitor& v, vertex_descriptor, vertex_reference_t, void> vdesc) { + { v.on_finish_vertex(vdesc) }; + }; + +// Edge visitor concepts +template +concept has_on_examine_edge = // + requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + { v.on_examine_edge(edesc) }; + }; +template +concept has_on_edge_relaxed = // + requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + { v.on_edge_relaxed(edesc) }; + }; +template +concept has_on_edge_not_relaxed = // + requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + { v.on_edge_not_relaxed(edesc) }; + }; +template +concept has_on_edge_minimized = // + requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + { v.on_edge_minimized(edesc) }; + }; +template +concept has_on_edge_not_minimized = + requires(Visitor& v, edge_descriptor, true, edge_reference_t, void> edesc) { + { v.on_edge_not_minimized(edesc) }; + }; + +// Visitor structs and classes +struct empty_visitor {}; + /** * @brief An always-empty random_access_range. * * A unique range type that can be used at compile time to determine if predecessors need to * be evaluated. * - * This is not in the P1709 proposal. It's a quick hack to allow us to implement quickly. + * This is not in the P1709 proposal. It's an implementation detail that allows us to have + * a single implementation for the Dijkstra and Bellman-Ford shortest paths algorithms that + * can be used by other overloads. */ class _null_range_type : public std::vector { using T = size_t; diff --git a/include/graph/algorithm/dijkstra_shortest_paths.hpp b/include/graph/algorithm/dijkstra_shortest_paths.hpp index b4e0523..c446acf 100644 --- a/include/graph/algorithm/dijkstra_shortest_paths.hpp +++ b/include/graph/algorithm/dijkstra_shortest_paths.hpp @@ -26,43 +26,6 @@ namespace graph { -template -class dijkstra_visitor_base { - // Types -public: - using graph_type = G; - using vertex_desc_type = vertex_descriptor, vertex_reference_t, void>; - using sourced_edge_desc_type = edge_descriptor, true, edge_reference_t, void>; - - // Visitor Functions -public: - // vertex visitor functions - constexpr void on_initialize_vertex(const vertex_desc_type& vdesc) {} - constexpr void on_discover_vertex(const vertex_desc_type& vdesc) {} - constexpr void on_examine_vertex(const vertex_desc_type& vdesc) {} - constexpr void on_finish_vertex(const vertex_desc_type& vdesc) {} - - // edge visitor functions - constexpr void on_examine_edge(const sourced_edge_desc_type& edesc) {} - constexpr void on_edge_relaxed(const sourced_edge_desc_type& edesc) {} - constexpr void on_edge_not_relaxed(const sourced_edge_desc_type& edesc) {} -}; - -template -concept dijkstra_visitor = //is_arithmetic && - requires(Visitor& v, Visitor::vertex_desc_type& vdesc, Visitor::sourced_edge_desc_type& edesc) { - //typename Visitor::distance_type; - - { v.on_initialize_vertex(vdesc) }; - { v.on_discover_vertex(vdesc) }; - { v.on_examine_vertex(vdesc) }; - { v.on_finish_vertex(vdesc) }; - - { v.on_examine_edge(edesc) }; - { v.on_edge_relaxed(edesc) }; - { v.on_edge_not_relaxed(edesc) }; - }; - /** * @brief Dijkstra's single-source shortest paths algorithm with a visitor. * @@ -98,7 +61,7 @@ template (edge_reference_t)>, - class Visitor = dijkstra_visitor_base, + class Visitor = empty_visitor, class Compare = less>, class Combine = plus>> requires convertible_to, vertex_id_t> && // @@ -107,14 +70,13 @@ requires convertible_to, vertex_id_t> && // sized_range && // convertible_to, range_value_t> && basic_edge_weight_function, Compare, Combine> -// && dijkstra_visitor -void dijkstra_shortest_paths( - G& g, +constexpr void dijkstra_shortest_paths( + G&& g, const Sources& sources, Distances& distances, Predecessors& predecessor, WF&& weight = [](edge_reference_t uv) { return range_value_t(1); }, // default weight(uv) -> 1 - Visitor&& visitor = dijkstra_visitor_base(), + Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), Combine&& combine = plus>()) { using id_type = vertex_id_t; @@ -163,8 +125,10 @@ void dijkstra_shortest_paths( Queue queue(qcompare); // (The optimizer removes this loop if on_initialize_vertex() is empty.) - for (id_type uid = 0; uid < N; ++uid) { - visitor.on_initialize_vertex({uid, *find_vertex(g, uid)}); + if constexpr (has_on_initialize_vertex) { + for (id_type uid = 0; uid < N; ++uid) { + visitor.on_initialize_vertex({uid, *find_vertex(g, uid)}); + } } // Seed the queue with the initial vertice(s) @@ -174,18 +138,24 @@ void dijkstra_shortest_paths( } queue.push(source); distances[static_cast(source)] = zero; // mark source as discovered - visitor.on_discover_vertex({source, *find_vertex(g, source)}); + if constexpr (has_on_discover_vertex) { + visitor.on_discover_vertex({source, *find_vertex(g, source)}); + } } // Main loop to process the queue while (!queue.empty()) { const id_type uid = queue.top(); queue.pop(); - visitor.on_examine_vertex({uid, *find_vertex(g, uid)}); + if constexpr (has_on_examine_vertex) { + visitor.on_examine_vertex({uid, *find_vertex(g, uid)}); + } // Process all outgoing edges from the current vertex for (auto&& [vid, uv, w] : views::incidence(g, uid, weight)) { - visitor.on_examine_edge({uid, vid, uv}); + if constexpr (has_on_examine_edge) { + visitor.on_examine_edge({uid, vid, uv}); + } // Negative weights are not allowed for Dijkstra's algorithm if constexpr (is_signed_v) { @@ -201,8 +171,12 @@ void dijkstra_shortest_paths( if (is_neighbor_undiscovered) { // tree_edge if (was_edge_relaxed) { - visitor.on_edge_relaxed({uid, vid, uv}); - visitor.on_discover_vertex({vid, *find_vertex(g, vid)}); + if constexpr (has_on_edge_relaxed) { + visitor.on_edge_relaxed({uid, vid, uv}); + } + if constexpr (has_on_discover_vertex) { + visitor.on_discover_vertex({vid, *find_vertex(g, vid)}); + } queue.push(vid); } else { // This is an indicator of a bug in the algorithm and should be investigated. @@ -212,10 +186,14 @@ void dijkstra_shortest_paths( } else { // non-tree edge if (was_edge_relaxed) { - visitor.on_edge_relaxed({uid, vid, uv}); + if constexpr (has_on_edge_relaxed) { + visitor.on_edge_relaxed({uid, vid, uv}); + } queue.push(vid); // re-enqueue vid to re-evaluate its neighbors with a shorter path } else { - visitor.on_edge_not_relaxed({uid, vid, uv}); + if constexpr (has_on_edge_not_relaxed) { + visitor.on_edge_not_relaxed({uid, vid, uv}); + } } } } @@ -223,7 +201,9 @@ void dijkstra_shortest_paths( // Note: while we *think* we're done with this vertex, we may not be. If the graph is unbalanced // and another path to this vertex has a lower accumulated weight, we'll process it again. // A consequence is that examine_vertex could be called twice (or more) on the same vertex. - visitor.on_finish_vertex({uid, *find_vertex(g, uid)}); + if constexpr (has_on_finish_vertex) { + visitor.on_finish_vertex({uid, *find_vertex(g, uid)}); + } } // while(!queue.empty()) } @@ -231,7 +211,7 @@ template (edge_reference_t)>, - class Visitor = dijkstra_visitor_base, + class Visitor = empty_visitor, class Compare = less>, class Combine = plus>> requires is_arithmetic_v> && // @@ -239,14 +219,13 @@ requires is_arithmetic_v> && // sized_range && // convertible_to, range_value_t> && basic_edge_weight_function, Compare, Combine> -// && dijkstra_visitor -void dijkstra_shortest_paths( - G& g, +constexpr void dijkstra_shortest_paths( + G&& g, const vertex_id_t source, Distances& distances, Predecessors& predecessor, WF&& weight = [](edge_reference_t uv) { return range_value_t(1); }, // default weight(uv) -> 1 - Visitor&& visitor = dijkstra_visitor_base(), + Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), Combine&& combine = plus>()) { dijkstra_shortest_paths(g, subrange(&source, (&source + 1)), distances, predecessor, weight, @@ -283,20 +262,19 @@ template (edge_reference_t)>, - class Visitor = dijkstra_visitor_base, + class Visitor = empty_visitor, class Compare = less>, class Combine = plus>> requires convertible_to, vertex_id_t> && // sized_range && // is_arithmetic_v> && // basic_edge_weight_function, Compare, Combine> -//&& dijkstra_visitor -void dijkstra_shortest_distances( - G& g, +constexpr void dijkstra_shortest_distances( + G&& g, const Sources& sources, Distances& distances, WF&& weight = [](edge_reference_t uv) { return range_value_t(1); }, // default weight(uv) -> 1 - Visitor&& visitor = dijkstra_visitor_base(), + Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), Combine&& combine = plus>()) { dijkstra_shortest_paths(g, sources, distances, _null_predecessors, forward(weight), forward(visitor), @@ -306,19 +284,18 @@ void dijkstra_shortest_distances( template (edge_reference_t)>, - class Visitor = dijkstra_visitor_base, + class Visitor = empty_visitor, class Compare = less>, class Combine = plus>> requires is_arithmetic_v> && // sized_range && // basic_edge_weight_function, Compare, Combine> -//&& dijkstra_visitor -void dijkstra_shortest_distances( - G& g, +constexpr void dijkstra_shortest_distances( + G&& g, const vertex_id_t source, Distances& distances, WF&& weight = [](edge_reference_t uv) { return range_value_t(1); }, // default weight(uv) -> 1 - Visitor&& visitor = dijkstra_visitor_base(), + Visitor&& visitor = empty_visitor(), Compare&& compare = less>(), Combine&& combine = plus>()) { dijkstra_shortest_paths(g, subrange(&source, (&source + 1)), distances, _null_predecessors, forward(weight), diff --git a/tests/bellman_shortest_paths_tests.cpp b/tests/bellman_shortest_paths_tests.cpp index 15c8b69..c550199 100644 --- a/tests/bellman_shortest_paths_tests.cpp +++ b/tests/bellman_shortest_paths_tests.cpp @@ -31,35 +31,9 @@ using std::plus; using std::is_arithmetic_v; using std::optional; -using graph::index_adjacency_list; -using graph::edge_weight_function; -using graph::basic_edge_weight_function; - -using graph::vertex_t; -using graph::vertex_id_t; -using graph::vertex_edge_range_t; -using graph::edge_t; -using graph::edge_value_t; - -using graph::vertices; -using graph::find_vertex; -using graph::vertex_value; -using graph::edges; -using graph::target_id; -using graph::target; -using graph::edge_value; -using graph::num_vertices; -using graph::vertex_reference_t; -using graph::edge_reference_t; - +using namespace graph; using graph::views::vertexlist; -using graph::shortest_path_infinite_distance; -using graph::init_shortest_paths; -using graph::bellman_ford_shortest_paths; -using graph::bellman_ford_shortest_distances; -using graph::bellman_visitor_base; - using routes_volf_graph_traits = graph::container::vofl_graph_traits; using routes_volf_graph_type = graph::container::dynamic_adjacency_graph; @@ -117,6 +91,37 @@ auto to_string(const Predecessors& predecessors) { return pred; } +template +using visited_vertex_t = vertex_descriptor, vertex_reference_t, void>; +template +using visited_edge_t = edge_descriptor, true, edge_reference_t, void>; + +template +class empty_bellman_ford_visitor { + // Types +public: + using graph_type = G; + using vertex_desc_type = visited_vertex_t; + using sourced_edge_desc_type = visited_edge_t; + + // Visitor Functions +public: + empty_bellman_ford_visitor() = default; + + // vertex visitor functions + constexpr void on_initialize_vertex(vertex_desc_type& vdesc) {} + constexpr void on_discover_vertex(vertex_desc_type& vdesc) {} + constexpr void on_examine_vertex(vertex_desc_type& vdesc) {} + constexpr void on_finish_vertex(vertex_desc_type& vdesc) {} + + // edge visitor functions + constexpr void on_examine_edge(sourced_edge_desc_type& edesc) {} + constexpr void on_edge_relaxed(sourced_edge_desc_type& edesc) {} + constexpr void on_edge_not_relaxed(sourced_edge_desc_type& edesc) {} + constexpr void on_edge_minimized(sourced_edge_desc_type& edesc) {} + constexpr void on_edge_not_minimized(sourced_edge_desc_type& edesc) {} +}; + TEST_CASE("Bellman-Ford's Common Shortest Segments", "[csv][vofl][shortest][segments][bellman][common]") { init_console(); using G = routes_volf_graph_type; @@ -131,7 +136,7 @@ TEST_CASE("Bellman-Ford's Common Shortest Segments", "[csv][vofl][shortest][segm auto weight = [](edge_reference_t uv) -> double { return 1.0; }; #if 0 - //using V = graph::bellman_visitor_base; + //using V = graph::empty_visitor; //static_assert(graph::bellman_visitor, "Visitor doesn't match bellman_visitor requirements"); #endif @@ -433,7 +438,7 @@ TEST_CASE("Bellman-Ford's General Shortest Segments", "[csv][vofl][shortest][seg Predecessors predecessors(size(vertices(g))); init_shortest_paths(distance, predecessors); auto weight = [](edge_reference_t uv) -> double { return 1.0; }; - auto visitor = bellman_visitor_base(); + auto visitor = empty_visitor(); #if 0 using Visitor = decltype(visitor); @@ -574,7 +579,7 @@ TEST_CASE("Bellman-Ford's General Shortest Paths", "[csv][vofl][shortest][paths] vector> predecessors(size(vertices(g))); init_shortest_paths(distance, predecessors); auto weight = [&g](edge_reference_t uv) -> double { return edge_value(g, uv); }; - auto visitor = bellman_visitor_base(); + auto visitor = empty_visitor(); optional> cycle_vertex_id = bellman_ford_shortest_paths( g, frankfurt_id, distance, predecessors, weight, visitor, std::less(), std::plus()); @@ -702,7 +707,7 @@ TEST_CASE("Bellman-Ford's General Shortest Distances", "[csv][vofl][shortest][di vector distance(size(vertices(g))); init_shortest_paths(distance); auto weight = [&g](edge_reference_t uv) -> double { return edge_value(g, uv); }; - auto visitor = bellman_visitor_base(); + auto visitor = empty_visitor(); // This test case just tests that these will compile without error. The distances will be the same as before. //bellman_ford_shortest_distances(g, frankfurt_id, distance, std::less(), std::plus()); diff --git a/tests/dijkstra_shortest_paths_tests.cpp b/tests/dijkstra_shortest_paths_tests.cpp index 9bbebfa..4da2da2 100644 --- a/tests/dijkstra_shortest_paths_tests.cpp +++ b/tests/dijkstra_shortest_paths_tests.cpp @@ -30,35 +30,9 @@ using std::less; using std::plus; using std::is_arithmetic_v; -using graph::index_adjacency_list; -using graph::edge_weight_function; -using graph::basic_edge_weight_function; - -using graph::vertex_t; -using graph::vertex_id_t; -using graph::vertex_edge_range_t; -using graph::edge_t; -using graph::edge_value_t; - -using graph::vertices; -using graph::find_vertex; -using graph::vertex_value; -using graph::edges; -using graph::target_id; -using graph::target; -using graph::edge_value; -using graph::num_vertices; -using graph::vertex_reference_t; -using graph::edge_reference_t; - +using namespace graph; using graph::views::vertexlist; -using graph::shortest_path_infinite_distance; -using graph::init_shortest_paths; -using graph::dijkstra_shortest_paths; -using graph::dijkstra_shortest_distances; -using graph::dijkstra_visitor_base; - using routes_volf_graph_traits = graph::container::vofl_graph_traits; using routes_volf_graph_type = graph::container::dynamic_adjacency_graph; @@ -116,6 +90,58 @@ auto to_string(const Predecessors& predecessors) { return pred; } +template +using visited_vertex_t = vertex_descriptor, vertex_reference_t, void>; +template +using visited_edge_t = edge_descriptor, true, edge_reference_t, void>; + +template +class empty_dijkstra_visitor { + // Types +public: + using graph_type = G; + using vertex_desc_type = visited_vertex_t; + using sourced_edge_desc_type = visited_edge_t; + + // Visitor Functions +public: + empty_dijkstra_visitor() = default; + + // vertex visitor functions + constexpr void on_initialize_vertex(vertex_desc_type& vdesc) {} + constexpr void on_discover_vertex(vertex_desc_type& vdesc) {} + constexpr void on_examine_vertex(vertex_desc_type& vdesc) {} + constexpr void on_finish_vertex(vertex_desc_type& vdesc) {} + + // edge visitor functions + constexpr void on_examine_edge(sourced_edge_desc_type& edesc) {} + constexpr void on_edge_relaxed(sourced_edge_desc_type& edesc) {} + constexpr void on_edge_not_relaxed(sourced_edge_desc_type& edesc) {} + constexpr void on_edge_minimized(sourced_edge_desc_type& edesc) {} + constexpr void on_edge_not_minimized(sourced_edge_desc_type& edesc) {} +}; + +TEST_CASE("Visitor Concept") { + using G = routes_volf_graph_type; + auto&& g = load_graph(TEST_DATA_ROOT_DIR "germany_routes.csv"); + vertex_id_t u_id = 0; + vertex_reference_t u = *find_vertex(g, u_id); + + using Visitor = empty_dijkstra_visitor; + using VDesc = Visitor::vertex_desc_type; + //Visitor visitor; + VDesc u_desc{u_id, u}; + static_assert(has_on_initialize_vertex); + static_assert(has_on_discover_vertex); + static_assert(has_on_examine_vertex); + static_assert(has_on_finish_vertex); + static_assert(has_on_examine_edge); + static_assert(has_on_edge_relaxed); + static_assert(has_on_edge_not_relaxed); + static_assert(has_on_edge_minimized); + static_assert(has_on_edge_not_minimized); +} + TEST_CASE("Dijkstra's Common Shortest Segments", "[csv][vofl][shortest][segments][dijkstra][common]") { init_console(); using G = routes_volf_graph_type; @@ -130,7 +156,7 @@ TEST_CASE("Dijkstra's Common Shortest Segments", "[csv][vofl][shortest][segments auto weight = [](edge_reference_t uv) -> double { return 1.0; }; #if 0 - //using V = graph::dijkstra_visitor_base; + //using V = graph::empty_visitor; //static_assert(graph::dijkstra_visitor, "Visitor doesn't match dijkstra_visitor requirements"); #endif @@ -431,7 +457,7 @@ TEST_CASE("Dijkstra's General Shortest Segments", "[csv][vofl][shortest][segment Predecessors predecessors(size(vertices(g))); init_shortest_paths(distance, predecessors); auto weight = [](edge_reference_t uv) -> double { return 1.0; }; - auto visitor = dijkstra_visitor_base(); + auto visitor = empty_visitor(); #if 0 using Visitor = decltype(visitor); @@ -572,7 +598,7 @@ TEST_CASE("Dijkstra's General Shortest Paths", "[csv][vofl][shortest][paths][dij vector> predecessors(size(vertices(g))); init_shortest_paths(distance, predecessors); auto weight = [&g](edge_reference_t uv) -> double { return edge_value(g, uv); }; - auto visitor = dijkstra_visitor_base(); + auto visitor = empty_visitor(); dijkstra_shortest_paths(g, frankfurt_id, distance, predecessors, weight, visitor, std::less(), std::plus()); @@ -700,7 +726,7 @@ TEST_CASE("Dijkstra's General Shortest Distances", "[csv][vofl][shortest][distan vector distance(size(vertices(g))); init_shortest_paths(distance); auto weight = [&g](edge_reference_t uv) -> double { return edge_value(g, uv); }; - auto visitor = dijkstra_visitor_base(); + auto visitor = empty_visitor(); // 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, std::less(), std::plus()); diff --git a/tests/visitor_dijkstra_tests.cpp b/tests/visitor_dijkstra_tests.cpp index 79fbc8b..1fc77ec 100644 --- a/tests/visitor_dijkstra_tests.cpp +++ b/tests/visitor_dijkstra_tests.cpp @@ -41,7 +41,6 @@ using graph::edge_value; using graph::degree; using graph::find_vertex; using graph::find_vertex_edge; -using graph::experimental::dijkstra_visitor_base; using graph::experimental::dijkstra_with_visitor; using graph::experimental::init_shortest_paths; @@ -62,7 +61,7 @@ auto find_frankfurt(G&& g) { return find_city(g, "Frankf\xC3\xBCrt"); } -struct my_dijkstra_visitor : dijkstra_visitor_base { +struct my_dijkstra_visitor : graph::experimental::dijkstra_visitor_base { using G = routes_vol_graph_type; using base_t = dijkstra_visitor_base;