Imports
Complete structural preservation for composed B-tree deletion
The branch packets for leaf deletion, separator replacement, sibling
rotation, and sibling merge are assembled here into one induction over
composedDelete. The bundled result simultaneously records key
containment, the root-sensitive structural postcondition, and raw height
preservation.
namespace CLRS.Chapter18.BTree
Raw composed deletion preserves the complete invariant packet under the CLRS
descent-readiness guard. Root calls may return the one-child empty-root
transient described by RootDeleteResult; non-root calls return an
ordinary NodeWF packet.
theorem composedDelete_packet
(t : Nat) (ht : 2 ≤ t) (x : Nat) (tr : BTree) :
∀ b, NodeWF t b tr → DeleteReady t b tr →
KeysSubset (composedDelete t x tr) tr ∧
RawDeleteResult t b (composedDelete t x tr) ∧
heightOf (composedDelete t x tr) = heightOf tr := by
induction x, tr using composedDelete.induct (t := t) <;>
intro b hparent hready
case case1 =>
rename_i x ks cs hleaf
have hcs : cs = [] := List.isEmpty_iff.mp hleaf
subst cs
simpa [composedDelete] using
(deleteLeaf_packet (x := x) hparent hready)
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 hleftReady' : DeleteReady t false left := by
simpa [DeleteReady] using hleftReady
have hrec := ih false hleftWF hleftReady'
have hrecWF :
NodeWF t false (composedDelete t (maxKey left) left) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
replacePredecessor_packet ht hparent hsep hleft hrecWF
hrec.2.2 hrec.1
have hraw :=
rawDeleteResult_of_nodeWF hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
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 hrightReady' : DeleteReady t false right := by
simpa [DeleteReady] using hrightReady
have hrec := ih false hrightWF hrightReady'
have hrecWF :
NodeWF t false (composedDelete t (minKey right) right) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
replaceSuccessor_packet ht hparent hsep hright hrecWF
hrec.2.2 hrec.1
have hraw :=
rawDeleteResult_of_nodeWF hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
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 hmergedReady : DeleteReady t false merged := by
simpa [merged] using
(mergeNodes_deleteReady ht (right := right) (sep := sep) hleftMin)
have hrec := ih false hmergedWF hmergedReady
have hrecWF :
NodeWF t false (composedDelete t sep merged) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
spliceMerged_packet hparent hready hsep hleft hright hrecWF
(by simpa [merged] using hrec.2.2) (by simpa [merged] using hrec.1)
have hraw :
RawDeleteResult t b
(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
cases b <;> simpa [RawDeleteResult] using hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
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 hchildMem : child ∈ cs :=
List.mem_iff_getElem?.mpr ⟨findChild ks x, hchild⟩
have hchildWF : NodeWF t false child :=
hparent.child hchildMem
have hchildReady' : DeleteReady t false child := by
simpa [DeleteReady] using hchildReady
have hrec := ih false hchildWF hchildReady'
have hrecWF :
NodeWF t false (composedDelete t x child) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
replaceChild_packet hparent hchild hrecWF hrec.2.2 hrec.1
have hraw :=
rawDeleteResult_of_nodeWF hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
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 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 htargetReady :
DeleteReady t false (rotateLeft left sep child).2.2 :=
rotateLeft_repaired_deleteReady ht hleftReady hchildMin
have hrec := ih false htargetWF htargetReady
have hrecWF :
NodeWF t false
(composedDelete t x (rotateLeft left sep child).2.2) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacketRaw :=
rotateLeft_reassembly_packet ht hparent hsep hleft hchildAt
hleftReady hchildMin hrecWF hrec.2.2 hrec.1
have hpacket :
NodeWF t b
(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))) ∧
heightOf
(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))) =
heightOf (node ks cs) ∧
KeysSubset
(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)))
(node ks cs) := by
simpa [show findChild ks x - 1 + 1 = findChild ks x by omega]
using hpacketRaw
have hraw :=
rawDeleteResult_of_nodeWF hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
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
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 htargetReady :
DeleteReady t false (rotateRight child sep right).1 :=
rotateRight_repaired_deleteReady ht hchildMin hrightReady
have hrec := ih false htargetWF htargetReady
have hrecWF :
NodeWF t false
(composedDelete t x (rotateRight child sep right).1) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
rotateRight_reassembly_packet ht hparent hsep hchild hright
hchildMin hrightReady hrecWF hrec.2.2 hrec.1
have hraw :=
rawDeleteResult_of_nodeWF hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
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 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 htarget.2.1
have hrecWF :
NodeWF t false
(composedDelete t x (mergeNodes left sep child)) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
spliceMerged_left_packet hpos hparent hready hsep hleft hchild
hrecWF hrec.2.2 hrec.1
have hraw :
RawDeleteResult t b
(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
simpa [RawDeleteResult] using hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
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 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 htarget.2.1
have hrecWF :
NodeWF t false
(composedDelete t x (mergeNodes left sep child)) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
spliceMerged_left_packet hpos hparent hready hsep hleft hchild
hrecWF hrec.2.2 hrec.1
have hraw :
RawDeleteResult t b
(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
simpa [RawDeleteResult] using hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
case case29 =>
rename_i x ks cs hnonempty i hnotPos child hchild hchildReady ih
simp only [i] at hnotPos
have hchildMem : child ∈ cs :=
List.mem_iff_getElem?.mpr ⟨0, hchild⟩
have hchildWF : NodeWF t false child :=
hparent.child hchildMem
have hchildReady' : DeleteReady t false child := by
simpa [DeleteReady] using hchildReady
have hrec := ih false hchildWF hchildReady'
have hrecWF :
NodeWF t false (composedDelete t x child) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
replaceChild_packet hparent hchild hrecWF hrec.2.2 hrec.1
have hraw :=
rawDeleteResult_of_nodeWF hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
case case30 =>
rename_i x ks cs hnonempty i hnotPos child hchild hchildNotReady
right hright hrightReady sep hsep ih
simp only [i] at hnotPos
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 htargetReady :
DeleteReady t false (rotateRight child sep right).1 :=
rotateRight_repaired_deleteReady ht hchildMin hrightReady
have hrec := ih false htargetWF htargetReady
have hrecWF :
NodeWF t false
(composedDelete t x (rotateRight child sep right).1) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
rotateRight_reassembly_packet ht hparent hsep hchild hright
hchildMin hrightReady hrecWF hrec.2.2 hrec.1
have hraw :=
rawDeleteResult_of_nodeWF hpacket.1
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 And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
case case32 =>
rename_i x ks cs hnonempty i hnotPos child hchild hchildNotReady
right hright hrightNotReady sep hsep ih
simp only [i] at hnotPos
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 htarget.2.1
have hrecWF :
NodeWF t false
(composedDelete t x (mergeNodes child sep right)) := by
simpa [RawDeleteResult] using hrec.2.1
have hpacket :=
spliceMerged_zero_packet hparent hready hsep hchild hright
hrecWF hrec.2.2 hrec.1
have hraw :
RawDeleteResult t b
(node (ks.drop 1)
([composedDelete t x (mergeNodes child sep right)] ++
cs.drop 2)) := by
simpa [RawDeleteResult] using hpacket.1
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]
exact And.intro hpacket.2.2 (And.intro hraw hpacket.2.1)
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 : _ < _, _›
omegaRaw deletion at a non-root node preserves its invariant packet, represented keys, and height when the CLRS descent guard holds.
theorem composedDelete_nonRoot_preserves
(t x : Nat) (ht : 2 ≤ t) {tr : BTree}
(hinv : NodeWF t false tr)
(hready : t ≤ numKeys tr) :
let out := composedDelete t x tr
KeysSubset out tr ∧
NodeWF t false out ∧
heightOf out = heightOf tr := by
have hpacket :=
composedDelete_packet t ht x tr false hinv
(by simpa [DeleteReady] using hready)
simpa [RawDeleteResult] using hpacketRaw deletion at the root preserves keys and height and returns either an ordinary root or the single-child transient consumed by root normalization.
theorem composedDelete_rootResult
(t x : Nat) (ht : 2 ≤ t) {tr : BTree}
(hwf : WellFormed t tr) :
let out := composedDelete t x tr
KeysSubset out tr ∧
RootDeleteResult t out ∧
heightOf out = heightOf tr := by
have hpacket :=
composedDelete_packet t ht x tr true hwf (deleteReady_root t tr)
simpa [RawDeleteResult] using hpacketend CLRS.Chapter18.BTree