Components and shortest paths #
The two prerequisites of the relative ear decomposition (lem:relative-ear) that no earlier
module builds: the component of a vertex, and a shortest walk between two vertices.
Both are then spent on the geometric heart of that lemma — a component of G - S has two
distinct neighbours in S, and a path between two of them whose interior lies outside S.
The component is a comprehension #
G.component u = {v | G.Reaches u v}, exactly as connectedComponentIn collects the points
a space reaches. Nothing restricts the comprehension to V(G): the empty walk already demands
a vertex of the graph (Graph.IsWalk.nil), so G.Reaches u v carries v ∈ V(G) with it, and
a clause v ∈ V(G) ∧ … would be redundant noise at every use site. When u ∉ V(G) the
component is empty, which is the convention that makes the covering statement
Graph.iUnion_component true with no side condition.
Reachability is an equivalence relation on V(G), so the component is closed under Reaches,
two components are equal or disjoint, and the components cover V(G). The one statement that
is not pure equivalence-relation bookkeeping is that the induced subgraph on a component
is connected: a walk between two vertices of a component never leaves it
(Graph.IsWalk.walkVertices_subset_component), so it is already a walk of the induced
subgraph, by Graph.IsWalk.anti.
Shortest walks need no finiteness #
The set of lengths of walks from u to v is a nonempty set of naturals, so it has a least
element — Nat.find, with no Graph.Finite hypothesis anywhere. That is worth noticing: the
blueprint says "in a finite graph", but finiteness is used there only to terminate the ear
process, never to find one shortest path.
A minimum-length walk is automatically a path (Graph.IsWalk.isPath_of_minLength). The proof
is the induction of Graph.IsWalk.contains_path run once more, with lengths attached: if the
step's source were revisited later, Graph.IsPath.from_visited would cut the tail down to a
strictly shorter walk with the same ends, and a path's edge list repeats nothing
(Graph.IsPath.nodup), so the cut piece really is no longer than what it came from
(List.subperm_of_subset).
The two neighbours, without a contradiction #
The blueprint argues by contradiction: "otherwise its unique neighbour would be a cut vertex".
Here the two neighbours are constructed, in the shape Graph.IsTwoConnected.no_bridge
already uses. A walk from the component out to a vertex of S crosses the boundary
(Graph.IsWalk.crossing), and the crossing edge's far end is in S — because a neighbour
outside S would still be in the component. That is the first neighbour c. For the second,
delete c: the big graph is still connected, so the same crossing argument runs inside
G - c, and its crossing edge's far end is a neighbour that is not c.
Two distinct vertices of S are needed, and used exactly once: the walk of the second step
must aim at a vertex of S other than c. In the application S is the vertex set of a
2-connected subgraph, which has three.
Blueprint #
Graph.component,Graph.induce_component_connected— "a componentLofG - V(H₀)" in the proof oflem:relative-ear.Graph.exists_minLength_isPath— "a shortest path throughL", same proof.Graph.IsTwoConnected.component_two_neighbors— "if a componentLofG - V(H₀)contains a vertex, it has at least two distinct neighbors inH₀; otherwise its unique neighbor would be a cut vertex ofG".Graph.IsTwoConnected.exists_path_through_component— "a shortest path throughLbetween two such neighbors is an ear": a path ofGbetween two distinct vertices ofS, whose every other vertex is outsideS, which has at least one such vertex, and each of whose edges has an end outsideS. The word ear is not used here and nothing about ears is assumed; this is the raw path that a consumer recognises as one.
Namespace #
Root Graph, as fixed by Schoenflies/Graph/Walk.lean.
Components #
The component of u in G: the vertices u reaches. A comprehension over the vertices,
not an indexed union of connected subgraphs; the membership test is Graph.Reaches itself,
which is why every closure property below is one line of the reachability API.
No v ∈ V(G) clause: Graph.Reaches already carries it, since the empty walk demands a
vertex of the graph. For u ∉ V(G) the component is empty.
Instances For
The subgraph induced on a component #
A walk out of a component stays in it: every vertex it visits is reachable from the component's base point, one step at a time.
A walk that starts in a component is a walk of the subgraph induced on it. Both ends of each of its edges are vertices it visits, so the edges survive the induction.
Shortest walks and shortest paths #
A shortest walk exists between any two vertices one of which reaches the other: the lengths of such walks form a nonempty set of naturals. No finiteness is needed.
A shortest walk is a path. If the vertex a step departs from were visited again, the
tail could be cut there (Graph.IsPath.from_visited) and the result would be a strictly
shorter walk with the same ends — strictly, because a path repeats no edge and the cut piece
is a sublist-up-to-permutation of what it came from.
A shortest path exists: among all walks between two vertices, one of least length, and it is a path. This is the blueprint's "shortest path".
Components of a vertex deletion #
From here on S : Set α is a set of vertices to be deleted, and the component in question is
one of G.deleteVerts S. Only two facts about the deletion are used, and both are about where
its walks can go.
A walk of G - S visits only vertices of G outside S — computed in G, which is the
form the freshness clause of a path of G reads.
A neighbour of a component of G - S that is outside S is in the component. The
edge joining them survives the deletion, so it extends the walk.
Walking out of a component of G - S meets S along an edge. The walk may live in
any subgraph K of G — it is run inside G - c once — but the component is always the one
of G - S, which is what makes the conclusion usable twice.
This is Graph.IsWalk.crossing plus the previous lemma: the crossing edge's far end is
outside the component, so it cannot be outside S.
The two neighbours of a component, and the path through it #
A component of G - S has two distinct neighbours in S — the first half of
lem:relative-ear, with the blueprint's contradiction turned into a construction.
S must contain two distinct vertices; in the application it is the vertex set of a
2-connected subgraph, which has three. The first neighbour c comes from a walk of G out of
the component to a vertex of S; the second from the same walk run inside G - c, which is
still connected because G is 2-connected, and aimed at a vertex of S other than c.
Reading off the vertices of a walk with one edge appended at the far end. Purely about
lists; used to check the freshness clause when a path inside a component is capped with an
edge back into S.
The path through a component — the second half of lem:relative-ear, without the word
ear: in a 2-connected G, from a vertex outside a set S that has two distinct vertices,
one gets a path of G whose two endpoints are distinct vertices of S, whose every other
vertex is outside S, which has at least one vertex outside S, and each of whose edges has
an end outside S.
The last two clauses are what make the ear process terminate and what make the path new: it
really does add a vertex, and none of its edges belongs to a subgraph whose vertices all lie
in S.
The path is built from the two neighbours of the component: the edge into the component, a
path across the component (in G - S, hence never touching S), and the edge back out.