Imports
Exact semantics for raw B-tree deletion
This module proves that executable CLRS deletion removes exactly one occurrence of the requested key. The core theorem needs only the node invariant and the minimum-degree bound; uniqueness and top-level descent readiness are not required.
namespace CLRS.Chapter18.BTreeprivate theorem NodeWF.node_keys_pairwise
{t : Nat} {b : Bool} {ks : List Nat} {cs : List BTree}
(h : NodeWF t b (node ks cs)) :
List.Pairwise (· ≤ ·) ks := by
have hs := h.sorted
unfold Sorted at hs
exact hs.1
private theorem composedDelete_keyBag_aux
(t : Nat) (ht : 2 ≤ t) (x : Nat) (tr : BTree) :
∀ b, NodeWF t b tr →
keyBag (composedDelete t x tr) = (keyBag tr).erase x := by
induction x, tr using composedDelete.induct (t := t) <;>
intro b hparent
case case1 =>
rename_i x ks cs hleaf
have hcs : cs = [] := List.isEmpty_iff.mp hleaf
subst cs
simpa [composedDelete, keyBag, keysOf] using
(sortedRemove_keyBag x ks)
case case2 =>
rename_i ks cs hnonempty sep left right hleftReady i hpos ki hsep hleft hright ih
simp only [i] at hpos
simp only [ki, i] at hsep hleft hright
have hleftMem : left ∈ cs :=
List.mem_iff_getElem?.mpr ⟨findChild ks sep - 1, hleft⟩
have hleftWF : NodeWF t false left :=
hparent.child hleftMem
have hrec := ih false hleftWF
have hexact :=
replacePredecessor_keyBag_erase ht hparent hsep hleft hrec
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t sep (node ks cs) =
node (ks.set (findChild ks sep - 1) (maxKey left))
(cs.set (findChild ks sep - 1)
(composedDelete t (maxKey left) left)) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte, hpos]
rw [hsep]
rw [hleft, hright]
simp [hleftReady]
rw [hdeleteEq]
exact hexact
case case3 =>
rename_i ks cs hnonempty sep left right hleftNotReady hrightReady
i hpos ki hsep hleft hright ih
simp only [i] at hpos
simp only [ki, i] at hsep hleft hright
have hrightMem : right ∈ cs :=
List.mem_iff_getElem?.mpr ⟨findChild ks sep - 1 + 1, hright⟩
have hrightWF : NodeWF t false right :=
hparent.child hrightMem
have hrec := ih false hrightWF
have hexact :=
replaceSuccessor_keyBag_erase ht hparent hsep hright hrec
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t sep (node ks cs) =
node (ks.set (findChild ks sep - 1) (minKey right))
(cs.set (findChild ks sep - 1 + 1)
(composedDelete t (minKey right) right)) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte, hpos]
rw [hsep]
rw [hleft, hright]
simp [hleftNotReady, hrightReady]
rw [hdeleteEq]
exact hexact
case case4 =>
rename_i ks cs hnonempty sep left right hleftNotReady hrightNotReady
merged i hpos ki hsep hleft hright ih
simp only [i] at hpos
simp only [ki, i] at hsep hleft hright
obtain ⟨hleftWF, hrightWF, hsiblings, hleftLe, hrightGe⟩ :=
hparent.adjacent_children hsep hleft hright
have hleftMin : numKeys left = t - 1 :=
numKeys_eq_t_sub_one_of_not_ready hleftWF.occupancy hleftNotReady
have hrightMin : numKeys right = t - 1 :=
numKeys_eq_t_sub_one_of_not_ready hrightWF.occupancy hrightNotReady
have hmerged :=
mergeNodes_nodeWF ht hleftWF hrightWF hleftMin hrightMin
hsiblings hleftLe hrightGe
have hmergedWF : NodeWF t false merged := by
simpa [merged] using hmerged.1
have hrec := ih false hmergedWF
have hroute :
sep ∈ keysOf (node ks cs) →
sep ∈ keysOf (mergeNodes left sep right) := by
intro _
exact
(mem_keysOf_mergeNodes left sep right sep).2
(Or.inr (Or.inl rfl))
have hexact :=
spliceMerged_keyBag_erase hsep hleft hright hroute
(by simpa [merged] using hrec)
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t sep (node ks cs) =
node
(ks.take (findChild ks sep - 1) ++
ks.drop (findChild ks sep - 1 + 1))
(cs.take (findChild ks sep - 1) ++
[composedDelete t sep merged] ++
cs.drop (findChild ks sep - 1 + 2)) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte, hpos]
rw [hsep]
rw [hleft, hright]
simp [hleftNotReady, hrightNotReady, merged]
rw [hdeleteEq]
exact hexact
case case7 =>
rename_i x ks cs hnonempty i hpos ki oldSep hsep hne child hchild
hchildReady ih
simp only [i] at hpos
simp only [ki, i] at hsep
simp only [i] at hchild
have hxkeys : x ∉ ks := by
intro hx
have hfound :=
findChild_pos_and_pred_eq_of_mem hparent.node_keys_pairwise hx
have holdEq : oldSep = x :=
Option.some.inj (hsep.symm.trans hfound.2)
exact hne holdEq
have hroute :
x ∈ keysOf (node ks cs) → x ∈ keysOf child :=
findChild_selected_child_mem hparent.node_keys_pairwise
hparent.childBounded hxkeys hchild
have hchildMem : child ∈ cs :=
List.mem_iff_getElem?.mpr ⟨findChild ks x, hchild⟩
have hchildWF : NodeWF t false child :=
hparent.child hchildMem
have hrec := ih false hchildWF
have hexact :=
replaceChild_keyBag_erase hchild hroute hrec
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t x (node ks cs) =
node ks (cs.set (findChild ks x) (composedDelete t x child)) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte, hpos]
rw [hsep]
rw [hchild]
simp [hchildReady]
exact fun heq => (hne heq).elim
rw [hdeleteEq]
exact hexact
case case8 =>
rename_i x ks cs hnonempty i hpos ki oldSep hsepOld hne child hchild
hchildNotReady left hleft hleftReady sep hsep ih
simp only [i] at hpos hchild hleft hsep
simp only [ki, i] at hsepOld
have holdSepEq : oldSep = sep :=
Option.some.inj (hsepOld.symm.trans hsep)
subst oldSep
have hxkeys : x ∉ ks := by
intro hx
have hfound :=
findChild_pos_and_pred_eq_of_mem hparent.node_keys_pairwise hx
have hsepEq : sep = x :=
Option.some.inj (hsep.symm.trans hfound.2)
exact hne hsepEq
have hroute :
x ∈ keysOf (node ks cs) → x ∈ keysOf child :=
findChild_selected_child_mem hparent.node_keys_pairwise
hparent.childBounded hxkeys hchild
have hchildAt :
cs[(findChild ks x - 1) + 1]? = some child := by
simpa [show findChild ks x - 1 + 1 = findChild ks x by omega]
using hchild
obtain ⟨hleftWF, hchildWF, hsiblings, hleftLe, hchildGe⟩ :=
hparent.adjacent_children hsep hleft hchildAt
have hchildMin : numKeys child = t - 1 :=
numKeys_eq_t_sub_one_of_not_ready hchildWF.occupancy
hchildNotReady
have hrotated :=
rotateLeft_nodeWF ht hleftWF hchildWF hleftReady hchildMin
hsiblings hleftLe hchildGe
have htargetWF :
NodeWF t false (rotateLeft left sep child).2.2 :=
hrotated.2.1
have hrec := ih false htargetWF
have hexactRaw :=
rotateLeft_reassembly_keyBag_erase
hsep hleft hchildAt hroute hrec
have hexact :
keyBag
(node
(ks.set (findChild ks x - 1)
(rotateLeft left sep child).2.1)
((cs.set (findChild ks x - 1)
(rotateLeft left sep child).1).set
(findChild ks x)
(composedDelete t x
(rotateLeft left sep child).2.2))) =
(keyBag (node ks cs)).erase x := by
simpa [show findChild ks x - 1 + 1 = findChild ks x by omega]
using hexactRaw
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t x (node ks cs) =
node
(ks.set (findChild ks x - 1)
(rotateLeft left sep child).2.1)
((cs.set (findChild ks x - 1)
(rotateLeft left sep child).1).set
(findChild ks x)
(composedDelete t x
(rotateLeft left sep child).2.2)) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte, hpos]
rw [hsepOld]
rw [hchild]
rw [hleft]
simp [hne, hchildNotReady, hleftReady]
rw [hdeleteEq]
exact hexact
case case10 =>
rename_i x ks cs hnonempty i hpos ki oldSep hsepOld hne child hchild
hchildNotReady left hleft hleftNotReady right hright hrightReady
sep hsep ih
simp only [i] at hpos hchild hleft hright hsep
simp only [ki, i] at hsepOld
have hxkeys : x ∉ ks := by
intro hx
have hfound :=
findChild_pos_and_pred_eq_of_mem hparent.node_keys_pairwise hx
have holdEq : oldSep = x :=
Option.some.inj (hsepOld.symm.trans hfound.2)
exact hne holdEq
have hroute :
x ∈ keysOf (node ks cs) → x ∈ keysOf child :=
findChild_selected_child_mem hparent.node_keys_pairwise
hparent.childBounded hxkeys hchild
obtain ⟨hchildWF, hrightWF, hsiblings, hchildLe, hrightGe⟩ :=
hparent.adjacent_children hsep hchild hright
have hchildMin : numKeys child = t - 1 :=
numKeys_eq_t_sub_one_of_not_ready hchildWF.occupancy
hchildNotReady
have hrotated :=
rotateRight_nodeWF ht hchildWF hrightWF hchildMin hrightReady
hsiblings hchildLe hrightGe
have htargetWF :
NodeWF t false (rotateRight child sep right).1 :=
hrotated.1
have hrec := ih false htargetWF
have hexact :=
rotateRight_reassembly_keyBag_erase
hsep hchild hright hroute hrec
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t x (node ks cs) =
node
(ks.set (findChild ks x)
(rotateRight child sep right).2.1)
((cs.set (findChild ks x)
(composedDelete t x
(rotateRight child sep right).1)).set
(findChild ks x + 1)
(rotateRight child sep right).2.2) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte, hpos]
rw [hsepOld]
rw [hchild]
rw [hleft]
rw [hright]
rw [hsep]
simp [hne, hchildNotReady, hleftNotReady, hrightReady]
rw [hdeleteEq]
exact hexact
case case12 =>
rename_i x ks cs hnonempty i hpos ki oldSep hsepOld hne child hchild
hchildNotReady left hleft hleftNotReady rightSib hrightSib
hrightNotReady sep hsep ih
simp only [i] at hpos hchild hleft hrightSib hsep
simp only [ki, i] at hsepOld
have holdSepEq : oldSep = sep :=
Option.some.inj (hsepOld.symm.trans hsep)
subst oldSep
have hxkeys : x ∉ ks := by
intro hx
have hfound :=
findChild_pos_and_pred_eq_of_mem hparent.node_keys_pairwise hx
have hsepEq : sep = x :=
Option.some.inj (hsep.symm.trans hfound.2)
exact hne hsepEq
have hrouteChild :
x ∈ keysOf (node ks cs) → x ∈ keysOf child :=
findChild_selected_child_mem hparent.node_keys_pairwise
hparent.childBounded hxkeys hchild
have hchildAt :
cs[(findChild ks x - 1) + 1]? = some child := by
simpa [show findChild ks x - 1 + 1 = findChild ks x by omega]
using hchild
obtain ⟨hleftWF, hchildWF, hsiblings, hleftLe, hchildGe⟩ :=
hparent.adjacent_children hsep hleft hchildAt
have htarget :=
mergeNodes_recursiveTarget ht hleftWF hchildWF
hleftNotReady hchildNotReady hsiblings hleftLe hchildGe
have hrec := ih false htarget.1
have hroute :
x ∈ keysOf (node ks cs) →
x ∈ keysOf (mergeNodes left sep child) := by
intro hx
exact
(mem_keysOf_mergeNodes left sep child x).2
(Or.inr (Or.inr (hrouteChild hx)))
have hexactRaw :=
spliceMerged_keyBag_erase hsep hleft hchildAt hroute hrec
have hexact :
keyBag
(node
(ks.take (findChild ks x - 1) ++ ks.drop (findChild ks x))
(cs.take (findChild ks x - 1) ++
[composedDelete t x (mergeNodes left sep child)] ++
cs.drop (findChild ks x + 1))) =
(keyBag (node ks cs)).erase x := by
simpa [show findChild ks x - 1 + 1 = findChild ks x by omega,
show findChild ks x - 1 + 2 = findChild ks x + 1 by omega]
using hexactRaw
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t x (node ks cs) =
node
(ks.take (findChild ks x - 1) ++ ks.drop (findChild ks x))
(cs.take (findChild ks x - 1) ++
[composedDelete t x (mergeNodes left sep child)] ++
cs.drop (findChild ks x + 1)) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte, hpos]
rw [hsepOld]
rw [hchild]
rw [hleft]
rw [hrightSib]
simp [hne, hchildNotReady, hleftNotReady, hrightNotReady]
rw [hdeleteEq]
exact hexact
case case14 =>
rename_i x ks cs hnonempty i hpos ki oldSep hsepOld hne child hchild
hchildNotReady left hleft hleftNotReady hrightNone sep hsep ih
simp only [i] at hpos hchild hleft hrightNone hsep
simp only [ki, i] at hsepOld
have holdSepEq : oldSep = sep :=
Option.some.inj (hsepOld.symm.trans hsep)
subst oldSep
have hxkeys : x ∉ ks := by
intro hx
have hfound :=
findChild_pos_and_pred_eq_of_mem hparent.node_keys_pairwise hx
have hsepEq : sep = x :=
Option.some.inj (hsep.symm.trans hfound.2)
exact hne hsepEq
have hrouteChild :
x ∈ keysOf (node ks cs) → x ∈ keysOf child :=
findChild_selected_child_mem hparent.node_keys_pairwise
hparent.childBounded hxkeys hchild
have hchildAt :
cs[(findChild ks x - 1) + 1]? = some child := by
simpa [show findChild ks x - 1 + 1 = findChild ks x by omega]
using hchild
obtain ⟨hleftWF, hchildWF, hsiblings, hleftLe, hchildGe⟩ :=
hparent.adjacent_children hsep hleft hchildAt
have htarget :=
mergeNodes_recursiveTarget ht hleftWF hchildWF
hleftNotReady hchildNotReady hsiblings hleftLe hchildGe
have hrec := ih false htarget.1
have hroute :
x ∈ keysOf (node ks cs) →
x ∈ keysOf (mergeNodes left sep child) := by
intro hx
exact
(mem_keysOf_mergeNodes left sep child x).2
(Or.inr (Or.inr (hrouteChild hx)))
have hexactRaw :=
spliceMerged_keyBag_erase hsep hleft hchildAt hroute hrec
have hexact :
keyBag
(node
(ks.take (findChild ks x - 1) ++ ks.drop (findChild ks x))
(cs.take (findChild ks x - 1) ++
[composedDelete t x (mergeNodes left sep child)] ++
cs.drop (findChild ks x + 1))) =
(keyBag (node ks cs)).erase x := by
simpa [show findChild ks x - 1 + 1 = findChild ks x by omega,
show findChild ks x - 1 + 2 = findChild ks x + 1 by omega]
using hexactRaw
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t x (node ks cs) =
node
(ks.take (findChild ks x - 1) ++ ks.drop (findChild ks x))
(cs.take (findChild ks x - 1) ++
[composedDelete t x (mergeNodes left sep child)] ++
cs.drop (findChild ks x + 1)) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte, hpos]
rw [hsepOld]
rw [hchild]
rw [hleft]
rw [hrightNone]
simp [hne, hchildNotReady, hleftNotReady]
rw [hdeleteEq]
exact hexact
case case29 =>
rename_i x ks cs hnonempty i hnotPos child hchild hchildReady ih
simp only [i] at hnotPos
have hfindZero : findChild ks x = 0 :=
Nat.eq_zero_of_not_pos hnotPos
have hxkeys : x ∉ ks := by
intro hx
exact hnotPos
(findChild_pos_and_pred_eq_of_mem hparent.node_keys_pairwise hx).1
have hchildSelected :
cs[findChild ks x]? = some child := by
simpa [hfindZero] using hchild
have hroute :
x ∈ keysOf (node ks cs) → x ∈ keysOf child :=
findChild_selected_child_mem hparent.node_keys_pairwise
hparent.childBounded hxkeys hchildSelected
have hchildMem : child ∈ cs :=
List.mem_iff_getElem?.mpr ⟨0, hchild⟩
have hchildWF : NodeWF t false child :=
hparent.child hchildMem
have hrec := ih false hchildWF
have hexact :=
replaceChild_keyBag_erase hchild hroute hrec
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t x (node ks cs) =
node ks (cs.set 0 (composedDelete t x child)) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte]
rw [hchild]
simp [hchildReady]
exact fun hpos => (hnotPos hpos).elim
rw [hdeleteEq]
exact hexact
case case30 =>
rename_i x ks cs hnonempty i hnotPos child hchild hchildNotReady
right hright hrightReady sep hsep ih
simp only [i] at hnotPos
have hfindZero : findChild ks x = 0 :=
Nat.eq_zero_of_not_pos hnotPos
have hxkeys : x ∉ ks := by
intro hx
exact hnotPos
(findChild_pos_and_pred_eq_of_mem hparent.node_keys_pairwise hx).1
have hchildSelected :
cs[findChild ks x]? = some child := by
simpa [hfindZero] using hchild
have hroute :
x ∈ keysOf (node ks cs) → x ∈ keysOf child :=
findChild_selected_child_mem hparent.node_keys_pairwise
hparent.childBounded hxkeys hchildSelected
obtain ⟨hchildWF, hrightWF, hsiblings, hchildLe, hrightGe⟩ :=
hparent.adjacent_children hsep hchild hright
have hchildMin : numKeys child = t - 1 :=
numKeys_eq_t_sub_one_of_not_ready hchildWF.occupancy
hchildNotReady
have hrotated :=
rotateRight_nodeWF ht hchildWF hrightWF hchildMin hrightReady
hsiblings hchildLe hrightGe
have htargetWF :
NodeWF t false (rotateRight child sep right).1 :=
hrotated.1
have hrec := ih false htargetWF
have hexact :=
rotateRight_reassembly_keyBag_erase hsep hchild hright hroute hrec
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t x (node ks cs) =
node (ks.set 0 (rotateRight child sep right).2.1)
((cs.set 0
(composedDelete t x
(rotateRight child sep right).1)).set 1
(rotateRight child sep right).2.2) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte]
rw [dif_neg hnotPos]
rw [hchild]
simp only
rw [dif_neg hchildNotReady]
rw [hright]
simp only
rw [dif_pos hrightReady]
rw [hsep]
rw [hdeleteEq]
exact hexact
case case32 =>
rename_i x ks cs hnonempty i hnotPos child hchild hchildNotReady
right hright hrightNotReady sep hsep ih
simp only [i] at hnotPos
have hfindZero : findChild ks x = 0 :=
Nat.eq_zero_of_not_pos hnotPos
have hxkeys : x ∉ ks := by
intro hx
exact hnotPos
(findChild_pos_and_pred_eq_of_mem hparent.node_keys_pairwise hx).1
have hchildSelected :
cs[findChild ks x]? = some child := by
simpa [hfindZero] using hchild
have hrouteChild :
x ∈ keysOf (node ks cs) → x ∈ keysOf child :=
findChild_selected_child_mem hparent.node_keys_pairwise
hparent.childBounded hxkeys hchildSelected
obtain ⟨hchildWF, hrightWF, hsiblings, hchildLe, hrightGe⟩ :=
hparent.adjacent_children hsep hchild hright
have htarget :=
mergeNodes_recursiveTarget ht hchildWF hrightWF
hchildNotReady hrightNotReady hsiblings hchildLe hrightGe
have hrec := ih false htarget.1
have hroute :
x ∈ keysOf (node ks cs) →
x ∈ keysOf (mergeNodes child sep right) := by
intro hx
exact
(mem_keysOf_mergeNodes child sep right x).2
(Or.inl (hrouteChild hx))
have hexact :=
spliceMerged_keyBag_erase hsep hchild hright hroute hrec
have hnotLeaf : cs.isEmpty = false :=
Bool.eq_false_of_not_eq_true hnonempty
have hdeleteEq :
composedDelete t x (node ks cs) =
node (ks.drop 1)
([composedDelete t x (mergeNodes child sep right)] ++
cs.drop 2) := by
rw [composedDelete]
simp only [hnotLeaf, Bool.false_eq_true, ↓reduceIte]
rw [dif_neg hnotPos]
rw [hchild]
simp only
rw [dif_neg hchildNotReady]
rw [hright]
simp only
rw [dif_neg hrightNotReady]
rw [hsep]
rw [hdeleteEq]
simpa using hexact
all_goals
exfalso
try dsimp only at *
first
| apply findChild_predecessor_none_absurd
· assumption
· assumption
| apply hparent.findChild_leftSibling_none_absurd
· assumption
| apply hparent.findChild_none_absurd
· assumption
| have hrel := hparent.children_rel
have htwo :=
hparent.two_le_children_of_not_empty ht (by simp_all)
simp_all [List.getElem?_eq_some_iff]
all_goals
obtain ⟨hindex, _⟩ := ‹∃ h : _ < _, _›
omegaExecutable CLRS deletion removes exactly one occurrence of the requested key. No uniqueness assumption and no top-level descent-readiness premise are needed.
theorem composedDelete_keyBag
(t x : Nat) (ht : 2 ≤ t) {tr : BTree} {b : Bool}
(hinv : NodeWF t b tr) :
keyBag (composedDelete t x tr) =
(keyBag tr).erase x := by
exact composedDelete_keyBag_aux t ht x tr b hinvDeletion preserves membership of every key distinct from the request.
theorem composedDelete_mem_iff_of_ne
(t x y : Nat) (ht : 2 ≤ t) {tr : BTree} {b : Bool}
(hinv : NodeWF t b tr) (hyx : y ≠ x) :
mem y (composedDelete t x tr) ↔ mem y tr := by
have hbag := composedDelete_keyBag t x ht hinv
have hmem :
y ∈ (keyBag tr).erase x ↔ y ∈ keyBag tr :=
Multiset.mem_erase_of_ne hyx
rw [← hbag] at hmem
simpa only [mem, keyBag, Multiset.mem_coe] using hmemExact one-occurrence deletion preserves uniqueness of the flattened key list.
theorem composedDelete_uniqueKeys
(t x : Nat) (ht : 2 ≤ t) {tr : BTree} {b : Bool}
(hinv : NodeWF t b tr) (hunique : UniqueKeys tr) :
UniqueKeys (composedDelete t x tr) := by
unfold UniqueKeys at hunique ⊢
have hbag := composedDelete_keyBag t x ht hinv
have hcoe :
(↑(keysOf (composedDelete t x tr)) : Multiset Nat) =
↑((keysOf tr).erase x) := by
simpa only [keyBag, Multiset.coe_erase] using hbag
have hperm :
(keysOf (composedDelete t x tr)).Perm
((keysOf tr).erase x) :=
Multiset.coe_eq_coe.mp hcoe
exact hperm.nodup_iff.mpr (List.Nodup.erase x hunique)end CLRS.Chapter18.BTree