Imports
import Mathlib.Tactic-- Prototype in development: silence the unused-simp-argument linter noise.
set_option linter.unusedSimpArgs falseRandomized treap (prototype)
A treap is a binary search tree whose nodes also carry a priority, kept as
a heap: every node's priority is at least the priorities of its children (a
max-heap order). If the priorities are distinct and chosen uniformly at
random, the treap on a fixed set of (key, priority) pairs is unique and
has expected height O(log n), which makes a treap a randomized balanced
BST.
This module is a prototype: the executable insert/member and the
correctness half — membership, BST preservation, and max-heap preservation —
are all kernel-checked. The probabilistic analysis is developed separately:
TreapRandom proves the harmonic expected-depth bound, and
TreapHeight proves the headline E[height] ≤ 30 · H_n result.
These extension pages remain outside the textbook coverage ledger.
The membership theorems carry an IsBST (binary-search-tree) hypothesis:
the executable member really is a guided search, and for a non-BST tree
a rotation can change what the search finds, so the statement is only
meaningful for well-formed trees.
Main results (all kernel-checked):
-
Membership:
keys_insert,member_iff_keys,member_insert,insert_member. -
BST preservation:
IsBST_insert(withIsBST_rotL/IsBST_rotR). -
Heap preservation:
prioOf_insert(the structural core),IsHeap_insert(the capstone), withprioLE_insert,insert_of_mem_keys,IsHeap_rotL/IsHeap_rotR.
Analysis layers:
-
TreapRandom: expected depthO(log n)under uniformly random distinct priorities. -
TreapHeight: the explicit expected-height boundE[height] ≤ 30 · H_n.
Notation conventions:
-
α: key type with decidable linear order -
priority :
Nat, treated as an opaque tie-breaker -
IsBST t:tis a binary search tree on its keys
namespace CLRS.Extensions
A treap over keys α: either empty, or a node carrying a key, a priority,
and left/right subtrees.
inductive Treap (α : Type u) where
| nil : Treap α
| node (key : α) (prio : Nat) (left right : Treap α) : Treap α
deriving Reprnamespace TreapThe height of a treap: the number of nodes on a longest root-to-leaf path.
The finite set of keys occurring in a treap.
def keys [DecidableEq α] : Treap α → Finset α
| nil => ∅
| node k _ l r => Insert.insert k (keys l ∪ keys r)
Membership test: whether x occurs as a key (guided search over the
BST).
def member [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) : Treap α → Bool
| nil => false
| node k _ l r =>
if x = k then true
else if x < k then member x l
else member x rRight rotation: promote the left child to the root.
def rotR : Treap α → Treap α
| node a pa (node b pb lb rb) r => node b pb lb (node a pa rb r)
| t => tLeft rotation: promote the right child to the root.
def rotL : Treap α → Treap α
| node a pa l (node b pb lb rb) => node b pb (node a pa l lb) rb
| t => t
Insert (x, p) into a treap, preserving the BST order on keys and the
max-heap order on priorities. Existing keys are kept unchanged.
def insert [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) (p : Nat) : Treap α → Treap α
| nil => node x p nil nil
| node k pk l r =>
if x < k then
let l' := insert x p l
match l' with
| node _ p' _ _ => if p' > pk then rotR (node k pk l' r) else node k pk l' r
| nil => node k pk l' r
else if k < x then
let r' := insert x p r
match r' with
| node _ p' _ _ => if p' > pk then rotL (node k pk l r') else node k pk l r'
| nil => node k pk l r'
else node k pk l r
insert never returns the empty tree.
theorem insert_ne_nil [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) (p : Nat)
(t : Treap α) : insert x p t ≠ nil := by
induction t with
| nil => simp [insert]
| node k pk l r ih_l ih_r =>
by_cases h1 : x < k
· -- x < k: insert follows the left branch and always returns a node
simp [insert, h1]
cases insert x p l with
| nil => simp
| node b pb lb rb =>
by_cases hrot : pb > pk
· simp [rotR, hrot]
· simp [hrot]
· by_cases h2 : k < x
· -- k < x: insert follows the right branch
simp [insert, h1, h2]
cases insert x p r with
| nil => simp
| node b pb lb rb =>
by_cases hrot : pb > pk
· simp [rotL, hrot]
· simp [hrot]
· -- x = k: tree unchanged
simp [insert, h1, h2]Right rotation preserves the key set.
theorem keys_rotR [DecidableEq α] (t : Treap α) : keys (rotR t) = keys t := by
cases t with
| nil => rfl
| node a pa l r =>
cases l with
| nil => rfl
| node b pb lb rb =>
ext y
simp [keys, rotR, Finset.mem_insert, Finset.mem_union, or_assoc, or_left_comm, or_comm]Left rotation preserves the key set.
theorem keys_rotL [DecidableEq α] (t : Treap α) : keys (rotL t) = keys t := by
cases t with
| nil => rfl
| node a pa l r =>
cases r with
| nil => rfl
| node b pb lb rb =>
ext y
simp [keys, rotL, Finset.mem_insert, Finset.mem_union, or_assoc, or_left_comm, or_comm]
Inserting (x, p) adds exactly the key x to the key set.
theorem keys_insert [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) (p : Nat)
(t : Treap α) : keys (insert x p t) = Insert.insert x (keys t) := by
induction t with
| nil => simp [insert, keys]
| node k pk l r ih_l ih_r =>
by_cases h1 : x < k
· by_cases h2 : k < x
· exfalso
exact (lt_asymm h1 h2)
· -- x < k (and not k < x)
cases hl' : insert x p l with
| nil =>
exfalso
exact insert_ne_nil x p l hl'
| node b pb lb rb =>
have hlkey : keys (node b pb lb rb) = Insert.insert x (keys l) := by
rw [← hl']
exact ih_l
by_cases hrot : pb > pk
· simp [insert, h1, hl', hrot]
rw [keys_rotR]
ext y
change y ∈ Insert.insert k (keys (node b pb lb rb) ∪ keys r) ↔
y ∈ Insert.insert x (Insert.insert k (keys l ∪ keys r))
rw [hlkey]
simp [Finset.mem_insert, Finset.mem_union, or_assoc, or_left_comm, or_comm]
· simp [insert, h1, hl', hrot]
ext y
change y ∈ Insert.insert k (keys (node b pb lb rb) ∪ keys r) ↔
y ∈ Insert.insert x (Insert.insert k (keys l ∪ keys r))
rw [hlkey]
simp [Finset.mem_insert, Finset.mem_union, or_assoc, or_left_comm, or_comm]
· by_cases h2 : k < x
· -- k < x
cases hr' : insert x p r with
| nil =>
exfalso
exact insert_ne_nil x p r hr'
| node b pb lb rb =>
have hrkey : keys (node b pb lb rb) = Insert.insert x (keys r) := by
rw [← hr']
exact ih_r
by_cases hrot : pb > pk
· simp [insert, h1, h2, hr', hrot]
rw [keys_rotL]
ext y
change y ∈ Insert.insert k (keys l ∪ keys (node b pb lb rb)) ↔
y ∈ Insert.insert x (Insert.insert k (keys l ∪ keys r))
rw [hrkey]
simp [Finset.mem_insert, Finset.mem_union, or_assoc, or_left_comm, or_comm]
· simp [insert, h1, h2, hr', hrot]
ext y
change y ∈ Insert.insert k (keys l ∪ keys (node b pb lb rb)) ↔
y ∈ Insert.insert x (Insert.insert k (keys l ∪ keys r))
rw [hrkey]
simp [Finset.mem_insert, Finset.mem_union, or_assoc, or_left_comm, or_comm]
· -- x = k: insert keeps the node unchanged
have hxk : x = k := le_antisymm (le_of_not_gt h2) (le_of_not_gt h1)
simp [insert, h1, h2, hxk, keys, Finset.insert_idem]A treap is a binary search tree when every key in the left subtree is smaller than the root and every key in the right subtree is larger, and this holds recursively.
def IsBST [LinearOrder α] [DecidableEq α] : Treap α → Prop
| nil => True
| node k _ l r =>
IsBST l ∧ IsBST r ∧ (∀ y ∈ keys l, y < k) ∧ (∀ y ∈ keys r, k < y)Right rotation preserves well-formedness (BST).
theorem IsBST_rotR [LinearOrder α] [DecidableEq α] [DecidableLT α] {t : Treap α}
(h : IsBST t) : IsBST (rotR t) := by
cases t with
| nil => simpa [rotR] using h
| node a pa l r =>
cases l with
| nil => simpa [rotR] using h
| node b pb lb rb =>
rcases h with ⟨hl, hr, hlt, hgt⟩
rcases hl with ⟨hlb, hrb, hltb, hgtrb⟩
have hba : b < a := hlt b (by simp [keys])
simp [rotR]
refine ⟨hlb, ?_, hltb, ?_⟩
· -- IsBST (node a pa rb r)
refine ⟨hrb, hr, ?_, hgt⟩
intro y hy
exact hlt y (by simp [keys, hy])
· -- ∀ y ∈ keys (node a pa rb r), b < y
intro y hy
have hy' : y ∈ Insert.insert a (keys rb ∪ keys r) := by simpa [keys] using hy
by_cases hya : y = a
· rw [hya]; exact hba
· by_cases hyrb : y ∈ keys rb
· exact hgtrb y hyrb
· have hyr : y ∈ keys r := by simpa [hya, hyrb] using hy'
exact lt_trans hba (hgt y hyr)Left rotation preserves well-formedness (BST).
theorem IsBST_rotL [LinearOrder α] [DecidableEq α] [DecidableLT α] {t : Treap α}
(h : IsBST t) : IsBST (rotL t) := by
cases t with
| nil => simpa [rotL] using h
| node a pa l r =>
cases r with
| nil => simpa [rotL] using h
| node b pb lb rb =>
rcases h with ⟨hl, hr, hlt, hgt⟩
rcases hr with ⟨hlb, hrb, hltb, hgtrb⟩
have hab : a < b := hgt b (by simp [keys])
simp [rotL]
refine ⟨?_, hrb, ?_, hgtrb⟩
· -- IsBST (node a pa l lb)
refine ⟨hl, hlb, hlt, ?_⟩
intro y hy
exact hgt y (by simp [keys, hy])
· -- ∀ y ∈ keys (node a pa l lb), y < b
intro y hy
have hy' : y ∈ Insert.insert a (keys l ∪ keys lb) := by simpa [keys] using hy
by_cases hyb : y ∈ keys lb
· exact hltb y hyb
· by_cases hya : y = a
· rw [hya]; exact hab
· have hyl : y ∈ keys l := by simpa [hya, hyb] using hy'
exact lt_trans (hlt y hyl) habInserting into a well-formed treap keeps it well-formed.
theorem IsBST_insert [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) (p : Nat)
(t : Treap α) : IsBST t → IsBST (insert x p t) := by
induction t with
| nil => intro _; simp [insert, IsBST, keys]
| node k pk l r ih_l ih_r =>
intro h
rcases h with ⟨hl, hr, hlt, hgt⟩
by_cases h1 : x < k
· by_cases h2 : k < x
· exfalso
exact (lt_asymm h1 h2)
· cases hl' : insert x p l with
| nil => exfalso; exact insert_ne_nil x p l hl'
| node b pb lb rb =>
have hlbst : IsBST (node b pb lb rb) := by
rw [← hl']
exact ih_l hl
have hnew : IsBST (node k pk (node b pb lb rb) r) := by
refine ⟨hlbst, hr, ?_, hgt⟩
intro y hy
have hyins : y ∈ keys (insert x p l) := by rw [hl']; exact hy
have hykeys : y ∈ Insert.insert x (keys l) := by
rw [keys_insert x p l] at hyins
exact hyins
by_cases hyx : y = x
· rw [hyx]; exact h1
· exact hlt y (by simpa [hyx] using hykeys)
by_cases hrot : pb > pk
· have hrot' : IsBST (rotR (node k pk (node b pb lb rb) r)) := IsBST_rotR hnew
simpa [insert, h1, hl', hrot]
· simpa [insert, h1, hl', hrot]
· by_cases h2 : k < x
· cases hr' : insert x p r with
| nil => exfalso; exact insert_ne_nil x p r hr'
| node b pb lb rb =>
have hrbst : IsBST (node b pb lb rb) := by
rw [← hr']
exact ih_r hr
have hnew : IsBST (node k pk l (node b pb lb rb)) := by
refine ⟨hl, hrbst, hlt, ?_⟩
intro y hy
have hyins : y ∈ keys (insert x p r) := by rw [hr']; exact hy
have hykeys : y ∈ Insert.insert x (keys r) := by
rw [keys_insert x p r] at hyins
exact hyins
by_cases hyx : y = x
· rw [hyx]; exact h2
· exact hgt y (by simpa [hyx] using hykeys)
by_cases hrot : pb > pk
· have hrot' : IsBST (rotL (node k pk l (node b pb lb rb))) := IsBST_rotL hnew
simpa [insert, h1, h2, hr', hrot]
· simpa [insert, h1, h2, hr', hrot]
· -- x = k: insert keeps the node unchanged
simp [insert, h1, h2]
exact ⟨hl, hr, hlt, hgt⟩In a well-formed treap, the guided search agrees with set membership.
theorem member_iff_keys [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) :
∀ t : Treap α, IsBST t → (member x t = true ↔ x ∈ keys t) := by
intro t
induction t with
| nil => simp [member, keys]
| node k pk l r ih_l ih_r =>
intro h
rcases h with ⟨hl, hr, hlt, hgt⟩
by_cases hx : x = k
· simp [member, keys, hx]
· have hxne : x ≠ k := hx
by_cases hxlt : x < k
· have hxnr : x ∉ keys r := by
intro hxr
exact (lt_asymm hxlt (hgt x hxr))
simp [member, hxne, hxlt]
rw [ih_l hl]
simp [keys, hxne, hxnr]
· have hxnl : x ∉ keys l := by
intro hxl
exact hxlt (hlt x hxl)
simp [member, hxne, hxlt]
rw [ih_r hr]
simp [keys, hxne, hxnl]
Target (proved). Membership of insert x p t is the old
membership together with the new key, for well-formed treaps.
theorem member_insert [LinearOrder α] [DecidableEq α] [DecidableLT α] (y x : α) (p : Nat)
(t : Treap α) (h : IsBST t) :
member y (insert x p t) = true ↔ member y t = true ∨ y = x := by
rw [member_iff_keys y (insert x p t) (IsBST_insert x p t h), keys_insert,
member_iff_keys y t h]
simp [Finset.mem_insert, or_assoc, or_left_comm, or_comm]
Target (proved). Inserting x and then searching for it always
finds it, for well-formed treaps.
theorem insert_member [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) (p : Nat)
(t : Treap α) (h : IsBST t) : member x (insert x p t) = true := by
rw [member_iff_keys x (insert x p t) (IsBST_insert x p t h), keys_insert]
exact Finset.mem_insert_self x (keys t)Heap correctness
A treap must also satisfy the max-heap property on priorities: every node's
priority is at least its children's. This section proves that insert
preserves it. The subtle part is that a single rotation repairs exactly one
heap violation along the insertion path; the structural fact that makes it
tick is prioOf_insert — insertion attaches the new priority p
only to the new key x and leaves every existing key's priority
untouched.
The priority attached to a key y in a treap (0 if y
is absent).
def prioOf [LinearOrder α] [DecidableEq α] [DecidableLT α] (t : Treap α) (y : α) : Nat :=
match t with
| nil => 0
| node k p l r =>
if y = k then p
else if y < k then prioOf l y
else prioOf r y
prioLE p t: the priority of every key present in t is at
most p.
def prioLE [LinearOrder α] [DecidableEq α] [DecidableLT α] (p : Nat) (t : Treap α) : Prop :=
∀ y ∈ keys t, prioOf t y ≤ pA treap is a max-heap on priorities when every node's priority is at least the priorities of its children, recursively.
def IsHeap [LinearOrder α] [DecidableEq α] [DecidableLT α] : Treap α → Prop
| nil => True
| node _ p l r => IsHeap l ∧ IsHeap r ∧ prioLE p l ∧ prioLE p rRight rotation preserves the priority attached to every key, on a well-formed (BST) treap.
theorem prioOf_rotR [LinearOrder α] [DecidableEq α] [DecidableLT α] {t : Treap α}
(h : IsBST t) (y : α) : prioOf (rotR t) y = prioOf t y := by
cases t with
| nil => rfl
| node a pa l r =>
cases l with
| nil => rfl
| node b pb lb rb =>
rcases h with ⟨hl, hr, hlt, hgt⟩
rcases hl with ⟨hlb, hrb, hltb, hgtrb⟩
have hba : b < a := hlt b (by simp [keys])
by_cases h1 : y = b
· simp [prioOf, rotR, h1, hba, ne_of_lt hba]
· have h1ne : y ≠ b := h1
by_cases h2 : y < b
· have hya : y < a := lt_trans h2 hba
have hyane : y ≠ a := ne_of_lt hya
simp [prioOf, rotR, h1ne, h2, hya, hyane]
· by_cases h3 : y = a
· have hanb : ¬ a < b := fun hab => lt_asymm hab hba
simp [prioOf, rotR, h1ne, h2, h3, Ne.symm (ne_of_lt hba), hanb]
· have h3ne : y ≠ a := h3
by_cases h4 : y < a
· simp [prioOf, rotR, h1ne, h2, h3ne, h4]
· simp [prioOf, rotR, h1ne, h2, h3ne, h4]Left rotation preserves the priority attached to every key, on a well-formed (BST) treap.
theorem prioOf_rotL [LinearOrder α] [DecidableEq α] [DecidableLT α] {t : Treap α}
(h : IsBST t) (y : α) : prioOf (rotL t) y = prioOf t y := by
cases t with
| nil => rfl
| node a pa l r =>
cases r with
| nil => rfl
| node b pb lb rb =>
rcases h with ⟨hl, hr, hlt, hgt⟩
rcases hr with ⟨hlb, hrb, hltb, hgtrb⟩
have hab : a < b := hgt b (by simp [keys])
by_cases h1 : y = a
· simp [prioOf, rotL, h1, hab, ne_of_lt hab]
· have h1ne : y ≠ a := h1
by_cases h2 : y < a
· have hyb : y < b := lt_trans h2 hab
have hybne : y ≠ b := ne_of_lt hyb
simp [prioOf, rotL, h1ne, h2, hyb, hybne]
· by_cases h3 : y = b
· have hbna : ¬ b < a := fun hba => lt_asymm hba hab
simp [prioOf, rotL, h1ne, h2, h3, Ne.symm (ne_of_lt hab), hbna]
· have h3ne : y ≠ b := h3
by_cases h4 : y < b
· simp [prioOf, rotL, h1ne, h2, h3ne, h4]
· simp [prioOf, rotL, h1ne, h2, h3ne, h4]
Inserting a fresh key attaches the new priority p exactly to the
new key x and leaves every existing key's priority untouched.
theorem prioOf_insert [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) (p : Nat)
(t : Treap α) (h : IsBST t) (hx : x ∉ keys t) :
∀ y : α, prioOf (insert x p t) y = if y = x then p else prioOf t y := by
intro y
induction t with
| nil => simp [insert, prioOf]
| node k pk l r ih_l ih_r =>
rcases h with ⟨hl, hr, hlt, hgt⟩
have hxl : x ∉ keys l := by
intro hxl'
exact hx (by simp [keys, hxl'])
have hxr : x ∉ keys r := by
intro hxr'
exact hx (by simp [keys, hxr'])
by_cases h1 : x < k
· by_cases h2 : k < x
· exfalso
exact (lt_asymm h1 h2)
· -- x < k
cases hl' : insert x p l with
| nil => exfalso; exact insert_ne_nil x p l hl'
| node b pb lb rb =>
have hlbst : IsBST (node b pb lb rb) := by rw [← hl']; exact IsBST_insert x p l hl
have hnew : IsBST (node k pk (node b pb lb rb) r) := by
refine ⟨hlbst, hr, ?_, hgt⟩
intro z hz
have hzins : z ∈ keys (insert x p l) := by rw [hl']; exact hz
have hzkeys : z ∈ Insert.insert x (keys l) := by rw [keys_insert x p l] at hzins; exact hzins
by_cases hzx : z = x
· rw [hzx]; exact h1
· exact hlt z (by simpa [hzx] using hzkeys)
by_cases hrot : pb > pk
· -- rotR branch
simp [insert, h1, hl', hrot]
have hprio : prioOf (rotR (node k pk (node b pb lb rb) r)) y =
prioOf (node k pk (node b pb lb rb) r) y := prioOf_rotR hnew y
rw [hprio]
by_cases hyk : y = k
· simp [prioOf, hyk, Ne.symm (ne_of_lt h1)]
· have hykne : y ≠ k := hyk
by_cases hylt : y < k
· rw [← hl']
simp [prioOf, hykne, hylt]
exact ih_l hl hxl
· have hyxne : y ≠ x := fun hyx => hylt (by simpa [hyx] using h1)
simp [prioOf, hykne, hylt, hyxne]
· simp [insert, h1, hl', hrot]
by_cases hyk : y = k
· simp [prioOf, hyk, Ne.symm (ne_of_lt h1)]
· have hykne : y ≠ k := hyk
by_cases hylt : y < k
· rw [← hl']
simp [prioOf, hykne, hylt]
exact ih_l hl hxl
· have hyxne : y ≠ x := fun hyx => hylt (by simpa [hyx] using h1)
simp [prioOf, hykne, hylt, hyxne]
· by_cases h2 : k < x
· -- k < x
cases hr' : insert x p r with
| nil => exfalso; exact insert_ne_nil x p r hr'
| node b pb lb rb =>
have hrbst : IsBST (node b pb lb rb) := by rw [← hr']; exact IsBST_insert x p r hr
have hnew : IsBST (node k pk l (node b pb lb rb)) := by
refine ⟨hl, hrbst, hlt, ?_⟩
intro z hz
have hzins : z ∈ keys (insert x p r) := by rw [hr']; exact hz
have hzkeys : z ∈ Insert.insert x (keys r) := by rw [keys_insert x p r] at hzins; exact hzins
by_cases hzx : z = x
· rw [hzx]; exact h2
· exact hgt z (by simpa [hzx] using hzkeys)
by_cases hrot : pb > pk
· -- rotL branch
simp [insert, h1, h2, hr', hrot]
have hprio : prioOf (rotL (node k pk l (node b pb lb rb))) y =
prioOf (node k pk l (node b pb lb rb)) y := prioOf_rotL hnew y
rw [hprio]
by_cases hyk : y = k
· simp [prioOf, hyk, ne_of_lt h2]
· have hykne : y ≠ k := hyk
by_cases hylt : y < k
· have hyxne : y ≠ x := fun hyx => h1 (by simpa [hyx] using hylt)
simp [prioOf, hykne, hylt, hyxne]
· rw [← hr']
simp [prioOf, hykne, hylt]
exact ih_r hr hxr
· simp [insert, h1, h2, hr', hrot]
by_cases hyk : y = k
· simp [prioOf, hyk, ne_of_lt h2]
· have hykne : y ≠ k := hyk
by_cases hylt : y < k
· have hyxne : y ≠ x := fun hyx => h1 (by simpa [hyx] using hylt)
simp [prioOf, hykne, hylt, hyxne]
· rw [← hr']
simp [prioOf, hykne, hylt]
exact ih_r hr hxr
· -- x = k (impossible: x is fresh)
have hxk : x = k := le_antisymm (le_of_not_gt h2) (le_of_not_gt h1)
exfalso
exact hx (by simp [keys, hxk])Inserting an already-present key leaves the treap unchanged (duplicate keys are ignored), on a well-formed treap.
theorem insert_of_mem_keys [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) (p : Nat)
(t : Treap α) (h : IsBST t) (hh : IsHeap t) : x ∈ keys t → insert x p t = t := by
intro hx
induction t with
| nil => simp [keys] at hx
| node k pk l r ih_l ih_r =>
rcases h with ⟨hl, hr, hlt, hgt⟩
rcases hh with ⟨hhl, hhr, hpl, hpr⟩
by_cases h1 : x < k
· by_cases h2 : k < x
· exfalso
exact (lt_asymm h1 h2)
· -- x < k: the BST routes x into the left subtree
have hxl : x ∈ keys l := by
have hx' : x ∈ Insert.insert k (keys l ∪ keys r) := by simpa [keys] using hx
have hxk : x ≠ k := ne_of_lt h1
have hxnr : x ∉ keys r := by
intro hxr
exact (lt_asymm h1 (hgt x hxr))
simpa [hxk, hxnr] using hx'
have hrec : insert x p l = l := ih_l hl hhl hxl
simp [insert, h1, hrec]
cases l with
| nil => simp
| node b pb lb rb =>
have hpb_pk : pb ≤ pk := by
simpa [prioOf] using hpl b (by simp [keys])
by_cases hrot : pb > pk
· exfalso
exact (not_lt_of_ge hpb_pk) hrot
· simp [hrot]
· by_cases h2 : k < x
· -- k < x: the BST routes x into the right subtree
have hxr : x ∈ keys r := by
have hx' : x ∈ Insert.insert k (keys l ∪ keys r) := by simpa [keys] using hx
have hxk : x ≠ k := ne_of_gt h2
have hxnl : x ∉ keys l := by
intro hxl
exact (lt_asymm (hlt x hxl) h2)
simpa [hxk, hxnl] using hx'
have hrec : insert x p r = r := ih_r hr hhr hxr
simp [insert, h1, h2, hrec]
cases r with
| nil => simp
| node b pb lb rb =>
have hpb_pk : pb ≤ pk := by
simpa [prioOf] using hpr b (by simp [keys])
by_cases hrot : pb > pk
· exfalso
exact (not_lt_of_ge hpb_pk) hrot
· simp [hrot]
· -- x = k: the node is returned unchanged
simp [insert, h1, h2]
Inserting a key of priority p ≤ c into a treap whose priorities are
all at most c keeps every priority at most c.
theorem prioLE_insert [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) (p c : Nat)
(t : Treap α) (h : IsBST t) (hh : IsHeap t) (hc : prioLE c t) (hp : p ≤ c) :
prioLE c (insert x p t) := by
unfold prioLE
intro y hy
have hy' : y ∈ Insert.insert x (keys t) := by
rw [keys_insert x p t] at hy
exact hy
by_cases hxm : x ∈ keys t
· -- duplicate: insert keeps the tree, so the bound is unchanged
have hdup : insert x p t = t := insert_of_mem_keys x p t h hh hxm
rw [hdup] at hy ⊢
exact hc y hy
· -- fresh key: the only new priority is `p`, which is already ≤ c
by_cases hyx : y = x
· rw [prioOf_insert x p t h hxm y]
simp [hyx]
exact hp
· have hyt : y ∈ keys t := by
simpa [hyx] using hy'
rw [prioOf_insert x p t h hxm y]
simp [hyx]
exact hc y hyt
The priority of an absent key is 0.
theorem prioOf_eq_zero_of_not_mem [LinearOrder α] [DecidableEq α] [DecidableLT α] {t : Treap α}
{y : α} (h : y ∉ keys t) : prioOf t y = 0 := by
induction t with
| nil => rfl
| node k pk l r ih_l ih_r =>
have hyk : y ≠ k := by
intro hyk
exact h (by simp [keys, hyk])
by_cases hylt : y < k
· have hyl : y ∉ keys l := by
intro hyl'
exact h (by simp [keys, hyl'])
simp [prioOf, hyk, hylt]
exact ih_l hyl
· have hyr : y ∉ keys r := by
intro hyr'
exact h (by simp [keys, hyr'])
simp [prioOf, hyk, hylt]
exact ih_r hyr
A prioLE bound applies to the priority of every key, present or
absent.
theorem prioOf_le_of_prioLE [LinearOrder α] [DecidableEq α] [DecidableLT α] {t : Treap α}
{c : Nat} (h : prioLE c t) : ∀ y, prioOf t y ≤ c := by
intro y
by_cases hym : y ∈ keys t
· exact h y hym
· have hz : prioOf t y = 0 := prioOf_eq_zero_of_not_mem hym
rw [hz]
exact Nat.zero_le cPromoting the left child above the root keeps the max-heap property, given that the promoted child's priority is at least the root's and the moved subtree stays bounded by the root's priority.
theorem IsHeap_rotR [LinearOrder α] [DecidableEq α] [DecidableLT α] {a b : α} {pa pb : Nat}
{lb rb r : Treap α} (hl' : IsHeap (node b pb lb rb)) (hr : IsHeap r)
(hpb : pa ≤ pb) (hpa_rb : prioLE pa rb) (hpa_r : prioLE pa r) :
IsHeap (rotR (node a pa (node b pb lb rb) r)) := by
rcases hl' with ⟨hlb, hrb, hpb_lb, hpb_rb⟩
change IsHeap (node b pb lb (node a pa rb r))
refine ⟨hlb, ?_, hpb_lb, ?_⟩
· -- IsHeap (node a pa rb r)
refine ⟨hrb, hr, hpa_rb, hpa_r⟩
· -- prioLE pb (node a pa rb r)
unfold prioLE
intro y hy
have hy' : y ∈ Insert.insert a (keys rb ∪ keys r) := by simpa [keys] using hy
by_cases hya : y = a
· rw [hya]
have hpa_prio : prioOf (node a pa rb r) a = pa := by simp [prioOf]
rw [hpa_prio]
exact hpb
· have hya_ne : y ≠ a := hya
by_cases hylt : y < a
· have hprio : prioOf (node a pa rb r) y = prioOf rb y := by
simp [prioOf, hya_ne, hylt]
rw [hprio]
exact prioOf_le_of_prioLE hpb_rb y
· have hprio : prioOf (node a pa rb r) y = prioOf r y := by
simp [prioOf, hya_ne, hylt]
rw [hprio]
exact le_trans (prioOf_le_of_prioLE hpa_r y) hpbPromoting the right child above the root keeps the max-heap property, symmetrically.
theorem IsHeap_rotL [LinearOrder α] [DecidableEq α] [DecidableLT α] {a b : α} {pa pb : Nat}
{l lb rb : Treap α} (hl : IsHeap l) (hr' : IsHeap (node b pb lb rb))
(hpb : pa ≤ pb) (hpa_lb : prioLE pa lb) (hpa_l : prioLE pa l) :
IsHeap (rotL (node a pa l (node b pb lb rb))) := by
rcases hr' with ⟨hlb, hrb, hpb_lb, hpb_rb⟩
change IsHeap (node b pb (node a pa l lb) rb)
refine ⟨?_, hrb, ?_, hpb_rb⟩
· -- IsHeap (node a pa l lb)
refine ⟨hl, hlb, hpa_l, hpa_lb⟩
· -- prioLE pb (node a pa l lb)
unfold prioLE
intro y hy
have hy' : y ∈ Insert.insert a (keys l ∪ keys lb) := by simpa [keys] using hy
by_cases hya : y = a
· rw [hya]
have hpa_prio : prioOf (node a pa l lb) a = pa := by simp [prioOf]
rw [hpa_prio]
exact hpb
· have hya_ne : y ≠ a := hya
by_cases hylt : y < a
· have hprio : prioOf (node a pa l lb) y = prioOf l y := by
simp [prioOf, hya_ne, hylt]
rw [hprio]
exact le_trans (prioOf_le_of_prioLE hpa_l y) hpb
· have hprio : prioOf (node a pa l lb) y = prioOf lb y := by
simp [prioOf, hya_ne, hylt]
rw [hprio]
exact le_trans (prioOf_le_of_prioLE hpa_lb y) hpb
In a max-heap treap, if the root priority is at most c then every
priority is at most c.
theorem prioLE_of_heap_root_le [LinearOrder α] [DecidableEq α] [DecidableLT α]
{b : α} {pb c : Nat} {lb rb : Treap α}
(hheap : IsHeap (node b pb lb rb)) (hpb : pb ≤ c) :
prioLE c (node b pb lb rb) := by
rcases hheap with ⟨hlb, hrb, hpb_lb, hpb_rb⟩
unfold prioLE
intro y hy
have hy' : y ∈ Insert.insert b (keys lb ∪ keys rb) := by simpa [keys] using hy
by_cases hyb : y = b
· rw [hyb]
have hprio : prioOf (node b pb lb rb) b = pb := by simp [prioOf]
rw [hprio]
exact hpb
· by_cases hylt : y < b
· have hprio : prioOf (node b pb lb rb) y = prioOf lb y := by simp [prioOf, hyb, hylt]
rw [hprio]
exact le_trans (prioOf_le_of_prioLE hpb_lb y) hpb
· have hprio : prioOf (node b pb lb rb) y = prioOf rb y := by simp [prioOf, hyb, hylt]
rw [hprio]
exact le_trans (prioOf_le_of_prioLE hpb_rb y) hpbCapstone. Inserting into a well-formed (BST + heap) treap keeps it a valid treap: the single rotation along the insertion path repairs exactly the one heap violation.
theorem IsHeap_insert [LinearOrder α] [DecidableEq α] [DecidableLT α] (x : α) (p : Nat)
(t : Treap α) : IsBST t → IsHeap t → IsHeap (insert x p t) := by
intro h hh
induction t with
| nil => simp [insert, IsHeap, prioLE, keys]
| node k pk l r ih_l ih_r =>
rcases h with ⟨hl, hr, hlt, hgt⟩
rcases hh with ⟨hhl, hhr, hpl, hpr⟩
by_cases h1 : x < k
· by_cases h2 : k < x
· exfalso
exact (lt_asymm h1 h2)
· -- x < k: insert into the left subtree
have hhl' : IsHeap (insert x p l) := ih_l hl hhl
cases hl' : insert x p l with
| nil => exfalso; exact insert_ne_nil x p l hl'
| node b pb lb rb =>
have hlbst' : IsBST (node b pb lb rb) := by rw [← hl']; exact IsBST_insert x p l hl
have hhl'' : IsHeap (node b pb lb rb) := by simpa [hl'] using hhl'
by_cases hrot : pb > pk
· -- rotation branch: the moved subtree rb stays bounded by pk
have hxnl : x ∉ keys l := by
intro hxl
have hdup : insert x p l = l := insert_of_mem_keys x p l hl hhl hxl
rw [hdup] at hl'
have hpb_pk : pb ≤ pk := by
have hpb' : prioOf l b ≤ pk := hpl b (by simp [keys, hl'])
simpa [hl', prioOf] using hpb'
exact (not_lt_of_ge hpb_pk) hrot
have hbx : b = x := by
have hb_mem' : b ∈ keys (insert x p l) := by rw [hl']; simp [keys]
have hbmem : b ∈ Insert.insert x (keys l) := by
rw [keys_insert x p l] at hb_mem'
exact hb_mem'
by_cases hbxl : b = x
· exact hbxl
· exfalso
have hb_l : b ∈ keys l := by simpa [hbxl] using hbmem
have hpb_eq : pb = prioOf l b := by
have hpi : prioOf (insert x p l) b = if b = x then p else prioOf l b :=
prioOf_insert x p l hl hxnl b
have hpi' : prioOf (insert x p l) b = pb := by rw [hl']; simp [prioOf]
rw [hpi'] at hpi
simp [hbxl] at hpi
exact hpi
have hpb_pk : pb ≤ pk := by rw [hpb_eq]; exact hpl b hb_l
exact (not_lt_of_ge hpb_pk) hrot
have hpk_rb : prioLE pk rb := by
unfold prioLE
intro z hz
have hb_lt_z : b < z := hlbst'.2.2.2 z hz
have hzx : z ≠ x := by
intro hzx'
have : x < x := by simp [hbx, hzx'] at hb_lt_z ⊢
exact (lt_irrefl x this)
have hzins : z ∈ keys (insert x p l) := by rw [hl']; simp [keys, hz]
have hzkeys : z ∈ Insert.insert x (keys l) := by
rw [keys_insert x p l] at hzins
exact hzins
have hzl : z ∈ keys l := by simpa [hzx] using hzkeys
have hprio : prioOf rb z = prioOf l z := by
have hpi : prioOf (insert x p l) z = if z = x then p else prioOf l z :=
prioOf_insert x p l hl hxnl z
have hpi' : prioOf (insert x p l) z = prioOf rb z := by
rw [hl']
have hzb : z ≠ b := ne_of_gt hb_lt_z
have hznlt : ¬ z < b := not_lt_of_gt hb_lt_z
simp [prioOf, hzb, hznlt]
rw [hpi'] at hpi
simp [hzx] at hpi
exact hpi
rw [hprio]
exact hpl z hzl
simp [insert, h1, hl', hrot]
exact IsHeap_rotR hhl'' hhr (le_of_lt hrot) hpk_rb hpr
· -- no rotation: the root priority already bounds everything
simp [insert, h1, hl', hrot]
refine ⟨hhl'', hhr, prioLE_of_heap_root_le hhl'' (not_lt.mp hrot), hpr⟩
· by_cases h2 : k < x
· -- k < x: insert into the right subtree (symmetric)
have hhr' : IsHeap (insert x p r) := ih_r hr hhr
cases hr' : insert x p r with
| nil => exfalso; exact insert_ne_nil x p r hr'
| node b pb lb rb =>
have hrbst' : IsBST (node b pb lb rb) := by rw [← hr']; exact IsBST_insert x p r hr
have hhr'' : IsHeap (node b pb lb rb) := by simpa [hr'] using hhr'
by_cases hrot : pb > pk
· -- rotation branch: the moved subtree lb stays bounded by pk
have hxnr : x ∉ keys r := by
intro hxr
have hdup : insert x p r = r := insert_of_mem_keys x p r hr hhr hxr
rw [hdup] at hr'
have hpb_pk : pb ≤ pk := by
have hpb' : prioOf r b ≤ pk := hpr b (by simp [keys, hr'])
simpa [hr', prioOf] using hpb'
exact (not_lt_of_ge hpb_pk) hrot
have hbx : b = x := by
have hb_mem' : b ∈ keys (insert x p r) := by rw [hr']; simp [keys]
have hbmem : b ∈ Insert.insert x (keys r) := by
rw [keys_insert x p r] at hb_mem'
exact hb_mem'
by_cases hbxl : b = x
· exact hbxl
· exfalso
have hb_r : b ∈ keys r := by simpa [hbxl] using hbmem
have hpb_eq : pb = prioOf r b := by
have hpi : prioOf (insert x p r) b = if b = x then p else prioOf r b :=
prioOf_insert x p r hr hxnr b
have hpi' : prioOf (insert x p r) b = pb := by rw [hr']; simp [prioOf]
rw [hpi'] at hpi
simp [hbxl] at hpi
exact hpi
have hpb_pk : pb ≤ pk := by rw [hpb_eq]; exact hpr b hb_r
exact (not_lt_of_ge hpb_pk) hrot
have hpk_lb : prioLE pk lb := by
unfold prioLE
intro z hz
have hz_lt_b : z < b := hrbst'.2.2.1 z hz
have hzx : z ≠ x := by
intro hzx'
have : x < x := by simp [hbx, hzx'] at hz_lt_b ⊢
exact (lt_irrefl x this)
have hzins : z ∈ keys (insert x p r) := by rw [hr']; simp [keys, hz]
have hzkeys : z ∈ Insert.insert x (keys r) := by
rw [keys_insert x p r] at hzins
exact hzins
have hzr : z ∈ keys r := by simpa [hzx] using hzkeys
have hprio : prioOf lb z = prioOf r z := by
have hpi : prioOf (insert x p r) z = if z = x then p else prioOf r z :=
prioOf_insert x p r hr hxnr z
have hpi' : prioOf (insert x p r) z = prioOf lb z := by
rw [hr']
have hzb : z ≠ b := ne_of_lt hz_lt_b
simp [prioOf, hzb, hz_lt_b]
rw [hpi'] at hpi
simp [hzx] at hpi
exact hpi
rw [hprio]
exact hpr z hzr
simp [insert, h1, h2, hr', hrot]
exact IsHeap_rotL hhl hhr'' (le_of_lt hrot) hpk_lb hpl
· -- no rotation
simp [insert, h1, h2, hr', hrot]
refine ⟨hhl, hhr'', hpl, prioLE_of_heap_root_le hhr'' (not_lt.mp hrot)⟩
· -- x = k: duplicate, tree unchanged
simp [insert, h1, h2]
exact ⟨hhl, hhr, hpl, hpr⟩end Treapend CLRS.Extensions