19.2. Linked-List Representation of Disjoint Sets
The CLRS linked-list representation stores, for every element, the head of its
set and stores a set size at each head. The executable model below makes that
table-level behavior explicit. A weighted union redirects every head pointer
in the class with the smaller recorded size. The returned cost uses that size;
it equals actual changed pointers only when recorded sizes equal the cardinality
of the represented classes. The WeightedExecution companion proves this
invariant from singleton initialization and derives the whole-trace rewrite bound
from the actual changed representatives.
Main results:
-
Theorem
LinkedList.weightedUnion_sameSet_iff: weighted union has the exact abstract merge semantics. -
Theorem
LinkedList.weightedUnion_preserves_headInvariant: every head remains a representative. -
Theorem
LinkedList.weightedUnion_changed_doubles: whenever an element's representative pointer is rewritten, its recorded set size at least doubles. -
Theorems
LinkedList.move_count_le_log2andLinkedList.total_rewrites_le_n_mul_log2: the standard CLRS aggregate conditional arithmetic bound extracted from supplied doubling events. -
The
WeightedExecutioncompanion constructs those move counts from a mixed UNION/FIND execution, maintains class-size cardinality, and proves the initialized total-rewrite and query-output contracts.
namespace CLRSnamespace Chapter21namespace LinkedListopen FinsetTable-level model of the linked-list disjoint-set representation.
structure State (n : Nat) where
head : Fin n → Fin n
size : Fin n → Natnamespace Statevariable {n : Nat}Two elements are in the same represented list exactly when their heads agree.
The size recorded at the representative of x.
Every stored head is itself a representative.
The represented abstract partition.
def partition (s : State n) : Partition (Fin n) where
sameSet := s.sameSet
refl := fun _ => rfl
symm := fun h => h.symm
trans := fun hab hbc => hab.trans hbc
The initial state containing n singleton lists.
@[simp]
theorem singleton_head (x : Fin n) :
(singleton n).head x = x :=
rfl@[simp]
theorem singleton_size (x : Fin n) :
(singleton n).setSize x = 1 :=
rfltheorem singleton_headInvariant (n : Nat) :
(singleton n).HeadInvariant := by
intro x
rfltheorem singleton_sameSet_iff (x y : Fin n) :
(singleton n).sameSet x y ↔ x = y :=
Iff.rfl
Redirect the class of src to the head of dst.
def mergeToward (s : State n) (src dst : Fin n) : State n where
head z := if s.head z = s.head src then s.head dst else s.head z
size z :=
if z = s.head dst then s.setSize src + s.setSize dst
else if z = s.head src then 0
else s.size z
Weighted union redirects the class with the smaller recorded size. The second
component is that recorded-size charge; equality with actual pointer changes
requires the companion's WeightedExecution.Sized invariant and is proved
by WeightedExecution.union_changes_cost. Arbitrary malformed size fields
do not have this interpretation.
def weightedUnion (s : State n) (x y : Fin n) : State n × Nat :=
if s.head x = s.head y then
(s, 0)
else if s.setSize x ≤ s.setSize y then
(s.mergeToward x y, s.setSize x)
else
(s.mergeToward y x, s.setSize y)Redirecting one distinct class to another has the exact merge relation.
theorem mergeToward_sameSet_iff (s : State n) {x y : Fin n}
(_hxy : ¬s.sameSet x y) (a b : Fin n) :
(s.mergeToward x y).sameSet a b ↔
s.sameSet a b ∨
(s.sameSet a x ∧ s.sameSet y b) ∨
(s.sameSet a y ∧ s.sameSet x b) := by
unfold sameSet at ⊢
by_cases ha : s.head a = s.head x
· by_cases hb : s.head b = s.head x
· simp [mergeToward, ha, hb]
· constructor
· intro h
simp [mergeToward, ha, hb] at h
exact Or.inr (Or.inl ⟨ha, h⟩)
· intro h
rcases h with hab | ⟨⟨_, hyb⟩ | ⟨_, hxb⟩⟩
· exact (hb (hab.symm.trans ha)).elim
· simpa [mergeToward, ha, hb] using hyb
· exact (hb hxb.symm).elim
· by_cases hb : s.head b = s.head x
· constructor
· intro h
simp [mergeToward, ha, hb] at h
exact Or.inr (Or.inr ⟨h, hb.symm⟩)
· intro h
rcases h with hab | ⟨⟨hax, _⟩ | ⟨hay, _⟩⟩
· exact (ha (hab.trans hb)).elim
· exact (ha hax).elim
· simpa [mergeToward, ha, hb] using hay
· constructor
· intro h
exact Or.inl (by simpa [mergeToward, ha, hb] using h)
· intro h
rcases h with hab | ⟨⟨hax, _⟩ | ⟨_, hxb⟩⟩
· simpa [mergeToward, ha, hb] using hab
· exact (ha hax).elim
· exact (hb hxb.symm).elimWeighted union implements the Section 19.1 abstract union operation.
theorem weightedUnion_sameSet_iff (s : State n) (x y a b : Fin n) :
(s.weightedUnion x y).1.sameSet a b ↔
s.sameSet a b ∨
(s.sameSet a x ∧ s.sameSet y b) ∨
(s.sameSet a y ∧ s.sameSet x b) := by
by_cases hxy : s.sameSet x y
· change s.head x = s.head y at hxy
rw [show s.weightedUnion x y = (s, 0) by simp [weightedUnion, hxy]]
change s.sameSet a b ↔ _
constructor
· exact Or.inl
· intro h
rcases h with hab | ⟨⟨hax, hyb⟩ | ⟨hay, hxb⟩⟩
· exact hab
· exact (s.partition.trans (s.partition.trans hax hxy) hyb)
· exact (s.partition.trans (s.partition.trans hay
(s.partition.symm hxy)) hxb)
· by_cases hle : s.setSize x ≤ s.setSize y
· change ¬s.head x = s.head y at hxy
rw [show s.weightedUnion x y = (s.mergeToward x y, s.setSize x) by
simp [weightedUnion, hxy, hle]]
exact s.mergeToward_sameSet_iff hxy a b
· have hyx : ¬s.sameSet y x := by
intro h
exact hxy h.symm
change ¬s.head x = s.head y at hxy
change ¬s.head y = s.head x at hyx
rw [show s.weightedUnion x y = (s.mergeToward y x, s.setSize y) by
simp [weightedUnion, hxy, hle]]
rw [s.mergeToward_sameSet_iff hyx]
aesopWeighted union refines the abstract partition merge.
theorem weightedUnion_refines_merge (s : State n) (x y a b : Fin n) :
((s.weightedUnion x y).1.partition).sameSet a b ↔
((s.partition).merge x y).sameSet a b := by
rw [Partition.merge_sameSet_iff]
exact s.weightedUnion_sameSet_iff x y a bRedirecting a class preserves idempotent representative pointers.
theorem mergeToward_preserves_headInvariant (s : State n) {x y : Fin n}
(hinv : s.HeadInvariant) (hxy : ¬s.sameSet x y) :
(s.mergeToward x y).HeadInvariant := by
intro z
unfold sameSet at hxy
by_cases hz : s.head z = s.head x
· have hyx : ¬s.head (s.head y) = s.head x := by
rw [hinv y]
exact Ne.symm hxy
simpa [mergeToward, hz, hyx] using hinv y
· have hzx : ¬s.head (s.head z) = s.head x := by
rw [hinv z]
exact hz
simpa [mergeToward, hz, hzx] using hinv zWeighted union preserves the representative invariant.
theorem weightedUnion_preserves_headInvariant (s : State n) (x y : Fin n)
(hinv : s.HeadInvariant) :
(s.weightedUnion x y).1.HeadInvariant := by
by_cases hxy : s.sameSet x y
· change s.head x = s.head y at hxy
simpa [weightedUnion, hxy] using hinv
· by_cases hle : s.setSize x ≤ s.setSize y
· change ¬s.head x = s.head y at hxy
simpa [weightedUnion, hxy, hle] using
s.mergeToward_preserves_headInvariant hinv hxy
· have hyx : ¬s.sameSet y x := fun h => hxy h.symm
change ¬s.head x = s.head y at hxy
change ¬s.head y = s.head x at hyx
simpa [weightedUnion, hxy, hle] using
s.mergeToward_preserves_headInvariant hinv hyxA weighted union never charges more rewrites than either input set size.
theorem weightedUnion_cost_le_left (s : State n) (x y : Fin n) :
(s.weightedUnion x y).2 ≤ s.setSize x := by
simp only [weightedUnion]
split <;> rename_i hxy
· exact Nat.zero_le _
· split <;> rename_i hle
· exact Nat.le_refl _
· exact Nat.le_of_lt (Nat.lt_of_not_ge hle)Symmetric rewrite-cost bound for weighted union.
theorem weightedUnion_cost_le_right (s : State n) (x y : Fin n) :
(s.weightedUnion x y).2 ≤ s.setSize y := by
simp only [weightedUnion]
split <;> rename_i hxy
· exact Nat.zero_le _
· split <;> rename_i hle
· exact hle
· exact Nat.le_refl _If an element's representative pointer changes, the size recorded at its new representative is at least twice the old represented-set size.
theorem weightedUnion_changed_doubles (s : State n) (x y z : Fin n)
(hchanged : (s.weightedUnion x y).1.head z ≠ s.head z) :
2 * s.setSize z ≤ (s.weightedUnion x y).1.setSize z := by
by_cases hxy : s.sameSet x y
· change s.head x = s.head y at hxy
rw [show s.weightedUnion x y = (s, 0) by simp [weightedUnion, hxy]] at hchanged
exact (hchanged rfl).elim
· by_cases hle : s.setSize x ≤ s.setSize y
· change ¬s.head x = s.head y at hxy
rw [show s.weightedUnion x y = (s.mergeToward x y, s.setSize x) by
simp [weightedUnion, hxy, hle]] at hchanged ⊢
have hz : s.head z = s.head x := by
by_contra hz
apply hchanged
simp [mergeToward, hz]
unfold setSize at hle ⊢
simp [mergeToward, setSize, hz]
omega
· change ¬s.head x = s.head y at hxy
rw [show s.weightedUnion x y = (s.mergeToward y x, s.setSize y) by
simp [weightedUnion, hxy, hle]] at hchanged ⊢
have hz : s.head z = s.head y := by
by_contra hz
apply hchanged
simp [mergeToward, hz]
have hyx : s.head y ≠ s.head x := by
exact fun h => hxy h.symm
unfold setSize at hle ⊢
simp [mergeToward, setSize, hz]
omegaRepeated size doublings give an exponential lower bound.
theorem pow_le_of_repeated_doubling (sizeAt : Nat → Nat) (k : Nat)
(hzero : 1 ≤ sizeAt 0)
(hstep : ∀ i, i < k → 2 * sizeAt i ≤ sizeAt (i + 1)) :
2 ^ k ≤ sizeAt k := by
induction k with
| zero => simpa using hzero
| succ k ih =>
have ih' : 2 ^ k ≤ sizeAt k :=
ih (fun i hi => hstep i (Nat.lt_trans hi (Nat.lt_succ_self k)))
calc
2 ^ (k + 1) = 2 * 2 ^ k := by
rw [Nat.pow_succ]
omega
_ ≤ 2 * sizeAt k := Nat.mul_le_mul_left 2 ih'
_ ≤ sizeAt (k + 1) := hstep k (Nat.lt_succ_self k)An element whose class doubles on every move is rewritten at most logarithmically often.
theorem move_count_le_log2 {sizeAt : Nat → Nat} {k total : Nat}
(htotal : total ≠ 0)
(hzero : 1 ≤ sizeAt 0)
(hstep : ∀ i, i < k → 2 * sizeAt i ≤ sizeAt (i + 1))
(hfinal : sizeAt k ≤ total) :
k ≤ Nat.log2 total := by
apply (Nat.le_log2 htotal).2
exact Nat.le_trans (pow_le_of_repeated_doubling sizeAt k hzero hstep) hfinal
Summing the per-element logarithmic rewrite bound gives n log n.
theorem total_rewrites_le_n_mul_log2 (moves : Fin n → Nat)
(hmoves : ∀ z, moves z ≤ Nat.log2 n) :
∑ z, moves z ≤ n * Nat.log2 n := by
calc
∑ z, moves z ≤ ∑ _z : Fin n, Nat.log2 n := by
exact Finset.sum_le_sum fun z _ => hmoves z
_ = n * Nat.log2 n := by simpend Stateend LinkedListend Chapter21end CLRSDefinitions and proofs
CLRSLean.FourthEdition.Chapter_19.Section_19_2_Linked_List_Representation.WeightedExecution
Weighted-union traces and aggregate pointer rewrites
The execution starts from the native head-table state and runs arbitrary FIND and weighted UNION commands. Each union enumerates the representatives that actually changed, then derives both its rewrite total and per-element move counts from this list. No move events or doubling assumptions are supplied by a caller. The initialized invariant identifies every recorded class size with the cardinality of its actual head fiber.
The returned total is the sum of constructed per-element counts and is at most
n * Nat.log2 n. Adding one abstract controller event per command gives
m + n * Nat.log2 n. This is the head-pointer rewrite model: enumeration
of audit events, persistent function evaluation, and linked-list allocation are
outside the charged model. It is not a runtime bound for these instrumentation
lists or an implementation of explicit linked-list cells.
namespace CLRS.Chapter21.LinkedList.WeightedExecutionopen Finset Statevariable {n : Nat}def classOf (s : State n) (x : Fin n) : Finset (Fin n) :=
univ.filter (fun z => s.head z = s.head x)Recorded class sizes agree with the actual represented partition.
theorem singleton_sized : Sized (singleton n) := by
intro z
simp [setSize, State.singleton, classOf, Finset.filter_eq']theorem class_disjoint (s : State n) {x y : Fin n} (h : s.head x ≠ s.head y) :
Disjoint (classOf s x) (classOf s y) := by
apply Finset.disjoint_left.mpr
simp only [classOf, mem_filter, mem_univ, true_and]
intro z hx hy
exact h (hx.symm.trans hy)theorem merge_class_left (s : State n) (x y z : Fin n)
(hz : s.head z = s.head x) :
classOf (s.mergeToward x y) z = classOf s x ∪ classOf s y := by
ext w
by_cases hw : s.head w = s.head x <;> simp [classOf, mergeToward, hz, hw]theorem merge_class_right (s : State n) (x y z : Fin n)
(hxy : s.head x ≠ s.head y) (hz : s.head z = s.head y) :
classOf (s.mergeToward x y) z = classOf s x ∪ classOf s y := by
ext w
by_cases hw : s.head w = s.head x <;> simp [classOf, mergeToward, hz, hw, hxy]
theorem merge_class_other (s : State n) (x y z : Fin n)
(hzx : s.head z ≠ s.head x) (hzy : s.head z ≠ s.head y) :
classOf (s.mergeToward x y) z = classOf s z := by
ext w
by_cases hw : s.head w = s.head x
· have hwz : s.head w ≠ s.head z := by rw [hw]; exact Ne.symm hzx
simp [classOf, mergeToward, hzx, Ne.symm hzy, hw, Ne.symm hzx]
· simp [classOf, mergeToward, hzx, hw]
theorem merge_sized (s : State n) (x y : Fin n)
(hs : Sized s) (hxy : s.head x ≠ s.head y) : Sized (s.mergeToward x y) := by
intro z
by_cases hzx : s.head z = s.head x
· rw [merge_class_left s x y z hzx, card_union_of_disjoint (class_disjoint s hxy)]
simp [setSize, mergeToward, hzx, ← hs x, ← hs y]
· by_cases hzy : s.head z = s.head y
· rw [merge_class_right s x y z hxy hzy, card_union_of_disjoint (class_disjoint s hxy)]
simp [setSize, mergeToward, hzy, ← hs x, ← hs y]
· rw [merge_class_other s x y z hzx hzy]
simpa [setSize, mergeToward, hzx, hzy] using hs ztheorem union_sized (s : State n) (x y : Fin n) (hs : Sized s) :
Sized (s.weightedUnion x y).1 := by
unfold weightedUnion
split
· exact hs
· rename_i hxy
split
· exact merge_sized s x y hs hxy
· exact merge_sized s y x hs (Ne.symm hxy)theorem merge_size_mono (s : State n) (x y z : Fin n)
(_hxy : s.head x ≠ s.head y) :
s.setSize z ≤ (s.mergeToward x y).setSize z := by
by_cases hzx : s.head z = s.head x
· simp [setSize, mergeToward, hzx]
· by_cases hzy : s.head z = s.head y
· simp [setSize, mergeToward, hzy]
· simp [setSize, mergeToward, hzx, hzy]theorem union_size_mono (s : State n) (x y z : Fin n) :
s.setSize z ≤ (s.weightedUnion x y).1.setSize z := by
unfold weightedUnion
split
· exact Nat.le_refl _
· rename_i hxy
split
· exact merge_size_mono s x y z hxy
· exact merge_size_mono s y x z (Ne.symm hxy)Enumerate actual pre/post representative changes for the audit ledger.
def changes (s t : State n) : List (Fin n) :=
(List.finRange n).filter (fun z => decide (t.head z ≠ s.head z))
theorem changes_count (s t : State n) (z : Fin n) :
(changes s t).count z = if t.head z ≠ s.head z then 1 else 0 := by
by_cases h : t.head z ≠ s.head z
· rw [if_pos h]
exact List.count_eq_one_of_mem ((List.nodup_finRange n).filter _) (by simp [changes, h])
· rw [if_neg h]
apply List.count_eq_zero.mpr
simp [changes, h]theorem sum_counts (xs : List (Fin n)) : ∑ z, xs.count z = xs.length := by
induction xs with
| nil => simp
| cons x xs ih => simp [List.count_cons, Finset.sum_add_distrib, ih, beq_iff_eq]theorem changes_length (s t : State n) :
(changes s t).length = ∑ z, (changes s t).count z := by
exact (sum_counts (changes s t)).symmtheorem merge_changes (s : State n) (x y : Fin n)
(hxy : s.head x ≠ s.head y) :
changes s (s.mergeToward x y) =
(List.finRange n).filter (fun z => decide (s.head z = s.head x)) := by
apply List.filter_congr
intro z _
by_cases hz : s.head z = s.head x
· simp [mergeToward, hz, Ne.symm hxy]
· simp [mergeToward, hz]
theorem merge_changes_length (s : State n) (x y : Fin n)
(hxy : s.head x ≠ s.head y) :
(changes s (s.mergeToward x y)).length = (classOf s x).card := by
rw [merge_changes s x y hxy]
rw [← List.toFinset_card_of_nodup ((List.nodup_finRange n).filter _)]
congr 1
ext z
simp [classOf]theorem union_changes_cost (s : State n) (x y : Fin n) (hs : Sized s) :
(changes s (s.weightedUnion x y).1).length = (s.weightedUnion x y).2 := by
unfold weightedUnion
split
· simp [changes]
· rename_i hxy
split
· exact (merge_changes_length s x y hxy).trans (hs x).symm
· exact (merge_changes_length s y x (Ne.symm hxy)).trans (hs y).symmstructure Step (n : Nat) where
state : State n
output : Option (Fin n)
rewritten : List (Fin n)def step (s : State n) : Operation (Fin n) → Step n
| .find x => ⟨s, some (s.head x), []⟩
| .union x y =>
let next := s.weightedUnion x y
⟨next.1, none, changes s next.1⟩theorem step_sized (s : State n) (op : Operation (Fin n)) (hs : Sized s) :
Sized (step s op).state := by
cases op with
| find x => exact hs
| union x y => exact union_sized s x y hstheorem step_headInvariant (s : State n) (op : Operation (Fin n))
(hs : s.HeadInvariant) : (step s op).state.HeadInvariant := by
cases op with
| find x => exact hs
| union x y => exact s.weightedUnion_preserves_headInvariant x y hstheorem step_growth (s : State n) (op : Operation (Fin n)) (z : Fin n) :
2 ^ (step s op).rewritten.count z * s.setSize z ≤ (step s op).state.setSize z := by
cases op with
| find x => simp [step]
| union x y =>
simp only [step, changes_count]
split
· simpa using s.weightedUnion_changed_doubles x y z ‹_›
· simpa using union_size_mono s x y zstructure Run (n : Nat) where
state : State n
outputs : List (Option (Fin n))
moves : Fin n → Nat
rewrites : Nat
commands : NatRun native transitions, returning query outputs and the derived rewrite ledger.
def execute (s : State n) : List (Operation (Fin n)) → Run n
| [] => ⟨s, [], fun _ => 0, 0, 0⟩
| op :: ops =>
let current := step s op
let rest := execute current.state ops
⟨rest.state, current.output :: rest.outputs,
fun z => current.rewritten.count z + rest.moves z,
current.rewritten.length + rest.rewrites, rest.commands + 1⟩theorem execute_sized (s : State n) (ops : List (Operation (Fin n))) (hs : Sized s) :
Sized (execute s ops).state := by
induction ops generalizing s with
| nil => exact hs
| cons op ops ih => exact ih _ (step_sized s op hs)theorem execute_headInvariant (s : State n) (ops : List (Operation (Fin n)))
(hs : s.HeadInvariant) : (execute s ops).state.HeadInvariant := by
induction ops generalizing s with
| nil => exact hs
| cons op ops ih => exact ih _ (step_headInvariant s op hs)The returned rewrite total is exactly the sum of its per-element move counts.
theorem execute_rewrites_eq_sum (s : State n) (ops : List (Operation (Fin n))) :
(execute s ops).rewrites = ∑ z, (execute s ops).moves z := by
induction ops generalizing s with
| nil => simp [execute]
| cons op ops ih =>
simp only [execute, Finset.sum_add_distrib, ← ih]
congr 1
exact (sum_counts (step s op).rewritten).symmtheorem execute_growth (s : State n) (ops : List (Operation (Fin n))) (z : Fin n) :
2 ^ (execute s ops).moves z * s.setSize z ≤ (execute s ops).state.setSize z := by
induction ops generalizing s with
| nil => simp [execute]
| cons op ops ih =>
have hg := step_growth s op z
have ht := ih (step s op).state
simp only [execute, pow_add]
calc
_ = 2 ^ (execute (step s op).state ops).moves z *
(2 ^ (step s op).rewritten.count z * s.setSize z) := by ring
_ ≤ 2 ^ (execute (step s op).state ops).moves z * (step s op).state.setSize z :=
Nat.mul_le_mul_left _ hg
_ ≤ _ := ht
theorem execute_singleton_moves_le (ops : List (Operation (Fin n))) (z : Fin n) :
(execute (State.singleton n) ops).moves z ≤ Nat.log2 n := by
have hs := execute_sized (State.singleton n) ops singleton_sized
have hg := execute_growth (State.singleton n) ops z
rw [singleton_size, Nat.mul_one, hs z] at hg
apply (Nat.le_log2 (by have h := z.isLt; omega)).2
exact hg.trans (by simpa [classOf] using Finset.card_le_card (Finset.filter_subset
(fun w => (execute (State.singleton n) ops).state.head w =
(execute (State.singleton n) ops).state.head z) (univ : Finset (Fin n))))Aggregate doubling bound for arbitrary operations from singleton sets.
theorem execute_singleton_rewrites_le (ops : List (Operation (Fin n))) :
(execute (State.singleton n) ops).rewrites ≤ n * Nat.log2 n := by
rw [execute_rewrites_eq_sum]
exact total_rewrites_le_n_mul_log2 _ (execute_singleton_moves_le ops)private theorem partition_ext {P Q : Partition (Fin n)}
(h : ∀ x y, P.sameSet x y ↔ Q.sameSet x y) : P = Q := by
cases P
cases Q
congr
funext x y
exact propext (h x y)theorem step_refines_spec (s : State n) (op : Operation (Fin n)) :
(step s op).state.partition = stepSpec s.partition op := by
cases op with
| find x => rfl
| union x y =>
apply partition_ext
intro a b
exact s.weightedUnion_refines_merge x y a b
theorem execute_refines_spec (s : State n) (ops : List (Operation (Fin n))) :
(execute s ops).state.partition = runSpec s.partition ops := by
induction ops generalizing s with
| nil => rfl
| cons op ops ih =>
change (execute (step s op).state ops).state.partition = runSpec (stepSpec s.partition op) ops
rw [ih, step_refines_spec]theorem execute_commands (s : State n) (ops : List (Operation (Fin n))) :
(execute s ops).commands = ops.length := by
induction ops generalizing s with
| nil => rfl
| cons op ops ih => simp [execute, ih]theorem execute_outputs_length (s : State n) (ops : List (Operation (Fin n))) :
(execute s ops).outputs.length = ops.length := by
induction ops generalizing s with
| nil => rfl
| cons op ops ih => simp [execute, ih]theorem execute_append_state (s : State n) (xs ys : List (Operation (Fin n))) :
(execute s (xs ++ ys)).state = (execute (execute s xs).state ys).state := by
induction xs generalizing s with
| nil => rfl
| cons op xs ih => exact ih (step s op).statetheorem execute_append_outputs (s : State n) (xs ys : List (Operation (Fin n))) :
(execute s (xs ++ ys)).outputs =
(execute s xs).outputs ++ (execute (execute s xs).state ys).outputs := by
induction xs generalizing s with
| nil => rfl
| cons op xs ih => simp [execute, ih]A FIND returns the representative in the state reached by its preceding commands.
theorem execute_find_output (s : State n) (before suffix : List (Operation (Fin n)))
(x : Fin n) :
(execute s (before ++ .find x :: suffix)).outputs[before.length]? =
some (some ((execute s before).state.head x)) := by
rw [execute_append_outputs, List.getElem?_append_right (by rw [execute_outputs_length])]
simp [execute_outputs_length, execute, step]Returned FIND representatives are resident representatives of the queried class.
theorem execute_find_representative (s : State n) (before : List (Operation (Fin n)))
(hs : s.HeadInvariant) (x : Fin n) :
(execute s before).state.sameSet x ((execute s before).state.head x) ∧
(execute s before).state.head ((execute s before).state.head x) =
(execute s before).state.head x := by
have hi := execute_headInvariant s before hs x
exact ⟨hi.symm, hi⟩One abstract command event plus actual representative-pointer changes. This excludes scanning head tables to enumerate the audit events.
theorem execute_singleton_charged_le (ops : List (Operation (Fin n))) :
(execute (State.singleton n) ops).charged ≤ ops.length + n * Nat.log2 n := by
unfold Run.charged
rw [execute_commands]
exact Nat.add_le_add_left (execute_singleton_rewrites_le ops) _end CLRS.Chapter21.LinkedList.WeightedExecution