Skip to content

Commit

Permalink
Merge pull request #95 from stdgraph/cpo
Browse files Browse the repository at this point in the history
Convert CPOs from tag_invoke
  • Loading branch information
pratzl committed Feb 11, 2024
2 parents edf5093 + 3d058e7 commit 7108cad
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 506 deletions.
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,5 @@ is being considered, subject to the size of the proposal and other priorities.
Committee ([WG21](https://isocpp.org/std/the-committee)).
- Bob Steagal for his [gcc-builder & clang-builder scripts](https://github.com/BobSteagall)
- Jason Turner for his [cpp_starter_project](https://github.com/lefticus/cpp_starter_project)
- René Ferdinand Rivera Morell for his [duck_invoke](https://github.com/bfgroup/duck_invoke), an implementation
of tag_invoke ([P1895](https://wg21.link/P1895)) that works for both gcc and msvc. Minor modifications have
been made so it it in the std namespace.
- Vincent La for his [cvs-parser](https://github.com/vincentlaucsb/csv-parser)
- The ISO C++ Standards Committee (WG21) for [C++](http://eel.is/c++draft/)
82 changes: 49 additions & 33 deletions ToDo.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
## Open

### ToDo
- Graph API
- Graph Container Interface (GCI)
- [ ] Common
- [ ] Apply tag_invoke design in P2300 [wait to see if we want to use tag_invoke]
- [ ] Use Neibloid style for all CPOs
- [x] Ranges
- [ ] Concepts and type_traits
- [x] graph: adjacency_list, sourced_adjacency_list, adjacency_matrix, undirected_incidence_graph
- [x] graph: adjacency_list, sourced_adjacency_list, adjacency_matrix
- [ ] **view concepts: vertex_view, edge_view, neighbor_view returned from graph views**
- [ ] **function concepts: VVF, EVF**
- [ ] Edgelist concept(s)
- [ ] Graph API
- [ ] depth() CPO? bfs, dfs. size() is different; depth for BFS takes extra work and is diff concept.
- [x] cancel() CPO? bfs, dfs: no, member only
Expand All @@ -37,24 +38,29 @@
- [x] view functions should be in std::graph::view
- [ ] add range overloads to appropriate views (DFS, BFS, topo_sort, etc.)
- [ ] vertexlist
- [ ] Copy VVF to iterator (not reference)
- [ ] Accept VVF(g,u) & allow vertex_value?
- [ ] Use VVF&& instead of const VVF&
- [x] verify it is a std\::ranges\::view<>
- [x] Implement vertexlist(g,vr)
- [x] Implement vertexlist(g,vr,vvf)
- [ ] Implement basic_vertexlist(g,vr)
- [ ] Implement basic_vertexlist(g,vr,vvf)
- [ ] Extend support for vvf(uid), in addition to vvf(u)
- [ ] incidence
- [ ] Copy EVF to iterator (not reference)
- [ ] Use EVF&& instead of const EVF&
- [ ] unit tests for undirected_graph\<G\>
- [x] verify it is a std\::ranges\::view<>
- [ ] neighbors
- [ ] Copy VVF to iterator (not reference)
- [ ] Use VVF&& instead of const VVF&
- [ ] Extend support for vvf(uid), in addition to vvf(u)
- [ ] unit tests for undirected_graph\<G\>
- [x] verify it is a std\::ranges\::view<>
- [ ] Implement basic_neighbors(g,vr)
- [ ] Implement basic_neighbors(g,vr,vvf)
- [ ] edgelist
- [ ] Copy EVF to iterator (not reference)
- [ ] Use EVF&& instead of const EVF&
- [ ] unit tests for undirected_graph\<G\>
- [x] verify it is a std\::ranges\::view<>
- [x] vertices_depth_first_search_view
- [x] vertices_dfs_view
- [x] validate results & add unit tests
- [x] support Cancelable
- [x] support VVF
Expand All @@ -63,8 +69,8 @@
- [x] verify it is a std::ranges::view<>
- [x] create CPOs
- [x] Use real_target_id(g,uv,src) for both directed_incidence_graph & undirected_incidence_graph to consolidate code
- [x] Add allocator parameter & use with _colors
- [x] edges_depth_first_search_view
- [ ] basic_vertices_dfs_view
- [x] edges_dfs_view
- [x] validate results & add unit tests
- [x] support Cancelable
- [x] support EVF
Expand All @@ -73,32 +79,43 @@
- [x] support begin, end, depth/size, empty, swap free functions
- [x] verify it is a std::ranges::view<>
- [x] create CPOs: edges, sourced_edges
- [x] Use real_target_id(g,uv,src) for both directed_incidence_graph & undirected_incidence_graph to consolidate code
- [x] Add allocator parameter & use with _colors
- [ ] **bfs_vertex_range**
- [ ] **bfs_edge_range**
- [ ] topological_sort_vertex_range
- [ ] topological_sort_edge_range
- [ ] basic__edges_dfs_view
- [ ] vertices_bfs_view
- [ ] edges_bfs_view
- [ ] topological_sort_vertices_view
- [ ] topological_sort_edges_view
- [ ] allow options to exclude vertex/edge reference on results (Andrew)
- [ ] Common
- [ ] Add depth(search) CPO for dfs, bfs, topo_sort
- [ ] Add size(search) CPO for dfs, bfs, topo_sort
- Algorithms
- [ ] Common
- [ ] Add depth(search) CPO for dfs, bfs, topo_sort
- [ ] Add size(search) CPO for dfs, bfs, topo_sort
- [ ] Algorithms (full & simplified/book)
- [ ] Shortest Paths
- [x] Dijkstra book (impl from AndrewL)
- [ ] **dijkstra_shortest_path**
- [ ] **bellman_ford_shortest_path**
- [x] Shortest Paths
- [x] Dijkstra_clrs (book impl from AndrewL)
- [x] dijkstra_shortest_path
- [x] bellman_ford_shortest_path
- [ ] Clustering
- [ ] Triangle counting
- [ ] Communities
- [ ] Label propagation
- [ ] Components
- [ ] connected_components
- [ ] strongly_connected_components
- [ ] strongly_connected_components (Kosaraju & Tarjan)
- [ ] biconnected_components
- [ ] articulation_points
- [ ] Directed Acyclic Graphs
- [ ] Topological Sort, Single Source
- [ ] Maximal Independent Set
- [ ] Maximal Independent Set
- [ ] Link Analysis
- [ ] Jaccard Coefficient
- [ ] Minimal Spanning Tree
- [ ] Kruskal Minimum Spanning Tree
- [ ] Prim Minimal Spanning Tree
- [ ] Others to consider
- [ ] page_rank; not a good candidate for the standard because there are too many options; better as an example
- [ ] Edgelist algorithms (prove design; not for P1709)
- [ ] Maximal Independent Set (edgelist)
- [ ] Union Find (edgelist)
- [ ] page_rank
- [ ] betweenness_centrality
- [ ] triangle_count
- [ ] Minimum spanning tree
Expand All @@ -118,16 +135,13 @@
- [ ] validate & add unit tests
- Graph Containers (data structures)
- [x] compressed_graph (for P1709)
- [ ] **Use concepts for load, load_edges, load_vertices, ctors**
- [x] Support VV=void
- [x] Support EV=void
- [x] Use copyable_vertex & copyable_edge concepts in graph ctors, load functions
- [x] Add ctor with initializer_list for simple demo
- [ ] Implement load_graph(), load_vertices(), load_edges() CPOs (define concepts)
- [ ] dynamic_graph
- [ ] **Use concepts for load, load_edges, load_vertices, ctors**
- [ ] Implement load_graph(), load_vertices(), load_edges() CPOs (define concepts)
- [ ] test push_or_insert() to assure it does the right thing for const, value, &, &&, ...
- [ ] graph with map-based vertices (requires different algorithm impl)
- [x] Use copyable_vertex & copyable_edge concepts in graph ctors, load functions
- [ ] Support non-integral vertex_ids
- [ ] constexpr graph based on std::array
- [ ] undirected_adjacency_list<EV,VV,GV,VId,Alloc>
- [x] directed_adjacency_vector (retired)
Expand Down Expand Up @@ -168,6 +182,8 @@
- C\+\+20 and C\+\+23
- [ ] modules
- [ ] coroutines (simplify DFS, BFS & TopoSort?)
- [ ] Examples
- [ ] ABC
- Documentation
- [x] Decprecate original "graph" repository
- [ ] README.md
Expand Down
2 changes: 1 addition & 1 deletion cmake/FetchFMT.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ message(STATUS "Cloning External Project: fmt")
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 8.1.1
GIT_TAG 10.2.1
)

FetchContent_GetProperties(fmt)
Expand Down
58 changes: 0 additions & 58 deletions example/CppCon2022/rr_adaptor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
// https://www.reddit.com/r/cpp/comments/4yp7fv/c17_structured_bindings_convert_struct_to_a_tuple/
// https://gist.github.com/utilForever/1a058050b8af3ef46b58bcfa01d5375d

#define EDGES_CPO 1

template <class T, class... TArgs>
decltype(void(T{std::declval<TArgs>()...}), std::true_type{}) test_is_braces_constructible(int);

Expand Down Expand Up @@ -157,47 +155,19 @@ class rr_adaptor {
}

private: // tag_invoke definitions
#if VERTICES_CPO
friend constexpr vertices_range& vertices(graph_type& g) { return g.vertices_; }
friend constexpr const vertices_range& vertices(const graph_type& g) { return g.vertices_; }
#else
friend constexpr vertices_range& tag_invoke(std::graph::tag_invoke::vertices_fn_t, graph_type& g) {
return g.vertices_;
}
friend constexpr const vertices_range& tag_invoke(std::graph::tag_invoke::vertices_fn_t, const graph_type& g) {
return g.vertices_;
}
#endif

friend vertex_id_type vertex_id(const graph_type& g, std::ranges::iterator_t<vertices_range> ui) {
return static_cast<vertex_id_type>(ui -
std::ranges::begin(g.vertices_)); // overriden to assure correct type returned
}

#if EDGES_CPO
friend constexpr edges_range& edges(graph_type& g, vertex_type& u) { return u; }
friend constexpr const edges_range& edges(const graph_type& g, const vertex_type& u) { return u; }

friend constexpr edges_range& edges(graph_type& g, const vertex_id_type uid) { return g.vertices_[uid]; }
friend constexpr const edges_range& edges(const graph_type& g, const vertex_id_type uid) { return g.vertices_[uid]; }
#else
friend constexpr edges_range& tag_invoke(std::graph::tag_invoke::edges_fn_t, graph_type& g, vertex_type& u) {
return u;
}
friend constexpr const edges_range&
tag_invoke(std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_type& u) {
return u;
}

friend constexpr edges_range&
tag_invoke(std::graph::tag_invoke::edges_fn_t, graph_type& g, const vertex_id_type uid) {
return g.vertices_[uid];
}
friend constexpr const edges_range&
tag_invoke(std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_id_type uid) {
return g.vertices_[uid];
}
#endif

friend constexpr vertex_id_type target_id(const graph_type& g, const edge_type& uv) noexcept {
return get<0>(to_tuple(uv));
Expand Down Expand Up @@ -401,24 +371,14 @@ class rr_adaptor2 {
}

private:
#if VERTICES_CPO
friend constexpr vertices_range& vertices(graph_type& g) { return g.vertices_; }
friend constexpr const vertices_range& vertices(const graph_type& g) { return g.vertices_; }
#else
friend constexpr vertices_range& tag_invoke(std::graph::tag_invoke::vertices_fn_t, graph_type& g) {
return g.vertices_;
}
friend constexpr const vertices_range& tag_invoke(std::graph::tag_invoke::vertices_fn_t, const graph_type& g) {
return g.vertices_;
}
#endif

friend vertex_id_type vertex_id(const graph_type& g, std::ranges::iterator_t<vertices_range> ui) {
return static_cast<vertex_id_type>(ui -
std::ranges::begin(g.vertices_)); // overriden to assure correct type returned
}

#if EDGES_CPO
friend constexpr edges_range& edges(graph_type& g, vertex_type& u) { return get<0>(to_tuple(u)); }
friend constexpr const edges_range& edges(const graph_type& g, const vertex_type& u) { return get<0>(to_tuple(u)); }

Expand All @@ -428,24 +388,6 @@ class rr_adaptor2 {
friend constexpr const edges_range& edges(const graph_type& g, const vertex_id_type uid) {
return get<0>(to_tuple(g.vertices_[uid]));
}
#else
friend constexpr edges_range& tag_invoke(std::graph::tag_invoke::edges_fn_t, graph_type& g, vertex_type& u) {
return get<0>(to_tuple(u));
}
friend constexpr const edges_range&
tag_invoke(std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_type& u) {
return get<0>(to_tuple(u));
}

friend constexpr edges_range&
tag_invoke(std::graph::tag_invoke::edges_fn_t, graph_type& g, const vertex_id_type uid) {
return get<0>(to_tuple(g.vertices_[uid]));
}
friend constexpr const edges_range&
tag_invoke(std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_id_type uid) {
return get<0>(to_tuple(g.vertices_[uid]));
}
#endif

friend constexpr vertex_id_type target_id(const graph_type& g, const edge_type& uv) noexcept {
return get<0>(to_tuple(uv));
Expand Down
58 changes: 2 additions & 56 deletions include/graph/container/compressed_graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -738,8 +738,7 @@ class compressed_graph_base
//v_vector_type v_; // v_[n] holds the edge value for col_index_[n]
//row_values_type row_value_; // row_value_[r] holds the value for row_index_[r], for VV!=void

private: // tag_invoke properties
#if VERTICES_CPO
private: // CPO properties
friend constexpr vertices_type vertices(compressed_graph_base& g) {
if (g.row_index_.empty())
return vertices_type(g.row_index_); // really empty
Expand All @@ -752,27 +751,11 @@ class compressed_graph_base
else
return const_vertices_type(g.row_index_.begin(), g.row_index_.end() - 1); // don't include terminating row
}
#else
friend constexpr vertices_type tag_invoke(::std::graph::tag_invoke::vertices_fn_t, compressed_graph_base& g) {
if (g.row_index_.empty())
return vertices_type(g.row_index_); // really empty
else
return vertices_type(g.row_index_.begin(), g.row_index_.end() - 1); // don't include terminating row
}
friend constexpr const_vertices_type tag_invoke(::std::graph::tag_invoke::vertices_fn_t,
const compressed_graph_base& g) {
if (g.row_index_.empty())
return const_vertices_type(g.row_index_); // really empty
else
return const_vertices_type(g.row_index_.begin(), g.row_index_.end() - 1); // don't include terminating row
}
#endif

friend vertex_id_type vertex_id(const compressed_graph_base& g, const_iterator ui) {
return static_cast<vertex_id_type>(ui - g.row_index_.begin());
}

#if EDGES_CPO
friend constexpr edges_type edges(graph_type& g, vertex_type& u) {
static_assert(ranges::contiguous_range<row_index_vector>, "row_index_ must be a contiguous range to get next row");
vertex_type* u2 = &u + 1;
Expand Down Expand Up @@ -802,40 +785,6 @@ class compressed_graph_base
return const_edges_type(g.col_index_.begin() + g.row_index_[uid].index,
g.col_index_.begin() + g.row_index_[uid + 1].index);
}
#else
friend constexpr edges_type tag_invoke(::std::graph::tag_invoke::edges_fn_t, graph_type& g, vertex_type& u) {
static_assert(ranges::contiguous_range<row_index_vector>, "row_index_ must be a contiguous range to get next row");
vertex_type* u2 = &u + 1;
assert(static_cast<size_t>(u2 - &u) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(u.index) <= g.col_index_.size() &&
static_cast<size_t>(u2->index) <= g.col_index_.size()); // in col_index_ bounds?
return edges_type(g.col_index_.begin() + u.index, g.col_index_.begin() + u2->index);
}
friend constexpr const_edges_type
tag_invoke(::std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_type& u) {
static_assert(ranges::contiguous_range<row_index_vector>, "row_index_ must be a contiguous range to get next row");
const vertex_type* u2 = &u + 1;
assert(static_cast<size_t>(u2 - &u) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(u.index) <= g.col_index_.size() &&
static_cast<size_t>(u2->index) <= g.col_index_.size()); // in col_index_ bounds?
return const_edges_type(g.col_index_.begin() + u.index, g.col_index_.begin() + u2->index);
}

friend constexpr edges_type
tag_invoke(::std::graph::tag_invoke::edges_fn_t, graph_type& g, const vertex_id_type uid) {
assert(static_cast<size_t>(uid + 1) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(g.row_index_[uid + 1].index) <= g.col_index_.size()); // in col_index_ bounds?
return edges_type(g.col_index_.begin() + g.row_index_[uid].index,
g.col_index_.begin() + g.row_index_[uid + 1].index);
}
friend constexpr const_edges_type
tag_invoke(::std::graph::tag_invoke::edges_fn_t, const graph_type& g, const vertex_id_type uid) {
assert(static_cast<size_t>(uid + 1) < g.row_index_.size()); // in row_index_ bounds?
assert(static_cast<size_t>(g.row_index_[uid + 1].index) <= g.col_index_.size()); // in col_index_ bounds?
return const_edges_type(g.col_index_.begin() + g.row_index_[uid].index,
g.col_index_.begin() + g.row_index_[uid + 1].index);
}
#endif


// target_id(g,uv), target(g,uv)
Expand Down Expand Up @@ -959,7 +908,7 @@ class compressed_graph : public compressed_graph_base<EV, VV, GV, VId, EIndex, A
constexpr compressed_graph(const initializer_list<copyable_edge_t<VId, EV>>& ilist, const Alloc& alloc = Alloc())
: base_type(ilist, alloc) {}

private: // tag_invoke properties
private: // CPO properties
friend constexpr value_type& graph_value(graph_type& g) { return g.value_; }
friend constexpr const value_type& graph_value(const graph_type& g) { return g.value_; }

Expand Down Expand Up @@ -1020,9 +969,6 @@ class compressed_graph<EV, VV, void, VId, EIndex, Alloc>
constexpr compressed_graph(const initializer_list<copyable_edge_t<VId, EV>>& ilist, const Alloc& alloc = Alloc())
: base_type(ilist, alloc) {}


public: // Operations
private: // tag_invoke properties
};

} // namespace std::graph::container
Loading

0 comments on commit 7108cad

Please sign in to comment.