Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
Try doing some basic maths questions in the Lean Theorem Prover. Functions, real numbers, equivalence relations and groups. Click on README.md and then on "Open in CoCalc with one click".
Project: Xena
Views: 18536License: APACHE
/- Copyright (c) 2019 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ import data.equiv.basic data.set.lattice tactic.tauto universes u v w x /-- A `pequiv` is a partial equivalence, a representation of a bijection between a subset of `α` and a subset of `β` -/ structure pequiv (α : Type u) (β : Type v) := (to_fun : α → option β) (inv_fun : β → option α) (inv : ∀ (a : α) (b : β), a ∈ inv_fun b ↔ b ∈ to_fun a) infixr ` ≃. `:25 := pequiv namespace pequiv variables {α : Type u} {β : Type v} {γ : Type w} {δ : Type x} open function option instance : has_coe_to_fun (α ≃. β) := ⟨_, to_fun⟩ @[simp] lemma coe_mk_apply (f₁ : α → option β) (f₂ : β → option α) (h) (x : α) : (pequiv.mk f₁ f₂ h : α → option β) x = f₁ x := rfl @[ext] lemma ext : ∀ {f g : α ≃. β} (h : ∀ x, f x = g x), f = g | ⟨f₁, f₂, hf⟩ ⟨g₁, g₂, hg⟩ h := have h : f₁ = g₁, from funext h, have ∀ b, f₂ b = g₂ b, begin subst h, assume b, have hf := λ a, hf a b, have hg := λ a, hg a b, cases h : g₂ b with a, { simp only [h, option.not_mem_none, false_iff] at hg, simp only [hg, iff_false] at hf, rwa [option.eq_none_iff_forall_not_mem] }, { rw [← option.mem_def, hf, ← hg, h, option.mem_def] } end, by simp [*, funext_iff] lemma ext_iff {f g : α ≃. β} : f = g ↔ ∀ x, f x = g x := ⟨congr_fun ∘ congr_arg _, ext⟩ @[refl] protected def refl (α : Type*) : α ≃. α := { to_fun := some, inv_fun := some, inv := λ _ _, eq_comm } @[symm] protected def symm (f : α ≃. β) : β ≃. α := { to_fun := f.2, inv_fun := f.1, inv := λ _ _, (f.inv _ _).symm } lemma mem_iff_mem (f : α ≃. β) : ∀ {a : α} {b : β}, a ∈ f.symm b ↔ b ∈ f a := f.3 lemma eq_some_iff (f : α ≃. β) : ∀ {a : α} {b : β}, f.symm b = some a ↔ f a = some b := f.3 @[trans] protected def trans (f : α ≃. β) (g : β ≃. γ) : pequiv α γ := { to_fun := λ a, (f a).bind g, inv_fun := λ a, (g.symm a).bind f.symm, inv := λ a b, by simp [*, and.comm, eq_some_iff f, eq_some_iff g] at * } @[simp] lemma refl_apply (a : α) : pequiv.refl α a = some a := rfl @[simp] lemma symm_refl : (pequiv.refl α).symm = pequiv.refl α := rfl @[simp] lemma symm_refl_apply (a : α) : (pequiv.refl α).symm a = some a := rfl @[simp] lemma symm_symm (f : α ≃. β) : f.symm.symm = f := by cases f; refl @[simp] lemma symm_symm_apply (f : α ≃. β) (a : α) : f.symm.symm a = f a := by rw symm_symm lemma symm_injective : function.injective (@pequiv.symm α β) := injective_of_has_left_inverse ⟨_, symm_symm⟩ lemma trans_assoc (f : α ≃. β) (g : β ≃. γ) (h : γ ≃. δ) : (f.trans g).trans h = f.trans (g.trans h) := ext (λ _, option.bind_assoc _ _ _) lemma mem_trans (f : α ≃. β) (g : β ≃. γ) (a : α) (c : γ) : c ∈ f.trans g a ↔ ∃ b, b ∈ f a ∧ c ∈ g b := option.bind_eq_some' lemma trans_eq_some (f : α ≃. β) (g : β ≃. γ) (a : α) (c : γ) : f.trans g a = some c ↔ ∃ b, f a = some b ∧ g b = some c := option.bind_eq_some' lemma trans_eq_none (f : α ≃. β) (g : β ≃. γ) (a : α) : f.trans g a = none ↔ (∀ b c, b ∉ f a ∨ c ∉ g b) := by simp only [eq_none_iff_forall_not_mem, mem_trans]; push_neg; tauto @[simp] lemma refl_trans (f : α ≃. β) : (pequiv.refl α).trans f = f := by ext; dsimp [pequiv.trans]; refl @[simp] lemma trans_refl (f : α ≃. β) : f.trans (pequiv.refl β) = f := by ext; dsimp [pequiv.trans]; simp @[simp] lemma refl_trans_apply (f : α ≃. β) (a : α) : (pequiv.refl α).trans f a = f a := by rw refl_trans @[simp] lemma trans_refl_apply (f : α ≃. β) (a : α) : f.trans (pequiv.refl β) a = f a := by rw trans_refl protected lemma inj (f : α ≃. β) {a₁ a₂ : α} {b : β} (h₁ : b ∈ f a₁) (h₂ : b ∈ f a₂) : a₁ = a₂ := by rw ← mem_iff_mem at *; cases h : f.symm b; simp * at * lemma injective_of_forall_ne_is_some (f : α ≃. β) (a₂ : α) (h : ∀ (a₁ : α), a₁ ≠ a₂ → is_some (f a₁)) : injective f := injective_of_has_left_inverse ⟨λ b, option.rec_on b a₂ (λ b', option.rec_on (f.symm b') a₂ id), λ x, begin classical, cases hfx : f x, { have : x = a₂, from not_imp_comm.1 (h x) (hfx.symm ▸ by simp), simp [this] }, { simp only [hfx], rw [(eq_some_iff f).2 hfx], refl } end⟩ lemma injective_of_forall_is_some {f : α ≃. β} (h : ∀ (a : α), is_some (f a)) : injective f := (classical.em (nonempty α)).elim (λ hn, injective_of_forall_ne_is_some f (classical.choice hn) (λ a _, h a)) (λ hn x, (hn ⟨x⟩).elim) section of_set variables (s : set α) [decidable_pred s] def of_set (s : set α) [decidable_pred s] : α ≃. α := { to_fun := λ a, if a ∈ s then some a else none, inv_fun := λ a, if a ∈ s then some a else none, inv := λ a b, by split_ifs; finish [eq_comm] } lemma mem_of_set_self_iff {s : set α} [decidable_pred s] {a : α} : a ∈ of_set s a ↔ a ∈ s := by dsimp [of_set]; split_ifs; simp * lemma mem_of_set_iff {s : set α} [decidable_pred s] {a b : α} : a ∈ of_set s b ↔ a = b ∧ a ∈ s := by dsimp [of_set]; split_ifs; split; finish @[simp] lemma of_set_eq_some_self_iff {s : set α} {h : decidable_pred s} {a : α} : of_set s a = some a ↔ a ∈ s := mem_of_set_self_iff @[simp] lemma of_set_eq_some_iff {s : set α} {h : decidable_pred s} {a b : α} : of_set s b = some a ↔ a = b ∧ a ∈ s := mem_of_set_iff @[simp] lemma of_set_symm : (of_set s).symm = of_set s := rfl @[simp] lemma of_set_univ : of_set set.univ = pequiv.refl α := by ext; dsimp [of_set]; simp [eq_comm] @[simp] lemma of_set_eq_refl {s : set α} [decidable_pred s] : of_set s = pequiv.refl α ↔ s = set.univ := ⟨λ h, begin rw [set.eq_univ_iff_forall], intro, rw [← mem_of_set_self_iff, h], exact rfl end, λ h, by simp only [of_set_univ.symm, h]; congr⟩ end of_set lemma symm_trans_rev (f : α ≃. β) (g : β ≃. γ) : (f.trans g).symm = g.symm.trans f.symm := rfl lemma trans_symm (f : α ≃. β) : f.trans f.symm = of_set {a | (f a).is_some} := begin ext, dsimp [pequiv.trans], simp only [eq_some_iff f, option.is_some_iff_exists, option.mem_def, bind_eq_some', of_set_eq_some_iff], split, { rintros ⟨b, hb₁, hb₂⟩, exact ⟨pequiv.inj _ hb₂ hb₁, b, hb₂⟩ }, { simp {contextual := tt} } end lemma symm_trans (f : α ≃. β) : f.symm.trans f = of_set {b | (f.symm b).is_some} := symm_injective $ by simp [symm_trans_rev, trans_symm, -symm_symm] lemma trans_symm_eq_iff_forall_is_some {f : α ≃. β} : f.trans f.symm = pequiv.refl α ↔ ∀ a, is_some (f a) := by rw [trans_symm, of_set_eq_refl, set.eq_univ_iff_forall]; refl instance : lattice.has_bot (α ≃. β) := ⟨{ to_fun := λ _, none, inv_fun := λ _, none, inv := by simp }⟩ @[simp] lemma bot_apply (a : α) : (⊥ : α ≃. β) a = none := rfl @[simp] lemma symm_bot : (⊥ : α ≃. β).symm = ⊥ := rfl @[simp] lemma trans_bot (f : α ≃. β) : f.trans (⊥ : β ≃. γ) = ⊥ := by ext; dsimp [pequiv.trans]; simp @[simp] lemma bot_trans (f : β ≃. γ) : (⊥ : α ≃. β).trans f = ⊥ := by ext; dsimp [pequiv.trans]; simp lemma is_some_symm_get (f : α ≃. β) {a : α} (h : is_some (f a)) : is_some (f.symm (option.get h)) := is_some_iff_exists.2 ⟨a, by rw [f.eq_some_iff, some_get]⟩ section single variables [decidable_eq α] [decidable_eq β] [decidable_eq γ] def single (a : α) (b : β) : α ≃. β := { to_fun := λ x, if x = a then some b else none, inv_fun := λ x, if x = b then some a else none, inv := λ _ _, by simp; split_ifs; cc } lemma mem_single (a : α) (b : β) : b ∈ single a b a := if_pos rfl lemma mem_single_iff (a₁ a₂ : α) (b₁ b₂ : β) : b₁ ∈ single a₂ b₂ a₁ ↔ a₁ = a₂ ∧ b₁ = b₂ := by dsimp [single]; split_ifs; simp [*, eq_comm] @[simp] lemma symm_single (a : α) (b : β) : (single a b).symm = single b a := rfl @[simp] lemma single_apply (a : α) (b : β) : single a b a = some b := if_pos rfl @[simp] lemma symm_single_apply (a : α) (b : β) : (single a b).symm b = some a := by dsimp; simp lemma single_apply_of_ne {a₁ a₂ : α} (h : a₁ ≠ a₂) (b : β) : single a₁ b a₂ = none := if_neg h.symm lemma single_trans_of_mem (a : α) {b : β} {c : γ} {f : β ≃. γ} (h : c ∈ f b) : (single a b).trans f = single a c := begin ext, dsimp [single, pequiv.trans], split_ifs; simp * at * end lemma trans_single_of_mem {a : α} {b : β} (c : γ) {f : α ≃. β} (h : b ∈ f a) : f.trans (single b c) = single a c := symm_injective $ single_trans_of_mem _ ((mem_iff_mem f).2 h) @[simp] lemma single_trans_single (a : α) (b : β) (c : γ) : (single a b).trans (single b c) = single a c := single_trans_of_mem _ (mem_single _ _) @[simp] lemma single_subsingleton_eq_refl [subsingleton α] (a b : α) : single a b = pequiv.refl α := begin ext i j, dsimp [single], rw [if_pos (subsingleton.elim i a), subsingleton.elim i j, subsingleton.elim b j] end lemma trans_single_of_eq_none {b : β} (c : γ) {f : α ≃. β} (h : f.symm b = none) : f.trans (single b c) = ⊥ := begin ext, simp only [eq_none_iff_forall_not_mem, option.mem_def, f.eq_some_iff] at h, dsimp [pequiv.trans, single], simp, intros, split_ifs; simp * at * end lemma single_trans_of_eq_none (a : α) {b : β} {f : β ≃. γ} (h : f b = none) : (single a b).trans f = ⊥ := symm_injective $ trans_single_of_eq_none _ h lemma single_trans_single_of_ne {b₁ b₂ : β} (h : b₁ ≠ b₂) (a : α) (c : γ) : (single a b₁).trans (single b₂ c) = ⊥ := single_trans_of_eq_none _ (single_apply_of_ne h.symm _) end single section order open lattice instance : partial_order (α ≃. β) := { le := λ f g, ∀ (a : α) (b : β), b ∈ f a → b ∈ g a, le_refl := λ _ _ _, id, le_trans := λ f g h fg gh a b, (gh a b) ∘ (fg a b), le_antisymm := λ f g fg gf, ext begin assume a, cases h : g a with b, { exact eq_none_iff_forall_not_mem.2 (λ b hb, option.not_mem_none b $ h ▸ fg a b hb) }, { exact gf _ _ h } end } lemma le_def {f g : α ≃. β} : f ≤ g ↔ (∀ (a : α) (b : β), b ∈ f a → b ∈ g a) := iff.rfl instance : order_bot (α ≃. β) := { bot_le := λ _ _ _ h, (not_mem_none _ h).elim, ..pequiv.partial_order, ..pequiv.lattice.has_bot } instance [decidable_eq α] [decidable_eq β] : semilattice_inf_bot (α ≃. β) := { inf := λ f g, { to_fun := λ a, if f a = g a then f a else none, inv_fun := λ b, if f.symm b = g.symm b then f.symm b else none, inv := λ a b, begin have := @mem_iff_mem _ _ f a b, have := @mem_iff_mem _ _ g a b, split_ifs; finish end }, inf_le_left := λ _ _ _ _, by simp; split_ifs; cc, inf_le_right := λ _ _ _ _, by simp; split_ifs; cc, le_inf := λ f g h fg gh a b, begin have := fg a b, have := gh a b, simp [le_def], split_ifs; finish end, ..pequiv.lattice.order_bot } end order end pequiv namespace equiv variables {α : Type*} {β : Type*} {γ : Type*} def to_pequiv (f : α ≃ β) : α ≃. β := { to_fun := some ∘ f, inv_fun := some ∘ f.symm, inv := by simp [equiv.eq_symm_apply, eq_comm] } @[simp] lemma to_pequiv_refl : (equiv.refl α).to_pequiv = pequiv.refl α := rfl lemma to_pequiv_trans (f : α ≃ β) (g : β ≃ γ) : (f.trans g).to_pequiv = f.to_pequiv.trans g.to_pequiv := rfl lemma to_pequiv_symm (f : α ≃ β) : f.symm.to_pequiv = f.to_pequiv.symm := rfl lemma to_pequiv_apply (f : α ≃ β) (x : α) : f.to_pequiv x = some (f x) := rfl end equiv