Union-find realization and logarithmic step bounds #
This module realizes Cslib.DataStructure.DisjointSet.spec using Batteries.UnionFind
(disjoint-set forests with union by rank and path compression) together with an explicit component
counter, and establishes worst-case O(log n) per-operation parent-pointer traversal bounds.
Under path compression, internal nodes can lose descendants when compressed paths bypass them, so
the naive subtree-size invariant 2 ^ rank u ≤ |subtree u| is not preserved at internal nodes.
Following Cormen et al., Exercise 21.4-2, ValidRank instead bounds the
equivalence-class size of each root r < uf.size by 2 ^ uf.rank r ≤ (equivClass uf r).card.
Path compression preserves rootD, all node ranks, and the set of roots, so ValidRank is
preserved immediately across find as well as across push, root link, checkEquiv, and
union. Because node ranks strictly increase along non-root parent pointers (uf.rank_lt and
le_rank_root, matching Cormen et al., Lemma 21.4 and Corollary 21.5), every node
satisfies uf.rank i ≤ Nat.log 2 uf.size, and every find traverses at most
Nat.log 2 uf.size + 1 nodes.
Cost model and limitations #
The native trace of Exec counts parent-pointer inspections during find (1 at the root plus
1 per parent hop, matching recursive calls of Batteries.UnionFind.findAux), plus 1 link step
for Op.union and 1 counter read for Op.numComponents. Because Batteries.UnionFind.rankMax
is marked noncomputable, the helpers rankBound, findGo, and compressWithSteps are exposed
solely so that findSteps, step, and run reduce in the Lean kernel (rfl / decide) while
remaining propositionally equal to Batteries.UnionFind.find. This gives a worst-case O(log n)
bound from union by rank alone (not Tarjan's inverse-Ackermann O(α(n)) amortized bound), and
counts abstract forest steps in Lean rather than word-RAM instructions or array-copying overhead if
a Batteries.UnionFind value is shared non-linearly.
Main definitions #
ofSize: initialize aBatteries.UnionFindforest ofnsingleton classes.equivClass,ValidRank: root equivalence-class finsets and the root rank-size invariant2 ^ uf.rank r ≤ (equivClass uf r).card.findSteps,rankBound,findGo,compressWithSteps: computable path-compression step counter and kernel-reducible helpers propositionally equal toBatteries.UnionFind.find.State,init,step,Exec,Rep,impl,run: concrete disjoint-set state, operations,Cslib.DataStructure.StateTransitionImpl, and executable client runner.charge: worst-case per-operation step budget onFin n.
Main results #
find_rank,union_size,checkEquiv_size,checkEquiv_snd_eq_true: structural lemmas forBatteries.UnionFind.ValidRank.empty,ValidRank.push,ValidRank.ofSize,ValidRank.find,ValidRank.link,ValidRank.checkEquiv,ValidRank.union: preservation of the root rank-size invariant.ValidRank.two_pow_rank_le_size,ValidRank.rank_le_log: exponential class-size lower bound and logarithmic rank bounduf.rank i ≤ Nat.log 2 uf.size.findSteps_eq,findSteps_le_rank_sub_add_one,ValidRank.findSteps_le_log_add_one: recursive characterization andNat.log 2 uf.size + 1bound onfindtraversal length.Rep.validRank,Rep.rel_iff_equiv,Rep.numComp_eq,rep_init: representation invariant projections and initialization.stepBound,uniformStepBound,realized_client,run_correct: stateful resource certificates and adaptive-client correctness and cost theorems.
References #
Structural lemmas for Batteries.UnionFind #
Batteries.UnionFind.union preserves universe size.
Batteries.UnionFind.checkEquiv preserves universe size.
Batteries.UnionFind.checkEquiv preserves the equivalence relation.
Batteries.UnionFind.checkEquiv returns true iff x and y are equivalent.
Initialize a Batteries.UnionFind forest of n singleton classes {0}, …, {n - 1}.
Instances For
Root rank-size invariant and logarithmic rank bound #
The finite set of in-bounds elements of uf whose canonical root is r.
Instances For
Root rank-size invariant (Cormen et al., Exercise 21.4-2): every root r < uf.size
has equivalence class of cardinality at least 2 ^ uf.rank r.
Instances For
Logarithmic rank bound (Cormen et al., Exercise 21.4-2): every node in a rank-valid
Batteries.UnionFind forest has rank at most Nat.log 2 uf.size.
Computable path-compression wrapper and step bounds #
Computable strict upper bound on all node ranks in uf (matching Batteries.UnionFind.rankMax
without noncomputable).
Instances For
Structural-fuel traversal matching Batteries.UnionFind.findAux while counting visited nodes
(1 at the root check plus 1 per parent hop).
Instances For
Number of nodes inspected by Batteries.UnionFind.find starting at x (1 at the root plus
1 per parent pointer traversed).
Instances For
Every find inspects at least 1 node.
Because uf.rank increases strictly at every non-root parent hop, findSteps uf x is bounded
by (uf.rank (uf.rootD x) - uf.rank x) + 1.
Kernel-reducible path-compression find returning the updated Batteries.UnionFind, the root
in Fin uf.size, and findSteps uf x. Propositionally equal to Batteries.UnionFind.find.
Instances For
Stateful realization of DisjointSet.spec #
Concrete union-find state over Fin n: a Batteries.UnionFind forest of size n paired with
the maintained number of equivalence classes.
- uf : Batteries.UnionFind
Underlying
Batteries.UnionFindforest. Fixed universe size invariant.
- numComp : ℕ
Maintained number of connected components.
Instances For
Initial concrete disjoint-set state of n singleton components.
Instances For
init n represents the discrete partition Partition.discrete n of n singletons.
Semantic realization of DisjointSet.spec n by Batteries.UnionFind with path compression
and union by rank.
Instances For
Every adaptive disjoint-set client has a valid execution matching abstract partition semantics
and satisfying the additive O(log n) per-operation step bound.
Running the concrete union-find interpreter agrees with abstract Partition n semantics,
preserves Rep, and satisfies both the exact per-operation and uniform O(log n) step bounds.