diff --git a/include/graph/algorithm/bellman_ford_shortest_paths.hpp b/include/graph/algorithm/bellman_ford_shortest_paths.hpp index 701a974..1d1e0ae 100644 --- a/include/graph/algorithm/bellman_ford_shortest_paths.hpp +++ b/include/graph/algorithm/bellman_ford_shortest_paths.hpp @@ -39,7 +39,7 @@ namespace graph { * * @param g The graph. * @param predecessor The predecessor range. - * @param cycle_vertex_id A vertex id in the negative weight cycle. IF no negative weight cycle exists + * @param cycle_vertex_id A vertex id in the negative weight cycle. If no negative weight cycle exists * then there will be no vertex id defined. * @param out_cycle The output iterator that the vertex ids in the cycle are output to. */ @@ -84,9 +84,9 @@ void find_negative_cycle(G& g, * @tparam Predecessors The predecessor random access range. * @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. + * Function calls are removed by the optimizer if not used. * @tparam Compare Comparison function for Distance values. Defaults to less. - * @tparam Combine Combine function for Distance values. Defaults to plus. + * @tparam Combine Combine function for Distance values. Defaults to plus. * * @return optional>, where no vertex id is returned if all edges were minimized. * If an edge was not minimized, the on_edge_not_minimized event is called and a vertex id @@ -120,7 +120,7 @@ requires convertible_to, vertex_id_t> && // using weight_type = invoke_result_t>; using return_type = optional>; - // relxing the target is the function of reducing the distance from the source to the target + // relaxing 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); @@ -139,14 +139,14 @@ requires convertible_to, vertex_id_t> && // if (size(distances) < size(vertices(g))) { throw std::out_of_range( - std::format("bellman_ford_shortest_paths: size of distances is {} is less than the number of vertices {}", + std::format("bellman_ford_shortest_paths: size of distances of {} is less than the number of vertices {}", size(distances), size(vertices(g)))); } if constexpr (!is_same_v) { if (size(predecessor) < size(vertices(g))) { throw std::out_of_range( - std::format("bellman_ford_shortest_paths: size of predecessor is {} is less than the number of vertices {}", + std::format("bellman_ford_shortest_paths: size of predecessor of {} is less than the number of vertices {}", size(predecessor), size(vertices(g)))); } } @@ -259,9 +259,9 @@ requires is_arithmetic_v> && // * @tparam Distances The distance random access range. * @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. + * Function calls are removed by the optimizer if not used. * @tparam Compare Comparison function for Distance values. Defaults to less. - * @tparam Combine Combine function for Distance values. Defaults to plus. + * @tparam Combine Combine function for Distance values. Defaults to plus. * * @return optional>, where no vertex id is returned if all edges were minimized. * If an edge was not minimized, the on_edge_not_minimized event is called and a vertex id diff --git a/include/graph/algorithm/dijkstra_clrs.hpp b/include/graph/algorithm/dijkstra_clrs.hpp index 71549e7..3723b7c 100644 --- a/include/graph/algorithm/dijkstra_clrs.hpp +++ b/include/graph/algorithm/dijkstra_clrs.hpp @@ -11,11 +11,6 @@ template concept edge_weight_function = // e.g. weight(uv) std::copy_constructible && is_arithmetic_v>>; - -//edge_weight_function && -//strict_weak_order, range_value_t> && -//assignable_from , invoke_result_t >, - template concept basic_edge_weight_function2 = // e.g. weight(uv) is_arithmetic_v> && @@ -67,8 +62,8 @@ constexpr auto print_types(Ts...) { * @tparam Distance The distance range type. * @tparam Predecessor The predecessor range type. * - * @param graph The graph. - * @param source The source vertex. + * @param g The graph. + * @param seed The source vertex. * @param distance The distance vector. * @param predecessor The predecessor vector. * @param weight The edge weight function. @@ -159,7 +154,7 @@ void dijkstra_clrs( WF&& weight = [](edge_identifier_t uv) { return range_value_t(1); }) // default weight(uv) -> 1 { using id_type = vertex_id_t; - using weight_type = invoke_result_t>; + using weight_type = invoke_result_t>; const id_type seed_id = vertex_id(g, seed); size_t N(num_vertices(g)); diff --git a/include/graph/algorithm/dijkstra_shortest_paths.hpp b/include/graph/algorithm/dijkstra_shortest_paths.hpp index a17df81..f83b998 100644 --- a/include/graph/algorithm/dijkstra_shortest_paths.hpp +++ b/include/graph/algorithm/dijkstra_shortest_paths.hpp @@ -29,9 +29,9 @@ namespace graph { /** * @brief Dijkstra's single-source shortest paths algorithm with a visitor. * - * The implementation was taken from boost::graph dijkstra_shortes_paths_no_init. + * The implementation was taken from boost::graph dijkstra_shortest_paths_no_init. * - * Complexity: O(V * E) + * Complexity: O((V + E) log V) * * Pre-conditions: * - 0 <= source < num_vertices(g) @@ -52,9 +52,9 @@ namespace graph { * @tparam Predecessors The predecessor random access range. * @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. + * Function calls are removed by the optimizer if not used. * @tparam Compare Comparison function for Distance values. Defaults to less. - * @tparam Combine Combine function for Distance values. Defaults to plus. + * @tparam Combine Combine function for Distance values. Defaults to plus. */ template ; using weight_type = invoke_result_t>; - // relxing the target is the function of reducing the distance from the source to the target + // relaxing 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 { const id_type vid = target_id(g, e); @@ -233,7 +233,7 @@ constexpr void dijkstra_shortest_paths( } /** - * @brief Shortest distnaces from a single source using Dijkstra's single-source shortest paths algorithm + * @brief Shortest distances from a single source using Dijkstra's single-source shortest paths algorithm * with a visitor. * * This is identical to dijkstra_shortest_paths() except that it does not require a predecessors range. @@ -254,9 +254,9 @@ constexpr void dijkstra_shortest_paths( * @tparam Distances The distance random access range. * @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. + * Function calls are removed by the optimizer if not used. * @tparam Compare Comparison function for Distance values. Defaults to less. - * @tparam Combine Combine function for Distance values. Defaults to plus. + * @tparam Combine Combine function for Distance values. Defaults to plus. */ template 0; } - friend vertex_id_type vertex_id(const compressed_graph_base& g, const_iterator ui) { + friend constexpr vertex_id_type vertex_id(const compressed_graph_base& g, const_iterator ui) { return static_cast(ui - g.row_index_.begin()); } @@ -881,7 +881,7 @@ class compressed_graph_base friend constexpr auto num_vertices(const compressed_graph_base& g, partition_id_type pid) { assert(static_cast(pid) < g.partition_.size() - 1); - g.partition_[pid + 1] - g.partition_[pid]; + return g.partition_[pid + 1] - g.partition_[pid]; } friend constexpr auto vertices(const compressed_graph_base& g, partition_id_type pid) { diff --git a/include/graph/container/dynamic_graph.hpp b/include/graph/container/dynamic_graph.hpp index 5051251..86fcf43 100644 --- a/include/graph/container/dynamic_graph.hpp +++ b/include/graph/container/dynamic_graph.hpp @@ -190,9 +190,9 @@ using dynamic_adjacency_graph = dynamic_graph; using vertex_type = dynamic_vertex; - using edge_type = dynamic_edge_value; + using edge_type = dynamic_edge; public: constexpr dynamic_edge_value(const value_type& value) : value_(value) {} @@ -815,7 +815,7 @@ class dynamic_vertex * No additional space is used if the edge value type (EV) or vertex value type (VV) is void. * * The partition function is intended to determine the partition id for a vertex id on constructors. - * It has been added to assure the same interface as the compresssed_graph, but is not implemented + * It has been added to assure the same interface as the compressed_graph, but is not implemented * at this time. * * @tparam EV The edge value type. If "void" is used no user value is stored on the edge and @@ -1283,10 +1283,10 @@ class dynamic_graph_base { friend constexpr vertices_type& vertices(dynamic_graph_base& g) { return g.vertices_; } friend constexpr const vertices_type& vertices(const dynamic_graph_base& g) { return g.vertices_; } - friend auto num_edges(const dynamic_graph_base& g) { return g.edge_count_; } - friend bool has_edge(const dynamic_graph_base& g) { return g.edge_count_ > 0; } + friend constexpr auto num_edges(const dynamic_graph_base& g) { return g.edge_count_; } + friend constexpr bool has_edge(const dynamic_graph_base& g) { return g.edge_count_ > 0; } - friend vertex_id_type vertex_id(const dynamic_graph_base& g, typename vertices_type::const_iterator ui) { + friend constexpr vertex_id_type vertex_id(const dynamic_graph_base& g, typename vertices_type::const_iterator ui) { return static_cast(ui - g.vertices_.begin()); } @@ -1308,7 +1308,7 @@ class dynamic_graph_base { friend constexpr auto num_vertices(const dynamic_graph_base& g, partition_id_type pid) { assert(static_cast(pid) < g.partition_.size() - 1); - g.partition_[pid + 1] - g.partition_[pid]; + return g.partition_[pid + 1] - g.partition_[pid]; } friend constexpr auto vertices(const dynamic_graph_base& g, partition_id_type pid) { @@ -1340,7 +1340,7 @@ class dynamic_graph_base { * used as a key to find a vertex in the vertices container. * * The partition function is intended to determine the partition id for a vertex id on constructors. - * It has been added to assure the same interface as the compresssed_graph, but is not implemented + * It has been added to assure the same interface as the compressed_graph, but is not implemented * at this time. * * @tparam EV @showinitializer =void The edge value type. If "void" is used no user value is stored on the edge @@ -1521,14 +1521,14 @@ class dynamic_graph : public dynamic_graph_base requires convertible_to, VId> - dynamic_graph(const ERng& erng, + dynamic_graph(GV&& gv, + const ERng& erng, const VRng& vrng, EProj eproj, VProj vproj, - GV&& gv, const PartRng& partition_start_ids = std::vector(), allocator_type alloc = allocator_type()) - : base_type(erng, vrng, eproj, vproj, partition_start_ids, alloc), value_(move(gv)) {} + : base_type(erng, vrng, eproj, vproj, partition_start_ids, alloc), value_(std::move(gv)) {} // max_vertex_id, erng, eproj, alloc @@ -1539,7 +1539,7 @@ class dynamic_graph : public dynamic_graph_base && // integral>; // -// Suport the use of edge_info for edgelist edge definitions +// Support the use of edge_info for edgelist edge definitions // (Only types and values needed from edge_info are used and there is no // explicit use of edge_info. This is deemed more flexible and no // functionality is compromised for it.) @@ -1319,9 +1319,9 @@ namespace _Source { * Complexity: O(1) * * Default implementation: *(begin(vertices(g)) + source_id(g, uv)), - # if @source_id(g,uv) is defined for G and random_access_range> + * if @source_id(g,uv) is defined for G and random_access_range> * - * Not all graphs support a source on an edge. The existance of @c source_id(g,uv) function + * Not all graphs support a source on an edge. The existence of @c source_id(g,uv) function * for a graph type G determines if it is considered a "sourced" edge or not. If it is, * @c source(g,uv) will also exist. * @@ -2561,7 +2561,7 @@ namespace _HasEdge { return has_edge(__g); // intentional ADL } else if constexpr (_Strat_id == _St_ref::_Auto_eval) { for (auto&& u : vertices(__g)) - if (empty(edges(__g, u))) + if (!empty(edges(__g, u))) return true; return false; } else { diff --git a/include/graph/detail/graph_using.hpp b/include/graph/detail/graph_using.hpp index d548f18..d97ee39 100644 --- a/include/graph/detail/graph_using.hpp +++ b/include/graph/detail/graph_using.hpp @@ -5,6 +5,10 @@ #include #include #include +#include +#include +#include +#include namespace graph { // Containers are not included to avoid potential conflicts: vector, list, string, etc. @@ -19,6 +23,8 @@ using std::forward_iterator_tag; using std::declval; using std::allocator; using std::allocator_traits; +using std::unique_ptr; +using std::shared_ptr; using std::iter_difference_t; using std::iter_value_t; @@ -40,7 +46,6 @@ using std::is_arithmetic_v; using std::is_convertible_v; using std::is_same_v; using std::is_invocable_v; -using std::is_arithmetic_v; using std::is_void_v; using std::is_lvalue_reference_v; using std::is_signed_v; @@ -52,6 +57,7 @@ using std::remove_reference_t; using std::remove_pointer_t; using std::remove_cvref_t; using std::invoke_result_t; +using std::decay_t; using std::false_type; using std::true_type; @@ -62,6 +68,7 @@ using std::convertible_to; using std::integral; using std::invocable; using std::regular_invocable; +using std::predicate; // range concepts using std::ranges::range; @@ -110,4 +117,6 @@ using std::ranges::empty; using std::tuple_cat; using std::max; using std::min; +using std::swap; +using std::is_sorted; } // namespace graph diff --git a/include/graph/graph.hpp b/include/graph/graph.hpp index 7a4c41d..dbfdb07 100644 --- a/include/graph/graph.hpp +++ b/include/graph/graph.hpp @@ -7,7 +7,12 @@ * @defgroup graph_views Views / Adaptors * @defgroup graph_containers Containers * @defgroup graph_construction Graph Construction - * @defgroup graph_io Graph I/O + * @defgroup graph_io # ifdef ENABLE_EDGELIST_RANGE +template +concept basic_edgelist_range = std::ranges::forward_range && std::negation_v>; +template +concept edgelist_range = std::ranges::forward_range && std::negation_v>; +# endif Graph I/O * @defgroup graph_utilities Utilities * * @defgroup graph_concepts Graph Concepts @@ -283,7 +288,7 @@ concept edgelist_range = ranges::forward_range && negation_v u) { /** * @ingroup graph_properties - * @brief Concept for the existance of the find_vertex(g,uid) function for graph G. + * @brief Concept for the existence of the find_vertex(g,uid) function for graph G. * * Returns true if find_vertex(g,uid) exists for graph G. * @@ -313,7 +318,7 @@ concept has_find_vertex = requires(G&& g, vertex_id_t uid) { /** * @ingroup graph_properties - * @brief Concept for the existance of the find_vertex_edge(g,uid,vid) function for graph G. + * @brief Concept for the existence of the find_vertex_edge(g,uid,vid) function for graph G. * * Returns true if find_vertex_edge(g,u,vid) and find_vertex_edge(g,uid,vid) exists for graph G. * @@ -327,7 +332,7 @@ concept has_find_vertex_edge = requires(G&& g, vertex_id_t uid, vertex_id_t uid, vertex_id_t v /** * @ingroup graph_properties - * @ brief Specializable to define that a graph type has unordered edges. + * @brief Specializable to define that a graph type has unordered edges. * * Override for a graph type where source_id and target_id are unordered * on an edge so views and algorithms know to choose the correct target @@ -362,7 +367,7 @@ concept has_contains_edge = requires(G&& g, vertex_id_t uid, vertex_id_t v * namespace my_namespace { * template * class my_graph { ... }; - * template class< T> + * template * class my_edge { int src_id; int tgt_id; ... }; * } * namespace graph { diff --git a/include/graph/views/breadth_first_search.hpp b/include/graph/views/breadth_first_search.hpp index 24d1a79..a346a8f 100644 --- a/include/graph/views/breadth_first_search.hpp +++ b/include/graph/views/breadth_first_search.hpp @@ -16,10 +16,10 @@ // for(auto&& [vid,uv,val] : edges_breadth_first_search(g,seed,evf)) // for(auto&& [vid,uv,val] : edges_breadth_first_search(g,seeds,evf)) // -// for(auto&& [uid,vid,uv] : sourced_edges_depth_first_search(g,seed)) -// for(auto&& [uid,vid,uv] : sourced_edges_depth_first_search(g,seeds)) -// for(auto&& [uid,vid,uv,val] : sourced_edges_depth_first_search(g,seed,evf)) -// for(auto&& [uid,vid,uv,val] : sourced_edges_depth_first_search(g,seeds,evf)) +// for(auto&& [uid,vid,uv] : sourced_edges_breadth_first_search(g,seed)) +// for(auto&& [uid,vid,uv] : sourced_edges_breadth_first_search(g,seeds)) +// for(auto&& [uid,vid,uv,val] : sourced_edges_breadth_first_search(g,seed,evf)) +// for(auto&& [uid,vid,uv,val] : sourced_edges_breadth_first_search(g,seeds,evf)) // // Given bfs is one of the breadth-first views above, the following functions are also available. // @@ -268,7 +268,7 @@ class vertices_breadth_first_search_view : public bfs_base { internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -387,7 +387,7 @@ class vertices_breadth_first_search_view : public bfs_base { internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -623,7 +623,7 @@ class edges_breadth_first_search_view : public bfs_base internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -960,7 +960,7 @@ namespace views { constexpr _St_ref_evf _Strat_ref_evf = _Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy; if constexpr (_Strat_ref_evf == _St_ref_evf::_Non_member) { - return edges_breadth_first_search(__g, seed, alloc); // intentional ADL + return edges_breadth_first_search(__g, seed, evf, alloc); // intentional ADL } else if constexpr (_Strat_ref_evf == _St_ref_evf::_Auto_eval) { return edges_breadth_first_search_view<_G, _EVF, false>(__g, seed, evf, alloc); // default impl } else { @@ -1113,7 +1113,7 @@ namespace views { constexpr _St_ref_evf _Strat_ref_evf = _Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy; if constexpr (_Strat_ref_evf == _St_ref_evf::_Non_member) { - return sourced_edges_breadth_first_search(__g, seed, alloc); // intentional ADL + return sourced_edges_breadth_first_search(__g, seed, evf, alloc); // intentional ADL } else if constexpr (_Strat_ref_evf == _St_ref_evf::_Auto_eval) { return edges_breadth_first_search_view<_G, _EVF, true>(__g, seed, evf, alloc); // default impl } else { diff --git a/include/graph/views/depth_first_search.hpp b/include/graph/views/depth_first_search.hpp index ba3e6f3..8f3b53e 100644 --- a/include/graph/views/depth_first_search.hpp +++ b/include/graph/views/depth_first_search.hpp @@ -253,7 +253,7 @@ class vertices_depth_first_search_view : public dfs_base { internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -362,7 +362,7 @@ class vertices_depth_first_search_view : public dfs_base { internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -587,7 +587,7 @@ class edges_depth_first_search_view : public dfs_base> requires(_Choice_ref<_G&, _Alloc>._Strategy != _St_ref::_None) @@ -750,7 +750,7 @@ namespace views { } /** - * @brief Single Source, Breadth First Search for vertices with VVF + * @brief Single Source, Depth First Search for vertices with VVF * * Complexity: O(V + E) * @@ -762,7 +762,7 @@ namespace views { * @param vvf The vertex value function. * @param seed The vertex id to start the search. * - * @return A forward range for the breadth first search. + * @return A forward range for the depth first search. */ template > requires(_Choice_ref_vvf<_G&, _VVF, _Alloc>._Strategy != _St_ref_vvf::_None) @@ -871,7 +871,7 @@ namespace views { public: /** - * @brief Single Source, Breadth First Search for edges + * @brief Single Source, Depth First Search for edges * * Complexity: O(V + E) * @@ -881,7 +881,7 @@ namespace views { * @param g A graph instance. * @param seed The vertex id to start the search. * - * @return A forward range for the breadth first search. + * @return A forward range for the depth first search. */ template > requires(_Choice_ref<_G&, _Alloc>._Strategy != _St_ref::_None) @@ -901,7 +901,7 @@ namespace views { } /** - * @brief Single Source, Breadth First Search for edges with EVF + * @brief Single Source, Depth First Search for edges with EVF * * Complexity: O(V + E) * @@ -913,7 +913,7 @@ namespace views { * @param evf The vertex value function. * @param seed The vertex id to start the search. * - * @return A forward range for the breadth first search. + * @return A forward range for the depth first search. */ template > requires(_Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy != _St_ref_evf::_None) @@ -923,7 +923,7 @@ namespace views { constexpr _St_ref_evf _Strat_ref_evf = _Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy; if constexpr (_Strat_ref_evf == _St_ref_evf::_Non_member) { - return edges_depth_first_search(__g, seed, alloc); // intentional ADL + return edges_depth_first_search(__g, seed, evf, alloc); // intentional ADL } else if constexpr (_Strat_ref_evf == _St_ref_evf::_Auto_eval) { return edges_depth_first_search_view<_G, _EVF, false>(__g, seed, evf, alloc); // default impl } else { @@ -1024,7 +1024,7 @@ namespace views { public: /** - * @brief Single Source, Breadth First Search for source edges. + * @brief Single Source, Depth First Search for source edges. * * Complexity: O(V + E) * @@ -1034,7 +1034,7 @@ namespace views { * @param g A graph instance. * @param seed The vertex id to start the search. * - * @return A forward range for the breadth first search. + * @return A forward range for the depth first search. */ template > requires(_Choice_ref<_G&, _Alloc>._Strategy != _St_ref::_None) @@ -1055,7 +1055,7 @@ namespace views { /** - * @brief Single Source, Breadth First Search for edges with EVF + * @brief Single Source, Depth First Search for edges with EVF * * Complexity: O(V + E) * @@ -1067,7 +1067,7 @@ namespace views { * @param evf The vertex value function. * @param seed The vertex id to start the search. * - * @return A forward range for the breadth first search. + * @return A forward range for the depth first search. */ template > requires(_Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy != _St_ref_evf::_None) @@ -1077,7 +1077,7 @@ namespace views { constexpr _St_ref_evf _Strat_ref_evf = _Choice_ref_evf<_G&, _EVF, _Alloc>._Strategy; if constexpr (_Strat_ref_evf == _St_ref_evf::_Non_member) { - return sourced_edges_depth_first_search(__g, seed, alloc); // intentional ADL + return sourced_edges_depth_first_search(__g, seed, evf, alloc); // intentional ADL } else if constexpr (_Strat_ref_evf == _St_ref_evf::_Auto_eval) { return edges_depth_first_search_view<_G, _EVF, true>(__g, seed, evf, alloc); // default impl } else { diff --git a/include/graph/views/edgelist.hpp b/include/graph/views/edgelist.hpp index dd8ae51..6d6ae35 100644 --- a/include/graph/views/edgelist.hpp +++ b/include/graph/views/edgelist.hpp @@ -240,7 +240,7 @@ class edgelist_iterator : public edgelist_iterator_base { internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -426,7 +426,7 @@ namespace views { && invocable>; #ifdef ENABLE_EDGELIST_RANGE - template + template concept _Has_edgelist_all_proj_ADL = edgelist_range // && invocable>; template @@ -568,13 +568,15 @@ namespace views { * Complexity: O(E) * * Default implementation: - * using iterator_type = edgelist_iterator; - * edgelist_view(iterator_type(g), end(vertices(g))); + * using iterator_type = edgelist_iterator; + * edgelist_view(iterator_type(g, evf), end(vertices(g))); * * @tparam G The graph type. + * @tparam EVF The edge value function type. * @param g A graph instance. + * @param evf The edge value function. * @return A range of edges in graph g where the range value_type is - * edge_info,false,vertex_reference_t,void> + * edge_info,true,edge_reference_t,invoke_result_t>> */ template requires(_Choice_all_evf<_G&, EVF>._Strategy != _St_adjlist_all::_None) @@ -583,7 +585,7 @@ namespace views { constexpr _St_adjlist_all _Strat_ref = _Choice_all_evf<_G&, EVF>._Strategy; if constexpr (_Strat_ref == _St_adjlist_all::_Non_member) { - return edgelist(__g); // intentional ADL + return edgelist(__g, evf); // intentional ADL } else if constexpr (_Strat_ref == _St_adjlist_all::_Auto_eval) { using iterator_type = edgelist_iterator<_G, EVF>; return edgelist_view<_G, EVF>(iterator_type(__g, evf), end(vertices(__g))); @@ -605,8 +607,10 @@ namespace views { * * @tparam G The graph type. * @param __g A graph instance. + * @param first First vertex id in range. + * @param last Last vertex id in range. * @return A range of edges in graph __g where the range value_type is - * edge_info,false,vertex_reference_t,void> + * edge_info,true,edge_reference_t,void> */ template requires(_Choice_idrng<_G&>._Strategy != _St_adjlist_idrng::_None) @@ -615,7 +619,7 @@ namespace views { constexpr _St_adjlist_idrng _Strat_ref = _Choice_idrng<_G&>._Strategy; if constexpr (_Strat_ref == _St_adjlist_idrng::_Non_member) { - return edgelist(__g); // intentional ADL + return edgelist(__g, first, last); // intentional ADL } else if constexpr (_Strat_ref == _St_adjlist_idrng::_Auto_eval) { using iterator_type = edgelist_iterator<_G, void>; return edgelist_view<_G, void>(iterator_type(__g, find_vertex(__g, first)), find_vertex(__g, last)); @@ -627,18 +631,22 @@ namespace views { // edgelist(g,uid,vid,evf) /** - * @brief Get the edgelist of all edges in a graph, with edge values. + * @brief Get the edgelist of edges in a graph within a vertex id range, with edge values. * * Complexity: O(E) * * Default implementation: - * using iterator_type = edgelist_iterator<_G, void>; - * edgelist_view<_G, void>(iterator_type(g), end(vertices(g))); + * using iterator_type = edgelist_iterator<_G, EVF>; + * edgelist_view<_G, EVF>(iterator_type(__g, evf), end(vertices(__g))); * * @tparam _G The graph type. - * @param g A graph instance. - * @return A range of edges in graph g where the range value_type is - * edge_info,false,vertex_reference_t<_G>,void> + * @tparam EVF The edge value function type. + * @param __g A graph instance. + * @param first First vertex id in range. + * @param last Last vertex id in range. + * @param evf The edge value function. + * @return A range of edges in graph __g where the range value_type is + * edge_info,true,edge_reference_t<_G>,invoke_result_t>> */ template requires(_Choice_idrng_evf<_G&, EVF>._Strategy != _St_adjlist_idrng::_None) @@ -648,10 +656,10 @@ namespace views { constexpr _St_adjlist_idrng _Strat_ref = _Choice_idrng_evf<_G&, EVF>._Strategy; if constexpr (_Strat_ref == _St_adjlist_idrng::_Non_member) { - return edgelist(__g); // intentional ADL + return edgelist(__g, first, last, evf); // intentional ADL } else if constexpr (_Strat_ref == _St_adjlist_idrng::_Auto_eval) { using iterator_type = edgelist_iterator<_G, EVF>; - return edgelist_view<_G, void>(iterator_type(__g, evf), end(vertices(__g))); // default impl + return edgelist_view<_G, EVF>(iterator_type(__g, evf), end(vertices(__g))); // default impl } else { static_assert(_AlwaysFalse<_G>, "edgelist(g,uid,vid,evf) is not defined and the default implementation cannot be evaluated"); diff --git a/include/graph/views/incidence.hpp b/include/graph/views/incidence.hpp index 5a4d976..26ed671 100644 --- a/include/graph/views/incidence.hpp +++ b/include/graph/views/incidence.hpp @@ -82,7 +82,7 @@ class incidence_iterator : _detail::_source_vertex internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -195,10 +195,10 @@ class incidence_iterator if constexpr (unordered_edge) { static_assert(sourced_adjacency_list); if (target_id(*g_, *iter_) != this->source_vertex_id()) { - value_.shadow_.source_id = source_id(*g_.*iter_); + value_.shadow_.source_id = source_id(*g_, *iter_); value_.shadow_.target_id = target_id(*g_, *iter_); } else { - value_.shadow_.source_id = target_id(*g_.*iter_); + value_.shadow_.source_id = target_id(*g_, *iter_); value_.shadow_.target_id = source_id(*g_, *iter_); } } else if constexpr (Sourced) { @@ -207,7 +207,7 @@ class incidence_iterator value_.shadow_.target_id = target_id(*g_, *iter_); } else { value_.shadow_.source_id = this->source_vertex_id(); - value_.target_id = target_id(*g_, *iter_); + value_.shadow_.target_id = target_id(*g_, *iter_); } } else { value_.shadow_.target_id = target_id(*g_, *iter_); @@ -348,13 +348,15 @@ namespace views { * Complexity: O(n) * * Default implementation: - * incidence_view<_G, false, void>(incidence_iterator<_G, false, void>(__g, uid), - * end(edges(__g, uid))); + * incidence_view<_G, false, EVF>(incidence_iterator<_G, false, EVF>(__g, uid, evf), + * end(edges(__g, uid))); * * @tparam G The graph type. + * @tparam EVF The edge value function type. * @param g A graph instance. * @param uid Vertex id. - * @return A range of the outgoing incidence edges. + * @param evf Edge value function. + * @return A range of the outgoing incidence edges with values. */ template requires(_Choice_id_evf<_G&, EVF>._Strategy != _St_id::_None) @@ -363,7 +365,7 @@ namespace views { constexpr _St_id _Strat_id = _Choice_id_evf<_G&, EVF>._Strategy; if constexpr (_Strat_id == _St_id::_Non_member) { - return incidence(__g, uid); // intentional ADL + return incidence(__g, uid, evf); // intentional ADL } else if constexpr (_Strat_id == _St_id::_Auto_eval) { // default impl return incidence_view<_G, false, EVF>(incidence_iterator<_G, false, EVF>(__g, uid, evf), diff --git a/include/graph/views/neighbors.hpp b/include/graph/views/neighbors.hpp index 4f54767..fdd5ea6 100644 --- a/include/graph/views/neighbors.hpp +++ b/include/graph/views/neighbors.hpp @@ -18,7 +18,7 @@ // Since uid is passed to neighbors(), there's no need to include Sourced versions of // incidence(). // basic_neighbors(g,uid) is the same as basic_incidence(g,uid). It is retained for -// symmatry and to avoid confusion. +// symmetry and to avoid confusion. // namespace graph { @@ -28,10 +28,10 @@ class neighbor_iterator; /** - * @brief Iterator for an neighbors range of edges for a vertex. + * @brief Iterator for a neighbors range of vertices for a vertex. * * @tparam G Graph type - * @tparam VVF Edge Value Function type + * @tparam VVF Vertex Value Function type */ template class neighbor_iterator @@ -87,7 +87,7 @@ class neighbor_iterator internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -98,11 +98,11 @@ class neighbor_iterator if constexpr (unordered_edge) { static_assert(sourced_adjacency_list); if (target_id(*g_, *iter_) != this->source_vertex_id()) { - value_.shadow_.source_id = source_id(*g_.*iter_); + value_.shadow_.source_id = source_id(*g_, *iter_); value_.shadow_.target_id = target_id(*g_, *iter_); value_.shadow_.target = const_cast(&target(*g_, *iter_)); } else { - value_.shadow_.source_id = target_id(*g_.*iter_); + value_.shadow_.source_id = target_id(*g_, *iter_); value_.shadow_.target_id = source_id(*g_, *iter_); value_.shadow_.target = const_cast(&source(*g_, *iter_)); } @@ -186,7 +186,7 @@ class neighbor_iterator internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -210,11 +210,11 @@ class neighbor_iterator if constexpr (unordered_edge) { static_assert(sourced_adjacency_list); if (target_id(*g_, *iter_) != this->source_vertex_id()) { - value_.shadow_.source_id = source_id(*g_.*iter_); + value_.shadow_.source_id = source_id(*g_, *iter_); value_.shadow_.target_id = target_id(*g_, *iter_); value_.shadow_.target = const_cast(&target(*g_, *iter_)); } else { - value_.shadow_.source_id = target_id(*g_.*iter_); + value_.shadow_.source_id = target_id(*g_, *iter_); value_.shadow_.target_id = source_id(*g_, *iter_); value_.shadow_.target = const_cast(&source(*g_, *iter_)); } @@ -366,18 +366,20 @@ namespace views { } /** - * @brief Get the outgoing neighbors edges of a vertex id and include an edge value in the result. + * @brief Get the outgoing neighbors edges of a vertex id and include a vertex value in the result. * * Complexity: O(n) * * Default implementation: - * neighbors_view<_G, false, void>(neighbor_iterator<_G, false, void>(__g, uid), - * end(edges(__g, uid))); + * neighbors_view<_G, false, VVF>(neighbor_iterator<_G, false, VVF>(__g, uid, vvf), + * end(edges(__g, uid))); * * @tparam G The graph type. + * @tparam VVF The vertex value function type. * @param g A graph instance. * @param uid Vertex id. - * @return A range of the outgoing neighbors edges. + * @param vvf Vertex value function. + * @return A range of the outgoing neighbors edges with values. */ template requires(_Choice_id_vvf<_G&, VVF>._Strategy != _St_id::_None) @@ -386,7 +388,7 @@ namespace views { constexpr _St_id _Strat_id = _Choice_id_vvf<_G&, VVF>._Strategy; if constexpr (_Strat_id == _St_id::_Non_member) { - return neighbors(__g, uid); // intentional ADL + return neighbors(__g, uid, vvf); // intentional ADL } else if constexpr (_Strat_id == _St_id::_Auto_eval) { // default impl return neighbors_view<_G, false, VVF>(neighbor_iterator<_G, false, VVF>(__g, uid, vvf), end(edges(__g, uid))); diff --git a/include/graph/views/vertexlist.hpp b/include/graph/views/vertexlist.hpp index 4ca20cd..79bdcd7 100644 --- a/include/graph/views/vertexlist.hpp +++ b/include/graph/views/vertexlist.hpp @@ -63,7 +63,7 @@ class vertexlist_iterator { internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -145,7 +145,7 @@ class vertexlist_iterator { internal_value(const internal_value& rhs) : shadow_(rhs.shadow_) {} internal_value() : shadow_{} {} ~internal_value() {} - internal_value& operator=(const internal_value& rhs) { value_.shadow = rhs.value_.shadow; } + internal_value& operator=(const internal_value& rhs) { shadow_ = rhs.shadow_; return *this; } }; public: @@ -163,8 +163,7 @@ class vertexlist_iterator { public: constexpr reference operator*() const { value_.shadow_.vertex = &*iter_; - if constexpr (!is_void_v) - value_.shadow_.value = this->value_fn_(*iter_); + // vertex_value_type is void, so no value assignment needed return value_.value_; } @@ -328,16 +327,15 @@ namespace views { public: /** - * @brief The number of outgoing edges of a vertex. + * @brief Get a range of vertices for a graph. * * Complexity: O(1) * - * Default implementation: size(edges(g, u)) + * Default implementation: vertexlist_view<_G, void>(vertices(g)) * * @tparam G The graph type. * @param g A graph instance. - * @param u A vertex instance. - * @return The number of outgoing edges of vertex u. + * @return A range of vertices with their ids. */ template requires(_Choice_all<_G>._Strategy != _St_all::_None) @@ -354,6 +352,19 @@ namespace views { } } + /** + * @brief Get a range of vertices for a graph with values. + * + * Complexity: O(1) + * + * Default implementation: Uses vertexlist_iterator with vertex value function + * + * @tparam G The graph type. + * @tparam VVF The vertex value function type. + * @param g A graph instance. + * @param vvf Vertex value function. + * @return A range of vertices with their ids and values. + */ template requires(_Choice_vvf_all<_G, VVF>._Strategy != _St_all::_None) [[nodiscard]] constexpr auto operator()(_G&& __g, const VVF& vvf) const @@ -406,6 +417,21 @@ namespace views { } } + /** + * @brief Get a range of vertices for a graph from a vertex range with values. + * + * Complexity: O(1) + * + * Default implementation: Uses vertexlist_iterator with vertex range and value function + * + * @tparam G The graph type. + * @tparam Rng The vertex range type. + * @tparam VVF The vertex value function type. + * @param g A graph instance. + * @param vr A range of vertices. + * @param vvf Vertex value function. + * @return A range of vertices with their ids and values. + */ template requires(_Choice_vvf_rng<_G, Rng, VVF>._Strategy != _St_rng::_None) [[nodiscard]] constexpr auto operator()(_G&& __g, Rng&& vr, const VVF& vvf) const