Imports
Refinement from binary heaps to sorted Huffman queues
The ordered entry list is a proof-only observation. The executable operations use only the array heap; sorting appears solely in the refinement specification.
namespace CLRS.HuffmanV2Insert one entry into a priority-sorted proof view.
def insertEntry (e : HeapEntry) : List HeapEntry → List HeapEntry
| [] => [e]
| u :: us =>
if HeapEntry.PriorityLE e u then e :: u :: us
else u :: insertEntry e usCanonical priority-sorted observation of an entry multiset.
def orderedEntries : List HeapEntry → List HeapEntry
| [] => []
| e :: es => insertEntry e (orderedEntries es)@[simp] theorem insertEntry_length (e : HeapEntry) (es : List HeapEntry) :
(insertEntry e es).length = es.length + 1 := by
induction es with
| nil => rfl
| cons u us ih => simp [insertEntry]; split <;> simp [ih]theorem insertEntry_perm (e : HeapEntry) (es : List HeapEntry) :
(insertEntry e es).Perm (e :: es) := by
induction es with
| nil => rfl
| cons u us ih =>
simp only [insertEntry]
split
· rfl
· exact (List.Perm.cons u ih).trans (List.Perm.swap u e us).symm@[simp] theorem orderedEntries_length (es : List HeapEntry) :
(orderedEntries es).length = es.length := by
induction es with
| nil => rfl
| cons e es ih => simp [orderedEntries, ih]theorem orderedEntries_perm (es : List HeapEntry) :
(orderedEntries es).Perm es := by
induction es with
| nil => rfl
| cons e es ih =>
exact (insertEntry_perm e (orderedEntries es)).trans (List.Perm.cons e ih)theorem mem_insertEntry (x e : HeapEntry) (es : List HeapEntry) :
x ∈ insertEntry e es ↔ x = e ∨ x ∈ es := by
simpa only [List.mem_cons] using List.Perm.mem_iff (insertEntry_perm e es)theorem mem_orderedEntries (x : HeapEntry) (es : List HeapEntry) :
x ∈ orderedEntries es ↔ x ∈ es :=
List.Perm.mem_iff (orderedEntries_perm es)
theorem pairwise_insertEntry {e : HeapEntry} {es : List HeapEntry}
(hsorted : es.Pairwise HeapEntry.PriorityLE) :
(insertEntry e es).Pairwise HeapEntry.PriorityLE := by
induction es with
| nil => simp [insertEntry]
| cons u us ih =>
rw [List.pairwise_cons] at hsorted
simp only [insertEntry]
by_cases heu : HeapEntry.PriorityLE e u
· rw [if_pos heu, List.pairwise_cons]
refine ⟨?_, (List.pairwise_cons.mpr hsorted)⟩
intro x hx
simp only [List.mem_cons] at hx
rcases hx with hxu | hx
· subst x
exact heu
· exact HeapEntry.priorityLE_trans heu (hsorted.1 x hx)
· rw [if_neg heu, List.pairwise_cons]
refine ⟨?_, ih hsorted.2⟩
intro x hx
rw [mem_insertEntry] at hx
rcases hx with hxe | hx
· subst x
rcases HeapEntry.priorityLE_total u e with hue | heu'
· exact hue
· exact False.elim (heu heu')
· exact hsorted.1 x hxtheorem orderedEntries_pairwise (es : List HeapEntry) :
(orderedEntries es).Pairwise HeapEntry.PriorityLE := by
induction es with
| nil => simp [orderedEntries]
| cons e es ih => exact pairwise_insertEntry ihtheorem map_stamp_perm_of_perm {as bs : List HeapEntry} (h : as.Perm bs) :
(as.map HeapEntry.stamp).Perm (bs.map HeapEntry.stamp) := h.map _private theorem eq_of_same_stamp_mem_cons
{a b : HeapEntry} {as : List HeapEntry}
(hnodup : (HeapEntry.stamp a :: as.map HeapEntry.stamp).Nodup)
(hb : b ∈ a :: as) (hstamp : b.stamp = a.stamp) : b = a := by
simp only [List.mem_cons] at hb
rcases hb with hba | hb
· exact hba
· have hmem : b.stamp ∈ as.map HeapEntry.stamp :=
List.mem_map.mpr ⟨b, hb, rfl⟩
have hnot := (List.nodup_cons.mp hnodup).1
exact False.elim (hnot (hstamp ▸ hmem))A sorted permutation with distinct stamps is unique.
theorem eq_of_pairwise_priority_of_perm :
∀ {as bs : List HeapEntry},
as.Pairwise HeapEntry.PriorityLE →
bs.Pairwise HeapEntry.PriorityLE →
(as.map HeapEntry.stamp).Nodup →
as.Perm bs → as = bs
| [], bs, _, _, _, hperm => by
cases bs with
| nil => rfl
| cons b bs => simpa using hperm.length_eq
| a :: as, [], _, _, _, hperm => by simpa using hperm.length_eq
| a :: as, b :: bs, has, hbs, hnodup, hperm => by
rw [List.pairwise_cons] at has hbs
have hbIn : b ∈ a :: as :=
(List.Perm.mem_iff hperm).mpr (by simp)
have haIn : a ∈ b :: bs :=
(List.Perm.mem_iff hperm).mp (by simp)
have hab : HeapEntry.PriorityLE a b := by
simp only [List.mem_cons] at hbIn
rcases hbIn with hba | hbTail
· subst b
exact HeapEntry.priorityLE_refl _
· exact has.1 b hbTail
have hba : HeapEntry.PriorityLE b a := by
simp only [List.mem_cons] at haIn
rcases haIn with hab | haTail
· subst a
exact HeapEntry.priorityLE_refl _
· exact hbs.1 a haTail
have hcomponents := HeapEntry.priorityLE_antisymm_components hab hba
have habEq : b = a :=
eq_of_same_stamp_mem_cons hnodup hbIn hcomponents.2.symm
subst b
have htailPerm : as.Perm bs := hperm.cons_inv
have htailNodup : (as.map HeapEntry.stamp).Nodup :=
(List.nodup_cons.mp hnodup).2
rw [eq_of_pairwise_priority_of_perm has.2 hbs.2 htailNodup htailPerm]Priority sorting is invariant under permutations with distinct stamps.
theorem orderedEntries_eq_of_perm {as bs : List HeapEntry}
(hnodup : (as.map HeapEntry.stamp).Nodup) (hperm : as.Perm bs) :
orderedEntries as = orderedEntries bs := by
apply eq_of_pairwise_priority_of_perm
(orderedEntries_pairwise as) (orderedEntries_pairwise bs)
· exact (map_stamp_perm_of_perm (orderedEntries_perm as)).nodup_iff.mpr hnodup
· exact (orderedEntries_perm as).trans (hperm.trans (orderedEntries_perm bs).symm)theorem orderedEntries_stamps_nodup {es : List HeapEntry}
(h : (es.map HeapEntry.stamp).Nodup) :
((orderedEntries es).map HeapEntry.stamp).Nodup :=
(map_stamp_perm_of_perm (orderedEntries_perm es)).nodup_iff.mpr hHeap operation observations
def MinHeap.orderedView {params : HeapParams} (h : MinHeap params) :
List HeapEntry := orderedEntries h.datatheorem MinHeap.orderedView_insert {params : HeapParams} (h : MinHeap params)
(e : HeapEntry) (he : params.Bounded e)
(hnodup : ((e :: h.data).map HeapEntry.stamp).Nodup) :
(h.insert e he).orderedView = insertEntry e h.orderedView := by
change orderedEntries (h.insert e he).data =
orderedEntries (e :: h.data)
exact orderedEntries_eq_of_perm
((map_stamp_perm_of_perm (MinHeap.insert_perm h e he)).nodup_iff.mpr hnodup)
(MinHeap.insert_perm h e he)
theorem MinHeap.orderedView_extractMin {params : HeapParams}
{h h' : MinHeap params} {e : HeapEntry}
(hnodup : (h.data.map HeapEntry.stamp).Nodup)
(hextract : h.extractMin = some (e, h')) :
h.orderedView = e :: h'.orderedView := by
have hspec := MinHeap.extractMin_spec hextract
apply eq_of_pairwise_priority_of_perm
(orderedEntries_pairwise h.data) ?_ ?_ ?_
· rw [List.pairwise_cons]
refine ⟨?_, orderedEntries_pairwise h'.data⟩
intro u hu
have hu' : u ∈ h'.data := (mem_orderedEntries u h'.data).mp hu
have huOld : u ∈ h.data :=
(List.Perm.mem_iff hspec.1).mp (List.mem_cons_of_mem e hu')
exact hspec.2.2 u huOld
· exact (map_stamp_perm_of_perm (orderedEntries_perm h.data)).nodup_iff.mpr hnodup
· exact (orderedEntries_perm h.data).trans
(hspec.1.symm.trans (List.Perm.cons e (orderedEntries_perm h'.data).symm))Erasing stable entries to the existing sorted forest
theorem map_tree_insertEntry_of_stamp_lt (e : HeapEntry) (es : List HeapEntry)
(hstamps : ∀ u ∈ es, e.stamp < u.stamp) :
(insertEntry e es).map HeapEntry.tree =
insortTree e.tree (es.map HeapEntry.tree) := by
induction es with
| nil => rfl
| cons u us ih =>
simp only [insertEntry, insortTree, List.map_cons]
have hstamp := hstamps u (by simp)
by_cases hfreq : rootFreq e.tree ≤ rootFreq u.tree
· have hpriority : HeapEntry.PriorityLE e u := by
rcases Nat.lt_or_eq_of_le hfreq with hlt | heq
· exact Or.inl hlt
· exact Or.inr ⟨heq, Nat.le_of_lt hstamp⟩
simp [hpriority, hfreq]
· have hpriority : ¬ HeapEntry.PriorityLE e u := by
intro h
rcases h with hlt | ⟨heq, _⟩
· exact hfreq (Nat.le_of_lt hlt)
· exact hfreq (Nat.le_of_eq heq)
simp [hpriority, hfreq, ih (fun v hv => hstamps v (by simp [hv]))]
theorem orderedEntries_decorateFrom_trees (base : Nat) (ts : List HuffTree) :
(orderedEntries (decorateFrom base ts)).map HeapEntry.tree = sortForest ts := by
induction ts generalizing base with
| nil => rfl
| cons t ts ih =>
simp only [decorateFrom, orderedEntries, sortForest]
rw [map_tree_insertEntry_of_stamp_lt, ih]
intro u hu
have hu' : u ∈ decorateFrom (base + 1) ts :=
(mem_orderedEntries u (decorateFrom (base + 1) ts)).mp hu
have hge := decorateFrom_stamp_ge hu'
change base < u.stamp
omegatheorem orderedEntries_initial_trees (ts : List HuffTree) :
(orderedEntries (initialEntries ts)).map HeapEntry.tree = sortForest ts := by
exact orderedEntries_decorateFrom_trees ts.length tsend CLRS.HuffmanV2