Degree and the handshake lemma #
Degree counting on Mathlib's multigraph Graph α β, for graphs with finitely many vertices
and finitely many edges.
Carrying finiteness #
V(G) and E(G) are Set α and Set β, not types, so finiteness has to be carried
somehow. The choice made here — and inherited by every later graph module — is a
Prop-valued class
class Graph.Finite (G : Graph α β) : Prop
bundling V(G).Finite and E(G).Finite, with G.vertexFinset and G.edgeFinset derived
from it. The reasons:
- It is a
Prop, so it is proof irrelevant.G.vertexFinsetandG.degreetherefore do not depend on which finiteness proof is in scope, and two lemmas proved with different instances still compose. A bundledFinset-valued structure would not have that property: it duplicates thevertexSetdata and forces a↑G.vertexFinset = V(G)side condition at every call site. - It is a class, so it is silent at the call site — the statements below read like ordinary
graph theory instead of dragging two
Set.Finitehypotheses through every signature. The price is that a subgraph does not get an instance for free;Graph.Finite.of_leproduces one, andhaveIinstalls it locally. That is the right trade: in this development finiteness is a standing assumption on the ambient graph and subgraphs are formed constantly. Finite ↥V(G)andFinite ↥E(G)instances are provided too, so Mathlib's own machinery (Set.Finite.subset,Set.toFinite, ...) fires without help.
Counts are Set.ncard. Set.ncard is total — it is 0 on an infinite set — so G.degree
is defined for every graph and needs no instance argument; finiteness enters only where a
theorem actually needs it.
Degree #
G.degree x is the number of edge ends at x:
G.degree x = (G.incidenceSet x).ncard + (G.loopSet x).ncard
A non-loop edge at x is counted once, by the first summand. A loop at x is counted
twice, once by each summand. This is the definition the handshake lemma needs, and it agrees
with SimpleGraph.degree on loopless graphs.
Blueprint #
Graph.sum_degree_eq_two_mul_ncard_edgeSet— "the degree sum is twice the number of edges", the counting step in the proof of Lemmalem:three-leaf-tree(Trees with three leaves). The whole content isGraph.ncard_inc_add_ncard_isLoopAt: an edge has exactly two ends.Graph.IsLeaf— "the vertices of degree one are the leaves", same lemma.
Namespace #
Everything lives in the root Graph namespace rather than in Schoenflies, so that dot
notation G.degree, G.IsLeaf, G.vertexFinset works on a G : Graph α β. Later graph
modules should do the same.
Finiteness #
G.Finite says that the multigraph G has finitely many vertices and finitely many
edges. Both halves are needed: the vertex set does not bound the edge set (parallel edges)
and the edge set does not bound the vertex set (isolated vertices).
A finite graph has finitely many vertices.
A finite graph has finitely many edges.
Instances
A subgraph of a finite graph is finite. This is not an instance — H cannot be
recovered from the goal — so install it with let _ := Graph.Finite.of_le h.
Incidence sets, unfolded #
Degree #
An edge has exactly two ends #
This is the entire content of the handshake lemma: summed over the vertices, the number of ends an edge has there is two, whether the edge is a loop (two ends at one vertex) or not (one end at each of two vertices).
The handshake lemma #
The handshake lemma. The degrees of the vertices of a finite multigraph add up to twice the number of edges.
The proof is the double count: G.degree x is a sum over the edges of the number of ends
that edge has at x, the two sums commute, and each edge contributes exactly two
(Graph.ncard_inc_add_ncard_isLoopAt). Loops are allowed — that is exactly what the loop
term in Graph.degree buys.
The degree sum of a finite multigraph is even.
Leaves #
Every edge at a leaf is a non-loop edge there.
The converse of the two lemmas above: a vertex of G whose only incident edge is e,
and for which e is not a loop, is a leaf.