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) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Johannes Hölzl Galois connections - order theoretic adjoints. -/ import order.complete_lattice order.bounds order.order_iso open function set lattice universes u v w x variables {α : Type u} {β : Type v} {γ : Type w} {ι : Sort x} {a a₁ a₂ : α} {b b₁ b₂ : β} /-- A Galois connection is a pair of functions `l` and `u` satisfying `l a ≤ b ↔ a ≤ u b`. They are closely connected to adjoint functors in category theory. -/ def galois_connection [preorder α] [preorder β] (l : α → β) (u : β → α) := ∀a b, l a ≤ b ↔ a ≤ u b /-- Makes a Galois connection from an order-preserving bijection. -/ theorem order_iso.to_galois_connection [preorder α] [preorder β] (oi : @order_iso α β (≤) (≤)) : galois_connection oi oi.symm := λ b g, by rw [order_iso.ord' oi, order_iso.apply_symm_apply] namespace galois_connection section variables [preorder α] [preorder β] {l : α → β} {u : β → α} (gc : galois_connection l u) lemma monotone_intro (hu : monotone u) (hl : monotone l) (hul : ∀ a, a ≤ u (l a)) (hlu : ∀ a, l (u a) ≤ a) : galois_connection l u := assume a b, ⟨assume h, le_trans (hul _) (hu h), assume h, le_trans (hl h) (hlu _)⟩ include gc lemma l_le {a : α} {b : β} : a ≤ u b → l a ≤ b := (gc _ _).mpr lemma le_u {a : α} {b : β} : l a ≤ b → a ≤ u b := (gc _ _).mp lemma le_u_l (a) : a ≤ u (l a) := gc.le_u $ le_refl _ lemma l_u_le (a) : l (u a) ≤ a := gc.l_le $ le_refl _ lemma monotone_u : monotone u := assume a b H, gc.le_u (le_trans (gc.l_u_le a) H) lemma monotone_l : monotone l := assume a b H, gc.l_le (le_trans H (gc.le_u_l b)) lemma upper_bounds_l_image_subset {s : set α} : upper_bounds (l '' s) ⊆ u ⁻¹' upper_bounds s := assume b hb c, assume : c ∈ s, gc.le_u (hb (mem_image_of_mem _ ‹c ∈ s›)) lemma lower_bounds_u_image_subset {s : set β} : lower_bounds (u '' s) ⊆ l ⁻¹' lower_bounds s := assume a ha c, assume : c ∈ s, gc.l_le (ha (mem_image_of_mem _ ‹c ∈ s›)) lemma is_lub_l_image {s : set α} {a : α} (h : is_lub s a) : is_lub (l '' s) (l a) := ⟨mem_upper_bounds_image gc.monotone_l $ and.elim_left ‹is_lub s a›, assume b hb, gc.l_le $ and.elim_right ‹is_lub s a› $ gc.upper_bounds_l_image_subset hb⟩ lemma is_glb_u_image {s : set β} {b : β} (h : is_glb s b) : is_glb (u '' s) (u b) := ⟨mem_lower_bounds_image gc.monotone_u $ and.elim_left ‹is_glb s b›, assume a ha, gc.le_u $ and.elim_right ‹is_glb s b› $ gc.lower_bounds_u_image_subset ha⟩ lemma is_glb_l {a : α} : is_glb { b | a ≤ u b } (l a) := ⟨assume b, gc.l_le, assume b h, h $ gc.le_u_l _⟩ lemma is_lub_u {b : β} : is_lub { a | l a ≤ b } (u b) := ⟨assume b, gc.le_u, assume b h, h $ gc.l_u_le _⟩ end section partial_order variables [partial_order α] [partial_order β] {l : α → β} {u : β → α} (gc : galois_connection l u) include gc lemma u_l_u_eq_u : u ∘ l ∘ u = u := funext (assume x, le_antisymm (gc.monotone_u (gc.l_u_le _)) (gc.le_u_l _)) lemma l_u_l_eq_l : l ∘ u ∘ l = l := funext (assume x, le_antisymm (gc.l_u_le _) (gc.monotone_l (gc.le_u_l _))) end partial_order section order_top variables [order_top α] [order_top β] {l : α → β} {u : β → α} (gc : galois_connection l u) include gc lemma u_top : u ⊤ = ⊤ := eq_of_is_glb_of_is_glb (gc.is_glb_u_image is_glb_empty) $ by simp [is_glb_empty, image_empty] end order_top section order_bot variables [order_bot α] [order_bot β] {l : α → β} {u : β → α} (gc : galois_connection l u) include gc lemma l_bot : l ⊥ = ⊥ := eq_of_is_lub_of_is_lub (gc.is_lub_l_image is_lub_empty) $ by simp [is_lub_empty, image_empty] end order_bot section semilattice_sup variables [semilattice_sup α] [semilattice_sup β] {l : α → β} {u : β → α} (gc : galois_connection l u) include gc lemma l_sup : l (a₁ ⊔ a₂) = l a₁ ⊔ l a₂ := have {l a₂, l a₁} = l '' {a₂, a₁}, by simp [image_insert_eq, image_singleton], eq.symm $ is_lub_iff_sup_eq.mp $ by rw [this]; exact gc.is_lub_l_image (is_lub_insert_sup is_lub_singleton) end semilattice_sup section semilattice_inf variables [semilattice_inf α] [semilattice_inf β] {l : α → β} {u : β → α} (gc : galois_connection l u) include gc lemma u_inf : u (b₁ ⊓ b₂) = u b₁ ⊓ u b₂ := have {u b₂, u b₁} = u '' {b₂, b₁}, by simp [image_insert_eq, image_singleton], eq.symm $ is_glb_iff_inf_eq.mp $ by rw [this]; exact gc.is_glb_u_image (is_glb_insert_inf is_glb_singleton) end semilattice_inf section complete_lattice variables [complete_lattice α] [complete_lattice β] {l : α → β} {u : β → α} (gc : galois_connection l u) include gc lemma l_supr {f : ι → α} : l (supr f) = (⨆i, l (f i)) := eq.symm $ is_lub_iff_supr_eq.mp $ show is_lub (range (l ∘ f)) (l (supr f)), by rw [range_comp, ← Sup_range]; exact gc.is_lub_l_image is_lub_Sup lemma u_infi {f : ι → β} : u (infi f) = (⨅i, u (f i)) := eq.symm $ is_glb_iff_infi_eq.mp $ show is_glb (range (u ∘ f)) (u (infi f)), by rw [range_comp, ← Inf_range]; exact gc.is_glb_u_image is_glb_Inf end complete_lattice section complete_lattice variables [complete_lattice α] [complete_lattice β] {l : α → β} {u : β → α} (gc : galois_connection l u) include gc lemma l_Sup {s : set α} : l (Sup s) = (⨆a∈s, l a) := by simp [Sup_eq_supr, gc.l_supr] lemma u_Inf {s : set β} : u (Inf s) = (⨅a∈s, u a) := by simp [Inf_eq_infi, gc.u_infi] end complete_lattice /- Constructing Galois connections -/ section constructions protected lemma id [pα : preorder α] : @galois_connection α α pα pα id id := assume a b, iff.intro (λx, x) (λx, x) protected lemma compose [preorder α] [preorder β] [preorder γ] (l1 : α → β) (u1 : β → α) (l2 : β → γ) (u2 : γ → β) (gc1 : galois_connection l1 u1) (gc2 : galois_connection l2 u2) : galois_connection (l2 ∘ l1) (u1 ∘ u2) := by intros a b; rw [gc2, gc1] protected lemma dual [pα : preorder α] [pβ : preorder β] {l : α → β} {u : β → α} (gc : galois_connection l u) : @galois_connection (order_dual β) (order_dual α) _ _ u l := assume a b, (gc _ _).symm protected lemma dfun {ι : Type u} {α : ι → Type v} {β : ι → Type w} [∀i, preorder (α i)] [∀i, preorder (β i)] (l : Πi, α i → β i) (u : Πi, β i → α i) (gc : ∀i, galois_connection (l i) (u i)) : @galois_connection (Π i, α i) (Π i, β i) _ _ (λa i, l i (a i)) (λb i, u i (b i)) := assume a b, forall_congr $ assume i, gc i (a i) (b i) end constructions end galois_connection namespace nat lemma galois_connection_mul_div {k : ℕ} (h : k > 0) : galois_connection (λn, n * k) (λn, n / k) := assume x y, (le_div_iff_mul_le x y h).symm end nat /-- A Galois insertion is a Galois connection where `l ∘ u = id`. It also contains a constructive choice function, to give better definitional equalities when lifting order structures. -/ structure galois_insertion {α β : Type*} [preorder α] [preorder β] (l : α → β) (u : β → α) := (choice : Πx:α, u (l x) ≤ x → β) (gc : galois_connection l u) (le_l_u : ∀x, x ≤ l (u x)) (choice_eq : ∀a h, choice a h = l a) /-- A constructor for a Galois insertion with the trivial `choice` function. -/ def galois_insertion.monotone_intro {α β : Type*} [preorder α] [preorder β] {l : α → β} {u : β → α} (hu : monotone u) (hl : monotone l) (hul : ∀ a, a ≤ u (l a)) (hlu : ∀ b, l (u b) = b) : galois_insertion l u := { choice := λ x _, l x, gc := galois_connection.monotone_intro hu hl hul (λ b, le_of_eq (hlu b)), le_l_u := λ b, le_of_eq $ (hlu b).symm, choice_eq := λ _ _, rfl } /-- Makes a Galois insertion from an order-preserving bijection. -/ protected def order_iso.to_galois_insertion [preorder α] [preorder β] (oi : @order_iso α β (≤) (≤)) : @galois_insertion α β _ _ (oi) (oi.symm) := { choice := λ b h, oi b, gc := oi.to_galois_connection, le_l_u := λ g, le_of_eq (oi.right_inv g).symm, choice_eq := λ b h, rfl } /-- Lift the bottom along a Galois connection -/ def galois_connection.lift_order_bot {α β : Type*} [order_bot α] [partial_order β] {l : α → β} {u : β → α} (gc : galois_connection l u) : order_bot β := { bot := l ⊥, bot_le := assume b, gc.l_le $ bot_le, .. ‹partial_order β› } namespace galois_insertion open lattice variables [partial_order β] {l : α → β} {u : β → α} lemma l_u_eq [preorder α] (gi : galois_insertion l u) (b : β) : l (u b) = b := le_antisymm (gi.gc.l_u_le _) (gi.le_l_u _) /-- Lift the suprema along a Galois insertion -/ def lift_semilattice_sup [semilattice_sup α] (gi : galois_insertion l u) : semilattice_sup β := { sup := λa b, l (u a ⊔ u b), le_sup_left := assume a b, le_trans (gi.le_l_u a) $ gi.gc.monotone_l $ le_sup_left, le_sup_right := assume a b, le_trans (gi.le_l_u b) $ gi.gc.monotone_l $ le_sup_right, sup_le := assume a b c hac hbc, gi.gc.l_le $ sup_le (gi.gc.monotone_u hac) (gi.gc.monotone_u hbc), .. ‹partial_order β› } /-- Lift the infima along a Galois insertion -/ def lift_semilattice_inf [semilattice_inf α] (gi : galois_insertion l u) : semilattice_inf β := { inf := λa b, gi.choice (u a ⊓ u b) $ (le_inf (gi.gc.monotone_u $ gi.gc.l_le $ inf_le_left) (gi.gc.monotone_u $ gi.gc.l_le $ inf_le_right)), inf_le_left := by simp only [gi.choice_eq]; exact assume a b, gi.gc.l_le inf_le_left, inf_le_right := by simp only [gi.choice_eq]; exact assume a b, gi.gc.l_le inf_le_right, le_inf := by simp only [gi.choice_eq]; exact assume a b c hac hbc, le_trans (gi.le_l_u a) $ gi.gc.monotone_l $ le_inf (gi.gc.monotone_u hac) (gi.gc.monotone_u hbc), .. ‹partial_order β› } /-- Lift the suprema and infima along a Galois insertion -/ def lift_lattice [lattice α] (gi : galois_insertion l u) : lattice β := { .. gi.lift_semilattice_sup, .. gi.lift_semilattice_inf } /-- Lift the top along a Galois insertion -/ def lift_order_top [order_top α] (gi : galois_insertion l u) : order_top β := { top := gi.choice ⊤ $ le_top, le_top := by simp only [gi.choice_eq]; exact assume b, le_trans (gi.le_l_u b) (gi.gc.monotone_l le_top), .. ‹partial_order β› } /-- Lift the top, bottom, suprema, and infima along a Galois insertion -/ def lift_bounded_lattice [bounded_lattice α] (gi : galois_insertion l u) : bounded_lattice β := { .. gi.lift_lattice, .. gi.lift_order_top, .. gi.gc.lift_order_bot } /-- Lift all suprema and infima along a Galois insertion -/ def lift_complete_lattice [complete_lattice α] (gi : galois_insertion l u) : complete_lattice β := { Sup := λs, l (⨆ b∈s, u b), Sup_le := assume s a hs, gi.gc.l_le $ supr_le $ assume b, supr_le $ assume hb, gi.gc.monotone_u $ hs _ hb, le_Sup := assume s a ha, le_trans (gi.le_l_u a) $ gi.gc.monotone_l $ le_supr_of_le a $ le_supr_of_le ha $ le_refl _, Inf := λs, gi.choice (⨅ b∈s, u b) $ le_infi $ assume b, le_infi $ assume hb, gi.gc.monotone_u $ gi.gc.l_le $ infi_le_of_le b $ infi_le_of_le hb $ le_refl _, Inf_le := by simp only [gi.choice_eq]; exact assume s a ha, gi.gc.l_le $ infi_le_of_le a $ infi_le_of_le ha $ le_refl _, le_Inf := by simp only [gi.choice_eq]; exact assume s a hs, le_trans (gi.le_l_u a) $ gi.gc.monotone_l $ le_infi $ assume b, show u a ≤ ⨅ (H : b ∈ s), u b, from le_infi $ assume hb, gi.gc.monotone_u $ hs _ hb, .. gi.lift_bounded_lattice } end galois_insertion