2
2
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
3
3
Released under Apache 2.0 license as described in the file LICENSE.
4
4
Authors: Mario Carneiro
5
+
6
+ ! This file was ported from Lean 3 source module data.multiset.nodup
7
+ ! leanprover-community/mathlib commit 9003f28797c0664a49e4179487267c494477d853
8
+ ! Please do not edit these lines, except to modify the commit id
9
+ ! if you have ported upstream changes.
5
10
-/
6
- import Mathlib.Data.Multiset.Basic
11
+ import Mathlib.Data.List.Nodup
12
+ import Mathlib.Data.Multiset.Bind
13
+ import Mathlib.Data.Multiset.Range
14
+
7
15
/-!
8
- # The `nodup ` predicate for multisets without duplicate elements.
16
+ # The `Nodup ` predicate for multisets without duplicate elements.
9
17
-/
10
18
11
19
@@ -15,7 +23,255 @@ open Function List
15
23
16
24
variable {α β γ : Type _} {r : α → α → Prop } {s t : Multiset α} {a : α}
17
25
18
- /-- `nodup s` means that `s` has no duplicates, i.e. the multiplicity of
26
+ -- nodup
27
+ /-- `Nodup s` means that `s` has no duplicates, i.e. the multiplicity of
19
28
any element is at most 1. -/
20
29
def Nodup (s : Multiset α) : Prop :=
21
- Quot.liftOn s List.Nodup fun _ _ p ↦ propext p.nodup_iff
30
+ Quot.liftOn s List.Nodup fun _ _ p => propext p.nodup_iff
31
+ #align multiset.nodup Multiset.Nodup
32
+
33
+ @[simp]
34
+ theorem coe_nodup {l : List α} : @Nodup α l ↔ l.Nodup :=
35
+ Iff.rfl
36
+ #align multiset.coe_nodup Multiset.coe_nodup
37
+
38
+ @[simp]
39
+ theorem nodup_zero : @Nodup α 0 :=
40
+ Pairwise.nil
41
+ #align multiset.nodup_zero Multiset.nodup_zero
42
+
43
+ @[simp]
44
+ theorem nodup_cons {a : α} {s : Multiset α} : Nodup (a ::ₘ s) ↔ a ∉ s ∧ Nodup s :=
45
+ Quot.induction_on s fun _ => List.nodup_cons
46
+ #align multiset.nodup_cons Multiset.nodup_cons
47
+
48
+ theorem Nodup.cons (m : a ∉ s) (n : Nodup s) : Nodup (a ::ₘ s) :=
49
+ nodup_cons.2 ⟨m, n⟩
50
+ #align multiset.nodup.cons Multiset.Nodup.cons
51
+
52
+ @[simp]
53
+ theorem nodup_singleton : ∀ a : α, Nodup ({a} : Multiset α) :=
54
+ List.nodup_singleton
55
+ #align multiset.nodup_singleton Multiset.nodup_singleton
56
+
57
+ theorem Nodup.of_cons (h : Nodup (a ::ₘ s)) : Nodup s :=
58
+ (nodup_cons.1 h).2
59
+ #align multiset.nodup.of_cons Multiset.Nodup.of_cons
60
+
61
+ theorem Nodup.not_mem (h : Nodup (a ::ₘ s)) : a ∉ s :=
62
+ (nodup_cons.1 h).1
63
+ #align multiset.nodup.not_mem Multiset.Nodup.not_mem
64
+
65
+ theorem nodup_of_le {s t : Multiset α} (h : s ≤ t) : Nodup t → Nodup s :=
66
+ Multiset.leInductionOn h fun {_ _} => Nodup.sublist
67
+ #align multiset.nodup_of_le Multiset.nodup_of_le
68
+
69
+ theorem not_nodup_pair : ∀ a : α, ¬Nodup (a ::ₘ a ::ₘ 0 ) :=
70
+ List.not_nodup_pair
71
+ #align multiset.not_nodup_pair Multiset.not_nodup_pair
72
+
73
+ theorem nodup_iff_le {s : Multiset α} : Nodup s ↔ ∀ a : α, ¬a ::ₘ a ::ₘ 0 ≤ s :=
74
+ Quot.induction_on s fun _ =>
75
+ nodup_iff_sublist.trans <| forall_congr' fun a => not_congr (@repeat_le_coe _ a 2 _).symm
76
+ #align multiset.nodup_iff_le Multiset.nodup_iff_le
77
+
78
+ theorem nodup_iff_ne_cons_cons {s : Multiset α} : s.Nodup ↔ ∀ a t, s ≠ a ::ₘ a ::ₘ t :=
79
+ nodup_iff_le.trans
80
+ ⟨fun h a t s_eq => h a (s_eq.symm ▸ cons_le_cons a (cons_le_cons a (zero_le _))), fun h a le =>
81
+ let ⟨t, s_eq⟩ := le_iff_exists_add.mp le
82
+ h a t (by rwa [cons_add, cons_add, zero_add] at s_eq)⟩
83
+ #align multiset.nodup_iff_ne_cons_cons Multiset.nodup_iff_ne_cons_cons
84
+
85
+ theorem nodup_iff_count_le_one [DecidableEq α] {s : Multiset α} : Nodup s ↔ ∀ a, count a s ≤ 1 :=
86
+ Quot.induction_on s fun _l => List.nodup_iff_count_le_one
87
+ #align multiset.nodup_iff_count_le_one Multiset.nodup_iff_count_le_one
88
+
89
+ @[simp]
90
+ theorem count_eq_one_of_mem [DecidableEq α] {a : α} {s : Multiset α} (d : Nodup s) (h : a ∈ s) :
91
+ count a s = 1 :=
92
+ le_antisymm (nodup_iff_count_le_one.1 d a) (count_pos.2 h)
93
+ #align multiset.count_eq_one_of_mem Multiset.count_eq_one_of_mem
94
+
95
+ theorem count_eq_of_nodup [DecidableEq α] {a : α} {s : Multiset α} (d : Nodup s) :
96
+ count a s = if a ∈ s then 1 else 0 :=
97
+ by
98
+ split_ifs with h
99
+ · exact count_eq_one_of_mem d h
100
+ · exact count_eq_zero_of_not_mem h
101
+ #align multiset.count_eq_of_nodup Multiset.count_eq_of_nodup
102
+
103
+ theorem nodup_iff_pairwise {α} {s : Multiset α} : Nodup s ↔ Pairwise (· ≠ ·) s :=
104
+ Quotient.inductionOn s fun _ => (pairwise_coe_iff_pairwise fun _ _ => Ne.symm).symm
105
+ #align multiset.nodup_iff_pairwise Multiset.nodup_iff_pairwise
106
+
107
+ protected theorem Nodup.pairwise : (∀ a ∈ s, ∀ b ∈ s, a ≠ b → r a b) → Nodup s → Pairwise r s :=
108
+ Quotient.inductionOn s fun l h hl => ⟨l, rfl, hl.imp_of_mem fun {a b} ha hb => h a ha b hb⟩
109
+ #align multiset.nodup.pairwise Multiset.Nodup.pairwise
110
+
111
+ theorem Pairwise.forall (H : Symmetric r) (hs : Pairwise r s) :
112
+ ∀ ⦃a⦄, a ∈ s → ∀ ⦃b⦄, b ∈ s → a ≠ b → r a b :=
113
+ let ⟨_, hl₁, hl₂⟩ := hs
114
+ hl₁.symm ▸ hl₂.forall H
115
+ #align multiset.pairwise.forall Multiset.Pairwise.forall
116
+
117
+ theorem nodup_add {s t : Multiset α} : Nodup (s + t) ↔ Nodup s ∧ Nodup t ∧ Disjoint s t :=
118
+ Quotient.inductionOn₂ s t fun _ _ => nodup_append
119
+ #align multiset.nodup_add Multiset.nodup_add
120
+
121
+ theorem disjoint_of_nodup_add {s t : Multiset α} (d : Nodup (s + t)) : Disjoint s t :=
122
+ (nodup_add.1 d).2 .2
123
+ #align multiset.disjoint_of_nodup_add Multiset.disjoint_of_nodup_add
124
+
125
+ theorem Nodup.add_iff (d₁ : Nodup s) (d₂ : Nodup t) : Nodup (s + t) ↔ Disjoint s t := by
126
+ simp [nodup_add, d₁, d₂]
127
+ #align multiset.nodup.add_iff Multiset.Nodup.add_iff
128
+
129
+ theorem Nodup.of_map (f : α → β) : Nodup (map f s) → Nodup s :=
130
+ Quot.induction_on s fun _ => List.Nodup.of_map f
131
+ #align multiset.nodup.of_map Multiset.Nodup.of_map
132
+
133
+ theorem Nodup.map_on {f : α → β} :
134
+ (∀ x ∈ s, ∀ y ∈ s, f x = f y → x = y) → Nodup s → Nodup (map f s) :=
135
+ Quot.induction_on s fun _ => List.Nodup.map_on
136
+ #align multiset.nodup.map_on Multiset.Nodup.map_on
137
+
138
+ theorem Nodup.map {f : α → β} {s : Multiset α} (hf : Injective f) : Nodup s → Nodup (map f s) :=
139
+ Nodup.map_on fun _ _ _ _ h => hf h
140
+ #align multiset.nodup.map Multiset.Nodup.map
141
+
142
+ theorem inj_on_of_nodup_map {f : α → β} {s : Multiset α} :
143
+ Nodup (map f s) → ∀ x ∈ s, ∀ y ∈ s, f x = f y → x = y :=
144
+ Quot.induction_on s fun _ => List.inj_on_of_nodup_map
145
+ #align multiset.inj_on_of_nodup_map Multiset.inj_on_of_nodup_map
146
+
147
+ theorem nodup_map_iff_inj_on {f : α → β} {s : Multiset α} (d : Nodup s) :
148
+ Nodup (map f s) ↔ ∀ x ∈ s, ∀ y ∈ s, f x = f y → x = y :=
149
+ ⟨inj_on_of_nodup_map, fun h => d.map_on h⟩
150
+ #align multiset.nodup_map_iff_inj_on Multiset.nodup_map_iff_inj_on
151
+
152
+ theorem Nodup.filter (p : α → Bool) {s} : Nodup s → Nodup (filter p s) :=
153
+ Quot.induction_on s fun _ => List.Nodup.filter p
154
+ #align multiset.nodup.filter Multiset.Nodup.filter
155
+
156
+ @[simp]
157
+ theorem nodup_attach {s : Multiset α} : Nodup (attach s) ↔ Nodup s :=
158
+ Quot.induction_on s fun _ => List.nodup_attach
159
+ #align multiset.nodup_attach Multiset.nodup_attach
160
+
161
+ theorem Nodup.pmap {p : α → Prop } {f : ∀ a, p a → β} {s : Multiset α} {H}
162
+ (hf : ∀ a ha b hb, f a ha = f b hb → a = b) : Nodup s → Nodup (pmap f s H) :=
163
+ Quot.induction_on s (fun _ _ => List.Nodup.pmap hf) H
164
+ #align multiset.nodup.pmap Multiset.Nodup.pmap
165
+
166
+ instance nodupDecidable [DecidableEq α] (s : Multiset α) : Decidable (Nodup s) :=
167
+ Quotient.recOnSubsingleton s fun l => l.nodupDecidable
168
+ #align multiset.nodup_decidable Multiset.nodupDecidable
169
+
170
+ theorem Nodup.erase_eq_filter [DecidableEq α] (a : α) {s} :
171
+ Nodup s → s.erase a = Multiset.filter (· ≠ a) s :=
172
+ Quot.induction_on s fun _ d =>
173
+ congr_arg ((↑) : List α → Multiset α) <| List.Nodup.erase_eq_filter d a
174
+ #align multiset.nodup.erase_eq_filter Multiset.Nodup.erase_eq_filter
175
+
176
+ theorem Nodup.erase [DecidableEq α] (a : α) {l} : Nodup l → Nodup (l.erase a) :=
177
+ nodup_of_le (erase_le _ _)
178
+ #align multiset.nodup.erase Multiset.Nodup.erase
179
+
180
+ theorem Nodup.mem_erase_iff [DecidableEq α] {a b : α} {l} (d : Nodup l) :
181
+ a ∈ l.erase b ↔ a ≠ b ∧ a ∈ l := by
182
+ rw [d.erase_eq_filter b, mem_filter, and_comm]
183
+ simp
184
+ #align multiset.nodup.mem_erase_iff Multiset.Nodup.mem_erase_iff
185
+
186
+ theorem Nodup.not_mem_erase [DecidableEq α] {a : α} {s} (h : Nodup s) : a ∉ s.erase a := fun ha =>
187
+ (h.mem_erase_iff.1 ha).1 rfl
188
+ #align multiset.nodup.not_mem_erase Multiset.Nodup.not_mem_erase
189
+
190
+ protected theorem Nodup.product {t : Multiset β} : Nodup s → Nodup t → Nodup (product s t) :=
191
+ Quotient.inductionOn₂ s t fun l₁ l₂ d₁ d₂ => by simp [List.Nodup.product d₁ d₂]
192
+ #align multiset.nodup.product Multiset.Nodup.product
193
+
194
+ protected theorem Nodup.sigma {σ : α → Type _} {t : ∀ a, Multiset (σ a)} :
195
+ Nodup s → (∀ a, Nodup (t a)) → Nodup (s.sigma t) :=
196
+ Quot.induction_on s fun l₁ => by
197
+ choose f hf using fun a => Quotient.exists_rep (t a)
198
+ simpa [←funext hf] using List.Nodup.sigma
199
+ #align multiset.nodup.sigma Multiset.Nodup.sigma
200
+
201
+ protected theorem Nodup.filter_map (f : α → Option β) (H : ∀ a a' b, b ∈ f a → b ∈ f a' → a = a') :
202
+ Nodup s → Nodup (filterMap f s) :=
203
+ Quot.induction_on s fun _ => Nodup.filterMap H
204
+ #align multiset.nodup.filter_map Multiset.Nodup.filter_map
205
+
206
+ theorem nodup_range (n : ℕ) : Nodup (range n) :=
207
+ List.nodup_range _
208
+ #align multiset.nodup_range Multiset.nodup_range
209
+
210
+ theorem Nodup.inter_left [DecidableEq α] (t) : Nodup s → Nodup (s ∩ t) :=
211
+ nodup_of_le <| inter_le_left _ _
212
+ #align multiset.nodup.inter_left Multiset.Nodup.inter_left
213
+
214
+ theorem Nodup.inter_right [DecidableEq α] (s) : Nodup t → Nodup (s ∩ t) :=
215
+ nodup_of_le <| inter_le_right _ _
216
+ #align multiset.nodup.inter_right Multiset.Nodup.inter_right
217
+
218
+ @[simp]
219
+ theorem nodup_union [DecidableEq α] {s t : Multiset α} : Nodup (s ∪ t) ↔ Nodup s ∧ Nodup t :=
220
+ ⟨fun h => ⟨nodup_of_le (le_union_left _ _) h, nodup_of_le (le_union_right _ _) h⟩, fun ⟨h₁, h₂⟩ =>
221
+ nodup_iff_count_le_one.2 fun a => by
222
+ rw [count_union]
223
+ exact max_le (nodup_iff_count_le_one.1 h₁ a) (nodup_iff_count_le_one.1 h₂ a)⟩
224
+ #align multiset.nodup_union Multiset.nodup_union
225
+
226
+ @[simp]
227
+ theorem nodup_bind {s : Multiset α} {t : α → Multiset β} :
228
+ Nodup (bind s t) ↔ (∀ a ∈ s, Nodup (t a)) ∧ s.Pairwise fun a b => Disjoint (t a) (t b) :=
229
+ have h₁ : ∀ a, ∃ l : List β, t a = l := fun a => Quot.induction_on (t a) fun l => ⟨l, rfl⟩
230
+ let ⟨t', h'⟩ := Classical.axiom_of_choice h₁
231
+ have : t = fun a => ofList (t' a) := funext h'
232
+ have hd : Symmetric fun a b => List.Disjoint (t' a) (t' b) := fun a b h => h.symm
233
+ Quot.induction_on s <| by simp [this, List.nodup_bind, pairwise_coe_iff_pairwise hd]
234
+ #align multiset.nodup_bind Multiset.nodup_bind
235
+
236
+ theorem Nodup.ext {s t : Multiset α} : Nodup s → Nodup t → (s = t ↔ ∀ a, a ∈ s ↔ a ∈ t) :=
237
+ Quotient.inductionOn₂ s t fun _ _ d₁ d₂ => Quotient.eq.trans <| perm_ext d₁ d₂
238
+ #align multiset.nodup.ext Multiset.Nodup.ext
239
+
240
+ theorem le_iff_subset {s t : Multiset α} : Nodup s → (s ≤ t ↔ s ⊆ t) :=
241
+ Quotient.inductionOn₂ s t fun _ _ d => ⟨subset_of_le, d.subperm⟩
242
+ #align multiset.le_iff_subset Multiset.le_iff_subset
243
+
244
+ theorem range_le {m n : ℕ} : range m ≤ range n ↔ m ≤ n :=
245
+ (le_iff_subset (nodup_range _)).trans range_subset
246
+ #align multiset.range_le Multiset.range_le
247
+
248
+ theorem mem_sub_of_nodup [DecidableEq α] {a : α} {s t : Multiset α} (d : Nodup s) :
249
+ a ∈ s - t ↔ a ∈ s ∧ a ∉ t :=
250
+ ⟨fun h =>
251
+ ⟨mem_of_le tsub_le_self h, fun h' => by
252
+ refine' count_eq_zero.1 _ h
253
+ rw [count_sub a s t, tsub_eq_zero_iff_le]
254
+ exact le_trans (nodup_iff_count_le_one.1 d _) (count_pos.2 h')⟩,
255
+ fun ⟨h₁, h₂⟩ => Or.resolve_right (mem_add.1 <| mem_of_le le_tsub_add h₁) h₂⟩
256
+ #align multiset.mem_sub_of_nodup Multiset.mem_sub_of_nodup
257
+
258
+ theorem map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : Multiset α} {t : Multiset β}
259
+ (hs : s.Nodup) (ht : t.Nodup) (i : ∀ a ∈ s, β) (hi : ∀ a ha, i a ha ∈ t)
260
+ (h : ∀ a ha, f a = g (i a ha)) (i_inj : ∀ a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂)
261
+ (i_surj : ∀ b ∈ t, ∃ a ha, b = i a ha) : s.map f = t.map g :=
262
+ have : t = s.attach.map fun x => i x.1 x.2 :=
263
+ (ht.ext <|
264
+ (nodup_attach.2 hs).map <|
265
+ show Injective fun x : { x // x ∈ s } => i x x.2 from fun x y hxy =>
266
+ Subtype.ext <| i_inj x y x.2 y.2 hxy).2
267
+ fun x => by
268
+ simp only [mem_map, true_and_iff, Subtype.exists, eq_comm, mem_attach]
269
+ exact ⟨i_surj _, fun ⟨y, hy⟩ => hy.snd.symm ▸ hi _ _⟩
270
+ calc
271
+ s.map f = s.pmap (fun x _ => f x) fun _ => id := by rw [pmap_eq_map]
272
+ _ = s.attach.map fun x => f x.1 := by rw [pmap_eq_map_attach]
273
+ _ = t.map g := by rw [this, Multiset.map_map]; exact map_congr rfl fun x _ => h _ _
274
+
275
+ #align multiset.map_eq_map_of_bij_of_nodup Multiset.map_eq_map_of_bij_of_nodup
276
+
277
+ end Multiset
0 commit comments