Skip to content

Commit 108a3d1

Browse files
wkrozowskiTwoFX
andauthored
feat: add intersection on DTreeMap/TreeMap/TreeSet (#11165)
This PR provides intersection on `DTreeMap`/`TreeMap`/`TreeSet`and provides several lemmas about it. --------- Co-authored-by: Markus Himmel <[email protected]>
1 parent f7ed158 commit 108a3d1

File tree

20 files changed

+2370
-7
lines changed

20 files changed

+2370
-7
lines changed

src/Std/Data/DTreeMap/Basic.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,15 @@ def union (t₁ t₂ : DTreeMap α β cmp) : DTreeMap α β cmp :=
10441044

10451045
instance : Union (DTreeMap α β cmp) := ⟨union⟩
10461046

1047+
/--
1048+
Computes the intersection of the given tree maps. The result will only contain entries from the first map.
1049+
1050+
This function always merges the smaller map into the larger map.
1051+
-/
1052+
def inter (t₁ t₂ : DTreeMap α β cmp) : DTreeMap α β cmp :=
1053+
letI : Ord α := ⟨cmp⟩; ⟨t₁.inner.inter t₂.inner t₁.wf.balanced, @Impl.WF.inter _ _ _ _ t₂.inner t₁.wf.balanced t₁.wf⟩
1054+
1055+
instance : Inter (DTreeMap α β cmp) := ⟨inter⟩
10471056
/--
10481057
Erases multiple mappings from the tree map by iterating over the given collection and calling
10491058
`erase`.

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

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

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,26 @@ def filter! [Ord α] (f : (a : α) → β a → Bool) (t : Impl α β) : Impl α
772772
| false => link2! (filter! f l) (filter! f r)
773773
| true => link! k v (filter! f l) (filter! f r)
774774

775+
/-- Internal implementation detail of the tree map -/
776+
@[inline]
777+
def interSmallerFn [Ord α] (m : Impl α β) (sofar : { t : Impl α β // t.Balanced } ) (k : α) : { res : Impl α β // res.Balanced } :=
778+
match m.getEntry? k with
779+
| some kv' => let ⟨val, prop, _, _⟩ := (sofar.val.insert kv'.1 kv'.2 sofar.2); ⟨val, prop⟩
780+
| none => sofar
781+
782+
/-- Internal implementation detail of the tree map -/
783+
def interSmaller [Ord α] (m₁ : Impl α β) (m₂ : Impl α β) : Impl α β :=
784+
(m₂.foldl (fun sofar k _ => interSmallerFn m₁ sofar k) ⟨empty, balanced_empty⟩).1
785+
786+
/-- Internal implementation detail of the hash map -/
787+
def inter [Ord α] (m₁ m₂ : Impl α β) (h₁ : Balanced m₁) : Impl α β :=
788+
if m₁.size ≤ m₂.size then (m₁.filter (fun k _ => m₂.contains k) h₁).impl else interSmaller m₁ m₂
789+
790+
/-- Slower version of `inter!` which can be used in the absence of balance
791+
information but still assumes the preconditions of `filter`, otherwise might panic. -/
792+
def inter! [Ord α] (m₁ m₂ : Impl α β): Impl α β :=
793+
if m₁.size ≤ m₂.size then m₁.filter! (fun k _ => m₂.contains k) else interSmaller m₁ m₂
794+
775795
/--
776796
Changes the mapping of the key `k` by applying the function `f` to the current mapped value
777797
(if any). This function can be used to insert a new mapping, modify an existing one or delete it.
@@ -848,6 +868,15 @@ theorem balanced_modify [Ord α] [LawfulEqOrd α] {k f} {t : Impl α β} (ht : t
848868
have ihr := ihr ht.right
849869
tree_tac
850870

871+
theorem balanced_inter [Ord α] {t₁ t₂ : Impl α β} (ht : t₁.Balanced) : (t₁.inter t₂ ht).Balanced := by
872+
rw [inter]
873+
split
874+
· generalize (filter (fun k x => contains k t₂) t₁ ht) = m
875+
exact m.balanced_impl
876+
· rw [interSmaller]
877+
generalize (foldl (fun sofar k x => t₁.interSmallerFn sofar k) ⟨empty, _⟩ t₂) = m
878+
exact m.2
879+
851880
/--
852881
Returns a map that contains all mappings of `t₁` and `t₂`. In case that both maps contain the
853882
same key `k` with respect to `cmp`, the provided function is used to determine the new value from

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ inductive WF [Ord α] : {β : α → Type v} → Impl α β → Prop where
6161
| mergeWith {t₁ t₂ f h} [LawfulEqOrd α] : WF t₁ → WF (t₁.mergeWith f t₂ h).impl
6262
/-- `mergeWith` preserves well-formedness. Later shown to be subsumed by `.wf`. -/
6363
| constMergeWith {t₁ t₂ f h} : WF t₁ → WF (Impl.Const.mergeWith f t₁ t₂ h).impl
64+
/-- `inter` preserves well-formedness. Later shown to be subsumed by `.wf`. -/
65+
| inter {t₁ t₂ h} : WF t₁ → WF (t₁.inter t₂ h)
6466

6567
/--
6668
A well-formed tree is balanced. This is needed here already because we need to know that the
@@ -72,6 +74,7 @@ theorem WF.balanced [Ord α] {t : Impl α β} (h : WF t) : t.Balanced := by
7274
case empty => exact balanced_empty
7375
case modify ih => exact balanced_modify ih
7476
case constModify ih => exact Const.balanced_modify ih
77+
case inter ih => exact balanced_inter ih
7578

7679
theorem WF.eraseMany [Ord α] {ρ} [ForIn Id ρ α] {t : Impl α β} {l : ρ} {h} (hwf : WF t) :
7780
WF (t.eraseMany l h).val :=

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

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,40 @@ theorem toArray_eq_toArray_map {t : Impl α β} :
15291529

15301530
end Const
15311531

1532+
/-!
1533+
### interSmallerFn
1534+
-/
1535+
1536+
theorem WF.interSmallerFn {_ : Ord α} [TransOrd α] [BEq α] (m₁ : Impl α β) (m₂ : Impl α β)
1537+
(hm₂ :m₂.WF) (k : α) : (m₁.interSmallerFn ⟨m₂,hm₂.balanced⟩ k).1.WF := by
1538+
rw [Impl.interSmallerFn]
1539+
split
1540+
· exact WF.insert hm₂
1541+
· exact hm₂
1542+
1543+
theorem ordered_inter [Ord α] [TransOrd α] {l₁ l₂ : Impl α β} (hlb : l₁.Balanced)
1544+
(hlo : l₁.Ordered) : (l₁.inter l₂ hlb).Ordered := by
1545+
rw [inter]
1546+
split
1547+
· exact ordered_filter hlo
1548+
· rw [interSmaller]
1549+
rw [foldl_eq_foldl]
1550+
generalize l₂.toListModel = l₂
1551+
suffices ∀ {start}, start.val.Ordered → (List.foldl (fun acc p => interSmallerFn l₁ acc p.fst) start l₂).val.Ordered by
1552+
apply this
1553+
apply ordered_empty
1554+
intro s swf
1555+
induction l₂ generalizing s
1556+
case nil => simp [swf]
1557+
case cons h t ih =>
1558+
simp only [List.foldl_cons]
1559+
apply ih
1560+
simp only [Impl.interSmallerFn]
1561+
split
1562+
· apply ordered_insert
1563+
· exact swf
1564+
· exact swf
1565+
15321566
/-!
15331567
## Deducing that well-formed trees are ordered
15341568
-/
@@ -1549,6 +1583,7 @@ theorem WF.ordered [Ord α] [TransOrd α] {l : Impl α β} (h : WF l) : l.Ordere
15491583
· exact ordered_filter ‹_›
15501584
· exact ordered_mergeWith ‹_› ‹_›
15511585
· exact Const.ordered_mergeWith ‹_› ‹_›
1586+
· exact ordered_inter ‹_› ‹_›
15521587

15531588
/-!
15541589
## Deducing that additional operations are well-formed
@@ -1995,6 +2030,91 @@ theorem WF.filter! {_ : Ord α} {t : Impl α β} {f : (a : α) → β a → Bool
19952030
rw [← filter_eq_filter! (h := h.balanced)]
19962031
exact h.filter
19972032

2033+
theorem toListModel_interSmallerFn {_ : Ord α} [TransOrd α] [BEq α] [LawfulBEqOrd α] (m sofar : Impl α β) (h₁ : m.WF) (h₂ : sofar.WF)
2034+
(l : List ((a : α) × β a))
2035+
(k : α) (hml : List.Perm (sofar.toListModel) l) :
2036+
List.Perm (toListModel ((interSmallerFn m ⟨sofar,h₂.balanced⟩ k)).1)
2037+
(List.interSmallerFn (toListModel m) l k) := by
2038+
rw [interSmallerFn, List.interSmallerFn]
2039+
split
2040+
case h_1 _ val heq =>
2041+
simp only
2042+
rw [getEntry?_eq_getEntry?] at heq
2043+
simp only [heq]
2044+
apply List.Perm.trans
2045+
· apply toListModel_insert
2046+
· exact h₂.ordered
2047+
· apply insertEntry_of_perm
2048+
· apply Ordered.distinctKeys h₂.ordered
2049+
· exact hml
2050+
· exact h₁.ordered
2051+
case h_2 heq =>
2052+
simp only
2053+
rw [getEntry?_eq_getEntry?] at heq
2054+
simp only [heq, hml]
2055+
exact h₁.ordered
2056+
2057+
/-!
2058+
### interSmaller
2059+
-/
2060+
2061+
theorem toListModel_interSmaller {_ : Ord α} [TransOrd α] [BEq α] [LawfulBEqOrd α]
2062+
(m₁ : Impl α β) (m₂ : Impl α β) (hm₁ : m₁.WF) :
2063+
List.Perm (toListModel (m₁.interSmaller m₂))
2064+
(List.interSmaller (toListModel m₁) (toListModel m₂)) := by
2065+
rw [interSmaller, foldl_eq_foldl, List.interSmaller]
2066+
generalize toListModel m₂ = l
2067+
suffices ∀ m l', (hm : m.WF) → List.Perm (toListModel m) l' →
2068+
List.Perm (toListModel (List.foldl (fun a b => interSmallerFn m₁ a b.fst) ⟨m, hm.balanced⟩ l).val)
2069+
(List.foldl (fun sofar kv => List.interSmallerFn (toListModel m₁) sofar kv.fst) l' l) by
2070+
simpa using this empty [] WF.empty (by simp)
2071+
intro m l' hm hml'
2072+
induction l generalizing m l' with
2073+
| nil => simpa
2074+
| cons ht tl ih =>
2075+
rw [List.foldl_cons, List.foldl_cons]
2076+
exact ih _ _ (by apply WF.interSmallerFn _ _ hm) (toListModel_interSmallerFn _ _ hm₁ hm _ _ hml')
2077+
2078+
/-!
2079+
### inter
2080+
-/
2081+
2082+
theorem toListModel_inter {_ : Ord α} [TransOrd α] [BEq α] [LawfulBEqOrd α]
2083+
(m₁ : Impl α β) (m₂ : Impl α β) (hm₁ : m₁.WF) (hm₂ : m₂.WF) :
2084+
List.Perm (toListModel (m₁.inter m₂ hm₁.balanced)) ((toListModel m₁).filter fun p => containsKey p.1 (toListModel m₂)) := by
2085+
rw [inter]
2086+
split
2087+
· rw [toListModel_filter]
2088+
conv =>
2089+
lhs
2090+
lhs
2091+
ext e
2092+
rw [@contains_eq_containsKey α β _ _ _ _ e.fst m₂ hm₂.ordered]
2093+
· apply List.Perm.trans (toListModel_interSmaller _ _ hm₁) (List.interSmaller_perm_filter _ _ hm₁.ordered.distinctKeys)
2094+
2095+
/-!
2096+
### inter!
2097+
-/
2098+
2099+
theorem inter_eq_inter! [Ord α] {l₁ l₂: Impl α β} {h} :
2100+
(inter l₁ l₂ h) = inter! l₁ l₂ := by
2101+
rw [inter, inter!]
2102+
split
2103+
· rw [filter_eq_filter!]
2104+
· rfl
2105+
2106+
theorem toListModel_inter! {_ : Ord α} [TransOrd α] [BEq α] [LawfulBEqOrd α]
2107+
(m₁ : Impl α β) (m₂ : Impl α β) (hm₁ : m₁.WF) (hm₂ : m₂.WF) :
2108+
List.Perm (toListModel (m₁.inter! m₂)) ((toListModel m₁).filter fun p => containsKey p.1 (toListModel m₂)) := by
2109+
rw [← @inter_eq_inter! _ _ _ _ _ hm₁.balanced]
2110+
exact toListModel_inter _ _ hm₁ hm₂
2111+
2112+
theorem WF.inter! {_ : Ord α} [TransOrd α]
2113+
{m₁ m₂ : Impl α β} (wh₁ : m₁.WF) :
2114+
(inter! m₁ m₂).WF := by
2115+
rw [← @inter_eq_inter! _ _ _ _ _ wh₁.balanced]
2116+
exact WF.inter wh₁
2117+
19982118
/-!
19992119
### map
20002120
-/

0 commit comments

Comments
 (0)