Skip to content

Commit 2da5b52

Browse files
wkrozowskiTwoFX
andauthored
feat: add difference on DTreeMap/TreeMap/TreeSet (#11407)
This PR adds the difference operation on `DTreeMap`/`TreeMap`/`TreeSet` and proves several lemmas about it. --------- Co-authored-by: Markus Himmel <[email protected]>
1 parent ca23ed0 commit 2da5b52

File tree

19 files changed

+2385
-2
lines changed

19 files changed

+2385
-2
lines changed

src/Std/Data/DTreeMap/Basic.lean

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,14 +1053,23 @@ def inter (t₁ t₂ : DTreeMap α β cmp) : DTreeMap α β cmp :=
10531053
letI : Ord α := ⟨cmp⟩; ⟨t₁.inner.inter t₂.inner t₁.wf.balanced, @Impl.WF.inter _ _ _ _ t₂.inner t₁.wf.balanced t₁.wf⟩
10541054

10551055
instance : Inter (DTreeMap α β cmp) := ⟨inter⟩
1056+
1057+
/--
1058+
Computes the difference of the given tree maps.
1059+
This function always iterates through the smaller map.
1060+
-/
1061+
def diff (t₁ t₂ : DTreeMap α β cmp) : DTreeMap α β cmp :=
1062+
letI : Ord α := ⟨cmp⟩; ⟨t₁.inner.diff t₂.inner t₁.wf.balanced, @Impl.WF.diff α β _ t₁.inner t₁.wf t₂.inner⟩
1063+
1064+
instance : SDiff (DTreeMap α β cmp) := ⟨diff⟩
1065+
10561066
/--
10571067
Erases multiple mappings from the tree map by iterating over the given collection and calling
10581068
`erase`.
10591069
-/
10601070
@[inline]
10611071
def eraseMany {ρ} [ForIn Id ρ α] (t : DTreeMap α β cmp) (l : ρ) : DTreeMap α β cmp :=
10621072
letI : Ord α := ⟨cmp⟩; ⟨t.inner.eraseMany l t.wf.balanced, t.wf.eraseMany⟩
1063-
10641073
namespace Const
10651074

10661075
variable {β : Type v}

src/Std/Data/DTreeMap/Internal/Lemmas.lean

Lines changed: 727 additions & 1 deletion
Large diffs are not rendered by default.

src/Std/Data/DTreeMap/Internal/Operations.lean

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,36 @@ def eraseMany! [Ord α] {ρ : Type w} [ForIn Id ρ α] (t : Impl α β) (l : ρ)
481481
r := ⟨r.val.erase! a, fun h₀ h₁ => h₁ _ _ (r.2 h₀ h₁)⟩
482482
return r
483483

484+
/-- A tree map obtained by erasing elements from `t`, bundled with an inductive principle. -/
485+
abbrev IteratedEntryErasureFrom [Ord α] (t) :=
486+
{ t' // ∀ {P : Impl α β → Prop}, P t → (∀ t'' a h, P t'' → P (t''.erase a h).impl) → P t' }
487+
488+
/-- Iterate over `l` and erase all of its elements from `t`. -/
489+
@[inline]
490+
def eraseManyEntries [Ord α] {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] (t : Impl α β) (l : ρ) (h : t.Balanced) :
491+
IteratedEntryErasureFrom t := Id.run do
492+
let mut r := ⟨t, fun h _ => h⟩
493+
for ⟨a, _⟩ in l do
494+
let hr := r.2 h (fun t'' a h _ => (t''.erase a h).balanced_impl)
495+
r := ⟨r.val.erase a hr |>.impl, fun h₀ h₁ => h₁ _ _ _ (r.2 h₀ h₁)⟩
496+
return r
497+
498+
/-- A tree map obtained by erasing elements from `t`, bundled with an inductive principle. -/
499+
abbrev IteratedSlowEntryErasureFrom [Ord α] (t) :=
500+
{ t' // ∀ {P : Impl α β → Prop}, P t → (∀ t'' a, P t'' → P (t''.erase! a)) → P t' }
501+
502+
/--
503+
Slower version of `eraseManyEntries` which can be used in absence of balance information but still
504+
assumes the preconditions of `eraseManyEntries`, otherwise might panic.
505+
-/
506+
@[inline]
507+
def eraseManyEntries! [Ord α] {ρ : Type w} [ForIn Id ρ ((a : α) × β a)] (t : Impl α β) (l : ρ) :
508+
IteratedSlowErasureFrom t := Id.run do
509+
let mut r := ⟨t, fun h _ => h⟩
510+
for ⟨a, _⟩ in l do
511+
r := ⟨r.val.erase! a, fun h₀ h₁ => h₁ _ _ (r.2 h₀ h₁)⟩
512+
return r
513+
484514
/-- A tree map obtained by inserting elements into `t`, bundled with an inductive principle. -/
485515
abbrev IteratedInsertionInto [Ord α] (t) :=
486516
{ t' // ∀ {P : Impl α β → Prop}, P t → (∀ t'' a b h, P t'' → P (t''.insert a b h).impl) → P t' }
@@ -792,6 +822,20 @@ information but still assumes the preconditions of `filter`, otherwise might pan
792822
def inter! [Ord α] (m₁ m₂ : Impl α β): Impl α β :=
793823
if m₁.size ≤ m₂.size then m₁.filter! (fun k _ => m₂.contains k) else interSmaller m₁ m₂
794824

825+
/--
826+
Computes the difference of the given tree maps.
827+
This function always iterates through the smaller map.
828+
-/
829+
def diff [Ord α] (t₁ t₂ : Impl α β) (h₁ : t₁.Balanced) : Impl α β :=
830+
if t₁.size ≤ t₂.size then (t₁.filter (fun p _ => !t₂.contains p) h₁).impl else (t₁.eraseManyEntries t₂ h₁)
831+
832+
/--
833+
Slower version of `diff` which can be used in the absence of balance
834+
information but still assumes the preconditions of `diff`, otherwise might panic.
835+
-/
836+
def diff! [Ord α] (t₁ t₂ : Impl α β) : Impl α β :=
837+
if t₁.size ≤ t₂.size then t₁.filter! (fun p _ => !t₂.contains p) else t₁.eraseManyEntries! t₂
838+
795839
/--
796840
Changes the mapping of the key `k` by applying the function `f` to the current mapped value
797841
(if any). This function can be used to insert a new mapping, modify an existing one or delete it.

src/Std/Data/DTreeMap/Internal/WF/Defs.lean

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ theorem WF.balanced [Ord α] {t : Impl α β} (h : WF t) : t.Balanced := by
7676
case constModify ih => exact Const.balanced_modify ih
7777
case inter ih => exact balanced_inter ih
7878

79+
theorem WF.eraseManyEntries [Ord α] {ρ} [ForIn Id ρ ((a : α) × β a)] {t : Impl α β} {l : ρ} {h} (hwf : WF t) :
80+
WF (t.eraseManyEntries l h).val :=
81+
(t.eraseManyEntries l h).2 hwf fun _ _ _ hwf' => hwf'.erase
82+
7983
theorem WF.eraseMany [Ord α] {ρ} [ForIn Id ρ α] {t : Impl α β} {l : ρ} {h} (hwf : WF t) :
8084
WF (t.eraseMany l h).val :=
8185
(t.eraseMany l h).2 hwf fun _ _ _ hwf' => hwf'.erase
@@ -110,6 +114,13 @@ theorem WF.union [Ord α] {t₁ : Impl α β} {h₁ : t₁.WF} {t₂ : Impl α
110114
. apply WF.insertManyIfNew h₂
111115
. apply WF.insertMany h₁
112116

117+
theorem WF.diff [Ord α] {t₁ : Impl α β} {h₁ : t₁.WF} {t₂ : Impl α β} :
118+
(t₁.diff t₂ h₁.balanced).WF := by
119+
simp [Impl.diff]
120+
split
121+
· apply WF.filter h₁
122+
· apply WF.eraseManyEntries h₁
123+
113124
section Const
114125

115126
variable {β : Type v}

src/Std/Data/DTreeMap/Internal/WF/Lemmas.lean

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,75 @@ theorem WF.eraseMany! {_ : Ord α} [TransOrd α] {ρ} [ForIn Id ρ α] {l : ρ}
16611661
{t : Impl α β} (h : t.WF) : (t.eraseMany! l).1.WF :=
16621662
(t.eraseMany! l).2 h (fun _ _ h' => h'.erase!)
16631663

1664+
/-!
1665+
### `eraseManyEntries`
1666+
-/
1667+
1668+
theorem eraseManyEntries!_eq_foldl {_ : Ord α} {l : List ((a : α) × β a)} {t : Impl α β} :
1669+
(t.eraseManyEntries! l).val = l.foldl (init := t) fun acc ⟨k, _⟩ => acc.erase! k := by
1670+
simp [eraseManyEntries!, ← List.foldl_hom Subtype.val, List.forIn_pure_yield_eq_foldl]
1671+
1672+
theorem eraseManyEntries_eq_foldl {_ : Ord α} {l : List ((a : α) × β a)} {t : Impl α β} (h : t.Balanced) :
1673+
(t.eraseManyEntries l h).val = l.foldl (init := t) fun acc ⟨k, _⟩ => acc.erase! k := by
1674+
simp [eraseManyEntries, erase_eq_erase!, ← List.foldl_hom Subtype.val, List.forIn_pure_yield_eq_foldl]
1675+
1676+
theorem eraseManyEntries_impl_eq_foldl {_ : Ord α} {t₁ : Impl α β} (h₁ : t₁.Balanced) {t₂ : Impl α β} :
1677+
(t₁.eraseManyEntries t₂ h₁).val = t₂.foldl (init := t₁) fun acc k _ => acc.erase! k := by
1678+
simp [foldl_eq_foldl]
1679+
rw [← eraseManyEntries_eq_foldl]
1680+
rotate_left
1681+
· exact h₁
1682+
· simp only [eraseManyEntries, pure, ForIn.forIn, Id.run_bind]
1683+
rw [forIn_eq_forIn_toListModel]
1684+
congr
1685+
1686+
theorem eraseManyEntries!_impl_eq_foldl {_ : Ord α} {t₁ : Impl α β} {t₂ : Impl α β} :
1687+
(t₁.eraseManyEntries! t₂).val = t₂.foldl (init := t₁) fun acc k _ => acc.erase! k := by
1688+
simp [foldl_eq_foldl]
1689+
rw [← eraseManyEntries!_eq_foldl]
1690+
simp only [eraseManyEntries!, pure, ForIn.forIn, Id.run_bind]
1691+
rw [forIn_eq_forIn_toListModel]
1692+
congr
1693+
1694+
theorem eraseManyEntries_impl_eq_eraseManyEntries! {_ : Ord α}
1695+
{t₁ t₂ : Impl α β} (h : t₁.Balanced) :
1696+
(t₁.eraseManyEntries t₂ h).val = (t₁.eraseManyEntries! t₂).val := by
1697+
simp only [eraseManyEntries_impl_eq_foldl, eraseManyEntries!_impl_eq_foldl]
1698+
1699+
theorem eraseManyEntries_impl_perm_eraseList {_ : Ord α} [BEq α] [LawfulBEqOrd α] [TransOrd α]
1700+
{t₁ : Impl α β} (h₁ : t₁.WF) {t₂ : Impl α β} :
1701+
List.Perm (t₁.eraseManyEntries t₂ h₁.balanced).val.toListModel (t₁.toListModel.eraseList (t₂.toListModel.map (·.1))) := by
1702+
rw [eraseManyEntries_impl_eq_foldl]
1703+
rw [foldl_eq_foldl]
1704+
induction t₂.toListModel generalizing t₁ with
1705+
| nil => rfl
1706+
| cons e es ih =>
1707+
simp only [List.foldl_cons]
1708+
apply List.Perm.trans (@ih (t₁.erase! e.1) (h₁.erase!))
1709+
apply eraseList_perm_of_perm_first
1710+
· apply toListModel_erase!
1711+
· exact h₁.balanced
1712+
· exact h₁.ordered
1713+
· apply h₁.erase!.ordered.distinctKeys
1714+
1715+
theorem toListModel_eraseManyEntries_impl {_ : Ord α} [BEq α] [LawfulBEqOrd α] [TransOrd α]
1716+
{t₁ : Impl α β} (h₁ : t₁.WF) {t₂ : Impl α β} :
1717+
List.Perm (t₁.eraseManyEntries t₂ h₁.balanced).val.toListModel (t₁.toListModel.filter (fun p => !List.contains (t₂.toListModel.map Sigma.fst) p.fst )) := by
1718+
apply List.Perm.trans
1719+
· apply eraseManyEntries_impl_perm_eraseList h₁
1720+
· apply eraseList_perm_filter_not_contains
1721+
· apply h₁.ordered.distinctKeys
1722+
1723+
theorem toListModel_eraseManyEntries!_impl {_ : Ord α} [BEq α] [LawfulBEqOrd α] [TransOrd α]
1724+
{t₁ : Impl α β} (h₁ : t₁.WF) {t₂ : Impl α β} :
1725+
List.Perm (t₁.eraseManyEntries! t₂).val.toListModel (t₁.toListModel.filter (fun p => !List.contains (t₂.toListModel.map Sigma.fst) p.fst)) := by
1726+
rw [← eraseManyEntries_impl_eq_eraseManyEntries! h₁.balanced]
1727+
apply toListModel_eraseManyEntries_impl h₁
1728+
1729+
theorem WF.eraseManyEntries! {_ : Ord α} [TransOrd α] {ρ} [ForIn Id ρ ((a : α) × β a)] {l : ρ}
1730+
{t : Impl α β} (h : t.WF) : (t.eraseManyEntries! l).1.WF :=
1731+
(t.eraseManyEntries! l).2 h (fun _ _ h' => h'.erase!)
1732+
16641733
/-!
16651734
### `insertMany`
16661735
-/
@@ -2048,6 +2117,40 @@ theorem toListModel_interSmallerFn {_ : Ord α} [TransOrd α] [BEq α] [LawfulBE
20482117
simp only [heq, hml]
20492118
exact h₁.ordered
20502119

2120+
/-!
2121+
### diff
2122+
-/
2123+
2124+
theorem toListModel_diff {_ : Ord α} [BEq α] [LawfulBEqOrd α] [TransOrd α]
2125+
{t₁ t₂ : Impl α β} (h₁ : t₁.WF) (h₂ : t₂.WF) :
2126+
List.Perm (t₁.diff t₂ h₁.balanced).toListModel (t₁.toListModel.filter (fun p => !List.contains (t₂.toListModel.map Sigma.fst) p.fst)) := by
2127+
rw [diff]
2128+
split
2129+
· simp only [toListModel_filter]
2130+
conv =>
2131+
lhs
2132+
lhs
2133+
ext e
2134+
congr
2135+
rw [contains_eq_containsKey h₂.ordered]
2136+
rw [containsKey_eq_contains_map_fst]
2137+
· apply toListModel_eraseManyEntries_impl h₁
2138+
2139+
theorem diff_eq_diff! [Ord α]
2140+
{t₁ t₂ : Impl α β} (h₁ : t₁.WF) :
2141+
(t₁.diff t₂ h₁.balanced) = t₁.diff! t₂ := by
2142+
simp only [diff, diff!]
2143+
split
2144+
· rw [filter_eq_filter!]
2145+
. rw [eraseManyEntries_impl_eq_eraseManyEntries! h₁.balanced]
2146+
2147+
theorem WF.diff! {_ : Ord α} [TransOrd α]
2148+
{t₁ : Impl α β} (h₁ : t₁.WF) {t₂ : Impl α β} : (t₁.diff! t₂).WF := by
2149+
simp only [Impl.diff!]
2150+
split
2151+
. exact WF.filter! h₁
2152+
. exact WF.eraseManyEntries! h₁
2153+
20512154
/-!
20522155
### interSmaller
20532156
-/

0 commit comments

Comments
 (0)