Binary heap
DefinitionParent index in a level-order binary tree#✓fully proved
In a binary tree stored in level order in an array indexed from \(0\), the parent index of a natural number \(i\) is \(\lfloor (i-1)/2 \rfloor\), where \(i - 1\) is truncated subtraction of natural numbers, so the root index \(0\) is sent to \(0\).
Used by 29
DefinitionLeft child index in a level-order binary tree#✓fully proved
In a binary tree stored in level order in an array indexed from \(0\), the left child of the node at index \(i\) has index \(2i + 1\).
Used by 12
DefinitionRight child index in an array-backed binary tree#✓fully proved
In the level-order layout of a binary tree in an array indexed from \(0\), the right child of the node at index \(i\) is at index \(2i + 2\).
Used by 16
TheoremThe parent of a valid nonroot index is valid#✓fully proved
For an array \(a\) of length \(|a|\) and an index \(i\) with \(0 < i < |a|\), the parent index \(\lfloor (i-1)/2 \rfloor\) of \(i\) is also less than \(|a|\).
theorem heapParent_lt_size {α : Type u} (a : Array α) (i : Nat)
(hi : i < a.size) (hpos : 0 < i) : heapParent i < a.size
def heapParent (i : Nat) : Nat := (i - 1) / 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:30
Uses 1 · Used by 27
DefinitionHeap order on a level-order array#✓fully proved
An array \(a\) over a type with a relation \(\le\), indexed from \(0\), is heap ordered when every entry other than the root is at least its parent entry: for every index \(i\) with \(0 < i < |a|\), where \(|a|\) is the length of \(a\), we have \(a_{\lfloor (i-1)/2 \rfloor} \le a_i\).
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
def heapParent (i : Nat) : Nat := (i - 1) / 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:30
theorem heapParent_lt_size {α : Type u} (a : Array α) (i : Nat)
(hi : i < a.size) (hpos : 0 < i) : heapParent i < a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:44
Uses 2 · Used by 30
StructureArrays ready for sift-up#✓fully proved
Let \(a\) be an array of length \(|a|\) over a type with a relation \(\le\), indexed from \(0\), and for \(j > 0\) let \(p(j) = \lfloor (j - 1)/2 \rfloor\) be the parent of \(j\). The array \(a\) is ready for sift-up at an index \(i\) when \(i < |a|\), when \(a_{p(j)} \le a_j\) for every \(j \ne i\) with \(0 < j < |a|\), and when, if \(i > 0\), also \(a_{p(i)} \le a_j\) for every \(j\) with \(0 < j < |a|\) and \(p(j) = i\).
structure SiftUpReady {α : Type u} [LE α] (a : Array α) (i : Nat) : Prop where
index_valid : i < a.size
ordered_except : ∀ j (hj : j < a.size), (hjpos : 0 < j) → j ≠ i →
a[heapParent j]'(heapParent_lt_size a j hj hjpos) ≤ a[j]
parent_below_children : ∀ j (hj : j < a.size), (hjpos : 0 < j) →
heapParent j = i → (hipos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i index_valid hipos) ≤ a[j]
def heapParent (i : Nat) : Nat := (i - 1) / 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:30
theorem heapParent_lt_size {α : Type u} (a : Array α) (i : Nat)
(hi : i < a.size) (hpos : 0 < i) : heapParent i < a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:44
index_valid : i < a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:56
Uses 2 · Used by 7
StructureSift-down precondition#✓fully proved
For an array \(a\) over a type ordered by \(\le\), write \(p(j) = \lfloor (j-1)/2 \rfloor\) for the parent of index \(j\). The array \(a\) is ready for sift-down at index \(i\) when \(i\) is a valid index of \(a\); \(a_{p(j)} \le a_j\) for every valid index \(j > 0\) with \(p(j) \ne i\); and, if \(i > 0\), \(a_{p(i)} \le a_j\) for every valid index \(j > 0\) with \(p(j) = i\).
Thus the only edges that may violate heap order are those leaving \(i\), and moving either child of \(i\) up to position \(i\) keeps the edge entering \(i\) ordered.
structure SiftDownReady {α : Type u} [LE α] (a : Array α) (i : Nat) : Prop where
index_valid : i < a.size
ordered_except : ∀ j (hj : j < a.size), (hjpos : 0 < j) →
heapParent j ≠ i →
a[heapParent j]'(heapParent_lt_size a j hj hjpos) ≤ a[j]
parent_below_children : ∀ j (hj : j < a.size), (hjpos : 0 < j) →
heapParent j = i → (hipos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i index_valid hipos) ≤ a[j]
def heapParent (i : Nat) : Nat := (i - 1) / 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:30
theorem heapParent_lt_size {α : Type u} (a : Array α) (i : Nat)
(hi : i < a.size) (hpos : 0 < i) : heapParent i < a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:44
index_valid : i < a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:66
Uses 2 · Used by 2
DefinitionSmaller child#✓fully proved
Let \(a\) be an array of length \(|a|\) over a linearly ordered type, indexed from \(0\), and let \(i\) be an index with children \(\ell = 2i + 1\) and \(r = 2i + 2\). If \(\ell \ge |a|\), then \(i\) has no smaller child. Otherwise the smaller child of \(i\) is \(r\) when \(r < |a|\) and \(a_r < a_\ell\), and \(\ell\) in every other case, so ties go to the left child.
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
def heapLeft (i : Nat) : Nat := 2 * i + 1
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:33
def heapRight (i : Nat) : Nat := 2 * i + 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:36
Uses 2 · Used by 19
TheoremThe smaller child has a larger index#✓fully proved
For every array \(a\) over a linearly ordered type and all indices \(i\) and \(c\), if \(c\) is the smaller child of \(i\) in \(a\), then \(i < c\).
theorem smallerChild_gt {α : Type u} [LinearOrder α]
(a : Array α) (i c : Nat)
(h : smallerChild a i = some c) : i < c
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:99
Uses 3 · Used by 13
TheoremThe smaller child is a valid index#✓fully proved
For every array \(a\) over a linearly ordered type and all indices \(i\) and \(c\), if \(c\) is the smaller child of \(i\) in \(a\), then \(c\) is less than the length \(|a|\) of \(a\).
theorem smallerChild_valid {α : Type u} [LinearOrder α]
(a : Array α) (i c : Nat)
(h : smallerChild a i = some c) : c < a.size
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:99
Uses 3 · Used by 13
DefinitionSift-up#✓fully proved
Given an array \(a\) of length \(|a|\) over a linearly ordered type, indexed from \(0\), and an index \(i\), the sift-up of \(a\) from \(i\) is defined by recursion on \(i\). If \(i = 0\) or \(i \ge |a|\), the result is \(a\). Otherwise let \(p = \lfloor (i - 1)/2 \rfloor\) be the parent of \(i\); if \(a_i < a_p\), the result is the sift-up from \(p\) of the array obtained from \(a\) by exchanging the entries at positions \(i\) and \(p\), and otherwise the result is \(a\).
Cslib.Algorithms.Lean.siftUp · 15 lines
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
if hi : i < a.size then
if hpos : 0 < i then
let p := heapParent i
if hlt : a[i] < a[p]'(heapParent_lt_size a i hi hpos) then
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
a
else
a
else
a
termination_by i
decreasing_by
exact heapParent_lt i hpos
def heapParent (i : Nat) : Nat := (i - 1) / 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:30
theorem heapParent_lt_size {α : Type u} (a : Array α) (i : Nat)
(hi : i < a.size) (hpos : 0 < i) : heapParent i < a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:44
Uses 2 · Used by 26
DefinitionSift-down#✓fully proved
Sifting down an array \(a\) over a linearly ordered type from index \(i\) works as follows. If \(i\) has a child in \(a\), that is, if \(2i+1\) is a valid index, let \(c\) be the child of \(i\) (among \(2i+1\) and \(2i+2\), if valid) holding the smaller value, preferring the left child \(2i+1\) on ties. If \(a_c < a_i\), swap the entries at \(i\) and \(c\) and continue sifting down from \(c\); otherwise, or if \(i\) has no child, return the array unchanged.
Cslib.Algorithms.Lean.siftDown · 15 lines
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
match hchild : smallerChild a i with
| none => a
| some c =>
have hc : c < a.size := smallerChild_valid a i c hchild
have hi : i < a.size := (smallerChild_gt a i c hchild).trans hc
if hlt : a[c] < a[i] then
siftDown (a.swap i c hi hc) c
else
a
termination_by a.size - i
decreasing_by
simp only [Array.size_swap]
have := smallerChild_gt a i c hchild
omega
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:99
theorem smallerChild_valid {α : Type u} [LinearOrder α]
(a : Array α) (i c : Nat)
(h : smallerChild a i = some c) : c < a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:153
theorem smallerChild_gt {α : Type u} [LinearOrder α]
(a : Array α) (i c : Nat)
(h : smallerChild a i = some c) : i < c
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:131
Uses 3 · Used by 11
TheoremSift-up permutes the array#✓fully proved
For every array \(a\) over a linearly ordered type and every index \(i\), the array obtained by sifting up \(a\) from \(i\) is a permutation of \(a\).
theorem siftUp_perm {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(siftUp a i).Perm a
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
if hi : i < a.size then
if hpos : 0 < i then
let p := heapParent i
if hlt : a[i] < a[p]'(heapParent_lt_size a i hi hpos) then
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
a
else
a
else
a
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:193
Uses 3 · Used by 18
TheoremBinary-heap sift-down permutes the array#✓fully proved
For every array \(a\) over a linearly ordered type and every index \(i\), the array obtained by sifting down \(a\) from \(i\) is a permutation of \(a\).
theorem siftDown_perm {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(siftDown a i).Perm a
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
match hchild : smallerChild a i with
| none => a
| some c =>
have hc : c < a.size := smallerChild_valid a i c hchild
have hi : i < a.size := (smallerChild_gt a i c hchild).trans hc
if hlt : a[c] < a[i] then
siftDown (a.swap i c hi hc) c
else
a
termination_by a.size - i
decreasing_by
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:210
Uses 4 · Used by 7
TheoremBinary-heap sift-up preserves the multiset of entries#✓fully proved
For every array \(a\) over a linearly ordered type and every index \(i\), the array obtained by sifting up \(a\) from \(i\) has the same multiset of entries as \(a\).
theorem siftUp_multiset {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(↑(siftUp a i).toList : Multiset α) = (↑a.toList : Multiset α)
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
if hi : i < a.size then
if hpos : 0 < i then
let p := heapParent i
if hlt : a[i] < a[p]'(heapParent_lt_size a i hi hpos) then
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
a
else
a
else
a
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:193
Uses 2 · Used by 1
TheoremBinary-heap sift-down preserves the multiset of entries#✓fully proved
For every array \(a\) over a linearly ordered type and every index \(i\), the array obtained by sifting down \(a\) from \(i\) has the same multiset of entries as \(a\).
theorem siftDown_multiset {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(↑(siftDown a i).toList : Multiset α) = (↑a.toList : Multiset α)
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
match hchild : smallerChild a i with
| none => a
| some c =>
have hc : c < a.size := smallerChild_valid a i c hchild
have hi : i < a.size := (smallerChild_gt a i c hchild).trans hc
if hlt : a[c] < a[i] then
siftDown (a.swap i c hi hc) c
else
a
termination_by a.size - i
decreasing_by
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:210
Uses 2
TheoremThe root of a heap-ordered binary-heap array is minimal#✓fully proved
If an array \(a\) over a linearly ordered type is heap-ordered, then \(a_0 \le a_i\) for every valid index \(i\) of \(a\).
theorem HeapOrdered.root_le {α : Type u} [LinearOrder α] {a : Array α}
(h : HeapOrdered a) (i : Nat) (hi : i < a.size) :
a[0]'(by omega) ≤ a[i]
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:49
Uses 3 · Used by 2
TheoremSift-up restores heap order#✓fully proved
Let \(a\) be an array over a linearly ordered type and let \(i\) be an index such that \(a\) is ready for sift-up at \(i\). Then the array obtained by sifting up \(a\) from \(i\) is heap ordered.
theorem siftUp_ordered {α : Type u} [LinearOrder α] (a : Array α) (i : Nat)
(h : SiftUpReady a i) : HeapOrdered (siftUp a i)
structure SiftUpReady {α : Type u} [LE α] (a : Array α) (i : Nat) : Prop where
index_valid : i < a.size
ordered_except : ∀ j (hj : j < a.size), (hjpos : 0 < j) → j ≠ i →
a[heapParent j]'(heapParent_lt_size a j hj hjpos) ≤ a[j]
parent_below_children : ∀ j (hj : j < a.size), (hjpos : 0 < j) →
heapParent j = i → (hipos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i index_valid hipos) ≤ a[j]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:55
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:49
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
if hi : i < a.size then
if hpos : 0 < i then
let p := heapParent i
if hlt : a[i] < a[p]'(heapParent_lt_size a i hi hpos) then
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
a
else
a
else
a
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:193
Uses 5 · Used by 6
TheoremSift-down restores heap order#✓fully proved
Let \(a\) be an array over a linearly ordered type that satisfies the sift-down precondition at a valid index \(i\): the only edges that may violate heap order are those leaving \(i\), and moving either child of \(i\) up to position \(i\) keeps the edge entering \(i\) ordered. Then the array obtained by sifting down \(a\) from \(i\) is heap-ordered.
theorem siftDown_ordered {α : Type u} [LinearOrder α] (a : Array α) (i : Nat)
(h : SiftDownReady a i) : HeapOrdered (siftDown a i)
structure SiftDownReady {α : Type u} [LE α] (a : Array α) (i : Nat) : Prop where
index_valid : i < a.size
ordered_except : ∀ j (hj : j < a.size), (hjpos : 0 < j) →
heapParent j ≠ i →
a[heapParent j]'(heapParent_lt_size a j hj hjpos) ≤ a[j]
parent_below_children : ∀ j (hj : j < a.size), (hjpos : 0 < j) →
heapParent j = i → (hipos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i index_valid hipos) ≤ a[j]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:65
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:49
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
match hchild : smallerChild a i with
| none => a
| some c =>
have hc : c < a.size := smallerChild_valid a i c hchild
have hi : i < a.size := (smallerChild_gt a i c hchild).trans hc
if hlt : a[c] < a[i] then
siftDown (a.swap i c hi hc) c
else
a
termination_by a.size - i
decreasing_by
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:210
Uses 10 · Used by 7
TheoremAppending to a heap-ordered array prepares it for sift-up#✓fully proved
If an array \(a\) of length \(n\) over a linearly ordered type is heap-ordered and \(x\) is any value, then the array obtained by appending \(x\) to \(a\) satisfies the sift-up precondition at index \(n\), the position of \(x\): the only edge that may violate heap order is the one entering index \(n\).
theorem push_siftUpReady {α : Type u} [LinearOrder α] (a : Array α)
(h : HeapOrdered a) (x : α) : SiftUpReady (a.push x) a.size
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:49
structure SiftUpReady {α : Type u} [LE α] (a : Array α) (i : Nat) : Prop where
index_valid : i < a.size
ordered_except : ∀ j (hj : j < a.size), (hjpos : 0 < j) → j ≠ i →
a[heapParent j]'(heapParent_lt_size a j hj hjpos) ≤ a[j]
parent_below_children : ∀ j (hj : j < a.size), (hjpos : 0 < j) →
heapParent j = i → (hipos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i index_valid hipos) ≤ a[j]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:55
Uses 4 · Used by 1
StructureBinary min-heap#✓fully proved
A binary min-heap over a linearly ordered type \(\alpha\) is an array \(a\) of elements of \(\alpha\) (its level-order storage), of length \(|a|\) and with entries \(a_0, \dots, a_{|a|-1}\), that is heap ordered: for every index \(i\) with \(0 < i < |a|\), the entry \(a_{\lfloor (i - 1)/2 \rfloor}\) at the parent index of \(i\) is at most \(a_i\).
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:49
data : Array α
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:540
Uses 1 · Used by 72
DefinitionElements of a binary min-heap#✓fully proved
The multiset of elements of a binary min-heap is the multiset of the entries of its level-order storage array, counted with multiplicity.
def MinHeap.elements {α : Type u} [LinearOrder α] (h : MinHeap α) : Multiset α :=
h.data.toList
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 1 · Used by 29
DefinitionEmpty binary min-heap#✓fully proved
The empty binary min-heap is the min-heap whose level-order storage array has no entries.
def MinHeap.empty {α : Type u} [LinearOrder α] : MinHeap α where
data := #[]
ordered := by simp [HeapOrdered]
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 4 · Used by 14
DefinitionInsertion into a binary min-heap#✓fully proved
To insert a value \(x\) into a binary min-heap \(h\), append \(x\) at the end of the level-order array of \(h\) and sift it up from its index (the old length of the array), repeatedly swapping it with its parent while it is smaller. The result is again a binary min-heap.
def MinHeap.push {α : Type u} [LinearOrder α] (h : MinHeap α) (x : α) : MinHeap α where
data := siftUp (h.data.push x) h.data.size
ordered := siftUp_ordered _ _ (push_siftUpReady h.data h.ordered x)
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
if hi : i < a.size then
if hpos : 0 < i then
let p := heapParent i
if hlt : a[i] < a[p]'(heapParent_lt_size a i hi hpos) then
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
a
else
a
else
a
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:193
theorem siftUp_ordered {α : Type u} [LinearOrder α] (a : Array α) (i : Nat)
(h : SiftUpReady a i) : HeapOrdered (siftUp a i)
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:369
theorem push_siftUpReady {α : Type u} [LinearOrder α] (a : Array α)
(h : HeapOrdered a) (x : α) : SiftUpReady (a.push x) a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:517
Uses 5 · Used by 26
DefinitionMinimum lookup in a binary heap#✓fully proved
For a binary min-heap \(h\), the minimum lookup returns the entry at index \(0\) (the root) of the storage array of \(h\) when that array is nonempty, and returns no value when it is empty.
def MinHeap.min? {α : Type u} [LinearOrder α] (h : MinHeap α) : Option α :=
h.data[0]?
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
TheoremBinary heap minimum lookup fails exactly when empty#✓fully proved
For a binary min-heap \(h\) over a linearly ordered type, looking up the minimum of \(h\) returns no value if and only if the storage array of \(h\) has size \(0\).
theorem MinHeap.min?_eq_none_iff {α : Type u} [LinearOrder α] (h : MinHeap α) :
h.min? = none ↔ h.data.size = 0
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 2
TheoremBinary heap minimum lookup succeeds exactly when nonempty#✓fully proved
For a binary min-heap \(h\) over a linearly ordered type, looking up the minimum of \(h\) returns a value if and only if the storage array of \(h\) has positive size.
theorem MinHeap.min?_isSome_iff {α : Type u} [LinearOrder α] (h : MinHeap α) :
h.min?.isSome ↔ 0 < h.data.size
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 2
TheoremThe binary heap minimum lookup returns a stored element#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type. If looking up the minimum of \(h\) returns \(x\), then \(x\) belongs to the multiset of elements of \(h\).
theorem MinHeap.min?_mem {α : Type u} [LinearOrder α] {h : MinHeap α} {x : α}
(hx : h.min? = some x) : x ∈ h.elements
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 3
TheoremThe binary heap minimum lookup is a lower bound#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type. If looking up the minimum of \(h\) returns \(x\), then \(x \le y\) for every element \(y\) of the multiset of elements of \(h\).
theorem MinHeap.min?_le {α : Type u} [LinearOrder α] {h : MinHeap α} {x y : α}
(hx : h.min? = some x) (hy : y ∈ h.elements) : x ≤ y
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 5
TheoremElements after binary heap insertion#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type and \(x\) a value. The multiset of elements of the heap obtained by inserting \(x\) into \(h\) is the multiset of elements of \(h\) with one more copy of \(x\) added.
theorem MinHeap.elements_push {α : Type u} [LinearOrder α] (h : MinHeap α) (x : α) :
(h.push x).elements = x ::ₘ h.elements
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 5 · Used by 13
TheoremBinary heap insertion adds one copy of the inserted value#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type and \(x\) a value. The multiplicity of \(x\) in the multiset of elements of the heap obtained by inserting \(x\) into \(h\) is one more than its multiplicity in the multiset of elements of \(h\).
theorem MinHeap.count_push_self {α : Type u} [LinearOrder α]
(h : MinHeap α) (x : α) :
Multiset.count x (h.push x).elements = Multiset.count x h.elements + 1
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 4
TheoremBinary heap insertion leaves other multiplicities unchanged#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type, and let \(x \ne y\) be values. Then \(y\) occurs in the multiset of elements of the heap obtained by inserting \(x\) into \(h\) exactly as many times as it occurs in the multiset of elements of \(h\).
theorem MinHeap.count_push_of_ne {α : Type u} [LinearOrder α]
(h : MinHeap α) {x y : α} (hyx : y ≠ x) :
Multiset.count y (h.push x).elements = Multiset.count y h.elements
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 4
TheoremInsertion into a binary min-heap preserves heap order#✓fully proved
For every binary min-heap \(h\) over a linearly ordered type and every value \(x\), the level-order array of the heap obtained by inserting \(x\) into \(h\) is heap-ordered: the entry at every nonroot index \(i\) is at least the entry at its parent index \(\lfloor (i-1)/2 \rfloor\).
theorem MinHeap.push_ordered {α : Type u} [LinearOrder α] (h : MinHeap α) (x : α) :
HeapOrdered (h.push x).data
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:49
Uses 3
DefinitionMoving the last entry to the root#✓fully proved
For a nonempty array \(a\) of length \(n\), this operation swaps the entries at indices \(0\) and \(n - 1\) and then deletes the final entry. The result has length \(n - 1\); when \(n \ge 2\) its entry at index \(0\) is \(a_{n-1}\) and its entry at each index \(0 < i < n - 1\) is \(a_i\).
def moveLastToRoot {α : Type u} (a : Array α) (hne : 0 < a.size) : Array α :=
(a.swap 0 (a.size - 1) hne (by omega)).pop
Used by 9
TheoremMoving the last entry to the root prepares a sift-down#✓fully proved
Let \(a\) be a heap-ordered array over a linearly ordered type with at least two entries, and let \(b\) be the array obtained from \(a\) by moving its last entry to the root. Then \(b\) is ready for sifting down at index \(0\): index \(0\) is valid in \(b\), and for every index \(j > 0\) of \(b\) whose parent index \(\lfloor (j - 1)/2 \rfloor\) is not \(0\), the entry of \(b\) at the parent index is at most \(b_j\).
theorem moveLastToRoot_siftDownReady {α : Type u} [LinearOrder α]
(a : Array α) (h : HeapOrdered a) (htwo : 1 < a.size) :
SiftDownReady (moveLastToRoot a (by omega)) 0
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:49
structure SiftDownReady {α : Type u} [LE α] (a : Array α) (i : Nat) : Prop where
index_valid : i < a.size
ordered_except : ∀ j (hj : j < a.size), (hjpos : 0 < j) →
heapParent j ≠ i →
a[heapParent j]'(heapParent_lt_size a j hj hjpos) ≤ a[j]
parent_below_children : ∀ j (hj : j < a.size), (hjpos : 0 < j) →
heapParent j = i → (hipos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i index_valid hipos) ≤ a[j]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:65
def moveLastToRoot {α : Type u} (a : Array α) (hne : 0 < a.size) : Array α :=
(a.swap 0 (a.size - 1) hne (by omega)).pop
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:623
Uses 5 · Used by 7
TheoremMoving the last entry to the root removes the old root#✓fully proved
For a nonempty array \(a\) over a linearly ordered type, the multiset of entries of the array obtained from \(a\) by moving its last entry to the root equals the multiset of entries of \(a\) with one occurrence of \(a_0\) removed.
theorem moveLastToRoot_elements {α : Type u} [LinearOrder α]
(a : Array α) (hne : 0 < a.size) :
(↑(moveLastToRoot a hne).toList : Multiset α) =
(↑a.toList : Multiset α).erase (a[0]'hne)
def moveLastToRoot {α : Type u} (a : Array α) (hne : 0 < a.size) : Array α :=
(a.swap 0 (a.size - 1) hne (by omega)).pop
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:623
Uses 1 · Used by 1
DefinitionRemoving the root of a nonempty binary min-heap#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type whose level-order array is nonempty. If the array has exactly one entry, the result is the empty heap. Otherwise the last entry of the array replaces the root, the array shrinks by one, and the result is the heap obtained by sifting this entry down from the root.
def MinHeap.extractTail {α : Type u} [LinearOrder α]
(h : MinHeap α) (hne : 0 < h.data.size) : MinHeap α :=
if hone : h.data.size = 1 then
MinHeap.empty
else
have htwo : 1 < h.data.size := by omega
let moved := moveLastToRoot h.data hne
⟨siftDown moved 0,
siftDown_ordered moved 0
(moveLastToRoot_siftDownReady h.data h.ordered htwo)⟩
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
def MinHeap.empty {α : Type u} [LinearOrder α] : MinHeap α where
data := #[]
ordered := by simp [HeapOrdered]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:548
Uses 7 · Used by 10
DefinitionExtracting the minimum of a binary min-heap#✓fully proved
For a binary min-heap \(h\) over a linearly ordered type, extraction returns nothing when the level-order array of \(h\) is empty. Otherwise it returns the root entry (the first entry of the array) together with the heap obtained from \(h\) by removing its root and restoring heap order.
def MinHeap.extractMin {α : Type u} [LinearOrder α]
(h : MinHeap α) : Option (α × MinHeap α) :=
if hne : 0 < h.data.size then
some (h.data[0]'hne, h.extractTail hne)
else
none
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 2 · Used by 29
TheoremExtraction from a binary min-heap fails exactly when it is empty#✓fully proved
For a binary min-heap \(h\) over a linearly ordered type, extracting the minimum of \(h\) returns no result if and only if the level-order storage array of \(h\) has size \(0\).
theorem MinHeap.extractMin_eq_none_iff {α : Type u} [LinearOrder α]
(h : MinHeap α) : h.extractMin = none ↔ h.data.size = 0
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 3 · Used by 3
TheoremThe value extracted from a binary min-heap is one of its elements#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type. If extracting the minimum from \(h\) succeeds and returns a value \(x\) together with a heap \(r\), then \(x\) belongs to the multiset of elements of \(h\).
theorem MinHeap.extractMin_mem {α : Type u} [LinearOrder α]
{h : MinHeap α} {x : α} {rest : MinHeap α}
(hx : h.extractMin = some (x, rest)) : x ∈ h.elements
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 4 · Used by 8
TheoremThe value extracted from a binary min-heap is minimal#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type. If extracting the minimum from \(h\) succeeds and returns a value \(x\) together with a heap \(r\), then \(x \le y\) for every value \(y\) in the multiset of elements of \(h\).
theorem MinHeap.extractMin_le {α : Type u} [LinearOrder α]
{h : MinHeap α} {x y : α} {rest : MinHeap α}
(hx : h.extractMin = some (x, rest)) (hy : y ∈ h.elements) : x ≤ y
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 6 · Used by 6
TheoremElements after binary heap extraction#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type. If extracting the minimum of \(h\) succeeds and returns the value \(x\) and the heap \(h'\), then the multiset of elements of \(h'\) is obtained from the multiset of elements of \(h\) by erasing one occurrence of \(x\).
theorem MinHeap.extractMin_elements {α : Type u} [LinearOrder α]
{h : MinHeap α} {x : α} {rest : MinHeap α}
(hx : h.extractMin = some (x, rest)) :
rest.elements = h.elements.erase x
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 12
TheoremBinary heap extraction splits off the minimum#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type. If extracting the minimum of \(h\) succeeds and returns the value \(x\) and the heap \(h'\), then the multiset of elements of \(h\) equals the multiset of elements of \(h'\) with one copy of \(x\) added.
The statement is phrased by adding \(x\) back, not by erasing it from the multiset of \(h\).
theorem MinHeap.extractMin_cons_elements {α : Type u} [LinearOrder α]
{h : MinHeap α} {x : α} {rest : MinHeap α}
(hx : h.extractMin = some (x, rest)) :
x ::ₘ rest.elements = h.elements
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 11 · Used by 15
TheoremBinary heap extraction removes one copy of the minimum#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type. If extracting the minimum of \(h\) succeeds and returns the value \(x\) and the heap \(h'\), then the multiplicity of \(x\) in the multiset of elements of \(h'\) is its multiplicity in the multiset of elements of \(h\) minus one.
theorem MinHeap.extractMin_count {α : Type u} [LinearOrder α]
{h : MinHeap α} {x : α} {rest : MinHeap α}
(hx : h.extractMin = some (x, rest)) :
Multiset.count x rest.elements = Multiset.count x h.elements - 1
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 4
TheoremBinary heap extraction leaves other multiplicities unchanged#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type. If extracting the minimum of \(h\) succeeds and returns the value \(x\) and the heap \(h'\), then every value \(y \ne x\) occurs in the multiset of elements of \(h'\) exactly as many times as in the multiset of elements of \(h\).
theorem MinHeap.extractMin_count_of_ne {α : Type u} [LinearOrder α]
{h : MinHeap α} {x y : α} {rest : MinHeap α}
(hx : h.extractMin = some (x, rest)) (hyx : y ≠ x) :
Multiset.count y rest.elements = Multiset.count y h.elements
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 4
TheoremMembership after extraction from a binary min-heap#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type, and suppose extracting the minimum from \(h\) succeeds and returns a value \(x\) together with a heap \(r\). Then every value \(y \ne x\) is an element of \(r\) if and only if it is an element of \(h\).
theorem MinHeap.extractMin_mem_of_ne_iff {α : Type u} [LinearOrder α]
{h : MinHeap α} {x y : α} {rest : MinHeap α}
(hx : h.extractMin = some (x, rest)) (hyx : y ≠ x) :
y ∈ rest.elements ↔ y ∈ h.elements
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 4 · Used by 3
TheoremExtraction from a binary min-heap leaves a heap-ordered array#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type. If extracting the minimum from \(h\) succeeds and returns a value \(x\) together with a heap \(r\), then the level-order array of \(r\) is heap ordered: every entry other than the root is at least its parent entry.
theorem MinHeap.extractMin_ordered {α : Type u} [LinearOrder α]
{h : MinHeap α} {x : α} {rest : MinHeap α}
(_hx : h.extractMin = some (x, rest)) : HeapOrdered rest.data
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:49
Uses 3
TheoremThe heap parent is one level up#✓fully proved
For every natural number \(i > 0\), the parent index \(p = \lfloor (i-1)/2 \rfloor\) satisfies \(\lfloor \log_2(p+1) \rfloor + 1 = \lfloor \log_2(i+1) \rfloor\); that is, in the level-order binary tree the parent of a nonroot index lies one level above it.
theorem log2_heapParent_add_one (i : Nat) (hi : 0 < i) :
Nat.log2 (heapParent i + 1) + 1 = Nat.log2 (i + 1)
def heapParent (i : Nat) : Nat := (i - 1) / 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:30
Uses 1 · Used by 2
DefinitionSift-up with comparison and swap counts#✓fully proved
Given an array \(a\) of length \(|a|\) over a linearly ordered type and an index \(i\), this computes the sift-up of \(a\) at \(i\) together with a cost \((c, s) \in \mathbb{N} \times \mathbb{N}\), where \(c\) counts value comparisons and \(s\) counts swaps. If \(i \ge |a|\) or \(i = 0\), the result is \(a\) with cost \((0, 0)\). Otherwise let \(p = \lfloor (i - 1)/2 \rfloor\) be the parent of \(i\). If \(a_i < a_p\), the result is this sift-up at \(p\) of the array obtained from \(a\) by exchanging the entries at positions \(i\) and \(p\), with cost \((1, 1)\) plus the cost of that recursive sift-up; otherwise the result is \(a\) with cost \((1, 0)\).
Cslib.Algorithms.Lean.TimeM.siftUp · 19 lines
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
if hi : i < a.size then
if hpos : 0 < i then do
tick (1, 0)
let p := heapParent i
if a[i] < a[p]'(heapParent_lt_size a i hi hpos) then do
tick (0, 1)
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
pure a
else
pure a
else
pure a
termination_by i
decreasing_by
unfold heapParent
omega
def heapParent (i : Nat) : Nat := (i - 1) / 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:30
theorem heapParent_lt_size {α : Type u} (a : Array α) (i : Nat)
(hi : i < a.size) (hpos : 0 < i) : heapParent i < a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:44
Uses 2 · Used by 6
TheoremCounting does not change the result of sift-up#✓fully proved
For every array \(a\) over a linearly ordered type and every natural number \(i\), the array returned by sift-up with comparison and swap counts on \(a\) at index \(i\) equals the array returned by the plain sift-up of \(a\) at \(i\).
theorem ret_siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(siftUp a i).ret = Cslib.Algorithms.Lean.siftUp a i
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
if hi : i < a.size then
if hpos : 0 < i then do
tick (1, 0)
let p := heapParent i
if a[i] < a[p]'(heapParent_lt_size a i hi hpos) then do
tick (0, 1)
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
pure a
else
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/Cost.lean:46
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
if hi : i < a.size then
if hpos : 0 < i then
let p := heapParent i
if hlt : a[i] < a[p]'(heapParent_lt_size a i hi hpos) then
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
a
else
a
else
a
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:193
Uses 4
TheoremComparison bound for sift-up#✓fully proved
For every array \(a\) over a linearly ordered type and every natural number \(i\), the number of value comparisons counted by sift-up with comparison and swap counts on \(a\) at index \(i\) is at most \(\lfloor \log_2(i+1) \rfloor\), the depth of index \(i\) in the level-order binary tree.
theorem comparisons_siftUp_le_log2 {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : (siftUp a i).time.1 ≤ Nat.log2 (i + 1)
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
if hi : i < a.size then
if hpos : 0 < i then do
tick (1, 0)
let p := heapParent i
if a[i] < a[p]'(heapParent_lt_size a i hi hpos) then do
tick (0, 1)
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
pure a
else
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/Cost.lean:46
Uses 4 · Used by 1
TheoremSwap bound for sift-up#✓fully proved
For every array \(a\) over a linearly ordered type and every natural number \(i\), the number of swaps counted by sift-up with comparison and swap counts on \(a\) at index \(i\) is at most \(\lfloor \log_2(i+1) \rfloor\), the depth of index \(i\) in the level-order binary tree.
theorem swaps_siftUp_le_log2 {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : (siftUp a i).time.2 ≤ Nat.log2 (i + 1)
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
if hi : i < a.size then
if hpos : 0 < i then do
tick (1, 0)
let p := heapParent i
if a[i] < a[p]'(heapParent_lt_size a i hi hpos) then do
tick (0, 1)
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
pure a
else
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/Cost.lean:46
Uses 4 · Used by 1
TheoremCombined comparison and swap bound for sift-up#✓fully proved
For every array \(a\) over a linearly ordered type and every natural number \(i\), if sift-up with comparison and swap counts on \(a\) at index \(i\) counts \(c\) comparisons and \(s\) swaps, then \(c + s \le 2 \lfloor \log_2(i+1) \rfloor\).
theorem events_siftUp_le_log2 {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(siftUp a i).time.1 + (siftUp a i).time.2 ≤ 2 * Nat.log2 (i + 1)
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
if hi : i < a.size then
if hpos : 0 < i then do
tick (1, 0)
let p := heapParent i
if a[i] < a[p]'(heapParent_lt_size a i hi hpos) then do
tick (0, 1)
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
pure a
else
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/Cost.lean:46
Uses 3
TheoremSift-up at the root costs nothing#✓fully proved
For every array \(a\) over a linearly ordered type, sift-up with comparison and swap counts on \(a\) at index \(0\) has cost \((0, 0)\): it counts no comparisons and no swaps.
theorem time_siftUp_zero {α : Type u} [LinearOrder α] (a : Array α) :
(siftUp a 0).time = (0, 0)
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
if hi : i < a.size then
if hpos : 0 < i then do
tick (1, 0)
let p := heapParent i
if a[i] < a[p]'(heapParent_lt_size a i hi hpos) then do
tick (0, 1)
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
pure a
else
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/Cost.lean:46
Uses 3
TheoremSift-up at an out-of-range index costs nothing#✓fully proved
For every array \(a\) of length \(|a|\) over a linearly ordered type and every natural number \(i\) with \(i \ge |a|\), sift-up with comparison and swap counts on \(a\) at index \(i\) has cost \((0, 0)\): it counts no comparisons and no swaps.
theorem time_siftUp_of_size_le {α : Type u} [LinearOrder α] (a : Array α) (i : Nat)
(hi : a.size ≤ i) : (siftUp a i).time = (0, 0)
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
if hi : i < a.size then
if hpos : 0 < i then do
tick (1, 0)
let p := heapParent i
if a[i] < a[p]'(heapParent_lt_size a i hi hpos) then do
tick (0, 1)
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
pure a
else
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/Cost.lean:46
Uses 3
DefinitionDecrease-key in a binary min-heap#✓fully proved
Given a binary min-heap \(h\) over a linearly ordered type, with level-order array \(a\), an index \(i < |a|\) and a value \(x \le a_i\), decrease-key returns the heap whose array is obtained from \(a\) by replacing the entry at position \(i\) with \(x\) and then sifting position \(i\) up, repeatedly swapping the entry with its parent while it is strictly smaller than the parent.
Cslib.Algorithms.Lean.MinHeap.decreaseKey · 49 lines
def MinHeap.decreaseKey {α : Type u} [LinearOrder α]
(h : MinHeap α) (i : Fin h.data.size) (x : α)
(hdecrease : x ≤ h.data[i.val]) : MinHeap α where
data := siftUp (h.data.set i.val x) i.val
ordered := siftUp_ordered _ _ (by
refine {
index_valid := by
rw [Array.size_set]
exact i.isLt
ordered_except := ?_
parent_below_children := ?_
}
· intro j hj hjpos hji
have hj' : j < h.data.size := by
rw [Array.size_set] at hj
exact hj
by_cases hp : heapParent j = i.val
· have hold := h.ordered j hj' hjpos
have hchain : x ≤ h.data[j] := by
apply hdecrease.trans
simpa only [hp] using hold
rw [Array.getElem_set, ite_eq_left hp.symm, Array.getElem_set,
ite_eq_right (Ne.symm hji)]
exact hchain
· have hold := h.ordered j hj' hjpos
rw [Array.getElem_set, ite_eq_right (Ne.symm hp), Array.getElem_set,
ite_eq_right (Ne.symm hji)]
exact hold
· intro j hj hjpos hp hipos
have hj' : j < h.data.size := by
rw [Array.size_set] at hj
exact hj
have hparent_ne : heapParent i.val ≠ i.val := by
unfold heapParent
omega
have hji : j ≠ i.val := by
intro hji
subst j
exact hparent_ne hp
have hparent := h.ordered i.val i.isLt hipos
have hchild := h.ordered j hj' hjpos
have hchain :
h.data[heapParent i.val]'(heapParent_lt_size h.data i.val i.isLt hipos) ≤
h.data[j] := by
apply hparent.trans
simpa only [hp] using hchild
rw [Array.getElem_set, ite_eq_right (Ne.symm hparent_ne), Array.getElem_set,
ite_eq_right (Ne.symm hji)]
exact hchain)
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
if hi : i < a.size then
if hpos : 0 < i then
let p := heapParent i
if hlt : a[i] < a[p]'(heapParent_lt_size a i hi hpos) then
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
a
else
a
else
a
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:193
theorem siftUp_ordered {α : Type u} [LinearOrder α] (a : Array α) (i : Nat)
(h : SiftUpReady a i) : HeapOrdered (siftUp a i)
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:369
Uses 7 · Used by 4
TheoremArray of a binary heap after decrease-key#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type, with level-order array \(a\), let \(i < |a|\) and let \(x \le a_i\). The array of the heap obtained by decreasing the key at position \(i\) to \(x\) equals the result of sifting up position \(i\) in the array obtained from \(a\) by replacing its entry at position \(i\) with \(x\).
theorem MinHeap.decreaseKey_data {α : Type u} [LinearOrder α]
(h : MinHeap α) (i : Fin h.data.size) (x : α)
(hdecrease : x ≤ h.data[i.val]) :
(h.decreaseKey i x hdecrease).data =
siftUp (h.data.set i.val x) i.val
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
def siftUp {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
if hi : i < a.size then
if hpos : 0 < i then
let p := heapParent i
if hlt : a[i] < a[p]'(heapParent_lt_size a i hi hpos) then
siftUp (a.swap i p hi (heapParent_lt_size a i hi hpos)) p
else
a
else
a
else
a
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:193
Uses 3 · Used by 2
TheoremDecrease-key yields a heap-ordered array#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type, with level-order array \(a\), let \(i < |a|\) and let \(x \le a_i\). The array of the heap obtained by decreasing the key at position \(i\) to \(x\) is heap-ordered: the entry at every nonroot position is at least the entry at its parent position.
theorem MinHeap.decreaseKey_ordered {α : Type u} [LinearOrder α]
(h : MinHeap α) (i : Fin h.data.size) (x : α)
(hdecrease : x ≤ h.data[i.val]) :
HeapOrdered (h.decreaseKey i x hdecrease).data
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
def HeapOrdered {α : Type u} [LE α] (a : Array α) : Prop :=
∀ i (hi : i < a.size), (hpos : 0 < i) →
a[heapParent i]'(heapParent_lt_size a i hi hpos) ≤ a[i]
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:49
Uses 3
TheoremDecrease-key preserves the heap size#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type, with level-order array \(a\), let \(i < |a|\) and let \(x \le a_i\). The array of the heap obtained by decreasing the key at position \(i\) to \(x\) has the same length as \(a\).
theorem MinHeap.decreaseKey_size {α : Type u} [LinearOrder α]
(h : MinHeap α) (i : Fin h.data.size) (x : α)
(hdecrease : x ≤ h.data[i.val]) :
(h.decreaseKey i x hdecrease).data.size = h.data.size
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
Uses 5
TheoremMultiset of a binary heap after decrease-key#✓fully proved
Let \(h\) be a binary min-heap over a linearly ordered type, with level-order array \(a\), let \(i < |a|\) and let \(x \le a_i\). The multiset of elements of the heap obtained by decreasing the key at position \(i\) to \(x\) is obtained from the multiset of elements of \(h\) by removing one occurrence of \(a_i\) and adding one occurrence of \(x\).
theorem MinHeap.decreaseKey_elements {α : Type u} [LinearOrder α]
(h : MinHeap α) (i : Fin h.data.size) (x : α)
(hdecrease : x ≤ h.data[i.val]) :
(h.decreaseKey i x hdecrease).elements =
x ::ₘ h.elements.erase (h.data[i.val])
structure MinHeap (α : Type u) [LinearOrder α] where
/-- The level-order storage array. -/
data : Array α
ordered : HeapOrdered data
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:538
TheoremThe smaller child lies one level below its parent#✓fully proved
Let \(a\) be an array over a linearly ordered type and let \(i\) and \(c\) be natural numbers. If \(c\) is the smaller child of \(i\) in \(a\), then \(\lfloor \log_2 (c+1) \rfloor = \lfloor \log_2 (i+1) \rfloor + 1\); that is, in the level-order binary tree stored in \(a\), the node \(c\) lies exactly one level below \(i\).
theorem log2_smallerChild_add_one {α : Type u} [LinearOrder α]
(a : Array α) (i c : Nat) (hchild : smallerChild a i = some c) :
Nat.log2 (c + 1) = Nat.log2 (i + 1) + 1
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:99
Uses 4 · Used by 2
TheoremThe smaller child's level is bounded by the array size#✓fully proved
Let \(a\) be an array over a linearly ordered type, of size \(|a|\), and let \(i\) and \(c\) be natural numbers. If \(c\) is the smaller child of \(i\) in \(a\), then \(\lfloor \log_2 (c+1) \rfloor \le \lfloor \log_2 |a| \rfloor\).
theorem log2_smallerChild_le_size {α : Type u} [LinearOrder α]
(a : Array α) (i c : Nat) (hchild : smallerChild a i = some c) :
Nat.log2 (c + 1) ≤ Nat.log2 a.size
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:99
Uses 2 · Used by 2
DefinitionTimed smaller-child selection#✓fully proved
Let \(a\) be an array over a linearly ordered type and \(i\) an index, with left child \(2i + 1\) and right child \(2i + 2\); cost is counted as the pair (value comparisons, array swaps). If both children are valid indices of \(a\), the selection costs \((1, 0)\) and returns the right child when its value is strictly less than the value at the left child, and the left child otherwise. If only the left child is a valid index, it returns the left child at cost \((0, 0)\). If the left child is not a valid index, it returns no child at cost \((0, 0)\).
def timedSmallerChild {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Option Nat) :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then do
tick (1, 0)
pure (if a[heapRight i] < a[heapLeft i] then
some (heapRight i) else some (heapLeft i))
else pure (some (heapLeft i))
else pure none
def heapLeft (i : Nat) : Nat := 2 * i + 1
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:33
def heapRight (i : Nat) : Nat := 2 * i + 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:36
Uses 2 · Used by 8
TheoremTimed child selection returns the smaller child#✓fully proved
For every array \(a\) over a linearly ordered type and every index \(i\), the value returned by timed child selection at \(i\), with its cost discarded, is the smaller child of \(i\) in \(a\) (an optional index, absent when \(i\) has no valid child).
theorem ret_timedSmallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) :
(timedSmallerChild a i).ret = smallerChild a i
def timedSmallerChild {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Option Nat) :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then do
tick (1, 0)
pure (if a[heapRight i] < a[heapLeft i] then
some (heapRight i) else some (heapLeft i))
else pure (some (heapLeft i))
else pure none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:62
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:99
Uses 4 · Used by 5
DefinitionSift-down with comparison and swap counts#✓fully proved
For an array \(a\) over a linearly ordered type and an index \(i\), timed sift-down returns an array together with a cost pair (value comparisons, array swaps), where costs add componentwise. If the left child index \(2i+1\) is not a valid index of \(a\), it returns \(a\) at cost \((0, 0)\). Otherwise let \(c\) be the smaller child of \(i\): the left child \(2i+1\), unless the right child \(2i+2\) is a valid index and \(a_{2i+2} < a_{2i+1}\), in which case \(c = 2i+2\). Selecting \(c\) costs one comparison when \(2i+2\) is a valid index and nothing otherwise. Comparing \(a_c\) with \(a_i\) costs one more comparison. If \(a_c < a_i\), the entries at \(i\) and \(c\) are swapped at the cost of one swap, and the result and remaining cost are those of timed sift-down from \(c\) in the swapped array; otherwise the result is \(a\).
Index arithmetic, bounds checks, pattern matching and recursive calls are free.
Cslib.Algorithms.Lean.TimeM.siftDown · 22 lines
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
let selected := timedSmallerChild a i
match hchild : selected.ret with
| none => ⟨a, selected.time⟩
| some c =>
have hcanonical : smallerChild a i = some c :=
(ret_timedSmallerChild a i).symm.trans hchild
have hc : c < a.size := smallerChild_valid a i c hcanonical
have hi : i < a.size := (smallerChild_gt a i c hcanonical).trans hc
let run : TimeM (Nat × Nat) (Array α) := do
tick (1, 0)
if hlt : a[c] < a[i] then
tick (0, 1)
siftDown (a.swap i c hi hc) c
else pure a
⟨run.ret, selected.time + run.time⟩
termination_by a.size - i
decreasing_by
simp only [Array.size_swap]
have := smallerChild_gt a i c hcanonical
omega
def timedSmallerChild {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Option Nat) :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then do
tick (1, 0)
pure (if a[heapRight i] < a[heapLeft i] then
some (heapRight i) else some (heapLeft i))
else pure (some (heapLeft i))
else pure none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:62
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:99
theorem ret_timedSmallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) :
(timedSmallerChild a i).ret = smallerChild a i
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:73
theorem smallerChild_valid {α : Type u} [LinearOrder α]
(a : Array α) (i c : Nat)
(h : smallerChild a i = some c) : c < a.size
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:153
theorem smallerChild_gt {α : Type u} [LinearOrder α]
(a : Array α) (i c : Nat)
(h : smallerChild a i = some c) : i < c
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:131
Uses 5 · Used by 7
TheoremTimed sift-down returns the sift-down result#✓fully proved
For every array \(a\) over a linearly ordered type and every index \(i\), the array returned by timed sift-down from \(i\), with its cost discarded, equals the array returned by sift-down from \(i\).
theorem ret_siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(siftDown a i).ret = Cslib.Algorithms.Lean.siftDown a i
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
let selected := timedSmallerChild a i
match hchild : selected.ret with
| none => ⟨a, selected.time⟩
| some c =>
have hcanonical : smallerChild a i = some c :=
(ret_timedSmallerChild a i).symm.trans hchild
have hc : c < a.size := smallerChild_valid a i c hcanonical
have hi : i < a.size := (smallerChild_gt a i c hcanonical).trans hc
let run : TimeM (Nat × Nat) (Array α) := do
tick (1, 0)
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:84
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) : Array α :=
match hchild : smallerChild a i with
| none => a
| some c =>
have hc : c < a.size := smallerChild_valid a i c hchild
have hi : i < a.size := (smallerChild_gt a i c hchild).trans hc
if hlt : a[c] < a[i] then
siftDown (a.swap i c hi hc) c
else
a
termination_by a.size - i
decreasing_by
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:210
TheoremCost of child selection#✓fully proved
Let \(a\) be an array over a linearly ordered type and \(i\) an index, and count cost as the pair (value comparisons, array swaps). The timed child selection at \(i\) in \(a\) has cost \((1, 0)\) if the right child index \(2i + 2\) is less than the size of \(a\), and cost \((0, 0)\) otherwise.
theorem time_timedSmallerChild {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(timedSmallerChild a i).time =
if heapRight i < a.size then (1, 0) else (0, 0)
def timedSmallerChild {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Option Nat) :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then do
tick (1, 0)
pure (if a[heapRight i] < a[heapLeft i] then
some (heapRight i) else some (heapLeft i))
else pure (some (heapLeft i))
else pure none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:62
def heapRight (i : Nat) : Nat := 2 * i + 2
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:36
TheoremChild selection at a node without children costs nothing#✓fully proved
Let \(a\) be an array over a linearly ordered type and \(i\) an index. If the smaller-child selection at \(i\) in \(a\) returns no child, then the timed child selection at \(i\), with cost counted as the pair (value comparisons, array swaps), has cost \((0, 0)\).
theorem time_timedSmallerChild_of_none {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) (hchild : smallerChild a i = none) :
(timedSmallerChild a i).time = (0, 0)
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:99
def timedSmallerChild {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Option Nat) :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then do
tick (1, 0)
pure (if a[heapRight i] < a[heapLeft i] then
some (heapRight i) else some (heapLeft i))
else pure (some (heapLeft i))
else pure none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:62
Uses 4 · Used by 3
TheoremSift-down performs at most one swap per remaining level#✓fully proved
Write \(|a|\) for the size of an array \(a\), and let \(\ell(n) = \lfloor \log_2 n \rfloor\) for \(n \ge 1\) and \(\ell(0) = 0\). For every array \(a\) over a linearly ordered type and every index \(i\), the number of array swaps counted by timed sift-down from \(i\) is at most \(\max(0, \ell(|a|) - \ell(i+1))\).
theorem siftDown_swaps_le {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(siftDown a i).time.2 ≤ Nat.log2 a.size - Nat.log2 (i + 1)
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
let selected := timedSmallerChild a i
match hchild : selected.ret with
| none => ⟨a, selected.time⟩
| some c =>
have hcanonical : smallerChild a i = some c :=
(ret_timedSmallerChild a i).symm.trans hchild
have hc : c < a.size := smallerChild_valid a i c hcanonical
have hi : i < a.size := (smallerChild_gt a i c hcanonical).trans hc
let run : TimeM (Nat × Nat) (Array α) := do
tick (1, 0)
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:84
Uses 11 · Used by 1
TheoremSift-down makes at most two comparisons per remaining level#✓fully proved
Write \(|a|\) for the size of an array \(a\), and let \(\ell(n) = \lfloor \log_2 n \rfloor\) for \(n \ge 1\) and \(\ell(0) = 0\). For every array \(a\) over a linearly ordered type and every index \(i\), the number of value comparisons counted by timed sift-down from \(i\) is at most \(2 \max(0, \ell(|a|) - \ell(i+1))\).
theorem siftDown_comparisons_le {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(siftDown a i).time.1 ≤ 2 * (Nat.log2 a.size - Nat.log2 (i + 1))
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
let selected := timedSmallerChild a i
match hchild : selected.ret with
| none => ⟨a, selected.time⟩
| some c =>
have hcanonical : smallerChild a i = some c :=
(ret_timedSmallerChild a i).symm.trans hchild
have hc : c < a.size := smallerChild_valid a i c hcanonical
have hi : i < a.size := (smallerChild_gt a i c hcanonical).trans hc
let run : TimeM (Nat × Nat) (Array α) := do
tick (1, 0)
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:84
Uses 11 · Used by 1
TheoremTotal sift-down cost is at most three per remaining level#✓fully proved
Write \(|a|\) for the size of an array \(a\), and let \(\ell(n) = \lfloor \log_2 n \rfloor\) for \(n \ge 1\) and \(\ell(0) = 0\). For every array \(a\) over a linearly ordered type and every index \(i\), the number of value comparisons plus the number of array swaps counted by timed sift-down from \(i\) is at most \(3 \max(0, \ell(|a|) - \ell(i+1))\).
theorem siftDown_time_le {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
(siftDown a i).time.1 + (siftDown a i).time.2 ≤
3 * (Nat.log2 a.size - Nat.log2 (i + 1))
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
let selected := timedSmallerChild a i
match hchild : selected.ret with
| none => ⟨a, selected.time⟩
| some c =>
have hcanonical : smallerChild a i = some c :=
(ret_timedSmallerChild a i).symm.trans hchild
have hc : c < a.size := smallerChild_valid a i c hcanonical
have hi : i < a.size := (smallerChild_gt a i c hcanonical).trans hc
let run : TimeM (Nat × Nat) (Array α) := do
tick (1, 0)
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:84
TheoremSift-down from a node without children costs nothing#✓fully proved
Let \(a\) be an array over a linearly ordered type and \(i\) an index. If the smaller-child selection at \(i\) in \(a\) returns no child, then sift-down from \(i\), with cost counted as the pair (value comparisons, array swaps), has cost \((0, 0)\): it makes no value comparisons and no array swaps.
theorem time_siftDown_of_smallerChild_none {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) (hchild : smallerChild a i = none) :
(siftDown a i).time = (0, 0)
def smallerChild {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) : Option Nat :=
if hl : heapLeft i < a.size then
if hr : heapRight i < a.size then
if a[heapRight i] < a[heapLeft i] then
some (heapRight i)
else
some (heapLeft i)
else
some (heapLeft i)
else
none
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:99
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
let selected := timedSmallerChild a i
match hchild : selected.ret with
| none => ⟨a, selected.time⟩
| some c =>
have hcanonical : smallerChild a i = some c :=
(ret_timedSmallerChild a i).symm.trans hchild
have hc : c < a.size := smallerChild_valid a i c hcanonical
have hi : i < a.size := (smallerChild_gt a i c hcanonical).trans hc
let run : TimeM (Nat × Nat) (Array α) := do
tick (1, 0)
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:84
Uses 7 · Used by 1
TheoremSift-down from a leaf costs nothing#✓fully proved
Let \(a\) be an array over a linearly ordered type, of size \(|a|\), and let \(i\) be an index with \(|a| \le 2i+1\), so that the left child of \(i\) is not a valid index (this includes invalid indices \(i\)). Then timed sift-down from \(i\) has cost pair \((0, 0)\): it counts no comparisons and no swaps.
theorem time_siftDown_of_heapLeft_ge {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) (h : a.size ≤ heapLeft i) :
(siftDown a i).time = (0, 0)
def heapLeft (i : Nat) : Nat := 2 * i + 1
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap.lean:33
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
let selected := timedSmallerChild a i
match hchild : selected.ret with
| none => ⟨a, selected.time⟩
| some c =>
have hcanonical : smallerChild a i = some c :=
(ret_timedSmallerChild a i).symm.trans hchild
have hc : c < a.size := smallerChild_valid a i c hcanonical
have hi : i < a.size := (smallerChild_gt a i c hcanonical).trans hc
let run : TimeM (Nat × Nat) (Array α) := do
tick (1, 0)
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:84
Uses 5 · Used by 1
TheoremSift-down from an invalid index costs nothing#✓fully proved
Let \(a\) be an array over a linearly ordered type, of size \(|a|\), and let \(i\) be a natural number with \(|a| \le i\). Then timed sift-down from \(i\) has cost pair \((0, 0)\): it counts no comparisons and no swaps.
theorem time_siftDown_of_size_le {α : Type u} [LinearOrder α]
(a : Array α) (i : Nat) (h : a.size ≤ i) :
(siftDown a i).time = (0, 0)
def siftDown {α : Type u} [LinearOrder α] (a : Array α) (i : Nat) :
TimeM (Nat × Nat) (Array α) :=
let selected := timedSmallerChild a i
match hchild : selected.ret with
| none => ⟨a, selected.time⟩
| some c =>
have hcanonical : smallerChild a i = some c :=
(ret_timedSmallerChild a i).symm.trans hchild
have hc : c < a.size := smallerChild_valid a i c hcanonical
have hi : i < a.size := (smallerChild_gt a i c hcanonical).trans hc
let run : TimeM (Nat × Nat) (Array α) := do
tick (1, 0)
⋯
CSLibExt/Algorithms/Lean/DataStructures/BinaryHeap/SiftDownCost.lean:84
Uses 3
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.