From f181fd93560317f385ce33fe9a57b1ea8a4821cc Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sat, 27 Jan 2024 13:03:55 -0500 Subject: [PATCH 1/3] Refactor concepts to reduce redundancy Created sourced_targeted_edge and target_edge_range Relocated property concepts at the beginning to be with the others --- include/graph/graph.hpp | 191 +++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 98 deletions(-) diff --git a/include/graph/graph.hpp b/include/graph/graph.hpp index 5e63849..7fac8d5 100644 --- a/include/graph/graph.hpp +++ b/include/graph/graph.hpp @@ -58,63 +58,12 @@ # define GRAPH_HPP namespace std::graph { -/** - * @ingroup graph_properties - * @brief Override for an edge type where source and target are unordered - * - * For instance, given: - * @code - * vertex_iterator_t ui = ...; - * for(auto&& uv : edges(g,*ui)) ... - * @endcode - * if(source_id(g,u) != vertex_id(ui)) then target_id(g,u) == vertex_id(ui) - * - * Example: - * @code - * namespace my_namespace { - * template - * class my_graph { ... }; - * } - * namespace std::graph { - * template - * inline constexpr bool is_undirected_edge_v>> = true; - * } - * @endcode - * - * @tparam name E The edge type with unordered source and target - */ -template -inline constexpr bool is_undirected_edge_v = false; // // graph concepts // -/** - * @ingroup graph_concepts - * @brief Concept for a range of vertices. - * - * A vertex range must be a sized forward range, at a minimum. - * - * Required functions that must also be defined include - * * @c vertices(g) that returns a range of vertices of a graph. - * * @c vertex_id(g,ui) that returns a vertex id for a graph and vertex iterator of the graph. - * - * @tparam G The graph type. - */ -template -concept _common_vertex_range = ranges::sized_range> && // - requires(G&& g, vertex_iterator_t ui) { vertex_id(g, ui); }; - -template -concept vertex_range = _common_vertex_range && ranges::forward_range>; - -template -concept index_vertex_range = _common_vertex_range && // - ranges::random_access_range> && integral>; - - /** * @ingroup graph_concepts * @brief Concept for a targeted edge. @@ -140,52 +89,53 @@ concept targeted_edge = requires(G&& g, edge_reference_t uv) { * @tparam E The edge type. */ template -concept sourced_edge = requires(G&& g, E& uv) { +concept sourced_edge = requires(G&& g, edge_reference_t uv) { source_id(g, uv); source(g, uv); }; -/** - * @brief Type trait to determine if an edge is sourced. - * - * Use @c is_sourced_edge::value to deterine if the edge is sourced. - * - * @tparam G The graph type. - * @tparam E The edge type. -*/ template -struct is_sourced_edge : public integral_constant> {}; +concept sourced_targeted_edge = targeted_edge && sourced_edge && // + requires(G&& g, edge_reference_t uv) { edge_id(g, uv); }; + /** - * @brief Type trait helper to determine if an edge is sourced. + * @ingroup graph_concepts + * @brief Concept for a basic range of vertices. * - * Use @c is_sourced_edge_v to deterine if the edge is sourced. + * A vertex range must be a sized range, at a minimum. + * + * Required functions that must also be defined include + * * @c vertices(g) that returns a range of vertices of a graph (via vertex_range_t) + * * @c vertex_id(g,ui) that returns a vertex id for a graph and vertex iterator of the graph. * * @tparam G The graph type. - * @tparam E The edge type. -*/ -template -inline constexpr bool is_sourced_edge_v = is_sourced_edge::value; + */ +template +concept _basic_vertex_range = ranges::sized_range> && // + requires(G&& g, vertex_iterator_t ui) { vertex_id(g, ui); }; + +template +concept vertex_range = _basic_vertex_range> && // + ranges::forward_range>; + +template +concept index_vertex_range = _basic_vertex_range> && // + ranges::random_access_range> && integral>; /** * @ingroup graph_concepts - * @brief Concept for an adjacency list graph. - * - * An index_adjacency list requires that the vertices range is a forward range, it has a targeted edge, - * and functionedges(g,uid) are defined. - * - * @tparam G The graph type. + * @brief Concept for a target edge range */ template -concept basic_adjacency_list = vertex_range && targeted_edge> && requires(G&& g, vertex_id_t& uid) { +concept target_edge_range = requires(G&& g, vertex_id_t uid, vertex_reference_t u) { { edges(g, uid) } -> ranges::forward_range; + { edges(g, u) } -> ranges::forward_range; }; -template -concept basic_index_adjacency_list = - index_vertex_range && targeted_edge> && requires(G&& g, vertex_id_t& uid) { - { edges(g, uid) } -> ranges::forward_range; - }; +//template +//concept basic_adjacency_list = targeted_edge> && edge_functions; + /** * @ingroup graph_concepts @@ -196,35 +146,30 @@ concept basic_index_adjacency_list = * @tparam G The graph type. */ template -concept adjacency_list = basic_adjacency_list && requires(G&& g, vertex_reference_t u) { - { edges(g, u) } -> ranges::forward_range; -}; +concept adjacency_list = vertex_range && // + target_edge_range && // + targeted_edge>; template -concept index_adjacency_list = basic_index_adjacency_list && requires(G&& g, vertex_reference_t u) { - { edges(g, u) } -> ranges::forward_range; -}; - -//template -//concept index_adjacency_list = adjacency_list && // -// ranges::random_access_range> && integral>; - - -// !is_same_v, vertex_edge_range_t> -// CSR fails this condition b/c row_index & col_index are both index_vectors; common? +concept index_adjacency_list = index_vertex_range && // + target_edge_range && // + targeted_edge>; /** * @ingroup graph_concepts - * @brief Concept for a sourced adjacency list. + * @brief Concept for an adjacency list graph with source_id(g,uv) * - * A sourced adjacency list extends the adjacency list by requiring that edges are souced edges - * and edge_id(g,uv) is defined. + * An adjacency list extends basic_adjacency_list to include function edges(g,u) for vertex reference u. * * @tparam G The graph type. */ template -concept sourced_adjacency_list = - adjacency_list && sourced_edge> && requires(G&& g, edge_reference_t uv) { edge_id(g, uv); }; +concept sourced_adjacency_list = adjacency_list && // + sourced_targeted_edge>; + +template +concept index_sourced_adjacency_list = index_adjacency_list && // + sourced_targeted_edge>; # ifdef ENABLE_EDGELIST_RANGE @@ -238,6 +183,28 @@ concept edgelist_range = ranges::forward_range && negation_v::value to deterine if the edge is sourced. + * + * @tparam G The graph type. + * @tparam E The edge type. +*/ +template +struct is_sourced_edge : public integral_constant> {}; + +/** + * @brief Type trait helper to determine if an edge is sourced. + * + * Use @c is_sourced_edge_v to deterine if the edge is sourced. + * + * @tparam G The graph type. + * @tparam E The edge type. +*/ +template +inline constexpr bool is_sourced_edge_v = is_sourced_edge::value; + /** * @ingroup graph_properties * @brief Concept for the existance of degree function for graph G. @@ -296,6 +263,34 @@ concept has_contains_edge = requires(G&& g, vertex_id_t uid, vertex_id_t v }; +/** + * @ingroup graph_properties + * @brief Override for an edge type where source and target are unordered + * + * For instance, given: + * @code + * vertex_iterator_t ui = ...; + * for(auto&& uv : edges(g,*ui)) ... + * @endcode + * if(source_id(g,u) != vertex_id(ui)) then target_id(g,u) == vertex_id(ui) + * + * Example: + * @code + * namespace my_namespace { + * template + * class my_graph { ... }; + * } + * namespace std::graph { + * template + * inline constexpr bool is_undirected_edge_v>> = true; + * } + * @endcode + * + * @tparam name E The edge type with unordered source and target + */ +template +inline constexpr bool is_undirected_edge_v = false; + /** * @ingroup graph_properties * @ brief Specializable to define that a graph type has unordered edges. From 9754d1bbf98417bb848cf2ca0061749bc93916d6 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sat, 27 Jan 2024 13:46:59 -0500 Subject: [PATCH 2/3] Add "basic" adjancy list concepts --- include/graph/graph.hpp | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/include/graph/graph.hpp b/include/graph/graph.hpp index 7fac8d5..79aa1c4 100644 --- a/include/graph/graph.hpp +++ b/include/graph/graph.hpp @@ -111,16 +111,16 @@ concept sourced_targeted_edge = targeted_edge && sourced_edge && // * * @tparam G The graph type. */ -template -concept _basic_vertex_range = ranges::sized_range> && // - requires(G&& g, vertex_iterator_t ui) { vertex_id(g, ui); }; +template // (exposition only) +concept _common_vertex_range = ranges::sized_range> && // + requires(G&& g, vertex_iterator_t ui) { vertex_id(g, ui); }; template -concept vertex_range = _basic_vertex_range> && // +concept vertex_range = _common_vertex_range> && // ranges::forward_range>; template -concept index_vertex_range = _basic_vertex_range> && // +concept index_vertex_range = _common_vertex_range> && // ranges::random_access_range> && integral>; /** @@ -128,8 +128,12 @@ concept index_vertex_range = _basic_vertex_range> && // * @brief Concept for a target edge range */ template -concept target_edge_range = requires(G&& g, vertex_id_t uid, vertex_reference_t u) { +concept basic_target_edge_range = requires(G&& g, vertex_id_t uid) { { edges(g, uid) } -> ranges::forward_range; +}; + +template +concept target_edge_range = basic_target_edge_range && requires(G&& g, vertex_reference_t u) { { edges(g, u) } -> ranges::forward_range; }; @@ -145,6 +149,16 @@ concept target_edge_range = requires(G&& g, vertex_id_t uid, vertex_reference * * @tparam G The graph type. */ +template +concept basic_adjacency_list = vertex_range && // + basic_target_edge_range && // + targeted_edge>; + +template +concept basic_index_adjacency_list = index_vertex_range && // + basic_target_edge_range && // + targeted_edge>; + template concept adjacency_list = vertex_range && // target_edge_range && // @@ -163,6 +177,14 @@ concept index_adjacency_list = index_vertex_range && // * * @tparam G The graph type. */ +template +concept basic_sourced_adjacency_list = basic_adjacency_list && // + sourced_targeted_edge>; + +template +concept basic_index_sourced_adjacency_list = basic_index_adjacency_list && // + sourced_targeted_edge>; + template concept sourced_adjacency_list = adjacency_list && // sourced_targeted_edge>; From 028d964b624a2c57b4f5162fe179b8367b5786e7 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sat, 27 Jan 2024 14:19:21 -0500 Subject: [PATCH 3/3] Replace concepts summary table with code Added sourced_targeted_edge & target_edge_range Make sure all combinations of {basic, sourced, index} combinations exist for adj list concepts. --- include/graph/graph.hpp | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/include/graph/graph.hpp b/include/graph/graph.hpp index 79aa1c4..283f40d 100644 --- a/include/graph/graph.hpp +++ b/include/graph/graph.hpp @@ -120,8 +120,9 @@ concept vertex_range = _common_vertex_range> && // ranges::forward_range>; template -concept index_vertex_range = _common_vertex_range> && // - ranges::random_access_range> && integral>; +concept index_vertex_range = _common_vertex_range> && // + ranges::random_access_range> && // + integral>; /** * @ingroup graph_concepts @@ -133,9 +134,10 @@ concept basic_target_edge_range = requires(G&& g, vertex_id_t uid) { }; template -concept target_edge_range = basic_target_edge_range && requires(G&& g, vertex_reference_t u) { - { edges(g, u) } -> ranges::forward_range; -}; +concept target_edge_range = basic_target_edge_range && // + requires(G&& g, vertex_reference_t u) { + { edges(g, u) } -> ranges::forward_range; + }; //template //concept basic_adjacency_list = targeted_edge> && edge_functions; @@ -145,7 +147,7 @@ concept target_edge_range = basic_target_edge_range && requires(G&& g, vertex * @ingroup graph_concepts * @brief Concept for an adjacency list graph. * - * An adjacency list extends basic_adjacency_list to include function edges(g,u) for vertex reference u. + * An basic_adjacency_list list defines the minimal adjacency list concepts without a vertex object. * * @tparam G The graph type. */ @@ -160,37 +162,37 @@ concept basic_index_adjacency_list = index_vertex_range && // targeted_edge>; template -concept adjacency_list = vertex_range && // - target_edge_range && // - targeted_edge>; +concept basic_sourced_adjacency_list = basic_adjacency_list && // + sourced_targeted_edge>; template -concept index_adjacency_list = index_vertex_range && // - target_edge_range && // - targeted_edge>; +concept basic_sourced_index_adjacency_list = basic_index_adjacency_list && // + sourced_targeted_edge>; + /** * @ingroup graph_concepts - * @brief Concept for an adjacency list graph with source_id(g,uv) + * @brief Concept for an adjacency list graph. * * An adjacency list extends basic_adjacency_list to include function edges(g,u) for vertex reference u. * * @tparam G The graph type. */ template -concept basic_sourced_adjacency_list = basic_adjacency_list && // - sourced_targeted_edge>; +concept adjacency_list = vertex_range && // + target_edge_range && // + targeted_edge>; template -concept basic_index_sourced_adjacency_list = basic_index_adjacency_list && // - sourced_targeted_edge>; - +concept index_adjacency_list = index_vertex_range && // + target_edge_range && // + targeted_edge>; template concept sourced_adjacency_list = adjacency_list && // sourced_targeted_edge>; template -concept index_sourced_adjacency_list = index_adjacency_list && // +concept sourced_index_adjacency_list = index_adjacency_list && // sourced_targeted_edge>;