Cycles, acyclicity and bridges #
This file sits directly on Schoenflies/Graph/Walk.lean and answers one question: which
edges of a multigraph lie on a cycle. Its main theorem is the blueprint's cycle criterion —
an edge lies on a cycle exactly when deleting it leaves its two ends joined — and a bridge is
read off it.
A cycle is presented through one of its edges #
G.IsCycleThrough e u v D is an edge e linking u to v, together with a path D
from u to v that does not use e. The closed walk is never assembled.
This is not a weakening. Every question the blueprint asks about a cycle is asked at an
edge — is this edge on a cycle, does deleting it disconnect its ends, is it a bridge, can it
be deleted from a spanning subgraph — so the edge is always available to present the cycle
through. And presenting it this way is what makes the definition short: the blueprint's
"connected subgraph in which every vertex has degree exactly two" would have to rule out, by
hand, every repetition that a closed walk can contain, whereas Graph.IsPath already forbids
them. The blueprint's own proof of the criterion runs in exactly this shape ("take a shortest
walk from x to y avoiding e; a shortest walk repeats no vertex, so it is a simple
path").
Length two is included, and is why edges are names. Two parallel edges — the same pair of
ends, two different names — are a cycle: one of them is e, the other is the one-edge path
D. The blueprint needs those ("two-vertex cycles do occur below, as boundaries of faces
created by overlays and by ears parallel to an existing edge"), and a walk that named
vertices could not tell the two apart.
Loops #
Mathlib's Graph allows an edge with both ends equal. A loop is taken to be a cycle of
length one, which is the usual convention and also what the blueprint's own definition
gives (a loop contributes two to the degree of its vertex, so the subgraph consisting of a
loop and its vertex is connected with every vertex of degree two). It comes out of the
definition here for free: G.IsLink e x x together with the empty path at x, which does
not use e, is a cycle through e. So Graph.liesOnCycle_of_isLoopAt needs no proof, no
graph is acyclic while carrying a loop, and no bridge is a loop. Nothing in this file
hypothesises looplessness.
Deletion #
Edge deletion is Mathlib's Graph.deleteEdges, not a new definition; G.deleteEdges {e} is
the graph with the single name e removed. What this file adds is the transfer interface —
a walk or a path survives a deletion exactly when it never took a deleted edge — which is the
whole content of a deletion argument, since which vertices an edge joins is not a question a
subgraph can answer differently. Graph.IsWalk.anti from Walk.lean is the engine;
Graph.IsPath.anti is proved here, since freshness has to be carried down too.
Blueprint #
Graph.liesOnCycle_iff_deleteEdges_reaches—lem:cycle-criterion, "in a finite graph, an edge lies on a cycle if and only if deleting it does not disconnect its endpoints", both directions, with the finiteness the proof does not use dropped. The two halves areGraph.LiesOnCycle.deleteEdges_reachesandGraph.LiesOnCycle.of_deleteEdges_reaches.Graph.IsBridge,Graph.isBridge_iff_not_reaches— the bridges oflem:subdivision-ear-preserve("a 2-connected graph has no bridge. Indeed, ifuvwere a bridge, the two components ofG - uv…"), stated as the separation of the two ends.Graph.IsAcyclic,Graph.Connected.deleteEdges_singleton— the acyclicity underneathlem:three-leaf-tree, and the minimal spanning subgraph of the H5 construction ("take a minimal connected subgraphT_ispanning the three terminals. It is a tree: an edge of a cycle could be deleted"), which is exactly the statement that deleting an edge on a cycle keeps the graph connected.Graph.IsPath.chord_liesOnCycle,Graph.IsAcyclic.mem_of_isLink_of_mem_walkVertices— the step oflem:three-leaf-tree's proof that says "a second neighbor on the path would close a cycle"; the form the tree module's longest-path argument consumes.
Visited vertices along an inclusion #
Walk.lean proves walkVertices monotone in the edge list. It is also monotone in the
graph, which is what pulling a path down into a subgraph needs: the freshness clause of a
path speaks about the subgraph's visited set, and that is the smaller one.
Edge deletion #
Graph.deleteEdges is Mathlib's. These are the four transfer lemmas every deletion argument
below reduces to.
Deleting edges never removes a vertex, so a walk in the deletion is a walk.
Conversely, a walk in the deletion could not have used a deleted name.
Cycles #
G.IsCycleThrough e u v D : the edge e links u to v, and D is a path from u
back to v that does not use e. The cycle is e together with D; it is presented
through e because that is the edge every question is asked about.
Instances For
G.LiesOnCycle e : the edge e lies on a cycle of G.
Equations
- G.LiesOnCycle e = ∃ (u : α) (v : α) (D : List β), G.IsCycleThrough e u v D
Instances For
An edge on a cycle is an edge of the graph. There is no converse hypothesis to carry
around: Graph.IsLink already forces it.
A loop is a cycle of length one. The path back is the empty one, which trivially avoids the loop.
Two parallel edges are a cycle, on both of them. This is the length-two case, and the reason a walk names its edges.
A cycle of a subgraph is a cycle of the graph.
The cycle criterion #
The blueprint's lem:cycle-criterion. Both directions are one step each, once the deletion
interface above is in place: forwards, the detour of the cycle is a walk that avoided e;
backwards, a path in the deletion cannot have used e because e is not there.
An edge on a cycle is not needed to join its ends: the rest of the cycle still does.
The ends are given as an arbitrary pair u, v that e links, not as the pair the cycle was
presented with — an edge has only two ends, so the two presentations agree up to a swap, and
reachability is symmetric.
An edge whose deletion leaves its ends joined lies on a cycle. The route that survives is a walk of the deletion, hence contains a path of the deletion, and a path of the deletion cannot have used the name that was deleted.
The cycle criterion: an edge lies on a cycle if and only if deleting it does not disconnect its endpoints.
A walk reroutes around an edge that lies on a cycle: wherever it took e, it can go
the long way round instead. Proved by induction along the walk rather than by splicing the
detour into the edge list, so nothing has to be said about what the spliced list looks
like.
Deleting an edge that lies on a cycle keeps the graph connected — the blueprint's "it is a tree: an edge of a cycle could be deleted", which is what makes a minimal connected spanning subgraph acyclic.
Chords #
An edge from the source of a path to a vertex the path already visits closes a cycle. This is the shape in which acyclicity is used: it says a path cannot be extended backwards onto itself.
A chord of a path lies on a cycle: the piece of the path from its source to the far end of the chord is a path avoiding the chord, so the chord closes it.
Acyclicity #
G.IsAcyclic : no edge of G lies on a cycle. Stated over the edges of G because that
is how a tree consumes it — every edge is a bridge — while Graph.IsAcyclic.not_liesOnCycle
drops the membership hypothesis for the uses that do not have it to hand.
Instances For
Acyclicity with no membership hypothesis: an edge on a cycle would be an edge.
An acyclic graph has no loop. No hypothesis is needed anywhere else in this layer because of this: looplessness is a consequence of acyclicity, not a side condition on it.
In an acyclic graph, an edge at the source of a path whose far end the path visits is one of the path's own edges. This is the blueprint's "a second neighbor on the path would close a cycle" — the step that makes the end of a longest path a leaf, which is what the tree module runs on.
Bridges #
G.IsBridge e : an edge of G that lies on no cycle. Equivalently — and this is the
form every use wants — an edge whose deletion separates its two ends
(Graph.isBridge_iff_not_reaches).
Instances For
A graph is acyclic exactly when every one of its edges is a bridge. This is the form the tree module wants acyclicity in: "it is a tree — an edge of a cycle could be deleted" reads backwards as "no edge can be deleted without separating its ends".