Skip to content

Commit 4365230

Browse files
authored
Gci paper (#123)
* Add GCI update strategy with all Q1-Q8 decisions resolved Strategy document for updating D3130 Container Interface paper to match graph-v3 implementation. All 8 open questions resolved: - Q1: Hybrid exposition-only convention for descriptors - Q2: Pass descriptors by value (full audit of 17 occurrences) - Q3: Drop trait gate on edge<G,E>, no edge_list descriptors/views - Q4: Keep adjacency matrix traits/concepts - Q5: raw_vertex_id_t exposition-only, vertex_id_store_t normative - Q6: Separate namespaces (std::graph::edge_list) - Q7: vertex_property_map in GCI (D3130) - Q8: source_id mandatory for descriptor-based edges * Phase A: Rewrite D3130 source files to match graph-v3 - Delete concepts_edges_before.hpp and concepts_basic_adj_list.hpp - Rewrite concepts_edges.hpp: single edge<G,E> concept (no trait gate, Q3) - Rewrite concepts_target_edge_range.hpp: out_edge_range + in_edge_range - Rewrite concepts_vertex_range.hpp: vertex<G,V>, vertex_range, index_vertex_range, mapped_vertex_range - Rewrite concepts_adj_list.hpp: adjacency_list, bidirectional, index, mapped variants - Rewrite descriptor.hpp: vertex_descriptor + edge_descriptor (exposition-only internals, Q1) - Rewrite descriptor_view.hpp: vertex_descriptor_view + edge_descriptor_view - Rewrite edgelist_concepts.hpp: 2-arg concepts in std::graph::edge_list namespace - Rewrite edgelist_types.hpp: 2-arg type aliases, add raw_vertex_id_t, remove edge_reference_t - Add descriptor_traits.hpp: is_vertex_descriptor, is_edge_descriptor, is_descriptor - Update container_interface.tex: add lstinputlisting for descriptor.hpp and descriptor_traits.hpp - Add gci_update_plan.md implementation plan * Phase B: Update type alias and traits tables - Traits table: update has_contains_edge to <G,V>, remove unordered/ordered edge traits, add bidirectional query traits (has_in_degree, has_find_in_edge, has_contains_in_edge), add compound traits (has_basic_queries, has_full_queries), note adjacency_matrix not yet in reference implementation - Type alias table: already updated in Phase A amend (remove graph/vertex/edge _reference_t, add vertex_id_store_t, raw-vertex-id-type, out_edge_*/in_edge_* types, backward-compat aliases) * Update phase overview with completion status * Phase C: Update function tables and CPO names - Graph table: rename has_edge(g)->has_edges(g), update default impl to use out_edges - Vertex table: rename edges->out_edges, degree->out_degree; add in_edges, in_degree; note backward-compat aliases (edges, degree); update vertex_edge_range_t->out_edge_range_t - Edge table: rename find_vertex_edge->find_out_edge, contains_edge->contains_out_edge; make source_id mandatory for descriptor-based edges (not optional); remove optional source_id separator; add find_in_edge, contains_in_edge rows; note backward-compat aliases - Edgelist table: 1-arg->2-arg CPOs (target_id(e)->target_id(el,uv), etc.); update contains_edge lambda to use 2-arg forms; rename has_edge->has_edges - Update prose references: edges(g,u)->out_edges(g,u), source_id(e)->source_id(el,uv), etc. - Fix LaTeX errors from Phase B: \textit inside \tcode, vertex_t<G>{} braces * Mark Phase C complete in plan * Phase D: Rewrite concept sections - Concepts intro: remove 'sourced' qualifier, add 'mapped' and 'bidirectional' - Edge Concepts: single edge<G,E> concept; explain removal of targeted/sourced split; simplify return-type rationale; keep precedent note about sized_range - Edge Range Concepts: explain out_edge_range + in_edge_range semantics - Vertex Concepts: describe vertex<G,V>, index_vertex_range, mapped_vertex_range - Adjacency List Concepts: list all 6 concepts and their axes; explain removal of basic_*/sourced_* variants due to descriptor design - Edgelist Concepts: explain 2-arg form and three concept levels * Mark Phase D complete in plan * Phase E: Rewrite descriptor section with motivation and split architecture - Add 'Why Descriptors?' motivation with comparison table (raw iterators vs descriptors) - Add implicit vertex support explanation (index-based descriptors work without materialised vertex storage) - Add automatic pattern recognition paragraph (random-access, associative, edge patterns) - Replace old monolithic descriptor prose with split architecture description: vertex_descriptor<VertexIter> and edge_descriptor<EdgeIter,VertexIter,EdgeDirection> - Fix inner_value() -> underlying_value(c) / inner_value(c) (container parameter required) - Add pass-by-value convention paragraph (descriptors trivially copyable, const& only in requires clauses) - Remove stale itemize list of descriptor properties (now covered in prose) - Keep all three lstinputlisting calls: descriptor.hpp, descriptor_traits.hpp, descriptor_view.hpp * Phase F: Update edgelist section — namespace, types table, edge_data patterns - Remove \phil note from Namespace subsection - Fix intro prose CPO args: source_id(el,e) -> source_id(el,uv) etc. - Types table: remove edge_reference_t<EL>; add raw-vertex-id-type (exposition-only); update vertex_id_t definition to use source_id(el,uv) (consistent with edgelist_types.hpp) - Pattern section: rename edge_info -> edge_data throughout (4 occurrences) - Pattern section: add pair<integral,integral> pattern - Pattern section: add edge_data reference variants: edge_data<VId,true,E&,void> and edge_data<VId,true,E&,EV> * Phase G: Add data structs, value function concepts, vertex property map - Add vertex_data/edge_data/neighbor_data struct families with specialization tables - Add copyable_vertex_t/copyable_edge_t/copyable_neighbor_t helper alias table - Add Value Function Concepts subsection: vertex_value_function, edge_value_function - Add Vertex Property Map subsection: vertex_property_map<G,T> type alias, make_vertex_property_map (eager+lazy), vertex_property_map_contains, vertex_property_map_get - Fix: use L{8cm} column spec in copyable_types table (arydshln requires at least one L column) - Fix: remove texcl-interpreted comment from vertex_property_map lstlisting * Phase H: Establish graph::adj_list and graph::edge_list as peer namespaces - GCI intro: introduce both namespaces by name; explain that adj_list is re-exported to graph:: but edge_list is not (vertex_id_t conflict) - Adjacency List Interface: add Namespace subsection explaining graph::adj_list, re-export to graph::, and when to use the qualified form - Edgelist Interface: expand Namespace subsection to explain the peer relationship, contrast the two ADTs, and note the shared CPOs (source_id, target_id, edge_value) * Phase H: Prose audit and revision history - Traits table: fix has_degree comment degree->out_degree, has_find_vertex_edge comment find_vertex_edge->find_out_edge, has_contains_edge comment contains_edge->contains_out_edge (adj_list CPO names) - Partition section: edges(g,uid,pid)/edges(g,u,pid) -> out_edges(g,uid,pid)/ out_edges(g,u,pid) - Revision history: add r4 entry summarising all descriptor, concept, CPO, type alias, data struct, namespace and edgelist changes from Phases A-H * Phase J: Cross-paper fixups for algorithms and shared spec text - tex/conventions.tex: vertex_reference_t<G> -> vertex_t<G> (descriptor row); edge_reference_t<G> -> edge_t<G> (edge descriptor row); vertex_info -> vertex_data (VProj description); edge_info -> edge_data (EProj description) - tex/specification.tex: vertex_reference_t<G> -> vertex_t<G> in vertex_value(), has_degree, has_find_vertex_edge, adjacency_list, incidence(), neighbors() (6 occurrences) - D3128_Algorithms/tex/algorithms.tex: edge_reference_t<G> -> edge_t<G> in basic_edge_weight_function and edge_weight_function concepts (2 occurrences) - D3128_Algorithms and D3130_Container_Interface both build cleanly * Update gci_update_plan and conventions.tex
1 parent 020d77e commit 4365230

18 files changed

Lines changed: 2453 additions & 405 deletions

D3128_Algorithms/tex/algorithms.tex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,12 @@ \subsection{Edge Weight Concepts}
148148
is_arithmetic_v<DistanceValue> &&
149149
strict_weak_order<Compare, DistanceValue, DistanceValue> &&
150150
assignable_from<add_lvalue_reference_t<DistanceValue>,
151-
invoke_result_t<Combine, DistanceValue, invoke_result_t<WF, edge_reference_t<G>>>>;
151+
invoke_result_t<Combine, DistanceValue, invoke_result_t<WF, edge_t<G>>>>;
152152

153153
// For exposition only
154154
template <class G, class WF, class DistanceValue>
155155
concept edge_weight_function = // e.g. weight(uv)
156-
is_arithmetic_v<invoke_result_t<WF, edge_reference_t<G>>> &&
156+
is_arithmetic_v<invoke_result_t<WF, edge_t<G>>> &&
157157
basic_edge_weight_function<G,
158158
WF,
159159
DistanceValue,
Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
// For exposition only
22

3-
template <class G>
4-
concept adjacency_list = vertex_range<G> && //
5-
targeted_edge_range<G> && //
6-
targeted_edge<G>;
3+
template <class G>
4+
concept adjacency_list = requires(G& g, vertex_t<G> u) {
5+
{ vertices(g) } -> vertex_range<G>;
6+
{ out_edges(g, u) } -> out_edge_range<G>;
7+
};
8+
9+
template <class G>
10+
concept index_adjacency_list = adjacency_list<G> &&
11+
index_vertex_range<G>;
712

8-
template <class G>
9-
concept index_adjacency_list = index_vertex_range<G> && //
10-
targeted_edge_range<G> && //
11-
targeted_edge<G>;
13+
template <class G>
14+
concept bidirectional_adjacency_list =
15+
adjacency_list<G> &&
16+
requires(G& g, vertex_t<G> u, in_edge_t<G> ie) {
17+
{ in_edges(g, u) } -> in_edge_range<G>;
18+
{ source_id(g, ie) } -> convertible_to<vertex_id_t<G>>;
19+
};
20+
21+
template <class G>
22+
concept index_bidirectional_adjacency_list =
23+
bidirectional_adjacency_list<G> &&
24+
index_vertex_range<G>;
1225

1326
template <class G>
14-
concept sourced_adjacency_list = vertex_range<G> && //
15-
targeted_edge_range<G> && //
16-
sourced_targeted_edge<G>;
27+
concept mapped_adjacency_list = adjacency_list<G> &&
28+
mapped_vertex_range<G>;
1729

1830
template <class G>
19-
concept sourced_index_adjacency_list = index_vertex_range<G> && //
20-
targeted_edge_range<G> && //
21-
sourced_targeted_edge<G>;
31+
concept mapped_bidirectional_adjacency_list =
32+
bidirectional_adjacency_list<G> &&
33+
mapped_vertex_range<G>;

D3130_Container_Interface/src/concepts_basic_adj_list.hpp

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
11
// For exposition only
22

3-
template <class G>
4-
concept targeted_edge = requires(G&& g, edge_reference_t<G> uv) {
5-
target(g, uv);
6-
target_id(g, uv);
7-
};
8-
9-
template <class G>
10-
concept sourced_edge = requires(G&& g, edge_reference_t<G> uv) {
11-
source(g, uv);
12-
source_id(g, uv);
13-
};
14-
15-
template <class G>
16-
concept sourced_targeted_edge = targeted_edge<G> && sourced_edge<G>;
3+
template <class G, class E>
4+
concept edge = requires(G& g, const E& e) {
5+
source_id(g, e);
6+
source(g, e);
7+
target_id(g, e);
8+
target(g, e);
9+
};

D3130_Container_Interface/src/concepts_edges_before.hpp

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// For exposition only
22

3-
template <class G>
4-
concept targeted_edge_range =
5-
basic_targeted_edge_range<G> &&
6-
requires(G&& g, vertex_reference_t<G> u, vertex_id_t<G> uid) {
7-
{ edges(g, u) } -> forward_range;
8-
{ edges(g, uid) } -> forward_range; // implies call to find\_vertex(g,uid)
9-
};
3+
template <class R, class G>
4+
concept out_edge_range = forward_range<R> &&
5+
edge<G, range_value_t<R>>;
6+
7+
template <class R, class G>
8+
concept in_edge_range = forward_range<R> &&
9+
edge<G, range_value_t<R>>;
Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
// For exposition only
22

3-
template <class G>
4-
concept _common_vertex_range = ranges::sized_range<vertex_range_t<G>> &&
5-
requires(G&& g, vertex_iterator_t<G> ui) { vertex_id(g, ui); };
3+
template <class G, class V>
4+
concept vertex = requires(G& g, const V& u, const vertex_id_t<G>& uid) {
5+
vertex_id(g, u);
6+
find_vertex(g, uid);
7+
};
8+
9+
template <class R, class G>
10+
concept vertex_range = forward_range<R> &&
11+
sized_range<R> &&
12+
vertex<G, remove_cvref_t<range_value_t<R>>>;
613

7-
template <class G>
8-
concept vertex_range = _common_vertex_range<vertex_range_t<G>> &&
9-
forward_range<vertex_range_t<G>>;
14+
template <class G>
15+
concept index_vertex_range =
16+
integral<vertex_id_t<G>> &&
17+
integral<typename vertex_range_t<G>::storage_type> &&
18+
requires(G& g) {
19+
{ vertices(g) } -> vertex_range<G>;
20+
};
1021

11-
template <class G>
12-
concept index_vertex_range = _common_vertex_range<vertex_range_t<G>> &&
13-
random_access_range<vertex_range_t<G>> &&
14-
integral<vertex_id_t<G>>;
22+
template <class G>
23+
concept mapped_vertex_range =
24+
!index_vertex_range<G> &&
25+
requires(G& g, const vertex_id_t<G>& uid) {
26+
{ vertices(g) } -> forward_range;
27+
find_vertex(g, uid);
28+
};
Lines changed: 73 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,81 @@
1-
template <forward_iterator InnerIter>
2-
class descriptor {
3-
public:
4-
using inner_iterator = InnerIter;
5-
using inner_value_type = iter_value_t<inner_iterator>;
6-
// preserve inner value constness based on inner\_iterator
7-
using inner_reference =
8-
conditional_t<is_const_v<remove_reference_t<decltype(*declval<inner_iterator>())>>,
9-
add_lvalue_reference_t<std::add_const_t<inner_value_type>>,
10-
add_lvalue_reference_t<inner_value_type>>;
11-
using inner_pointer =
12-
conditional_t<is_const_v<remove_reference_t<decltype(*declval<inner_iterator>())>>,
13-
add_pointer_t<std::add_const_t<inner_value_type>>,
14-
add_pointer_t<inner_value_type>>;
15-
16-
// Determine if this an index-based or iterator-based descriptor
17-
using id_type = ptrdiff_t;
18-
using value_type = conditional_t<random_access_iterator<inner_iterator>, id_type, inner_iterator>;
19-
20-
// Honor the const/non-const contract for the value type
21-
using pointer = std::add_pointer_t<value_type>;
22-
using const_pointer = std::add_pointer_t<std::add_const_t<value_type>>;
23-
24-
using reference = std::add_lvalue_reference_t<value_type>;
25-
using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
26-
27-
using difference_type = std::iter_difference_t<inner_iterator>;
28-
29-
constexpr descriptor() = default;
30-
constexpr descriptor(const descriptor&) = default;
31-
constexpr descriptor(descriptor&&) = default;
32-
constexpr ~descriptor() noexcept = default;
33-
34-
constexpr descriptor(InnerIter first, InnerIter it) : begin_(first);
35-
constexpr descriptor(InnerIter first, ptrdiff_t id);
36-
37-
// for testing
38-
template <forward_range R>
39-
requires is_convertible_v<iterator_t<R>, InnerIter>
40-
constexpr descriptor(R& r, inner_iterator it).
41-
42-
template <forward_range R>
43-
requires is_convertible_v<iterator_t<R>, InnerIter>
44-
constexpr descriptor(R& r, std::ptrdiff_t id = 0);
45-
46-
constexpr descriptor& operator=(const descriptor&) = default;
47-
constexpr descriptor& operator=(descriptor&&) = default;
48-
49-
// Properies
1+
// For exposition only
2+
3+
struct out_edge_tag {};
4+
struct in_edge_tag {};
5+
6+
template <class VertexIter>
7+
class vertex_descriptor {
508
public:
51-
constexpr value_type& value() const noexcept;
9+
using iterator_type = VertexIter;
10+
using value_type = iter_value_t<VertexIter>;
11+
12+
// index for random-access, iterator for bidirectional (for exposition only)
13+
using storage_type =
14+
conditional_t<random_access_iterator<VertexIter>, size_t, VertexIter>;
15+
16+
constexpr vertex_descriptor() = default;
17+
constexpr explicit vertex_descriptor(storage_type val) noexcept;
5218

53-
constexpr inner_iterator get_inner_iterator() const;
19+
// Properties
20+
constexpr storage_type value() const noexcept;
21+
constexpr decltype(auto) vertex_id() const noexcept;
5422

55-
[[nodiscard]] constexpr inner_reference inner_value() noexcept;
56-
[[nodiscard]] constexpr inner_reference inner_value() const noexcept;
23+
template <class Container>
24+
constexpr decltype(auto) underlying_value(Container& c) const noexcept;
5725

58-
// Operators
26+
template <class Container>
27+
constexpr decltype(auto) inner_value(Container& c) const noexcept;
28+
29+
// Iterator-like interface
30+
constexpr vertex_descriptor& operator++() noexcept;
31+
constexpr vertex_descriptor operator++(int) noexcept;
32+
33+
// Comparison
34+
constexpr auto operator<=>(const vertex_descriptor&) const noexcept = default;
35+
constexpr bool operator==(const vertex_descriptor&) const noexcept = default;
36+
37+
private:
38+
storage_type storage_ = storage_type(); // for exposition only
39+
};
40+
41+
42+
template <class EdgeIter,
43+
class VertexIter,
44+
class EdgeDirection = out_edge_tag>
45+
class edge_descriptor {
5946
public:
60-
//
61-
// dereference
62-
//
63-
// Note: range concept requirement: decltype(*descriptor) == value\_type\&
64-
[[nodiscard]] constexpr reference operator*() noexcept;
65-
[[nodiscard]] constexpr const_reference operator*() const noexcept;
66-
67-
[[nodiscard]] constexpr pointer operator->() noexcept;
68-
[[nodiscard]] constexpr const_pointer operator->() const noexcept;
69-
70-
//
71-
// operator ++ += +
72-
//
73-
constexpr descriptor& operator++();
74-
constexpr descriptor operator++(int);
75-
76-
constexpr descriptor& operator+=(iter_difference_t<inner_iterator> n)
77-
requires random_access_iterator<inner_iterator>;
78-
constexpr descriptor operator+(iter_difference_t<inner_iterator> n) const
79-
requires random_access_iterator<inner_iterator>;
80-
81-
//
82-
// operator -- -= -
83-
//
84-
constexpr descriptor& operator--()
85-
requires bidirectional_iterator<inner_iterator>;
86-
constexpr descriptor operator--(int)
87-
requires bidirectional_iterator<inner_iterator>;
88-
89-
constexpr descriptor& operator-=(iter_difference_t<inner_iterator> n)
90-
requires random_access_iterator<inner_iterator>;
91-
constexpr descriptor operator-(iter_difference_t<inner_iterator> n) const
92-
requires random_access_iterator<inner_iterator>;
93-
94-
template <class InnerIter2>
95-
constexpr iter_difference_t<inner_iterator> operator-(const descriptor<InnerIter2>& rhs) const
96-
requires random_access_iterator<inner_iterator>;
97-
98-
//
99-
// operator []
100-
//
101-
constexpr inner_reference operator[](iter_difference_t<inner_iterator> n) const
102-
requires random_access_iterator<inner_iterator>;
103-
104-
//
105-
// operators ==, <=>
106-
//
107-
constexpr bool operator==(const descriptor& rhs) const noexcept;
108-
109-
template <forward_iterator InnerIter2>
110-
requires std::equality_comparable_with<InnerIter, InnerIter2>
111-
constexpr bool operator==(const descriptor<InnerIter2>& rhs) const noexcept;
112-
113-
// for testing; useful in general?
114-
template <forward_iterator InnerIter2>
115-
requires std::equality_comparable_with<InnerIter, InnerIter2>
116-
constexpr bool operator==(const InnerIter2& rhs) const noexcept;
117-
118-
constexpr auto operator<=>(const descriptor& rhs) const noexcept
119-
requires std::integral<value_type> || std::random_access_iterator<inner_iterator>;
120-
121-
template <random_access_iterator InnerIter2>
122-
requires std::three_way_comparable_with<InnerIter, InnerIter2> &&
123-
(std::integral<value_type> || random_access_iterator<inner_iterator>)
124-
constexpr auto operator<=>(const descriptor<InnerIter2>& rhs) const noexcept;
47+
using edge_iterator_type = EdgeIter;
48+
using vertex_iterator_type = VertexIter;
49+
using vertex_desc = vertex_descriptor<VertexIter>;
50+
using edge_direction = EdgeDirection;
51+
52+
static constexpr bool is_in_edge = is_same_v<EdgeDirection, in_edge_tag>;
53+
static constexpr bool is_out_edge = is_same_v<EdgeDirection, out_edge_tag>;
54+
55+
// index for random-access, iterator for forward (for exposition only)
56+
using edge_storage_type =
57+
conditional_t<random_access_iterator<EdgeIter>, size_t, EdgeIter>;
58+
59+
constexpr edge_descriptor() = default;
60+
constexpr edge_descriptor(edge_storage_type edge_val,
61+
vertex_desc source) noexcept;
62+
63+
// Properties
64+
constexpr edge_storage_type value() const noexcept;
65+
constexpr vertex_desc source() const noexcept;
66+
constexpr decltype(auto) source_id() const noexcept;
67+
68+
template <class VertexData>
69+
constexpr auto target_id(const VertexData& vd) const noexcept;
70+
71+
template <class VertexData>
72+
constexpr decltype(auto) underlying_value(VertexData& vd) const noexcept;
73+
74+
// Comparison
75+
constexpr auto operator<=>(const edge_descriptor&) const noexcept = default;
76+
constexpr bool operator==(const edge_descriptor&) const noexcept = default;
12577

12678
private:
127-
value_type value_ = value_type(); // index or iterator (for exposition only)
128-
inner_iterator begin_ = inner_iterator(); // begin of the inner range (for exposition only)
79+
edge_storage_type edge_storage_ = edge_storage_type(); // for exposition only
80+
vertex_desc source_ = vertex_desc(); // for exposition only
12981
};

0 commit comments

Comments
 (0)