193 lines
8.6 KiB
Text
193 lines
8.6 KiB
Text
/-
|
||
Copyright (c) 2015 Leonardo de Moura. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Leonardo de Moura, Jeremy Avigad
|
||
|
||
Set-like operations on lists.
|
||
-/
|
||
|
||
universe variables uu vv
|
||
variables {α : Type uu} {β : Type vv}
|
||
|
||
namespace list
|
||
|
||
/- disjoint -/
|
||
section disjoint
|
||
|
||
def disjoint (l₁ l₂ : list α) : Prop := ∀ ⦃a⦄, (a ∈ l₁ → a ∈ l₂ → false)
|
||
|
||
lemma disjoint_left {l₁ l₂ : list α} : disjoint l₁ l₂ → ∀ {a}, a ∈ l₁ → a ∉ l₂ :=
|
||
λ d, d
|
||
|
||
lemma disjoint_right {l₁ l₂ : list α} : disjoint l₁ l₂ → ∀ {a}, a ∈ l₂ → a ∉ l₁ :=
|
||
λ d a i₂ i₁, d i₁ i₂
|
||
|
||
lemma disjoint.comm {l₁ l₂ : list α} : disjoint l₁ l₂ → disjoint l₂ l₁ :=
|
||
λ d a i₂ i₁, d i₁ i₂
|
||
|
||
lemma disjoint_of_subset_left {l₁ l₂ l : list α} : list.subset l₁ l → disjoint l l₂ → disjoint l₁ l₂ :=
|
||
λ ss d x xinl₁, d (ss xinl₁)
|
||
|
||
lemma disjoint_of_subset_right {l₁ l₂ l : list α} : list.subset l₂ l → disjoint l₁ l → disjoint l₁ l₂ :=
|
||
λ ss d x xinl xinl₁, d xinl (ss xinl₁)
|
||
|
||
lemma disjoint_of_disjoint_cons_left {a : α} {l₁ l₂} : disjoint (a::l₁) l₂ → disjoint l₁ l₂ :=
|
||
disjoint_of_subset_left (list.subset_cons _ _)
|
||
|
||
lemma disjoint_of_disjoint_cons_right {a : α} {l₁ l₂} : disjoint l₁ (a::l₂) → disjoint l₁ l₂ :=
|
||
disjoint_of_subset_right (list.subset_cons _ _)
|
||
|
||
lemma disjoint_nil_left (l : list α) : disjoint [] l :=
|
||
λ a ab, absurd ab (not_mem_nil a)
|
||
|
||
lemma disjoint_nil_right (l : list α) : disjoint l [] :=
|
||
disjoint.comm (disjoint_nil_left l)
|
||
|
||
lemma disjoint_cons_of_not_mem_of_disjoint {a : α} {l₁ l₂ : list α} :
|
||
a ∉ l₂ → disjoint l₁ l₂ → disjoint (a::l₁) l₂ :=
|
||
λ nainl₂ d x (xinal₁ : x ∈ a::l₁),
|
||
or.elim (eq_or_mem_of_mem_cons xinal₁)
|
||
(λ xeqa : x = a, eq.symm xeqa ▸ nainl₂)
|
||
(λ xinl₁ : x ∈ l₁, disjoint_left d xinl₁)
|
||
|
||
lemma disjoint_append_of_disjoint_left {l₁ l₂ l : list α} :
|
||
disjoint l₁ l → disjoint l₂ l → disjoint (l₁++l₂) l :=
|
||
λ d₁ d₂ x h, or.elim (mem_or_mem_of_mem_append h) (@d₁ x) (@d₂ x)
|
||
|
||
lemma disjoint_of_disjoint_append_left_left {l₁ l₂ l : list α} : disjoint (l₁++l₂) l → disjoint l₁ l :=
|
||
disjoint_of_subset_left (list.subset_append_left _ _)
|
||
|
||
lemma disjoint_of_disjoint_append_left_right {l₁ l₂ l : list α} : disjoint (l₁++l₂) l → disjoint l₂ l :=
|
||
disjoint_of_subset_left (list.subset_append_right _ _)
|
||
|
||
lemma disjoint_of_disjoint_append_right_left {l₁ l₂ l : list α} : disjoint l (l₁++l₂) → disjoint l l₁ :=
|
||
disjoint_of_subset_right (list.subset_append_left _ _)
|
||
|
||
lemma disjoint_of_disjoint_append_right_right {l₁ l₂ l : list α} : disjoint l (l₁++l₂) → disjoint l l₂ :=
|
||
disjoint_of_subset_right (list.subset_append_right _ _)
|
||
|
||
end disjoint
|
||
|
||
/- no duplicates predicate -/
|
||
|
||
inductive nodup {α : Type uu} : list α → Prop
|
||
| ndnil : nodup []
|
||
| ndcons : ∀ {a : α} {l : list α}, a ∉ l → nodup l → nodup (a::l)
|
||
|
||
section nodup
|
||
open nodup
|
||
|
||
theorem nodup_nil : @nodup α [] :=
|
||
ndnil
|
||
|
||
theorem nodup_cons {a : α} {l : list α} : a ∉ l → nodup l → nodup (a::l) :=
|
||
λ i n, ndcons i n
|
||
|
||
theorem nodup_singleton (a : α) : nodup [a] :=
|
||
nodup_cons (not_mem_nil a) nodup_nil
|
||
|
||
theorem nodup_of_nodup_cons : ∀ {a : α} {l : list α}, nodup (a::l) → nodup l
|
||
| a xs (ndcons i n) := n
|
||
|
||
theorem not_mem_of_nodup_cons : ∀ {a : α} {l : list α}, nodup (a::l) → a ∉ l
|
||
| a xs (ndcons i n) := i
|
||
|
||
theorem not_nodup_cons_of_mem {a : α} {l : list α} : a ∈ l → ¬ nodup (a :: l) :=
|
||
λ ainl d, absurd ainl (not_mem_of_nodup_cons d)
|
||
|
||
theorem nodup_of_sublist : Π {l₁ l₂ : list α}, l₁ <+ l₂ → nodup l₂ → nodup l₁
|
||
| ._ ._ sublist.slnil h := h
|
||
| ._ ._ (sublist.cons l₁ l₂ a s) (ndcons i n) := nodup_of_sublist s n
|
||
| ._ ._ (sublist.cons2 l₁ l₂ a s) (ndcons i n) :=
|
||
ndcons (λh, i (subset_of_sublist s h)) (nodup_of_sublist s n)
|
||
|
||
theorem not_nodup_cons_of_not_nodup {a : α} {l : list α} : ¬ nodup l → ¬ nodup (a :: l) :=
|
||
mt nodup_of_nodup_cons
|
||
|
||
theorem nodup_of_nodup_append_left {l₁ l₂ : list α} : nodup (l₁++l₂) → nodup l₁ :=
|
||
nodup_of_sublist (sublist_append_left l₁ l₂)
|
||
|
||
theorem nodup_of_nodup_append_right : ∀ {l₁ l₂ : list α}, nodup (l₁++l₂) → nodup l₂
|
||
| [] l₂ n := n
|
||
| (x::xs) l₂ n := nodup_of_nodup_append_right (nodup_of_nodup_cons n)
|
||
|
||
theorem disjoint_of_nodup_append : ∀ {l₁ l₂ : list α}, nodup (l₁++l₂) → disjoint l₁ l₂
|
||
| [] l₂ d := disjoint_nil_left l₂
|
||
| (x::xs) l₂ d :=
|
||
have nodup (x::(xs++l₂)), from d,
|
||
have x ∉ xs++l₂, from not_mem_of_nodup_cons this,
|
||
have nxinl₂ : x ∉ l₂, from not_mem_of_not_mem_append_right this,
|
||
assume a, assume : a ∈ x::xs,
|
||
or.elim (eq_or_mem_of_mem_cons this)
|
||
(assume : a = x, eq.symm this ▸ nxinl₂)
|
||
(assume ainxs : a ∈ xs,
|
||
have nodup (x::(xs++l₂)), from d,
|
||
have nodup (xs++l₂), from nodup_of_nodup_cons this,
|
||
have disjoint xs l₂, from disjoint_of_nodup_append this,
|
||
disjoint_left this ainxs)
|
||
|
||
theorem nodup_append_of_nodup_of_nodup_of_disjoint :
|
||
∀ {l₁ l₂ : list α}, nodup l₁ → nodup l₂ → disjoint l₁ l₂ → nodup (l₁++l₂)
|
||
| [] l₂ d₁ d₂ dsj := begin rw [nil_append], exact d₂ end
|
||
| (x::xs) l₂ d₁ d₂ dsj :=
|
||
have ndxs : nodup xs, from nodup_of_nodup_cons d₁,
|
||
have disjoint xs l₂, from disjoint_of_disjoint_cons_left dsj,
|
||
have ndxsl₂ : nodup (xs++l₂), from nodup_append_of_nodup_of_nodup_of_disjoint ndxs d₂ this,
|
||
have nxinxs : x ∉ xs, from not_mem_of_nodup_cons d₁,
|
||
have x ∉ l₂, from disjoint_left dsj (mem_cons_self x xs),
|
||
have x ∉ xs++l₂, from not_mem_append nxinxs this,
|
||
nodup_cons this ndxsl₂
|
||
|
||
theorem nodup_app_comm {l₁ l₂ : list α} (d : nodup (l₁++l₂)) : nodup (l₂++l₁) :=
|
||
have d₁ : nodup l₁, from nodup_of_nodup_append_left d,
|
||
have d₂ : nodup l₂, from nodup_of_nodup_append_right d,
|
||
have dsj : disjoint l₁ l₂, from disjoint_of_nodup_append d,
|
||
nodup_append_of_nodup_of_nodup_of_disjoint d₂ d₁ (disjoint.comm dsj)
|
||
|
||
theorem nodup_head {a : α} {l₁ l₂ : list α} (d : nodup (l₁++(a::l₂))) : nodup (a::(l₁++l₂)) :=
|
||
have d₁ : nodup (a::(l₂++l₁)), from nodup_app_comm d,
|
||
have d₂ : nodup (l₂++l₁), from nodup_of_nodup_cons d₁,
|
||
have d₃ : nodup (l₁++l₂), from nodup_app_comm d₂,
|
||
have nain : a ∉ l₂++l₁, from not_mem_of_nodup_cons d₁,
|
||
have nain₂ : a ∉ l₂, from not_mem_of_not_mem_append_left nain,
|
||
have nain₁ : a ∉ l₁, from not_mem_of_not_mem_append_right nain,
|
||
nodup_cons (not_mem_append nain₁ nain₂) d₃
|
||
|
||
theorem nodup_middle {a : α} {l₁ l₂ : list α} (d : nodup (a::(l₁++l₂))) : nodup (l₁++(a::l₂)) :=
|
||
have d₁ : nodup (l₁++l₂), from nodup_of_nodup_cons d,
|
||
have nain : a ∉ l₁++l₂, from not_mem_of_nodup_cons d,
|
||
have disj : disjoint l₁ l₂, from disjoint_of_nodup_append d₁,
|
||
have d₂ : nodup l₁, from nodup_of_nodup_append_left d₁,
|
||
have d₃ : nodup l₂, from nodup_of_nodup_append_right d₁,
|
||
have nain₂ : a ∉ l₂, from not_mem_of_not_mem_append_right nain,
|
||
have nain₁ : a ∉ l₁, from not_mem_of_not_mem_append_left nain,
|
||
have d₄ : nodup (a::l₂), from nodup_cons nain₂ d₃,
|
||
have disj₂ : disjoint l₁ (a::l₂), from disjoint.comm (disjoint_cons_of_not_mem_of_disjoint nain₁
|
||
(disjoint.comm disj)),
|
||
nodup_append_of_nodup_of_nodup_of_disjoint d₂ d₄ disj₂
|
||
|
||
theorem nodup_of_nodup_map (f : α → β) : ∀ {l : list α}, nodup (map f l) → nodup l
|
||
| [] d := ndnil
|
||
| (a::l) d := ndcons (mt (mem_map f) (not_mem_of_nodup_cons d))
|
||
(nodup_of_nodup_map (nodup_of_nodup_cons d))
|
||
|
||
theorem nodup_map {f : α → β} (I : function.injective f) :
|
||
∀ {l : list α}, nodup l → nodup (map f l)
|
||
| [] d := ndnil
|
||
| (b::l) d :=
|
||
have f b ∈ map f l → b ∈ l, from λ h,
|
||
let ⟨a, al, ab⟩ := exists_of_mem_map h in
|
||
match b, I ab with ._, rfl := al end,
|
||
ndcons (mt this (not_mem_of_nodup_cons d))
|
||
(nodup_map (nodup_of_nodup_cons d))
|
||
|
||
instance nodup_decidable [decidable_eq α] : ∀ l : list α, decidable (nodup l)
|
||
| [] := is_true ndnil
|
||
| (a :: l) := if h : a ∈ l
|
||
then is_false (λ nd, not_mem_of_nodup_cons nd h)
|
||
else decidable_of_decidable_of_iff (nodup_decidable l)
|
||
⟨nodup_cons h, nodup_of_nodup_cons⟩
|
||
|
||
end nodup
|
||
|
||
end list
|