Imports
import Mathlib
open Finset

CLRS Section 23.1 - Growing a minimum spanning tree

This section proves the exchange kernel behind the standard minimum-spanning-tree cut property:

  • replacing a heavier tree edge by a no-heavier edge preserves optimality;

  • a light edge crossing a cut is safe, provided the usual tree-exchange certificate is available.

The graph-specific fact that a spanning tree plus a crossing edge contains a replaceable crossing edge is kept as an explicit certificate. This keeps the first MST module focused on the reusable proof pattern rather than on a particular graph representation or union-find implementation.

Main results:

  • Theorem FiniteGraph.spanning_tree_maximal: a finite spanning tree is maximal among spanning trees under edge-set inclusion.

  • Theorems FiniteGraph.minimumSpanningTree_of_mstExtending_empty and FiniteGraph.minimumSpanningTree_iff_mstExtending_empty: the abstract empty-prefix optimum specification is equivalent to the concrete finite-graph minimum-spanning-tree specification.

  • Theorem FiniteGraph.exists_crossing_tree_edge_preserving_prefix: a spanning tree path across a respecting cut supplies a replaceable crossing tree edge outside the accepted prefix.

  • Theorem safe_edge_of_lightest_crossing: the CLRS cut property in safe-edge form.

namespace CLRSnamespace MSTvariable {V E : Type} [DecidableEq V] [DecidableEq E]

A finite edge-weight sum.

def weight (w : E Nat) (s : Finset E) : Nat := s.sum w

The small amount of graph structure needed to state cuts.

structure Graph (V E : Type) where src : E V dst : E V
namespace Graph

An edge crosses a cut when its endpoints are on opposite sides.

def Crosses (G : Graph V E) (S : Finset V) (e : E) : Prop := (G.src e S G.dst e S) (G.dst e S G.src e S)

A cut respects a partial solution when no selected edge crosses it.

def Respects (G : Graph V E) (S : Finset V) (A : Finset E) : Prop := e A, ¬ G.Crosses S e

The undirected adjacency relation induced by a selected edge set.

def AdjIn (G : Graph V E) (A : Finset E) (u v : V) : Prop := e A, (G.src e = u G.dst e = v) (G.src e = v G.dst e = u)

Connectivity using only edges from a selected edge set.

def ConnectedIn (G : Graph V E) (A : Finset E) (u v : V) : Prop := Relation.ReflTransGen (G.AdjIn A) u v
omit [DecidableEq V] [DecidableEq E] in theorem connected_refl (G : Graph V E) (A : Finset E) (v : V) : G.ConnectedIn A v v := Relation.ReflTransGen.reflomit [DecidableEq V] [DecidableEq E] in theorem adjIn_mono {G : Graph V E} {A B : Finset E} (hAB : A B) {u v : V} (h : G.AdjIn A u v) : G.AdjIn B u v := omit [DecidableEq V] [DecidableEq E] in theorem connected_mono {G : Graph V E} {A B : Finset E} (hAB : A B) {u v : V} (h : G.ConnectedIn A u v) : G.ConnectedIn B u v := induction h with

Any selected-edge connection from one side of a cut to the other uses at least one selected edge crossing that cut. This is the lightweight path/cut API used before introducing a heavier finite walk representation.

omit [DecidableEq E] intheorem connected_crosses_cut {G : Graph V E} {A : Finset E} {S : Finset V} {u v : V} (hconn : G.ConnectedIn A u v) (hu : u S) (hv : v S) : e, e A G.Crosses S e := induction hconn with exact e, heA, Or.inl hsrcS, exact ih ( ) exact e, heA, Or.inr hdstS, exact ih ( )
end Graph

Concrete finite graph specification

A concrete finite graph: finite vertex and edge sets plus endpoint maps.

structure FiniteGraph (V E : Type) [DecidableEq V] [DecidableEq E] extends Graph V E where vertices : Finset V edges : Finset E src_mem : e edges, src e vertices dst_mem : e edges, dst e vertices
namespace FiniteGraph

The selected edges span the finite vertex set.

def Spans (G : FiniteGraph V E) (A : Finset E) : Prop := u G.vertices, v G.vertices, G.toGraph.ConnectedIn A u v

A forest is characterized by the standard cycle-test property: removing any selected edge disconnects its endpoints.

def IsForest (G : FiniteGraph V E) (A : Finset E) : Prop := e A, ¬ G.toGraph.ConnectedIn (A.erase e) (G.src e) (G.dst e)

A finite-graph spanning tree: selected graph edges, spanning all vertices, and acyclic in the edge-removal sense.

def IsSpanningTree (G : FiniteGraph V E) (A : Finset E) : Prop := A G.edges G.Spans A G.IsForest A

A concrete minimum spanning tree for a finite graph and edge-weight map.

def IsMinimumSpanningTree (G : FiniteGraph V E) (w : E Nat) (T : Finset E) : Prop := G.IsSpanningTree T U, G.IsSpanningTree U weight w T weight w U
private theorem subset_erase_of_subset_of_not_mem {A T : Finset E} {e : E} (hAT : A T) (heA : e A) : A T.erase e :=

A spanning tree is maximal under edge-set inclusion among spanning trees. This is the concrete graph fact used by the abstract Kruskal theorem.

A spanning tree path between the endpoints of an edge crossing a cut contains a tree edge crossing that same cut.

theorem exists_crossing_tree_edge_of_cut (G : FiniteGraph V E) {T : Finset E} {S : Finset V} {e : E} (hT : G.IsSpanningTree T) (he : e G.edges) (hcross : G.toGraph.Crosses S e) : f, f T G.toGraph.Crosses S f :=

If the cut respects a prefix A, then the crossing tree edge found on the tree path is outside A. Consequently deleting it while inserting the crossing edge preserves the prefix edge set.

end FiniteGraph

A family of feasible spanning trees over the edge type.

structure Problem (E : Type) [DecidableEq E] where IsSpanningTree : Finset E Prop
namespace FiniteGraphdef toProblem (G : FiniteGraph V E) : Problem E where IsSpanningTree := G.IsSpanningTreeend FiniteGraph

T is a minimum feasible tree among all trees extending A.

structure IsMSTExtending (P : Problem E) (w : E Nat) (A T : Finset E) : Prop where tree : P.IsSpanningTree T includes : A T optimal : U, P.IsSpanningTree U A U weight w T weight w U
namespace FiniteGraph

The abstract empty-prefix optimum specification is the concrete finite-graph minimum-spanning-tree specification.

theorem minimumSpanningTree_of_mstExtending_empty (G : FiniteGraph V E) {w : E Nat} {T : Finset E} (h : IsMSTExtending G.toProblem w T) : G.IsMinimumSpanningTree w T := exact h.optimal U hUtree ( )

Conversely, a concrete finite-graph MST is an abstract optimum extending the empty prefix. This is useful when switching from textbook finite-graph statements back to the reusable Kruskal induction interface.

theorem mstExtending_empty_of_minimumSpanningTree (G : FiniteGraph V E) {w : E Nat} {T : Finset E} (h : G.IsMinimumSpanningTree w T) : IsMSTExtending G.toProblem w T :=

The empty-prefix abstract MST specification is equivalent to the concrete finite-graph minimum-spanning-tree specification.

theorem minimumSpanningTree_iff_mstExtending_empty (G : FiniteGraph V E) {w : E Nat} {T : Finset E} : G.IsMinimumSpanningTree w T IsMSTExtending G.toProblem w T :=
end FiniteGraph

An edge is safe for A if every optimum extending A can be turned into an optimum extending A ∪ {e} without losing optimality for the old prefix.

The second conjunct is what lets a Kruskal-style induction keep global optimality for the original prefix, not only optimality for the growing prefix.

def SafeEdge (P : Problem E) (w : E Nat) (A : Finset E) (e : E) : Prop := T, IsMSTExtending P w A T T', IsMSTExtending P w (insert e A) T' IsMSTExtending P w A T'
lemma IsMSTExtending.extend_insert_of_mem {P : Problem E} {w : E Nat} {A T : Finset E} {e : E} (hT : IsMSTExtending P w A T) (he : e T) : IsMSTExtending P w (insert e A) T := calc weight w (insert e (T.erase f)) = w e + weight w (T.erase f) := _ w f + weight w (T.erase f) := _ = weight w T :=

The CLRS exchange step: if adding e and dropping f gives another spanning tree and e is no heavier than f, then the exchanged tree is still minimum.

theorem mst_exchange_preserves_prefix {P : Problem E} {w : E Nat} {A T : Finset E} {e f : E} (hT : IsMSTExtending P w A T) (hf : f T) (he : e T) (h_tree : P.IsSpanningTree (insert e (T.erase f))) (h_extends : A insert e (T.erase f)) (h_weight : w e w f) : IsMSTExtending P w A (insert e (T.erase f)) :=

The same exchange step, packaged for the enlarged prefix.

theorem mst_exchange_step {P : Problem E} {w : E Nat} {A T : Finset E} {e f : E} (hT : IsMSTExtending P w A T) (hf : f T) (he : e T) (h_tree : P.IsSpanningTree (insert e (T.erase f))) (h_extends : A insert e (T.erase f)) (h_weight : w e w f) : IsMSTExtending P w (insert e A) (insert e (T.erase f)) :=

A cut certificate packages the graph-specific part of the CLRS proof.

For every optimum tree extending A that does not already contain e, the certificate provides a tree edge f crossing the same cut such that replacing f by e is feasible and preserves A. The light-edge condition then gives w e ≤ w f.

structure CutCertificate (G : Graph V E) (P : Problem E) (w : E Nat) (A : Finset E) (S : Finset V) (e : E) : Prop where crosses : G.Crosses S e respects : G.Respects S A lightest : f, G.Crosses S f w e w f exchange : T, IsMSTExtending P w A T e T f, f T G.Crosses S f P.IsSpanningTree (insert e (T.erase f)) A insert e (T.erase f)

CLRS cut property in safe-edge form.

omit [DecidableEq V] intheorem safe_edge_of_lightest_crossing {G : Graph V E} {P : Problem E} {w : E Nat} {A : Finset E} {S : Finset V} {e : E} (hcut : CutCertificate G P w A S e) : SafeEdge P w A e :=

A direct existence wrapper for using a safe edge in a larger proof.

theorem exists_mst_containing_safe_edge {P : Problem E} {w : E Nat} {A T : Finset E} {e : E} (hsafe : SafeEdge P w A e) (hT : IsMSTExtending P w A T) : T', IsMSTExtending P w (insert e A) T' := let T', hT', _ := hsafe T hT T', hT'
end MSTend CLRS