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. Authors: Johannes Hölzl Defines the inf/sup (semi)-lattice with optionally top/bot type class hierarchy. -/ import order.basic set_option old_structure_cmd true universes u v w -- TODO: move this eventually, if we decide to use them attribute [ematch] le_trans lt_of_le_of_lt lt_of_lt_of_le lt_trans section variable {α : Type u} -- TODO: this seems crazy, but it also seems to work reasonably well @[ematch] theorem le_antisymm' [partial_order α] : ∀ {a b : α}, (: a ≤ b :) → b ≤ a → a = b := @le_antisymm _ _ end /- TODO: automatic construction of dual definitions / theorems -/ namespace lattice reserve infixl ` ⊓ `:70 reserve infixl ` ⊔ `:65 /-- Typeclass for the `⊔` (`\lub`) notation -/ class has_sup (α : Type u) := (sup : α → α → α) /-- Typeclass for the `⊓` (`\glb`) notation -/ class has_inf (α : Type u) := (inf : α → α → α) infix ⊔ := has_sup.sup infix ⊓ := has_inf.inf section prio set_option default_priority 100 -- see Note [default priority] /-- A `semilattice_sup` is a join-semilattice, that is, a partial order with a join (a.k.a. lub / least upper bound, sup / supremum) operation `⊔` which is the least element larger than both factors. -/ class semilattice_sup (α : Type u) extends has_sup α, partial_order α := (le_sup_left : ∀ a b : α, a ≤ a ⊔ b) (le_sup_right : ∀ a b : α, b ≤ a ⊔ b) (sup_le : ∀ a b c : α, a ≤ c → b ≤ c → a ⊔ b ≤ c) end prio section semilattice_sup variables {α : Type u} [semilattice_sup α] {a b c d : α} @[simp] theorem le_sup_left : a ≤ a ⊔ b := semilattice_sup.le_sup_left a b @[ematch] theorem le_sup_left' : a ≤ (: a ⊔ b :) := semilattice_sup.le_sup_left a b @[simp] theorem le_sup_right : b ≤ a ⊔ b := semilattice_sup.le_sup_right a b @[ematch] theorem le_sup_right' : b ≤ (: a ⊔ b :) := semilattice_sup.le_sup_right a b theorem le_sup_left_of_le (h : c ≤ a) : c ≤ a ⊔ b := by finish theorem le_sup_right_of_le (h : c ≤ b) : c ≤ a ⊔ b := by finish theorem sup_le : a ≤ c → b ≤ c → a ⊔ b ≤ c := semilattice_sup.sup_le a b c @[simp] theorem sup_le_iff : a ⊔ b ≤ c ↔ a ≤ c ∧ b ≤ c := ⟨assume h : a ⊔ b ≤ c, ⟨le_trans le_sup_left h, le_trans le_sup_right h⟩, assume ⟨h₁, h₂⟩, sup_le h₁ h₂⟩ -- TODO: if we just write le_antisymm, Lean doesn't know which ≤ we want to use -- Can we do anything about that? theorem sup_of_le_left (h : b ≤ a) : a ⊔ b = a := by apply le_antisymm; finish theorem sup_of_le_right (h : a ≤ b) : a ⊔ b = b := by apply le_antisymm; finish theorem sup_le_sup (h₁ : a ≤ b) (h₂ : c ≤ d) : a ⊔ c ≤ b ⊔ d := by finish theorem sup_le_sup_left (h₁ : a ≤ b) (c) : c ⊔ a ≤ c ⊔ b := by finish theorem sup_le_sup_right (h₁ : a ≤ b) (c) : a ⊔ c ≤ b ⊔ c := by finish theorem le_of_sup_eq (h : a ⊔ b = b) : a ≤ b := by finish /-- A monotone function on a sup-semilattice is directed. -/ lemma directed_of_mono {β} (f : α → β) {r : β → β → Prop} (H : ∀ ⦃i j⦄, i ≤ j → r (f i) (f j)) : directed r f := λ a b, ⟨a ⊔ b, H le_sup_left, H le_sup_right⟩ @[simp] lemma sup_lt_iff [is_total α (≤)] {a b c : α} : b ⊔ c < a ↔ b < a ∧ c < a := begin cases (is_total.total (≤) b c) with h, { simp [sup_of_le_right h], exact ⟨λI, ⟨lt_of_le_of_lt h I, I⟩, λH, H.2⟩ }, { simp [sup_of_le_left h], exact ⟨λI, ⟨I, lt_of_le_of_lt h I⟩, λH, H.1⟩ } end @[simp] theorem sup_idem : a ⊔ a = a := by apply le_antisymm; finish instance sup_is_idempotent : is_idempotent α (⊔) := ⟨@sup_idem _ _⟩ theorem sup_comm : a ⊔ b = b ⊔ a := by apply le_antisymm; finish instance sup_is_commutative : is_commutative α (⊔) := ⟨@sup_comm _ _⟩ theorem sup_assoc : a ⊔ b ⊔ c = a ⊔ (b ⊔ c) := by apply le_antisymm; finish instance sup_is_associative : is_associative α (⊔) := ⟨@sup_assoc _ _⟩ lemma sup_left_comm (a b c : α) : a ⊔ (b ⊔ c) = b ⊔ (a ⊔ c) := by rw [← sup_assoc, ← sup_assoc, @sup_comm α _ a] lemma forall_le_or_exists_lt_sup (a : α) : (∀b, b ≤ a) ∨ (∃b, a < b) := suffices (∃b, ¬b ≤ a) → (∃b, a < b), by rwa [classical.or_iff_not_imp_left, classical.not_forall], assume ⟨b, hb⟩, have a ≠ a ⊔ b, from assume eq, hb $ eq.symm ▸ le_sup_right, ⟨a ⊔ b, lt_of_le_of_ne le_sup_left ‹a ≠ a ⊔ b›⟩ theorem semilattice_sup.ext_sup {α} {A B : semilattice_sup α} (H : ∀ x y : α, (by haveI := A; exact x ≤ y) ↔ x ≤ y) (x y : α) : (by haveI := A; exact (x ⊔ y)) = x ⊔ y := eq_of_forall_ge_iff $ λ c, by simp only [sup_le_iff]; rw [← H, @sup_le_iff α A, H, H] theorem semilattice_sup.ext {α} {A B : semilattice_sup α} (H : ∀ x y : α, (by haveI := A; exact x ≤ y) ↔ x ≤ y) : A = B := begin haveI this := partial_order.ext H, have ss := funext (λ x, funext $ semilattice_sup.ext_sup H x), cases A; cases B; injection this; congr' end lemma directed_of_sup {β : Type*} {r : β → β → Prop} {f : α → β} (hf : ∀a₁ a₂, a₁ ≤ a₂ → r (f a₁) (f a₂)) : directed r f := assume x y, ⟨x ⊔ y, hf _ _ le_sup_left, hf _ _ le_sup_right⟩ end semilattice_sup section prio set_option default_priority 100 -- see Note [default priority] /-- A `semilattice_inf` is a meet-semilattice, that is, a partial order with a meet (a.k.a. glb / greatest lower bound, inf / infimum) operation `⊓` which is the greatest element smaller than both factors. -/ class semilattice_inf (α : Type u) extends has_inf α, partial_order α := (inf_le_left : ∀ a b : α, a ⊓ b ≤ a) (inf_le_right : ∀ a b : α, a ⊓ b ≤ b) (le_inf : ∀ a b c : α, a ≤ b → a ≤ c → a ≤ b ⊓ c) end prio section semilattice_inf variables {α : Type u} [semilattice_inf α] {a b c d : α} @[simp] theorem inf_le_left : a ⊓ b ≤ a := semilattice_inf.inf_le_left a b @[ematch] theorem inf_le_left' : (: a ⊓ b :) ≤ a := semilattice_inf.inf_le_left a b @[simp] theorem inf_le_right : a ⊓ b ≤ b := semilattice_inf.inf_le_right a b @[ematch] theorem inf_le_right' : (: a ⊓ b :) ≤ b := semilattice_inf.inf_le_right a b theorem le_inf : a ≤ b → a ≤ c → a ≤ b ⊓ c := semilattice_inf.le_inf a b c theorem inf_le_left_of_le (h : a ≤ c) : a ⊓ b ≤ c := le_trans inf_le_left h theorem inf_le_right_of_le (h : b ≤ c) : a ⊓ b ≤ c := le_trans inf_le_right h @[simp] theorem le_inf_iff : a ≤ b ⊓ c ↔ a ≤ b ∧ a ≤ c := ⟨assume h : a ≤ b ⊓ c, ⟨le_trans h inf_le_left, le_trans h inf_le_right⟩, assume ⟨h₁, h₂⟩, le_inf h₁ h₂⟩ theorem inf_of_le_left (h : a ≤ b) : a ⊓ b = a := by apply le_antisymm; finish theorem inf_of_le_right (h : b ≤ a) : a ⊓ b = b := by apply le_antisymm; finish theorem inf_le_inf (h₁ : a ≤ b) (h₂ : c ≤ d) : a ⊓ c ≤ b ⊓ d := by finish theorem le_of_inf_eq (h : a ⊓ b = a) : a ≤ b := by finish /-- An antimonotone function on a sup-semilattice is directed. -/ lemma directed_of_antimono {β} (f : α → β) {r : β → β → Prop} (H : ∀ ⦃i j⦄, i ≤ j → r (f j) (f i)) : directed r f := λ a b, ⟨a ⊓ b, H inf_le_left, H inf_le_right⟩ @[simp] lemma lt_inf_iff [is_total α (≤)] {a b c : α} : a < b ⊓ c ↔ a < b ∧ a < c := begin cases (is_total.total (≤) b c) with h, { simp [inf_of_le_left h], exact ⟨λI, ⟨I, lt_of_lt_of_le I h⟩, λH, H.1⟩ }, { simp [inf_of_le_right h], exact ⟨λI, ⟨lt_of_lt_of_le I h, I⟩, λH, H.2⟩ } end @[simp] theorem inf_idem : a ⊓ a = a := by apply le_antisymm; finish instance inf_is_idempotent : is_idempotent α (⊓) := ⟨@inf_idem _ _⟩ theorem inf_comm : a ⊓ b = b ⊓ a := by apply le_antisymm; finish instance inf_is_commutative : is_commutative α (⊓) := ⟨@inf_comm _ _⟩ theorem inf_assoc : a ⊓ b ⊓ c = a ⊓ (b ⊓ c) := by apply le_antisymm; finish instance inf_is_associative : is_associative α (⊓) := ⟨@inf_assoc _ _⟩ lemma inf_left_comm (a b c : α) : a ⊓ (b ⊓ c) = b ⊓ (a ⊓ c) := by rw [← inf_assoc, ← inf_assoc, @inf_comm α _ a] lemma forall_le_or_exists_lt_inf (a : α) : (∀b, a ≤ b) ∨ (∃b, b < a) := suffices (∃b, ¬a ≤ b) → (∃b, b < a), by rwa [classical.or_iff_not_imp_left, classical.not_forall], assume ⟨b, hb⟩, have a ⊓ b ≠ a, from assume eq, hb $ eq ▸ inf_le_right, ⟨a ⊓ b, lt_of_le_of_ne inf_le_left ‹a ⊓ b ≠ a›⟩ theorem semilattice_inf.ext_inf {α} {A B : semilattice_inf α} (H : ∀ x y : α, (by haveI := A; exact x ≤ y) ↔ x ≤ y) (x y : α) : (by haveI := A; exact (x ⊓ y)) = x ⊓ y := eq_of_forall_le_iff $ λ c, by simp only [le_inf_iff]; rw [← H, @le_inf_iff α A, H, H] theorem semilattice_inf.ext {α} {A B : semilattice_inf α} (H : ∀ x y : α, (by haveI := A; exact x ≤ y) ↔ x ≤ y) : A = B := begin haveI this := partial_order.ext H, have ss := funext (λ x, funext $ semilattice_inf.ext_inf H x), cases A; cases B; injection this; congr' end lemma directed_of_inf {β : Type*} {r : β → β → Prop} {f : α → β} (hf : ∀a₁ a₂, a₁ ≤ a₂ → r (f a₂) (f a₁)) : directed r f := assume x y, ⟨x ⊓ y, hf _ _ inf_le_left, hf _ _ inf_le_right⟩ end semilattice_inf /- Lattices -/ section prio set_option default_priority 100 -- see Note [default priority] /-- A lattice is a join-semilattice which is also a meet-semilattice. -/ -- TODO(lint): Fix double namespace issue @[nolint] class lattice (α : Type u) extends semilattice_sup α, semilattice_inf α end prio section lattice variables {α : Type u} [lattice α] {a b c d : α} /- Distributivity laws -/ /- TODO: better names? -/ theorem sup_inf_le : a ⊔ (b ⊓ c) ≤ (a ⊔ b) ⊓ (a ⊔ c) := by finish theorem le_inf_sup : (a ⊓ b) ⊔ (a ⊓ c) ≤ a ⊓ (b ⊔ c) := by finish theorem inf_sup_self : a ⊓ (a ⊔ b) = a := le_antisymm (by finish) (by finish) theorem sup_inf_self : a ⊔ (a ⊓ b) = a := le_antisymm (by finish) (by finish) theorem ext {α} {A B : lattice α} (H : ∀ x y : α, (by haveI := A; exact x ≤ y) ↔ x ≤ y) : A = B := begin have SS : @lattice.to_semilattice_sup α A = @lattice.to_semilattice_sup α B := semilattice_sup.ext H, have II := semilattice_inf.ext H, resetI, cases A; cases B; injection SS; injection II; congr' end end lattice variables {α : Type u} {x y z w : α} section prio set_option default_priority 100 -- see Note [default priority] /-- A distributive lattice is a lattice that satisfies any of four equivalent distribution properties (of sup over inf or inf over sup, on the left or right). A classic example of a distributive lattice is the lattice of subsets of a set, and in fact this example is generic in the sense that every distributive lattice is realizable as a sublattice of a powerset lattice. -/ class distrib_lattice α extends lattice α := (le_sup_inf : ∀x y z : α, (x ⊔ y) ⊓ (x ⊔ z) ≤ x ⊔ (y ⊓ z)) end prio section distrib_lattice variables [distrib_lattice α] theorem le_sup_inf : ∀{x y z : α}, (x ⊔ y) ⊓ (x ⊔ z) ≤ x ⊔ (y ⊓ z) := distrib_lattice.le_sup_inf theorem sup_inf_left : x ⊔ (y ⊓ z) = (x ⊔ y) ⊓ (x ⊔ z) := le_antisymm sup_inf_le le_sup_inf theorem sup_inf_right : (y ⊓ z) ⊔ x = (y ⊔ x) ⊓ (z ⊔ x) := by simp only [sup_inf_left, λy:α, @sup_comm α _ y x, eq_self_iff_true] theorem inf_sup_left : x ⊓ (y ⊔ z) = (x ⊓ y) ⊔ (x ⊓ z) := calc x ⊓ (y ⊔ z) = (x ⊓ (x ⊔ z)) ⊓ (y ⊔ z) : by rw [inf_sup_self] ... = x ⊓ ((x ⊓ y) ⊔ z) : by simp only [inf_assoc, sup_inf_right, eq_self_iff_true] ... = (x ⊔ (x ⊓ y)) ⊓ ((x ⊓ y) ⊔ z) : by rw [sup_inf_self] ... = ((x ⊓ y) ⊔ x) ⊓ ((x ⊓ y) ⊔ z) : by rw [sup_comm] ... = (x ⊓ y) ⊔ (x ⊓ z) : by rw [sup_inf_left] theorem inf_sup_right : (y ⊔ z) ⊓ x = (y ⊓ x) ⊔ (z ⊓ x) := by simp only [inf_sup_left, λy:α, @inf_comm α _ y x, eq_self_iff_true] lemma eq_of_sup_eq_inf_eq {α : Type u} [distrib_lattice α] {a b c : α} (h₁ : b ⊓ a = c ⊓ a) (h₂ : b ⊔ a = c ⊔ a) : b = c := le_antisymm (calc b ≤ (c ⊓ a) ⊔ b : le_sup_right ... = (c ⊔ b) ⊓ (a ⊔ b) : sup_inf_right ... = c ⊔ (c ⊓ a) : by rw [←h₁, sup_inf_left, ←h₂]; simp only [sup_comm, eq_self_iff_true] ... = c : sup_inf_self) (calc c ≤ (b ⊓ a) ⊔ c : le_sup_right ... = (b ⊔ c) ⊓ (a ⊔ c) : sup_inf_right ... = b ⊔ (b ⊓ a) : by rw [h₁, sup_inf_left, h₂]; simp only [sup_comm, eq_self_iff_true] ... = b : sup_inf_self) end distrib_lattice /- Lattices derived from linear orders -/ @[priority 100] -- see Note [lower instance priority] instance lattice_of_decidable_linear_order {α : Type u} [o : decidable_linear_order α] : lattice α := { sup := max, le_sup_left := le_max_left, le_sup_right := le_max_right, sup_le := assume a b c, max_le, inf := min, inf_le_left := min_le_left, inf_le_right := min_le_right, le_inf := assume a b c, le_min, ..o } theorem sup_eq_max [decidable_linear_order α] : x ⊔ y = max x y := rfl theorem inf_eq_min [decidable_linear_order α] : x ⊓ y = min x y := rfl @[priority 100] -- see Note [lower instance priority] instance distrib_lattice_of_decidable_linear_order {α : Type u} [o : decidable_linear_order α] : distrib_lattice α := { le_sup_inf := assume a b c, match le_total b c with | or.inl h := inf_le_left_of_le $ sup_le_sup_left (le_inf (le_refl b) h) _ | or.inr h := inf_le_right_of_le $ sup_le_sup_left (le_inf h (le_refl c)) _ end, ..lattice.lattice_of_decidable_linear_order } instance nat.distrib_lattice : distrib_lattice ℕ := by apply_instance end lattice namespace monotone open lattice variables {α : Type u} {β : Type v} lemma le_map_sup [semilattice_sup α] [semilattice_sup β] {f : α → β} (h : monotone f) (x y : α) : f x ⊔ f y ≤ f (x ⊔ y) := sup_le (h le_sup_left) (h le_sup_right) lemma map_inf_le [semilattice_inf α] [semilattice_inf β] {f : α → β} (h : monotone f) (x y : α) : f (x ⊓ y) ≤ f x ⊓ f y := le_inf (h inf_le_left) (h inf_le_right) end monotone namespace order_dual open lattice variable (α : Type*) instance [has_inf α] : has_sup (order_dual α) := ⟨((⊓) : α → α → α)⟩ instance [has_sup α] : has_inf (order_dual α) := ⟨((⊔) : α → α → α)⟩ instance [semilattice_inf α] : semilattice_sup (order_dual α) := { le_sup_left := @inf_le_left α _, le_sup_right := @inf_le_right α _, sup_le := assume a b c hca hcb, @le_inf α _ _ _ _ hca hcb, .. order_dual.partial_order α, .. order_dual.lattice.has_sup α } instance [semilattice_sup α] : semilattice_inf (order_dual α) := { inf_le_left := @le_sup_left α _, inf_le_right := @le_sup_right α _, le_inf := assume a b c hca hcb, @sup_le α _ _ _ _ hca hcb, .. order_dual.partial_order α, .. order_dual.lattice.has_inf α } instance [lattice α] : lattice (order_dual α) := { .. order_dual.lattice.semilattice_sup α, .. order_dual.lattice.semilattice_inf α } instance [distrib_lattice α] : distrib_lattice (order_dual α) := { le_sup_inf := assume x y z, le_of_eq inf_sup_left.symm, .. order_dual.lattice.lattice α } end order_dual namespace prod open lattice variables (α : Type u) (β : Type v) instance [has_sup α] [has_sup β] : has_sup (α × β) := ⟨λp q, ⟨p.1 ⊔ q.1, p.2 ⊔ q.2⟩⟩ instance [has_inf α] [has_inf β] : has_inf (α × β) := ⟨λp q, ⟨p.1 ⊓ q.1, p.2 ⊓ q.2⟩⟩ instance [semilattice_sup α] [semilattice_sup β] : semilattice_sup (α × β) := { sup_le := assume a b c h₁ h₂, ⟨sup_le h₁.1 h₂.1, sup_le h₁.2 h₂.2⟩, le_sup_left := assume a b, ⟨le_sup_left, le_sup_left⟩, le_sup_right := assume a b, ⟨le_sup_right, le_sup_right⟩, .. prod.partial_order α β, .. prod.lattice.has_sup α β } instance [semilattice_inf α] [semilattice_inf β] : semilattice_inf (α × β) := { le_inf := assume a b c h₁ h₂, ⟨le_inf h₁.1 h₂.1, le_inf h₁.2 h₂.2⟩, inf_le_left := assume a b, ⟨inf_le_left, inf_le_left⟩, inf_le_right := assume a b, ⟨inf_le_right, inf_le_right⟩, .. prod.partial_order α β, .. prod.lattice.has_inf α β } instance [lattice α] [lattice β] : lattice (α × β) := { .. prod.lattice.semilattice_inf α β, .. prod.lattice.semilattice_sup α β } instance [distrib_lattice α] [distrib_lattice β] : distrib_lattice (α × β) := { le_sup_inf := assume a b c, ⟨le_sup_inf, le_sup_inf⟩, .. prod.lattice.lattice α β } end prod