Skip to content

Commit ee7a79d

Browse files
committed
test: locking behaviour against regressions
1 parent 50e90d2 commit ee7a79d

2 files changed

Lines changed: 67 additions & 14 deletions

File tree

doc/modules/ROOT/pages/adaptors/subgraph.adoc

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,47 @@ template <typename Graph>
3030
class subgraph;
3131
----
3232

33-
The `subgraph` class wraps an `adjacency_list` and maintains a tree of
34-
subgraphs. The root graph owns all vertices and edges. Child subgraphs hold
35-
subsets of the root's vertices, and their edge sets are _induced_: any edge in
36-
the root whose both endpoints are in the child automatically appears in the
37-
child.
38-
39-
Each subgraph uses _local_ descriptors (0-based within that subgraph). Use
40-
`local_to_global()` and `global_to_local()` to convert between local and root
41-
descriptors.
42-
43-
Adding an edge to a child subgraph also adds it to all ancestor subgraphs.
44-
Adding a vertex to a child subgraph also adds it to all ancestors.
33+
`subgraph` represents parts of a single graph as independent graphs, without
34+
copying the data and without the parts drifting out of sync with the whole. All
35+
vertices and edges are stored once, in the root graph. Each subgraph is a
36+
lightweight view onto a subset of that storage which still behaves like a full
37+
graph, so it can be passed to any BGL algorithm.
38+
39+
[TIP]
40+
====
41+
Consider a national road network: intersections are vertices and roads are
42+
edges. An analysis might focus on one city, then one district within that city,
43+
then compare against the whole country. Rather than three separate copies kept
44+
consistent by hand, `subgraph` keeps one dataset and offers lightweight views
45+
onto its parts. The country is the root, a city is a child subgraph, and a
46+
district is a child of that city. Each view behaves like a normal graph and can
47+
be handed to an algorithm such as `dijkstra_shortest_paths` exactly like any
48+
other BGL graph.
49+
====
50+
51+
These views nest into a tree. The _root_ subgraph holds the entire graph and
52+
owns all of its vertices and edges. Each _child_ is a subset of its parent's
53+
vertices, and a child may in turn have children of its own. A child's edges are
54+
_induced_: an edge belongs to a child exactly when both of its endpoints do, so
55+
only vertices are ever added to a child, never edges directly.
56+
57+
Because the storage is shared rather than copied, the levels stay linked in both
58+
directions. A property set at one level, such as an edge weight or a vertex
59+
color, is visible from every level. Adding a vertex or edge to a child also adds
60+
it to every ancestor up to the root, so an edit made while working on one part
61+
keeps the whole hierarchy consistent.
62+
63+
Each subgraph numbers its own vertices and edges 0-based, as required by the
64+
many algorithms that assume a contiguous index space. A descriptor is therefore
65+
meaningful only within one subgraph. `local_to_global()` and `global_to_local()`
66+
translate a descriptor between a subgraph's local numbering and the root's.
67+
68+
Choosing among the graph views:
69+
70+
* `filtered_graph` for a read-only view that hides some vertices or edges.
71+
* `copy_graph` for an independent copy that does not stay linked to the original.
72+
* `subgraph` when mutability, per-region local numbering, and a parent/child
73+
hierarchy over shared storage are all needed.
4574

4675
== Template Parameters
4776

@@ -102,16 +131,39 @@ edge_descriptor global_to_local(edge_descriptor e_global) const;
102131

103132
Convert between local (subgraph-relative) and global (root) descriptors.
104133

134+
WARNING: These conversions have a precondition. The element must belong to this
135+
subgraph. Passing a vertex or edge that is not in the subgraph is a precondition
136+
violation (checked with `BOOST_ASSERT` in debug builds, undefined behaviour
137+
otherwise). On the root subgraph the conversion is the identity, so any element
138+
is accepted. To convert an element that might not be present, test membership
139+
first with `find_vertex()` or `find_edge()`.
140+
105141
'''
106142

107143
[source,cpp]
108144
----
109145
std::pair<vertex_descriptor, bool>
110146
find_vertex(vertex_descriptor u_global) const;
147+
148+
std::pair<edge_descriptor, bool>
149+
find_edge(edge_descriptor e_global) const;
111150
----
112151

113-
Returns `(local_descriptor, true)` if the global vertex is in this subgraph,
114-
`(_, false)` otherwise.
152+
Membership queries that never assert. `find_vertex` returns
153+
`(local_descriptor, true)` if the global vertex is in this subgraph, and
154+
`(null_vertex(), false)` otherwise. `find_edge` behaves the same way for edges,
155+
returning a default-constructed `edge_descriptor` in the not-found case. These
156+
are the safe form of `global_to_local`, for the case where the element is not
157+
known in advance to be in the subgraph.
158+
159+
[NOTE]
160+
====
161+
*Descriptor identity and stability.* For an element that is present, the
162+
conversions round-trip: `global_to_local(local_to_global(x)) == x`, and the
163+
edge index is preserved. Properties live in the root's storage and are shared
164+
across the whole tree, so the same logical element carries the same property
165+
value no matter which subgraph's descriptor reaches it.
166+
====
115167

116168
=== Hierarchy Navigation
117169

test/Jamfile.v2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ alias graph_test_regular :
9797
[ run subgraph_bundled.cpp ]
9898
[ run subgraph_add.cpp : $(TEST_DIR) ]
9999
[ run subgraph_props.cpp ]
100+
[ run subgraph_global_local.cpp ]
100101

101102
[ run isomorphism.cpp ]
102103
[ run adjacency_matrix_test.cpp ]

0 commit comments

Comments
 (0)