Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit bde8690

Browse files
splcipher1024
authored andcommitted
feat(data/alist,data/finmap): union (#750)
1 parent eb96a25 commit bde8690

File tree

3 files changed

+265
-15
lines changed

3 files changed

+265
-15
lines changed

src/data/finmap.lean

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,20 @@ by cases s₁; cases s₂; refl
7979
{C : finmap β → Prop} (s : finmap β) (H : ∀ (a : alist β), C ⟦a⟧) : C s :=
8080
by rcases s with ⟨⟨a⟩, h⟩; exact H ⟨a, h⟩
8181

82+
@[elab_as_eliminator] theorem induction_on₂ {C : finmap β → finmap β → Prop}
83+
(s₁ s₂ : finmap β) (H : ∀ (a₁ a₂ : alist β), C ⟦a₁⟧ ⟦a₂⟧) : C s₁ s₂ :=
84+
induction_on s₁ $ λ l₁, induction_on s₂ $ λ l₂, H l₁ l₂
85+
86+
@[elab_as_eliminator] theorem induction_on₃ {C : finmap β → finmap β → finmap β → Prop}
87+
(s₁ s₂ s₃ : finmap β) (H : ∀ (a₁ a₂ a₃ : alist β), C ⟦a₁⟧ ⟦a₂⟧ ⟦a₃⟧) : C s₁ s₂ s₃ :=
88+
induction_on₂ s₁ s₂ $ λ l₁ l₂, induction_on s₃ $ λ l₃, H l₁ l₂ l₃
89+
8290
@[extensionality] theorem ext : ∀ {s t : finmap β}, s.entries = t.entries → s = t
8391
| ⟨l₁, h₁⟩ ⟨l₂, h₂⟩ H := by congr'
8492

93+
@[simp] theorem ext_iff {s t : finmap β} : s.entries = t.entries ↔ s = t :=
94+
⟨ext, congr_arg _⟩
95+
8596
/-- The predicate `a ∈ s` means that `s` has a value associated to the key `a`. -/
8697
instance : has_mem α (finmap β) := ⟨λ a s, a ∈ s.entries.keys⟩
8798

@@ -124,13 +135,19 @@ def singleton (a : α) (b : β a) : finmap β :=
124135

125136
variables [decidable_eq α]
126137

138+
instance has_decidable_eq [∀ a, decidable_eq (β a)] : decidable_eq (finmap β)
139+
| s₁ s₂ := decidable_of_iff _ ext_iff
140+
127141
/-- Look up the value associated to a key in a map. -/
128142
def lookup (a : α) (s : finmap β) : option (β a) :=
129143
lift_on s (lookup a) (λ s t, perm_lookup)
130144

131145
@[simp] theorem lookup_to_finmap (a : α) (s : alist β) :
132146
lookup a ⟦s⟧ = s.lookup a := rfl
133147

148+
@[simp] theorem lookup_empty (a) : lookup a (∅ : finmap β) = none :=
149+
rfl
150+
134151
theorem lookup_is_some {a : α} {s : finmap β} :
135152
(s.lookup a).is_some ↔ a ∈ s :=
136153
induction_on s $ λ s, alist.lookup_is_some
@@ -187,7 +204,7 @@ induction_on s $ λ s, by simp
187204
induction_on s $ lookup_erase a
188205

189206
@[simp] theorem lookup_erase_ne {a a'} {s : finmap β} (h : a ≠ a') :
190-
lookup a' (erase a s) = lookup a' s :=
207+
lookup a (erase a' s) = lookup a s :=
191208
induction_on s $ λ s, lookup_erase_ne h
192209

193210
/- insert -/
@@ -206,8 +223,8 @@ theorem insert_entries_of_neg {a : α} {b : β a} {s : finmap β} : a ∉ s →
206223
induction_on s $ λ s h,
207224
by simp [insert_entries_of_neg (mt mem_to_finmap.1 h)]
208225

209-
@[simp] theorem mem_insert {a a' : α} {b : β a} {s : finmap β} :
210-
a' ∈ insert a b s ↔ a = a' ∨ a' ∈ s :=
226+
@[simp] theorem mem_insert {a a' : α} {b' : β a'} {s : finmap β} :
227+
a ∈ insert a' b' s ↔ a = a' ∨ a ∈ s :=
211228
induction_on s mem_insert
212229

213230
@[simp] theorem lookup_insert {a} {b : β a} (s : finmap β) :
@@ -226,4 +243,40 @@ lift_on s (λ t, prod.map id to_finmap (extract a t)) $
226243
extract a s = (lookup a s, erase a s) :=
227244
induction_on s $ λ s, by simp [extract]
228245

246+
/- union -/
247+
248+
/-- `s₁ ∪ s₂` is the key-based union of two finite maps. It is left-biased: if
249+
there exists an `a ∈ s₁`, `lookup a (s₁ ∪ s₂) = lookup a s₁`. -/
250+
def union (s₁ s₂ : finmap β) : finmap β :=
251+
lift_on₂ s₁ s₂ (λ s₁ s₂, ⟦s₁ ∪ s₂⟧) $
252+
λ s₁ s₂ s₃ s₄ p₁₃ p₂₄, to_finmap_eq.mpr $ perm_union p₁₃ p₂₄
253+
254+
instance : has_union (finmap β) := ⟨union⟩
255+
256+
@[simp] theorem mem_union {a} {s₁ s₂ : finmap β} :
257+
a ∈ s₁ ∪ s₂ ↔ a ∈ s₁ ∨ a ∈ s₂ :=
258+
induction_on₂ s₁ s₂ $ λ _ _, mem_union
259+
260+
@[simp] theorem union_to_finmap (s₁ s₂ : alist β) : ⟦s₁⟧ ∪ ⟦s₂⟧ = ⟦s₁ ∪ s₂⟧ :=
261+
by simp [(∪), union]
262+
263+
theorem keys_union {s₁ s₂ : finmap β} : (s₁ ∪ s₂).keys = s₁.keys ∪ s₂.keys :=
264+
induction_on₂ s₁ s₂ $ λ s₁ s₂, finset.ext' $ by simp [keys]
265+
266+
@[simp] theorem lookup_union_left {a} {s₁ s₂ : finmap β} :
267+
a ∈ s₁ → lookup a (s₁ ∪ s₂) = lookup a s₁ :=
268+
induction_on₂ s₁ s₂ $ λ s₁ s₂, lookup_union_left
269+
270+
@[simp] theorem lookup_union_right {a} {s₁ s₂ : finmap β} :
271+
a ∉ s₁ → lookup a (s₁ ∪ s₂) = lookup a s₂ :=
272+
induction_on₂ s₁ s₂ $ λ s₁ s₂, lookup_union_right
273+
274+
@[simp] theorem mem_lookup_union {a} {b : β a} {s₁ s₂ : finmap β} :
275+
b ∈ lookup a (s₁ ∪ s₂) ↔ b ∈ lookup a s₁ ∨ a ∉ s₁ ∧ b ∈ lookup a s₂ :=
276+
induction_on₂ s₁ s₂ $ λ s₁ s₂, mem_lookup_union
277+
278+
theorem mem_lookup_union_middle {a} {b : β a} {s₁ s₂ s₃ : finmap β} :
279+
b ∈ lookup a (s₁ ∪ s₃) → a ∉ s₂ → b ∈ lookup a (s₁ ∪ s₂ ∪ s₃) :=
280+
induction_on₃ s₁ s₂ s₃ $ λ s₁ s₂ s₃, mem_lookup_union_middle
281+
229282
end finmap

src/data/list/alist.lean

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ instance : has_emptyc (alist β) := ⟨⟨[], nodupkeys_nil⟩⟩
4848
theorem not_mem_empty (a : α) : a ∉ (∅ : alist β) :=
4949
not_mem_nil a
5050

51+
@[simp] theorem empty_entries : (∅ : alist β).entries = [] := rfl
52+
5153
@[simp] theorem keys_empty : (∅ : alist β).keys = [] := rfl
5254

5355
/- singleton -/
@@ -56,6 +58,9 @@ not_mem_nil a
5658
def singleton (a : α) (b : β a) : alist β :=
5759
⟨[⟨a, b⟩], nodupkeys_singleton _⟩
5860

61+
@[simp] theorem singleton_entries (a : α) (b : β a) :
62+
(singleton a b).entries = [sigma.mk a b] := rfl
63+
5964
@[simp] theorem keys_singleton (a : α) (b : β a) : (singleton a b).keys = [a] := rfl
6065

6166
variables [decidable_eq α]
@@ -66,6 +71,9 @@ variables [decidable_eq α]
6671
def lookup (a : α) (s : alist β) : option (β a) :=
6772
s.entries.lookup a
6873

74+
@[simp] theorem lookup_empty (a) : lookup a (∅ : alist β) = none :=
75+
rfl
76+
6977
theorem lookup_is_some {a : α} {s : alist β} :
7078
(s.lookup a).is_some ↔ a ∈ s := lookup_is_some
7179

@@ -124,7 +132,7 @@ perm_kerase s₁.nodupkeys
124132
lookup_kerase a s.nodupkeys
125133

126134
@[simp] theorem lookup_erase_ne {a a'} {s : alist β} (h : a ≠ a') :
127-
lookup a' (erase a s) = lookup a' s :=
135+
lookup a (erase a' s) = lookup a s :=
128136
lookup_kerase_ne h
129137

130138
/- insert -/
@@ -142,8 +150,8 @@ theorem insert_entries_of_neg {a} {b : β a} {s : alist β} (h : a ∉ s) :
142150
(insert a b s).entries = ⟨a, b⟩ :: s.entries :=
143151
by rw [insert_entries, kerase_of_not_mem_keys h]
144152

145-
@[simp] theorem mem_insert {a a'} {b : β a} (s : alist β) :
146-
a' ∈ insert a b s ↔ a = a' ∨ a' ∈ s :=
153+
@[simp] theorem mem_insert {a a'} {b' : β a'} (s : alist β) :
154+
a ∈ insert a' b' s ↔ a = a' ∨ a ∈ s :=
147155
mem_keys_kinsert
148156

149157
@[simp] theorem keys_insert {a} {b : β a} (s : alist β) :
@@ -157,8 +165,8 @@ by simp only [insert_entries]; exact perm_kinsert s₁.nodupkeys p
157165
@[simp] theorem lookup_insert {a} {b : β a} (s : alist β) : lookup a (insert a b s) = some b :=
158166
by simp only [lookup, insert, lookup_kinsert]
159167

160-
@[simp] theorem lookup_insert_ne {a a'} {b : β a} {s : alist β} (h : a ≠ a') :
161-
lookup a' (insert a b s) = lookup a' s :=
168+
@[simp] theorem lookup_insert_ne {a a'} {b' : β a'} {s : alist β} (h : a ≠ a') :
169+
lookup a (insert a' b' s) = lookup a s :=
162170
lookup_kinsert_ne h
163171

164172
/- extract -/
@@ -175,4 +183,49 @@ end
175183
extract a s = (lookup a s, erase a s) :=
176184
by simp [extract]; split; refl
177185

186+
/- union -/
187+
188+
/-- `s₁ ∪ s₂` is the key-based union of two association lists. It is
189+
left-biased: if there exists an `a ∈ s₁`, `lookup a (s₁ ∪ s₂) = lookup a s₁`.
190+
-/
191+
def union (s₁ s₂ : alist β) : alist β :=
192+
⟨kunion s₁.entries s₂.entries, kunion_nodupkeys s₁.nodupkeys s₂.nodupkeys⟩
193+
194+
instance : has_union (alist β) := ⟨union⟩
195+
196+
@[simp] theorem union_entries {s₁ s₂ : alist β} :
197+
(s₁ ∪ s₂).entries = kunion s₁.entries s₂.entries :=
198+
rfl
199+
200+
@[simp] theorem empty_union {s : alist β} : (∅ : alist β) ∪ s = s :=
201+
ext rfl
202+
203+
@[simp] theorem union_empty {s : alist β} : s ∪ (∅ : alist β) = s :=
204+
ext $ by simp
205+
206+
@[simp] theorem mem_union {a} {s₁ s₂ : alist β} :
207+
a ∈ s₁ ∪ s₂ ↔ a ∈ s₁ ∨ a ∈ s₂ :=
208+
mem_keys_kunion
209+
210+
theorem perm_union {s₁ s₂ s₃ s₄ : alist β}
211+
(p₁₂ : s₁.entries ~ s₂.entries) (p₃₄ : s₃.entries ~ s₄.entries) :
212+
(s₁ ∪ s₃).entries ~ (s₂ ∪ s₄).entries :=
213+
by simp [perm_kunion s₃.nodupkeys p₁₂ p₃₄]
214+
215+
@[simp] theorem lookup_union_left {a} {s₁ s₂ : alist β} :
216+
a ∈ s₁ → lookup a (s₁ ∪ s₂) = lookup a s₁ :=
217+
lookup_kunion_left
218+
219+
@[simp] theorem lookup_union_right {a} {s₁ s₂ : alist β} :
220+
a ∉ s₁ → lookup a (s₁ ∪ s₂) = lookup a s₂ :=
221+
lookup_kunion_right
222+
223+
@[simp] theorem mem_lookup_union {a} {b : β a} {s₁ s₂ : alist β} :
224+
b ∈ lookup a (s₁ ∪ s₂) ↔ b ∈ lookup a s₁ ∨ a ∉ s₁ ∧ b ∈ lookup a s₂ :=
225+
mem_lookup_kunion
226+
227+
theorem mem_lookup_union_middle {a} {b : β a} {s₁ s₂ s₃ : alist β} :
228+
b ∈ lookup a (s₁ ∪ s₃) → a ∉ s₂ → b ∈ lookup a (s₁ ∪ s₂ ∪ s₃) :=
229+
mem_lookup_kunion_middle
230+
178231
end alist

0 commit comments

Comments
 (0)