/- Copyright (c) 2014 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura notation, basic datatypes and type classes -/ prelude import Init.Prelude import Init.SizeOf set_option linter.missingDocs true -- keep it documented universe u v w /-- `inline (f x)` is an indication to the compiler to inline the definition of `f` at the application site itself (by comparison to the `@[inline]` attribute, which applies to all applications of the function). -/ @[simp] def inline {α : Sort u} (a : α) : α := a theorem id.def {α : Sort u} (a : α) : id a = a := rfl /-- `flip f a b` is `f b a`. It is useful for "point-free" programming, since it can sometimes be used to avoid introducing variables. For example, `(·<·)` is the less-than relation, and `flip (·<·)` is the greater-than relation. -/ @[inline] def flip {α : Sort u} {β : Sort v} {φ : Sort w} (f : α → β → φ) : β → α → φ := fun b a => f a b @[simp] theorem Function.const_apply {y : β} {x : α} : const α y x = y := rfl @[simp] theorem Function.comp_apply {f : β → δ} {g : α → β} {x : α} : comp f g x = f (g x) := rfl theorem Function.comp_def {α β δ} (f : β → δ) (g : α → β) : f ∘ g = fun x => f (g x) := rfl attribute [simp] namedPattern /-- `Empty.elim : Empty → C` says that a value of any type can be constructed from `Empty`. This can be thought of as a compiler-checked assertion that a code path is unreachable. This is a non-dependent variant of `Empty.rec`. -/ @[macro_inline] def Empty.elim {C : Sort u} : Empty → C := Empty.rec /-- Decidable equality for Empty -/ instance : DecidableEq Empty := fun a => a.elim /-- `PEmpty.elim : Empty → C` says that a value of any type can be constructed from `PEmpty`. This can be thought of as a compiler-checked assertion that a code path is unreachable. This is a non-dependent variant of `PEmpty.rec`. -/ @[macro_inline] def PEmpty.elim {C : Sort _} : PEmpty → C := fun a => nomatch a /-- Decidable equality for PEmpty -/ instance : DecidableEq PEmpty := fun a => a.elim /-- Thunks are "lazy" values that are evaluated when first accessed using `Thunk.get/map/bind`. The value is then stored and not recomputed for all further accesses. -/ -- NOTE: the runtime has special support for the `Thunk` type to implement this behavior structure Thunk (α : Type u) : Type u where /-- Constructs a new thunk from a function `Unit → α` that will be called when the thunk is forced. -/ mk :: /-- Extract the getter function out of a thunk. Use `Thunk.get` instead. -/ private fn : Unit → α attribute [extern "lean_mk_thunk"] Thunk.mk /-- Store a value in a thunk. Note that the value has already been computed, so there is no laziness. -/ @[extern "lean_thunk_pure"] protected def Thunk.pure (a : α) : Thunk α := ⟨fun _ => a⟩ /-- Forces a thunk to extract the value. This will cache the result, so a second call to the same function will return the value in O(1) instead of calling the stored getter function. -/ -- NOTE: we use `Thunk.get` instead of `Thunk.fn` as the accessor primitive as the latter has an additional `Unit` argument @[extern "lean_thunk_get_own"] protected def Thunk.get (x : @& Thunk α) : α := x.fn () /-- Map a function over a thunk. -/ @[inline] protected def Thunk.map (f : α → β) (x : Thunk α) : Thunk β := ⟨fun _ => f x.get⟩ /-- Constructs a thunk that applies `f` to the result of `x` when forced. -/ @[inline] protected def Thunk.bind (x : Thunk α) (f : α → Thunk β) : Thunk β := ⟨fun _ => (f x.get).get⟩ @[simp] theorem Thunk.sizeOf_eq [SizeOf α] (a : Thunk α) : sizeOf a = 1 + sizeOf a.get := by cases a; rfl instance thunkCoe : CoeTail α (Thunk α) where -- Since coercions are expanded eagerly, `a` is evaluated lazily. coe a := ⟨fun _ => a⟩ /-- A variation on `Eq.ndrec` with the equality argument first. -/ abbrev Eq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : α → Sort u1} {b : α} (h : a = b) (m : motive a) : motive b := Eq.ndrec m h /-! # definitions -/ /-- If and only if, or logical bi-implication. `a ↔ b` means that `a` implies `b` and vice versa. By `propext`, this implies that `a` and `b` are equal and hence any expression involving `a` is equivalent to the corresponding expression with `b` instead. -/ structure Iff (a b : Prop) : Prop where /-- If `a → b` and `b → a` then `a` and `b` are equivalent. -/ intro :: /-- Modus ponens for if and only if. If `a ↔ b` and `a`, then `b`. -/ mp : a → b /-- Modus ponens for if and only if, reversed. If `a ↔ b` and `b`, then `a`. -/ mpr : b → a @[inherit_doc] infix:20 " <-> " => Iff @[inherit_doc] infix:20 " ↔ " => Iff /-- `Sum α β`, or `α ⊕ β`, is the disjoint union of types `α` and `β`. An element of `α ⊕ β` is either of the form `.inl a` where `a : α`, or `.inr b` where `b : β`. -/ inductive Sum (α : Type u) (β : Type v) where /-- Left injection into the sum type `α ⊕ β`. If `a : α` then `.inl a : α ⊕ β`. -/ | inl (val : α) : Sum α β /-- Right injection into the sum type `α ⊕ β`. If `b : β` then `.inr b : α ⊕ β`. -/ | inr (val : β) : Sum α β @[inherit_doc] infixr:30 " ⊕ " => Sum /-- `PSum α β`, or `α ⊕' β`, is the disjoint union of types `α` and `β`. It differs from `α ⊕ β` in that it allows `α` and `β` to have arbitrary sorts `Sort u` and `Sort v`, instead of restricting to `Type u` and `Type v`. This means that it can be used in situations where one side is a proposition, like `True ⊕' Nat`. The reason this is not the default is that this type lives in the universe `Sort (max 1 u v)`, which can cause problems for universe level unification, because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic. `PSum` is usually only used in automation that constructs sums of arbitrary types. -/ inductive PSum (α : Sort u) (β : Sort v) where /-- Left injection into the sum type `α ⊕' β`. If `a : α` then `.inl a : α ⊕' β`. -/ | inl (val : α) : PSum α β /-- Right injection into the sum type `α ⊕' β`. If `b : β` then `.inr b : α ⊕' β`. -/ | inr (val : β) : PSum α β @[inherit_doc] infixr:30 " ⊕' " => PSum instance {α β} [Inhabited α] : Inhabited (PSum α β) := ⟨PSum.inl default⟩ instance {α β} [Inhabited β] : Inhabited (PSum α β) := ⟨PSum.inr default⟩ /-- `Sigma β`, also denoted `Σ a : α, β a` or `(a : α) × β a`, is the type of dependent pairs whose first component is `a : α` and whose second component is `b : β a` (so the type of the second component can depend on the value of the first component). It is sometimes known as the dependent sum type, since it is the type level version of an indexed summation. -/ structure Sigma {α : Type u} (β : α → Type v) where /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : Sigma β`. (This will usually require a type ascription to determine `β` since it is not determined from `a` and `b` alone.) -/ mk :: /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/ fst : α /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/ snd : β fst attribute [unbox] Sigma /-- `PSigma β`, also denoted `Σ' a : α, β a` or `(a : α) ×' β a`, is the type of dependent pairs whose first component is `a : α` and whose second component is `b : β a` (so the type of the second component can depend on the value of the first component). It differs from `Σ a : α, β a` in that it allows `α` and `β` to have arbitrary sorts `Sort u` and `Sort v`, instead of restricting to `Type u` and `Type v`. This means that it can be used in situations where one side is a proposition, like `(p : Nat) ×' p = p`. The reason this is not the default is that this type lives in the universe `Sort (max 1 u v)`, which can cause problems for universe level unification, because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic. `PSigma` is usually only used in automation that constructs pairs of arbitrary types. -/ structure PSigma {α : Sort u} (β : α → Sort v) where /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : PSigma β`. (This will usually require a type ascription to determine `β` since it is not determined from `a` and `b` alone.) -/ mk :: /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/ fst : α /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/ snd : β fst /-- Existential quantification. If `p : α → Prop` is a predicate, then `∃ x : α, p x` asserts that there is some `x` of type `α` such that `p x` holds. To create an existential proof, use the `exists` tactic, or the anonymous constructor notation `⟨x, h⟩`. To unpack an existential, use `cases h` where `h` is a proof of `∃ x : α, p x`, or `let ⟨x, hx⟩ := h` where `. Because Lean has proof irrelevance, any two proofs of an existential are definitionally equal. One consequence of this is that it is impossible to recover the witness of an existential from the mere fact of its existence. For example, the following does not compile: ``` example (h : ∃ x : Nat, x = x) : Nat := let ⟨x, _⟩ := h -- fail, because the goal is `Nat : Type` x ``` The error message `recursor 'Exists.casesOn' can only eliminate into Prop` means that this only works when the current goal is another proposition: ``` example (h : ∃ x : Nat, x = x) : True := let ⟨x, _⟩ := h -- ok, because the goal is `True : Prop` trivial ``` -/ inductive Exists {α : Sort u} (p : α → Prop) : Prop where /-- Existential introduction. If `a : α` and `h : p a`, then `⟨a, h⟩` is a proof that `∃ x : α, p x`. -/ | intro (w : α) (h : p w) : Exists p /-- Auxiliary type used to compile `for x in xs` notation. This is the return value of the body of a `ForIn` call, representing the body of a for loop. It can be: * `.yield (a : α)`, meaning that we should continue the loop and `a` is the new state. `.yield` is produced by `continue` and reaching the bottom of the loop body. * `.done (a : α)`, meaning that we should early-exit the loop with state `a`. `.done` is produced by calls to `break` or `return` in the loop, -/ inductive ForInStep (α : Type u) where /-- `.done a` means that we should early-exit the loop. `.done` is produced by calls to `break` or `return` in the loop. -/ | done : α → ForInStep α /-- `.yield a` means that we should continue the loop. `.yield` is produced by `continue` and reaching the bottom of the loop body. -/ | yield : α → ForInStep α deriving Inhabited /-- `ForIn m ρ α` is the typeclass which supports `for x in xs` notation. Here `xs : ρ` is the type of the collection to iterate over, `x : α` is the element type which is made available inside the loop, and `m` is the monad for the encompassing `do` block. -/ class ForIn (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)) where /-- `forIn x b f : m β` runs a for-loop in the monad `m` with additional state `β`. This traverses over the "contents" of `x`, and passes the elements `a : α` to `f : α → β → m (ForInStep β)`. `b : β` is the initial state, and the return value of `f` is the new state as well as a directive `.done` or `.yield` which indicates whether to abort early or continue iteration. The expression ``` let mut b := ... for x in xs do b ← foo x b ``` in a `do` block is syntactic sugar for: ``` let b := ... let b ← forIn xs b (fun x b => do let b ← foo x b return .yield b) ``` (Here `b` corresponds to the variables mutated in the loop.) -/ forIn {β} [Monad m] (x : ρ) (b : β) (f : α → β → m (ForInStep β)) : m β export ForIn (forIn) /-- `ForIn' m ρ α d` is a variation on the `ForIn m ρ α` typeclass which supports the `for h : x in xs` notation. It is the same as `for x in xs` except that `h : x ∈ xs` is provided as an additional argument to the body of the for-loop. -/ class ForIn' (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)) (d : outParam $ Membership α ρ) where /-- `forIn' x b f : m β` runs a for-loop in the monad `m` with additional state `β`. This traverses over the "contents" of `x`, and passes the elements `a : α` along with a proof that `a ∈ x` to `f : (a : α) → a ∈ x → β → m (ForInStep β)`. `b : β` is the initial state, and the return value of `f` is the new state as well as a directive `.done` or `.yield` which indicates whether to abort early or continue iteration. -/ forIn' {β} [Monad m] (x : ρ) (b : β) (f : (a : α) → a ∈ x → β → m (ForInStep β)) : m β export ForIn' (forIn') /-- Auxiliary type used to compile `do` notation. It is used when compiling a do block nested inside a combinator like `tryCatch`. It encodes the possible ways the block can exit: * `pure (a : α) s` means that the block exited normally with return value `a`. * `return (b : β) s` means that the block exited via a `return b` early-exit command. * `break s` means that `break` was called, meaning that we should exit from the containing loop. * `continue s` means that `continue` was called, meaning that we should continue to the next iteration of the containing loop. All cases return a value `s : σ` which bundles all the mutable variables of the do-block. -/ inductive DoResultPRBC (α β σ : Type u) where /-- `pure (a : α) s` means that the block exited normally with return value `a` -/ | pure : α → σ → DoResultPRBC α β σ /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/ | return : β → σ → DoResultPRBC α β σ /-- `break s` means that `break` was called, meaning that we should exit from the containing loop -/ | break : σ → DoResultPRBC α β σ /-- `continue s` means that `continue` was called, meaning that we should continue to the next iteration of the containing loop -/ | continue : σ → DoResultPRBC α β σ /-- Auxiliary type used to compile `do` notation. It is the same as `DoResultPRBC α β σ` except that `break` and `continue` are not available because we are not in a loop context. -/ inductive DoResultPR (α β σ : Type u) where /-- `pure (a : α) s` means that the block exited normally with return value `a` -/ | pure : α → σ → DoResultPR α β σ /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/ | return : β → σ → DoResultPR α β σ /-- Auxiliary type used to compile `do` notation. It is an optimization of `DoResultPRBC PEmpty PEmpty σ` to remove the impossible cases, used when neither `pure` nor `return` are possible exit paths. -/ inductive DoResultBC (σ : Type u) where /-- `break s` means that `break` was called, meaning that we should exit from the containing loop -/ | break : σ → DoResultBC σ /-- `continue s` means that `continue` was called, meaning that we should continue to the next iteration of the containing loop -/ | continue : σ → DoResultBC σ /-- Auxiliary type used to compile `do` notation. It is an optimization of either `DoResultPRBC α PEmpty σ` or `DoResultPRBC PEmpty α σ` to remove the impossible case, used when either `pure` or `return` is never used. -/ inductive DoResultSBC (α σ : Type u) where /-- This encodes either `pure (a : α)` or `return (a : α)`: * `pure (a : α) s` means that the block exited normally with return value `a` * `return (b : β) s` means that the block exited via a `return b` early-exit command The one that is actually encoded depends on the context of use. -/ | pureReturn : α → σ → DoResultSBC α σ /-- `break s` means that `break` was called, meaning that we should exit from the containing loop -/ | break : σ → DoResultSBC α σ /-- `continue s` means that `continue` was called, meaning that we should continue to the next iteration of the containing loop -/ | continue : σ → DoResultSBC α σ /-- `HasEquiv α` is the typeclass which supports the notation `x ≈ y` where `x y : α`.-/ class HasEquiv (α : Sort u) where /-- `x ≈ y` says that `x` and `y` are equivalent. Because this is a typeclass, the notion of equivalence is type-dependent. -/ Equiv : α → α → Sort v @[inherit_doc] infix:50 " ≈ " => HasEquiv.Equiv /-- `EmptyCollection α` is the typeclass which supports the notation `∅`, also written as `{}`. -/ class EmptyCollection (α : Type u) where /-- `∅` or `{}` is the empty set or empty collection. It is supported by the `EmptyCollection` typeclass. -/ emptyCollection : α @[inherit_doc] notation "{" "}" => EmptyCollection.emptyCollection @[inherit_doc] notation "∅" => EmptyCollection.emptyCollection /-- `Task α` is a primitive for asynchronous computation. It represents a computation that will resolve to a value of type `α`, possibly being computed on another thread. This is similar to `Future` in Scala, `Promise` in Javascript, and `JoinHandle` in Rust. The tasks have an overridden representation in the runtime. -/ structure Task (α : Type u) : Type u where /-- `Task.pure (a : α)` constructs a task that is already resolved with value `a`. -/ pure :: /-- If `task : Task α` then `task.get : α` blocks the current thread until the value is available, and then returns the result of the task. -/ get : α deriving Inhabited, Nonempty attribute [extern "lean_task_pure"] Task.pure attribute [extern "lean_task_get_own"] Task.get namespace Task /-- Task priority. Tasks with higher priority will always be scheduled before ones with lower priority. -/ abbrev Priority := Nat /-- The default priority for spawned tasks, also the lowest priority: `0`. -/ def Priority.default : Priority := 0 /-- The highest regular priority for spawned tasks: `8`. Spawning a task with a priority higher than `Task.Priority.max` is not an error but will spawn a dedicated worker for the task, see `Task.Priority.dedicated`. Regular priority tasks are placed in a thread pool and worked on according to the priority order. -/ -- see `LEAN_MAX_PRIO` def Priority.max : Priority := 8 /-- Any priority higher than `Task.Priority.max` will result in the task being scheduled immediately on a dedicated thread. This is particularly useful for long-running and/or I/O-bound tasks since Lean will by default allocate no more non-dedicated workers than the number of cores to reduce context switches. -/ def Priority.dedicated : Priority := 9 set_option linter.unusedVariables.funArgs false in /-- `spawn fn : Task α` constructs and immediately launches a new task for evaluating the function `fn () : α` asynchronously. `prio`, if provided, is the priority of the task. -/ @[noinline, extern "lean_task_spawn"] protected def spawn {α : Type u} (fn : Unit → α) (prio := Priority.default) : Task α := ⟨fn ()⟩ set_option linter.unusedVariables.funArgs false in /-- `map f x` maps function `f` over the task `x`: that is, it constructs (and immediately launches) a new task which will wait for the value of `x` to be available and then calls `f` on the result. `prio`, if provided, is the priority of the task. If `sync` is set to true, `f` is executed on the current thread if `x` has already finished. -/ @[noinline, extern "lean_task_map"] protected def map (f : α → β) (x : Task α) (prio := Priority.default) (sync := false) : Task β := ⟨f x.get⟩ set_option linter.unusedVariables.funArgs false in /-- `bind x f` does a monad "bind" operation on the task `x` with function `f`: that is, it constructs (and immediately launches) a new task which will wait for the value of `x` to be available and then calls `f` on the result, resulting in a new task which is then run for a result. `prio`, if provided, is the priority of the task. If `sync` is set to true, `f` is executed on the current thread if `x` has already finished. -/ @[noinline, extern "lean_task_bind"] protected def bind (x : Task α) (f : α → Task β) (prio := Priority.default) (sync := false) : Task β := ⟨(f x.get).get⟩ end Task /-- `NonScalar` is a type that is not a scalar value in our runtime. It is used as a stand-in for an arbitrary boxed value to avoid excessive monomorphization, and it is only created using `unsafeCast`. It is somewhat analogous to C `void*` in usage, but the type itself is not special. -/ structure NonScalar where /-- You should not use this function -/ mk :: /-- You should not use this function -/ val : Nat /-- `PNonScalar` is a type that is not a scalar value in our runtime. It is used as a stand-in for an arbitrary boxed value to avoid excessive monomorphization, and it is only created using `unsafeCast`. It is somewhat analogous to C `void*` in usage, but the type itself is not special. This is the universe-polymorphic version of `PNonScalar`; it is preferred to use `NonScalar` instead where applicable. -/ inductive PNonScalar : Type u where /-- You should not use this function -/ | mk (v : Nat) : PNonScalar @[simp] protected theorem Nat.add_zero (n : Nat) : n + 0 = n := rfl theorem optParam_eq (α : Sort u) (default : α) : optParam α default = α := rfl /-! # Boolean operators -/ /-- `strictOr` is the same as `or`, but it does not use short-circuit evaluation semantics: both sides are evaluated, even if the first value is `true`. -/ @[extern "lean_strict_or"] def strictOr (b₁ b₂ : Bool) := b₁ || b₂ /-- `strictAnd` is the same as `and`, but it does not use short-circuit evaluation semantics: both sides are evaluated, even if the first value is `false`. -/ @[extern "lean_strict_and"] def strictAnd (b₁ b₂ : Bool) := b₁ && b₂ /-- `x != y` is boolean not-equal. It is the negation of `x == y` which is supplied by the `BEq` typeclass. Unlike `x ≠ y` (which is notation for `Ne x y`), this is `Bool` valued instead of `Prop` valued. It is mainly intended for programming applications. -/ @[inline] def bne {α : Type u} [BEq α] (a b : α) : Bool := !(a == b) @[inherit_doc] infix:50 " != " => bne /-- `LawfulBEq α` is a typeclass which asserts that the `BEq α` implementation (which supplies the `a == b` notation) coincides with logical equality `a = b`. In other words, `a == b` implies `a = b`, and `a == a` is true. -/ class LawfulBEq (α : Type u) [BEq α] : Prop where /-- If `a == b` evaluates to `true`, then `a` and `b` are equal in the logic. -/ eq_of_beq : {a b : α} → a == b → a = b /-- `==` is reflexive, that is, `(a == a) = true`. -/ protected rfl : {a : α} → a == a export LawfulBEq (eq_of_beq) instance : LawfulBEq Bool where eq_of_beq {a b} h := by cases a <;> cases b <;> first | rfl | contradiction rfl {a} := by cases a <;> decide instance [DecidableEq α] : LawfulBEq α where eq_of_beq := of_decide_eq_true rfl := of_decide_eq_self_eq_true _ instance : LawfulBEq Char := inferInstance instance : LawfulBEq String := inferInstance /-! # Logical connectives and equality -/ @[inherit_doc True.intro] def trivial : True := ⟨⟩ theorem mt {a b : Prop} (h₁ : a → b) (h₂ : ¬b) : ¬a := fun ha => h₂ (h₁ ha) theorem not_false : ¬False := id theorem not_not_intro {p : Prop} (h : p) : ¬ ¬ p := fun hn : ¬ p => hn h -- proof irrelevance is built in theorem proof_irrel {a : Prop} (h₁ h₂ : a) : h₁ = h₂ := rfl /-- If `h : α = β` is a proof of type equality, then `h.mp : α → β` is the induced "cast" operation, mapping elements of `α` to elements of `β`. You can prove theorems about the resulting element by induction on `h`, since `rfl.mp` is definitionally the identity function. -/ @[macro_inline] def Eq.mp {α β : Sort u} (h : α = β) (a : α) : β := h ▸ a /-- If `h : α = β` is a proof of type equality, then `h.mpr : β → α` is the induced "cast" operation in the reverse direction, mapping elements of `β` to elements of `α`. You can prove theorems about the resulting element by induction on `h`, since `rfl.mpr` is definitionally the identity function. -/ @[macro_inline] def Eq.mpr {α β : Sort u} (h : α = β) (b : β) : α := h ▸ b @[elab_as_elim] theorem Eq.substr {α : Sort u} {p : α → Prop} {a b : α} (h₁ : b = a) (h₂ : p a) : p b := h₁ ▸ h₂ theorem cast_eq {α : Sort u} (h : α = α) (a : α) : cast h a = a := rfl /-- `a ≠ b`, or `Ne a b` is defined as `¬ (a = b)` or `a = b → False`, and asserts that `a` and `b` are not equal. -/ @[reducible] def Ne {α : Sort u} (a b : α) := ¬(a = b) @[inherit_doc] infix:50 " ≠ " => Ne section Ne variable {α : Sort u} variable {a b : α} {p : Prop} theorem Ne.intro (h : a = b → False) : a ≠ b := h theorem Ne.elim (h : a ≠ b) : a = b → False := h theorem Ne.irrefl (h : a ≠ a) : False := h rfl theorem Ne.symm (h : a ≠ b) : b ≠ a := fun h₁ => h (h₁.symm) theorem ne_comm {α} {a b : α} : a ≠ b ↔ b ≠ a := ⟨Ne.symm, Ne.symm⟩ theorem false_of_ne : a ≠ a → False := Ne.irrefl theorem ne_false_of_self : p → p ≠ False := fun (hp : p) (h : p = False) => h ▸ hp theorem ne_true_of_not : ¬p → p ≠ True := fun (hnp : ¬p) (h : p = True) => have : ¬True := h ▸ hnp this trivial theorem true_ne_false : ¬True = False := ne_false_of_self trivial theorem false_ne_true : False ≠ True := fun h => h.symm ▸ trivial end Ne theorem Bool.of_not_eq_true : {b : Bool} → ¬ (b = true) → b = false | true, h => absurd rfl h | false, _ => rfl theorem Bool.of_not_eq_false : {b : Bool} → ¬ (b = false) → b = true | true, _ => rfl | false, h => absurd rfl h theorem ne_of_beq_false [BEq α] [LawfulBEq α] {a b : α} (h : (a == b) = false) : a ≠ b := by intro h'; subst h'; have : true = false := Eq.trans LawfulBEq.rfl.symm h; contradiction theorem beq_false_of_ne [BEq α] [LawfulBEq α] {a b : α} (h : a ≠ b) : (a == b) = false := have : ¬ (a == b) = true := by intro h'; rw [eq_of_beq h'] at h; contradiction Bool.of_not_eq_true this section variable {α β φ : Sort u} {a a' : α} {b b' : β} {c : φ} theorem HEq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} → β → Sort u1} (m : motive a) {β : Sort u2} {b : β} (h : HEq a b) : motive b := h.rec m theorem HEq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} → β → Sort u1} {β : Sort u2} {b : β} (h : HEq a b) (m : motive a) : motive b := h.rec m theorem HEq.elim {α : Sort u} {a : α} {p : α → Sort v} {b : α} (h₁ : HEq a b) (h₂ : p a) : p b := eq_of_heq h₁ ▸ h₂ theorem HEq.subst {p : (T : Sort u) → T → Prop} (h₁ : HEq a b) (h₂ : p α a) : p β b := HEq.ndrecOn h₁ h₂ theorem HEq.symm (h : HEq a b) : HEq b a := h.rec (HEq.refl a) theorem heq_of_eq (h : a = a') : HEq a a' := Eq.subst h (HEq.refl a) theorem HEq.trans (h₁ : HEq a b) (h₂ : HEq b c) : HEq a c := HEq.subst h₂ h₁ theorem heq_of_heq_of_eq (h₁ : HEq a b) (h₂ : b = b') : HEq a b' := HEq.trans h₁ (heq_of_eq h₂) theorem heq_of_eq_of_heq (h₁ : a = a') (h₂ : HEq a' b) : HEq a b := HEq.trans (heq_of_eq h₁) h₂ theorem type_eq_of_heq (h : HEq a b) : α = β := h.rec (Eq.refl α) end theorem eqRec_heq {α : Sort u} {φ : α → Sort v} {a a' : α} : (h : a = a') → (p : φ a) → HEq (Eq.recOn (motive := fun x _ => φ x) h p) p | rfl, p => HEq.refl p theorem heq_of_eqRec_eq {α β : Sort u} {a : α} {b : β} (h₁ : α = β) (h₂ : Eq.rec (motive := fun α _ => α) a h₁ = b) : HEq a b := by subst h₁ apply heq_of_eq exact h₂ theorem cast_heq {α β : Sort u} : (h : α = β) → (a : α) → HEq (cast h a) a | rfl, a => HEq.refl a variable {a b c d : Prop} theorem iff_iff_implies_and_implies (a b : Prop) : (a ↔ b) ↔ (a → b) ∧ (b → a) := Iff.intro (fun h => And.intro h.mp h.mpr) (fun h => Iff.intro h.left h.right) theorem Iff.refl (a : Prop) : a ↔ a := Iff.intro (fun h => h) (fun h => h) protected theorem Iff.rfl {a : Prop} : a ↔ a := Iff.refl a macro_rules | `(tactic| rfl) => `(tactic| exact Iff.rfl) theorem Iff.of_eq (h : a = b) : a ↔ b := h ▸ Iff.rfl theorem Iff.trans (h₁ : a ↔ b) (h₂ : b ↔ c) : a ↔ c := Iff.intro (h₂.mp ∘ h₁.mp) (h₁.mpr ∘ h₂.mpr) -- This is needed for `calc` to work with `iff`. instance : Trans Iff Iff Iff where trans := Iff.trans theorem Eq.comm {a b : α} : a = b ↔ b = a := Iff.intro Eq.symm Eq.symm theorem eq_comm {a b : α} : a = b ↔ b = a := Eq.comm theorem Iff.symm (h : a ↔ b) : b ↔ a := Iff.intro h.mpr h.mp theorem Iff.comm: (a ↔ b) ↔ (b ↔ a) := Iff.intro Iff.symm Iff.symm theorem iff_comm : (a ↔ b) ↔ (b ↔ a) := Iff.comm theorem And.symm : a ∧ b → b ∧ a := fun ⟨ha, hb⟩ => ⟨hb, ha⟩ theorem And.comm : a ∧ b ↔ b ∧ a := Iff.intro And.symm And.symm theorem and_comm : a ∧ b ↔ b ∧ a := And.comm theorem Or.symm : a ∨ b → b ∨ a := .rec .inr .inl theorem Or.comm : a ∨ b ↔ b ∨ a := Iff.intro Or.symm Or.symm theorem or_comm : a ∨ b ↔ b ∨ a := Or.comm /-! # Exists -/ theorem Exists.elim {α : Sort u} {p : α → Prop} {b : Prop} (h₁ : Exists (fun x => p x)) (h₂ : ∀ (a : α), p a → b) : b := match h₁ with | intro a h => h₂ a h /-! # Decidable -/ theorem decide_true_eq_true (h : Decidable True) : @decide True h = true := match h with | isTrue _ => rfl | isFalse h => False.elim <| h ⟨⟩ theorem decide_false_eq_false (h : Decidable False) : @decide False h = false := match h with | isFalse _ => rfl | isTrue h => False.elim h /-- Similar to `decide`, but uses an explicit instance -/ @[inline] def toBoolUsing {p : Prop} (d : Decidable p) : Bool := decide (h := d) theorem toBoolUsing_eq_true {p : Prop} (d : Decidable p) (h : p) : toBoolUsing d = true := decide_eq_true (inst := d) h theorem ofBoolUsing_eq_true {p : Prop} {d : Decidable p} (h : toBoolUsing d = true) : p := of_decide_eq_true (inst := d) h theorem ofBoolUsing_eq_false {p : Prop} {d : Decidable p} (h : toBoolUsing d = false) : ¬ p := of_decide_eq_false (inst := d) h instance : Decidable True := isTrue trivial instance : Decidable False := isFalse not_false namespace Decidable variable {p q : Prop} /-- Synonym for `dite` (dependent if-then-else). We can construct an element `q` (of any sort, not just a proposition) by cases on whether `p` is true or false, provided `p` is decidable. -/ @[macro_inline] def byCases {q : Sort u} [dec : Decidable p] (h1 : p → q) (h2 : ¬p → q) : q := match dec with | isTrue h => h1 h | isFalse h => h2 h theorem em (p : Prop) [Decidable p] : p ∨ ¬p := byCases Or.inl Or.inr set_option linter.unusedVariables.funArgs false in theorem byContradiction [dec : Decidable p] (h : ¬p → False) : p := byCases id (fun np => False.elim (h np)) theorem of_not_not [Decidable p] : ¬ ¬ p → p := fun hnn => byContradiction (fun hn => absurd hn hnn) theorem not_and_iff_or_not (p q : Prop) [d₁ : Decidable p] [d₂ : Decidable q] : ¬ (p ∧ q) ↔ ¬ p ∨ ¬ q := Iff.intro (fun h => match d₁, d₂ with | isTrue h₁, isTrue h₂ => absurd (And.intro h₁ h₂) h | _, isFalse h₂ => Or.inr h₂ | isFalse h₁, _ => Or.inl h₁) (fun (h) ⟨hp, hq⟩ => match h with | Or.inl h => h hp | Or.inr h => h hq) end Decidable section variable {p q : Prop} /-- Transfer a decidability proof across an equivalence of propositions. -/ @[inline] def decidable_of_decidable_of_iff [Decidable p] (h : p ↔ q) : Decidable q := if hp : p then isTrue (Iff.mp h hp) else isFalse fun hq => absurd (Iff.mpr h hq) hp /-- Transfer a decidability proof across an equality of propositions. -/ @[inline] def decidable_of_decidable_of_eq [Decidable p] (h : p = q) : Decidable q := decidable_of_decidable_of_iff (p := p) (h ▸ Iff.rfl) end @[macro_inline] instance {p q} [Decidable p] [Decidable q] : Decidable (p → q) := if hp : p then if hq : q then isTrue (fun _ => hq) else isFalse (fun h => absurd (h hp) hq) else isTrue (fun h => absurd h hp) instance {p q} [Decidable p] [Decidable q] : Decidable (p ↔ q) := if hp : p then if hq : q then isTrue ⟨fun _ => hq, fun _ => hp⟩ else isFalse fun h => hq (h.1 hp) else if hq : q then isFalse fun h => hp (h.2 hq) else isTrue ⟨fun h => absurd h hp, fun h => absurd h hq⟩ /-! # if-then-else expression theorems -/ theorem if_pos {c : Prop} {h : Decidable c} (hc : c) {α : Sort u} {t e : α} : (ite c t e) = t := match h with | isTrue _ => rfl | isFalse hnc => absurd hc hnc theorem if_neg {c : Prop} {h : Decidable c} (hnc : ¬c) {α : Sort u} {t e : α} : (ite c t e) = e := match h with | isTrue hc => absurd hc hnc | isFalse _ => rfl /-- Split an if-then-else into cases. The `split` tactic is generally easier to use than this theorem. -/ def iteInduction {c} [inst : Decidable c] {motive : α → Sort _} {t e : α} (hpos : c → motive t) (hneg : ¬c → motive e) : motive (ite c t e) := match inst with | isTrue h => hpos h | isFalse h => hneg h theorem dif_pos {c : Prop} {h : Decidable c} (hc : c) {α : Sort u} {t : c → α} {e : ¬ c → α} : (dite c t e) = t hc := match h with | isTrue _ => rfl | isFalse hnc => absurd hc hnc theorem dif_neg {c : Prop} {h : Decidable c} (hnc : ¬c) {α : Sort u} {t : c → α} {e : ¬ c → α} : (dite c t e) = e hnc := match h with | isTrue hc => absurd hc hnc | isFalse _ => rfl -- Remark: dite and ite are "defally equal" when we ignore the proofs. theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) : dite c (fun _ => t) (fun _ => e) = ite c t e := match h with | isTrue _ => rfl | isFalse _ => rfl instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e) := match dC with | isTrue _ => dT | isFalse _ => dE instance {c : Prop} {t : c → Prop} {e : ¬c → Prop} [dC : Decidable c] [dT : ∀ h, Decidable (t h)] [dE : ∀ h, Decidable (e h)] : Decidable (if h : c then t h else e h) := match dC with | isTrue hc => dT hc | isFalse hc => dE hc /-- Auxiliary definition for generating compact `noConfusion` for enumeration types -/ abbrev noConfusionTypeEnum {α : Sort u} {β : Sort v} [inst : DecidableEq β] (f : α → β) (P : Sort w) (x y : α) : Sort w := (inst (f x) (f y)).casesOn (fun _ => P) (fun _ => P → P) /-- Auxiliary definition for generating compact `noConfusion` for enumeration types -/ abbrev noConfusionEnum {α : Sort u} {β : Sort v} [inst : DecidableEq β] (f : α → β) {P : Sort w} {x y : α} (h : x = y) : noConfusionTypeEnum f P x y := Decidable.casesOn (motive := fun (inst : Decidable (f x = f y)) => Decidable.casesOn (motive := fun _ => Sort w) inst (fun _ => P) (fun _ => P → P)) (inst (f x) (f y)) (fun h' => False.elim (h' (congrArg f h))) (fun _ => fun x => x) /-! # Inhabited -/ instance : Inhabited Prop where default := True deriving instance Inhabited for NonScalar, PNonScalar, True, ForInStep theorem nonempty_of_exists {α : Sort u} {p : α → Prop} : Exists (fun x => p x) → Nonempty α | ⟨w, _⟩ => ⟨w⟩ /-! # Subsingleton -/ /-- A "subsingleton" is a type with at most one element. In other words, it is either empty, or has a unique element. All propositions are subsingletons because of proof irrelevance, but some other types are subsingletons as well and they inherit many of the same properties as propositions. `Subsingleton α` is a typeclass, so it is usually used as an implicit argument and inferred by typeclass inference. -/ class Subsingleton (α : Sort u) : Prop where /-- Construct a proof that `α` is a subsingleton by showing that any two elements are equal. -/ intro :: /-- Any two elements of a subsingleton are equal. -/ allEq : (a b : α) → a = b protected theorem Subsingleton.elim {α : Sort u} [h : Subsingleton α] : (a b : α) → a = b := h.allEq protected theorem Subsingleton.helim {α β : Sort u} [h₁ : Subsingleton α] (h₂ : α = β) (a : α) (b : β) : HEq a b := by subst h₂ apply heq_of_eq apply Subsingleton.elim instance (p : Prop) : Subsingleton p := ⟨fun a b => proof_irrel a b⟩ instance : Subsingleton Empty := ⟨(·.elim)⟩ instance : Subsingleton PEmpty := ⟨(·.elim)⟩ instance [Subsingleton α] [Subsingleton β] : Subsingleton (α × β) := ⟨fun {..} {..} => by congr <;> apply Subsingleton.elim⟩ instance (p : Prop) : Subsingleton (Decidable p) := Subsingleton.intro fun | isTrue t₁ => fun | isTrue _ => rfl | isFalse f₂ => absurd t₁ f₂ | isFalse f₁ => fun | isTrue t₂ => absurd t₂ f₁ | isFalse _ => rfl example [Subsingleton α] (p : α → Prop) : Subsingleton (Subtype p) := ⟨fun ⟨x, _⟩ ⟨y, _⟩ => by congr; exact Subsingleton.elim x y⟩ theorem recSubsingleton {p : Prop} [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u} [h₃ : ∀ (h : p), Subsingleton (h₁ h)] [h₄ : ∀ (h : ¬p), Subsingleton (h₂ h)] : Subsingleton (h.casesOn h₂ h₁) := match h with | isTrue h => h₃ h | isFalse h => h₄ h /-- An equivalence relation `~ : α → α → Prop` is a relation that is: * reflexive: `x ~ x` * symmetric: `x ~ y` implies `y ~ x` * transitive: `x ~ y` and `y ~ z` implies `x ~ z` Equality is an equivalence relation, and equivalence relations share many of the properties of equality. In particular, `Quot α r` is most well behaved when `r` is an equivalence relation, and in this case we use `Quotient` instead. -/ structure Equivalence {α : Sort u} (r : α → α → Prop) : Prop where /-- An equivalence relation is reflexive: `x ~ x` -/ refl : ∀ x, r x x /-- An equivalence relation is symmetric: `x ~ y` implies `y ~ x` -/ symm : ∀ {x y}, r x y → r y x /-- An equivalence relation is transitive: `x ~ y` and `y ~ z` implies `x ~ z` -/ trans : ∀ {x y z}, r x y → r y z → r x z /-- The empty relation is the relation on `α` which is always `False`. -/ def emptyRelation {α : Sort u} (_ _ : α) : Prop := False /-- `Subrelation q r` means that `q ⊆ r` or `∀ x y, q x y → r x y`. It is the analogue of the subset relation on relations. -/ def Subrelation {α : Sort u} (q r : α → α → Prop) := ∀ {x y}, q x y → r x y /-- The inverse image of `r : β → β → Prop` by a function `α → β` is the relation `s : α → α → Prop` defined by `s a b = r (f a) (f b)`. -/ def InvImage {α : Sort u} {β : Sort v} (r : β → β → Prop) (f : α → β) : α → α → Prop := fun a₁ a₂ => r (f a₁) (f a₂) /-- The transitive closure `r⁺` of a relation `r` is the smallest relation which is transitive and contains `r`. `r⁺ a z` if and only if there exists a sequence `a r b r ... r z` of length at least 1 connecting `a` to `z`. -/ inductive TC {α : Sort u} (r : α → α → Prop) : α → α → Prop where /-- If `r a b` then `r⁺ a b`. This is the base case of the transitive closure. -/ | base : ∀ a b, r a b → TC r a b /-- The transitive closure is transitive. -/ | trans : ∀ a b c, TC r a b → TC r b c → TC r a c /-! # Subtype -/ namespace Subtype theorem existsOfSubtype {α : Type u} {p : α → Prop} : { x // p x } → Exists (fun x => p x) | ⟨a, h⟩ => ⟨a, h⟩ variable {α : Type u} {p : α → Prop} protected theorem eq : ∀ {a1 a2 : {x // p x}}, val a1 = val a2 → a1 = a2 | ⟨_, _⟩, ⟨_, _⟩, rfl => rfl theorem eta (a : {x // p x}) (h : p (val a)) : mk (val a) h = a := by cases a exact rfl instance {α : Type u} {p : α → Prop} {a : α} (h : p a) : Inhabited {x // p x} where default := ⟨a, h⟩ instance {α : Type u} {p : α → Prop} [DecidableEq α] : DecidableEq {x : α // p x} := fun ⟨a, h₁⟩ ⟨b, h₂⟩ => if h : a = b then isTrue (by subst h; exact rfl) else isFalse (fun h' => Subtype.noConfusion h' (fun h' => absurd h' h)) end Subtype /-! # Sum -/ section variable {α : Type u} {β : Type v} instance Sum.inhabitedLeft [Inhabited α] : Inhabited (Sum α β) where default := Sum.inl default instance Sum.inhabitedRight [Inhabited β] : Inhabited (Sum α β) where default := Sum.inr default instance {α : Type u} {β : Type v} [DecidableEq α] [DecidableEq β] : DecidableEq (Sum α β) := fun a b => match a, b with | Sum.inl a, Sum.inl b => if h : a = b then isTrue (h ▸ rfl) else isFalse fun h' => Sum.noConfusion h' fun h' => absurd h' h | Sum.inr a, Sum.inr b => if h : a = b then isTrue (h ▸ rfl) else isFalse fun h' => Sum.noConfusion h' fun h' => absurd h' h | Sum.inr _, Sum.inl _ => isFalse fun h => Sum.noConfusion h | Sum.inl _, Sum.inr _ => isFalse fun h => Sum.noConfusion h end /-! # Product -/ instance [Inhabited α] [Inhabited β] : Inhabited (α × β) where default := (default, default) instance [Inhabited α] [Inhabited β] : Inhabited (MProd α β) where default := ⟨default, default⟩ instance [Inhabited α] [Inhabited β] : Inhabited (PProd α β) where default := ⟨default, default⟩ instance [DecidableEq α] [DecidableEq β] : DecidableEq (α × β) := fun (a, b) (a', b') => match decEq a a' with | isTrue e₁ => match decEq b b' with | isTrue e₂ => isTrue (e₁ ▸ e₂ ▸ rfl) | isFalse n₂ => isFalse fun h => Prod.noConfusion h fun _ e₂' => absurd e₂' n₂ | isFalse n₁ => isFalse fun h => Prod.noConfusion h fun e₁' _ => absurd e₁' n₁ instance [BEq α] [BEq β] : BEq (α × β) where beq := fun (a₁, b₁) (a₂, b₂) => a₁ == a₂ && b₁ == b₂ /-- Lexicographical order for products -/ def Prod.lexLt [LT α] [LT β] (s : α × β) (t : α × β) : Prop := s.1 < t.1 ∨ (s.1 = t.1 ∧ s.2 < t.2) instance Prod.lexLtDec [LT α] [LT β] [DecidableEq α] [DecidableEq β] [(a b : α) → Decidable (a < b)] [(a b : β) → Decidable (a < b)] : (s t : α × β) → Decidable (Prod.lexLt s t) := fun _ _ => inferInstanceAs (Decidable (_ ∨ _)) theorem Prod.lexLt_def [LT α] [LT β] (s t : α × β) : (Prod.lexLt s t) = (s.1 < t.1 ∨ (s.1 = t.1 ∧ s.2 < t.2)) := rfl theorem Prod.eta (p : α × β) : (p.1, p.2) = p := rfl /-- `Prod.map f g : α₁ × β₁ → α₂ × β₂` maps across a pair by applying `f` to the first component and `g` to the second. -/ def Prod.map {α₁ : Type u₁} {α₂ : Type u₂} {β₁ : Type v₁} {β₂ : Type v₂} (f : α₁ → α₂) (g : β₁ → β₂) : α₁ × β₁ → α₂ × β₂ | (a, b) => (f a, g b) /-! # Dependent products -/ theorem ex_of_PSigma {α : Type u} {p : α → Prop} : (PSigma (fun x => p x)) → Exists (fun x => p x) | ⟨x, hx⟩ => ⟨x, hx⟩ protected theorem PSigma.eta {α : Sort u} {β : α → Sort v} {a₁ a₂ : α} {b₁ : β a₁} {b₂ : β a₂} (h₁ : a₁ = a₂) (h₂ : Eq.ndrec b₁ h₁ = b₂) : PSigma.mk a₁ b₁ = PSigma.mk a₂ b₂ := by subst h₁ subst h₂ exact rfl /-! # Universe polymorphic unit -/ theorem PUnit.subsingleton (a b : PUnit) : a = b := by cases a; cases b; exact rfl theorem PUnit.eq_punit (a : PUnit) : a = ⟨⟩ := PUnit.subsingleton a ⟨⟩ instance : Subsingleton PUnit := Subsingleton.intro PUnit.subsingleton instance : Inhabited PUnit where default := ⟨⟩ instance : DecidableEq PUnit := fun a b => isTrue (PUnit.subsingleton a b) /-! # Setoid -/ /-- A setoid is a type with a distinguished equivalence relation, denoted `≈`. This is mainly used as input to the `Quotient` type constructor. -/ class Setoid (α : Sort u) where /-- `x ≈ y` is the distinguished equivalence relation of a setoid. -/ r : α → α → Prop /-- The relation `x ≈ y` is an equivalence relation. -/ iseqv : Equivalence r instance {α : Sort u} [Setoid α] : HasEquiv α := ⟨Setoid.r⟩ namespace Setoid variable {α : Sort u} [Setoid α] theorem refl (a : α) : a ≈ a := iseqv.refl a theorem symm {a b : α} (hab : a ≈ b) : b ≈ a := iseqv.symm hab theorem trans {a b c : α} (hab : a ≈ b) (hbc : b ≈ c) : a ≈ c := iseqv.trans hab hbc end Setoid /-! # Propositional extensionality -/ /-- The axiom of **propositional extensionality**. It asserts that if propositions `a` and `b` are logically equivalent (i.e. we can prove `a` from `b` and vice versa), then `a` and `b` are *equal*, meaning that we can replace `a` with `b` in all contexts. For simple expressions like `a ∧ c ∨ d → e` we can prove that because all the logical connectives respect logical equivalence, we can replace `a` with `b` in this expression without using `propext`. However, for higher order expressions like `P a` where `P : Prop → Prop` is unknown, or indeed for `a = b` itself, we cannot replace `a` with `b` without an axiom which says exactly this. This is a relatively uncontroversial axiom, which is intuitionistically valid. It does however block computation when using `#reduce` to reduce proofs directly (which is not recommended), meaning that canonicity, the property that all closed terms of type `Nat` normalize to numerals, fails to hold when this (or any) axiom is used: ``` set_option pp.proofs true def foo : Nat := by have : (True → True) ↔ True := ⟨λ _ => trivial, λ _ _ => trivial⟩ have := propext this ▸ (2 : Nat) exact this #reduce foo -- propext { mp := fun x x => True.intro, mpr := fun x => True.intro } ▸ 2 #eval foo -- 2 ``` `#eval` can evaluate it to a numeral because the compiler erases casts and does not evaluate proofs, so `propext`, whose return type is a proposition, can never block it. -/ axiom propext {a b : Prop} : (a ↔ b) → a = b theorem Eq.propIntro {a b : Prop} (h₁ : a → b) (h₂ : b → a) : a = b := propext <| Iff.intro h₁ h₂ -- Eq for Prop is now decidable if the equivalent Iff is decidable instance {p q : Prop} [d : Decidable (p ↔ q)] : Decidable (p = q) := match d with | isTrue h => isTrue (propext h) | isFalse h => isFalse fun heq => h (heq ▸ Iff.rfl) gen_injective_theorems% Prod gen_injective_theorems% PProd gen_injective_theorems% MProd gen_injective_theorems% Subtype gen_injective_theorems% Fin gen_injective_theorems% Array gen_injective_theorems% Sum gen_injective_theorems% PSum gen_injective_theorems% Nat gen_injective_theorems% Option gen_injective_theorems% List gen_injective_theorems% Except gen_injective_theorems% EStateM.Result gen_injective_theorems% Lean.Name gen_injective_theorems% Lean.Syntax @[simp] theorem beq_iff_eq [BEq α] [LawfulBEq α] (a b : α) : a == b ↔ a = b := ⟨eq_of_beq, by intro h; subst h; exact LawfulBEq.rfl⟩ /-! # Prop lemmas -/ /-- *Ex falso* for negation: from `¬a` and `a` anything follows. This is the same as `absurd` with the arguments flipped, but it is in the `Not` namespace so that projection notation can be used. -/ def Not.elim {α : Sort _} (H1 : ¬a) (H2 : a) : α := absurd H2 H1 /-- Non-dependent eliminator for `And`. -/ abbrev And.elim (f : a → b → α) (h : a ∧ b) : α := f h.left h.right /-- Non-dependent eliminator for `Iff`. -/ def Iff.elim (f : (a → b) → (b → a) → α) (h : a ↔ b) : α := f h.mp h.mpr /-- Iff can now be used to do substitutions in a calculation -/ theorem Iff.subst {a b : Prop} {p : Prop → Prop} (h₁ : a ↔ b) (h₂ : p a) : p b := Eq.subst (propext h₁) h₂ theorem Not.intro {a : Prop} (h : a → False) : ¬a := h theorem Not.imp {a b : Prop} (H2 : ¬b) (H1 : a → b) : ¬a := mt H1 H2 theorem not_congr (h : a ↔ b) : ¬a ↔ ¬b := ⟨mt h.2, mt h.1⟩ theorem not_not_not : ¬¬¬a ↔ ¬a := ⟨mt not_not_intro, not_not_intro⟩ theorem iff_of_true (ha : a) (hb : b) : a ↔ b := Iff.intro (fun _ => hb) (fun _ => ha) theorem iff_of_false (ha : ¬a) (hb : ¬b) : a ↔ b := Iff.intro ha.elim hb.elim theorem iff_true_left (ha : a) : (a ↔ b) ↔ b := Iff.intro (·.mp ha) (iff_of_true ha) theorem iff_true_right (ha : a) : (b ↔ a) ↔ b := Iff.comm.trans (iff_true_left ha) theorem iff_false_left (ha : ¬a) : (a ↔ b) ↔ ¬b := Iff.intro (mt ·.mpr ha) (iff_of_false ha) theorem iff_false_right (ha : ¬a) : (b ↔ a) ↔ ¬b := Iff.comm.trans (iff_false_left ha) theorem of_iff_true (h : a ↔ True) : a := h.mpr trivial theorem iff_true_intro (h : a) : a ↔ True := iff_of_true h trivial theorem not_of_iff_false : (p ↔ False) → ¬p := Iff.mp theorem iff_false_intro (h : ¬a) : a ↔ False := iff_of_false h id theorem not_iff_false_intro (h : a) : ¬a ↔ False := iff_false_intro (not_not_intro h) theorem not_true : (¬True) ↔ False := iff_false_intro (not_not_intro trivial) theorem not_false_iff : (¬False) ↔ True := iff_true_intro not_false theorem Eq.to_iff : a = b → (a ↔ b) := Iff.of_eq theorem iff_of_eq : a = b → (a ↔ b) := Iff.of_eq theorem neq_of_not_iff : ¬(a ↔ b) → a ≠ b := mt Iff.of_eq theorem iff_iff_eq : (a ↔ b) ↔ a = b := Iff.intro propext Iff.of_eq @[simp] theorem eq_iff_iff : (a = b) ↔ (a ↔ b) := iff_iff_eq.symm theorem eq_self_iff_true (a : α) : a = a ↔ True := iff_true_intro rfl theorem ne_self_iff_false (a : α) : a ≠ a ↔ False := not_iff_false_intro rfl theorem false_of_true_iff_false (h : True ↔ False) : False := h.mp trivial theorem false_of_true_eq_false (h : True = False) : False := false_of_true_iff_false (Iff.of_eq h) theorem true_eq_false_of_false : False → (True = False) := False.elim theorem iff_def : (a ↔ b) ↔ (a → b) ∧ (b → a) := iff_iff_implies_and_implies a b theorem iff_def' : (a ↔ b) ↔ (b → a) ∧ (a → b) := Iff.trans iff_def And.comm theorem true_iff_false : (True ↔ False) ↔ False := iff_false_intro (·.mp True.intro) theorem false_iff_true : (False ↔ True) ↔ False := iff_false_intro (·.mpr True.intro) theorem iff_not_self : ¬(a ↔ ¬a) | H => let f h := H.1 h h; f (H.2 f) theorem heq_self_iff_true (a : α) : HEq a a ↔ True := iff_true_intro HEq.rfl /-! ## implies -/ theorem not_not_of_not_imp : ¬(a → b) → ¬¬a := mt Not.elim theorem not_of_not_imp {a : Prop} : ¬(a → b) → ¬b := mt fun h _ => h @[simp] theorem imp_not_self : (a → ¬a) ↔ ¬a := Iff.intro (fun h ha => h ha ha) (fun h _ => h) theorem imp_intro {α β : Prop} (h : α) : β → α := fun _ => h theorem imp_imp_imp {a b c d : Prop} (h₀ : c → a) (h₁ : b → d) : (a → b) → (c → d) := (h₁ ∘ · ∘ h₀) theorem imp_iff_right {a : Prop} (ha : a) : (a → b) ↔ b := Iff.intro (· ha) (fun a _ => a) -- This is not marked `@[simp]` because we have `implies_true : (α → True) = True` theorem imp_true_iff (α : Sort u) : (α → True) ↔ True := iff_true_intro (fun _ => trivial) theorem false_imp_iff (a : Prop) : (False → a) ↔ True := iff_true_intro False.elim theorem true_imp_iff (α : Prop) : (True → α) ↔ α := imp_iff_right True.intro @[simp] theorem imp_self : (a → a) ↔ True := iff_true_intro id theorem imp_false : (a → False) ↔ ¬a := Iff.rfl theorem imp.swap : (a → b → c) ↔ (b → a → c) := Iff.intro flip flip theorem imp_not_comm : (a → ¬b) ↔ (b → ¬a) := imp.swap theorem imp_congr_left (h : a ↔ b) : (a → c) ↔ (b → c) := Iff.intro (· ∘ h.mpr) (· ∘ h.mp) theorem imp_congr_right (h : a → (b ↔ c)) : (a → b) ↔ (a → c) := Iff.intro (fun hab ha => (h ha).mp (hab ha)) (fun hcd ha => (h ha).mpr (hcd ha)) theorem imp_congr_ctx (h₁ : a ↔ c) (h₂ : c → (b ↔ d)) : (a → b) ↔ (c → d) := Iff.trans (imp_congr_left h₁) (imp_congr_right h₂) theorem imp_congr (h₁ : a ↔ c) (h₂ : b ↔ d) : (a → b) ↔ (c → d) := imp_congr_ctx h₁ fun _ => h₂ theorem imp_iff_not (hb : ¬b) : a → b ↔ ¬a := imp_congr_right fun _ => iff_false_intro hb /-! # Quotients -/ namespace Quot /-- The **quotient axiom**, or at least the nontrivial part of the quotient axiomatization. Quotient types are introduced by the `init_quot` command in `Init.Prelude` which introduces the axioms: ``` opaque Quot {α : Sort u} (r : α → α → Prop) : Sort u opaque Quot.mk {α : Sort u} (r : α → α → Prop) (a : α) : Quot r opaque Quot.lift {α : Sort u} {r : α → α → Prop} {β : Sort v} (f : α → β) : (∀ a b : α, r a b → f a = f b) → Quot r → β opaque Quot.ind {α : Sort u} {r : α → α → Prop} {β : Quot r → Prop} : (∀ a : α, β (Quot.mk r a)) → ∀ q : Quot r, β q ``` All of these axioms are true if we assume `Quot α r = α` and `Quot.mk` and `Quot.lift` are identity functions, so they do not add much. However this axiom cannot be explained in that way (it is false for that interpretation), so the real power of quotient types come from this axiom. It says that the quotient by `r` maps elements which are related by `r` to equal values in the quotient. Together with `Quot.lift` which says that functions which respect `r` can be lifted to functions on the quotient, we can deduce that `Quot α r` exactly consists of the equivalence classes with respect to `r`. It is important to note that `r` need not be an equivalence relation in this axiom. When `r` is not an equivalence relation, we are actually taking a quotient with respect to the equivalence relation generated by `r`. -/ axiom sound : ∀ {α : Sort u} {r : α → α → Prop} {a b : α}, r a b → Quot.mk r a = Quot.mk r b protected theorem liftBeta {α : Sort u} {r : α → α → Prop} {β : Sort v} (f : α → β) (c : (a b : α) → r a b → f a = f b) (a : α) : lift f c (Quot.mk r a) = f a := rfl protected theorem indBeta {α : Sort u} {r : α → α → Prop} {motive : Quot r → Prop} (p : (a : α) → motive (Quot.mk r a)) (a : α) : (ind p (Quot.mk r a) : motive (Quot.mk r a)) = p a := rfl /-- `Quot.liftOn q f h` is the same as `Quot.lift f h q`. It just reorders the argument `q : Quot r` to be first. -/ protected abbrev liftOn {α : Sort u} {β : Sort v} {r : α → α → Prop} (q : Quot r) (f : α → β) (c : (a b : α) → r a b → f a = f b) : β := lift f c q @[elab_as_elim] protected theorem inductionOn {α : Sort u} {r : α → α → Prop} {motive : Quot r → Prop} (q : Quot r) (h : (a : α) → motive (Quot.mk r a)) : motive q := ind h q theorem exists_rep {α : Sort u} {r : α → α → Prop} (q : Quot r) : Exists (fun a => (Quot.mk r a) = q) := q.inductionOn (fun a => ⟨a, rfl⟩) section variable {α : Sort u} variable {r : α → α → Prop} variable {motive : Quot r → Sort v} /-- Auxiliary definition for `Quot.rec`. -/ @[reducible, macro_inline] protected def indep (f : (a : α) → motive (Quot.mk r a)) (a : α) : PSigma motive := ⟨Quot.mk r a, f a⟩ protected theorem indepCoherent (f : (a : α) → motive (Quot.mk r a)) (h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b) : (a b : α) → r a b → Quot.indep f a = Quot.indep f b := fun a b e => PSigma.eta (sound e) (h a b e) protected theorem liftIndepPr1 (f : (a : α) → motive (Quot.mk r a)) (h : ∀ (a b : α) (p : r a b), Eq.ndrec (f a) (sound p) = f b) (q : Quot r) : (lift (Quot.indep f) (Quot.indepCoherent f h) q).1 = q := by induction q using Quot.ind exact rfl /-- Dependent recursion principle for `Quot`. This constructor can be tricky to use, so you should consider the simpler versions if they apply: * `Quot.lift`, for nondependent functions * `Quot.ind`, for theorems / proofs of propositions about quotients * `Quot.recOnSubsingleton`, when the target type is a `Subsingleton` * `Quot.hrecOn`, which uses `HEq (f a) (f b)` instead of a `sound p ▸ f a = f b` assummption -/ protected abbrev rec (f : (a : α) → motive (Quot.mk r a)) (h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b) (q : Quot r) : motive q := Eq.ndrecOn (Quot.liftIndepPr1 f h q) ((lift (Quot.indep f) (Quot.indepCoherent f h) q).2) @[inherit_doc Quot.rec] protected abbrev recOn (q : Quot r) (f : (a : α) → motive (Quot.mk r a)) (h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b) : motive q := q.rec f h /-- Dependent induction principle for a quotient, when the target type is a `Subsingleton`. In this case the quotient's side condition is trivial so any function can be lifted. -/ protected abbrev recOnSubsingleton [h : (a : α) → Subsingleton (motive (Quot.mk r a))] (q : Quot r) (f : (a : α) → motive (Quot.mk r a)) : motive q := by induction q using Quot.rec apply f apply Subsingleton.elim /-- Heterogeneous dependent recursion principle for a quotient. This may be easier to work with since it uses `HEq` instead of an `Eq.ndrec` in the hypothesis. -/ protected abbrev hrecOn (q : Quot r) (f : (a : α) → motive (Quot.mk r a)) (c : (a b : α) → (p : r a b) → HEq (f a) (f b)) : motive q := Quot.recOn q f fun a b p => eq_of_heq <| have p₁ : HEq (Eq.ndrec (f a) (sound p)) (f a) := eqRec_heq (sound p) (f a) HEq.trans p₁ (c a b p) end end Quot set_option linter.unusedVariables.funArgs false in /-- `Quotient α s` is the same as `Quot α r`, but it is specialized to a setoid `s` (that is, an equivalence relation) instead of an arbitrary relation. Prefer `Quotient` over `Quot` if your relation is actually an equivalence relation. -/ def Quotient {α : Sort u} (s : Setoid α) := @Quot α Setoid.r namespace Quotient /-- The canonical quotient map into a `Quotient`. -/ @[inline] protected def mk {α : Sort u} (s : Setoid α) (a : α) : Quotient s := Quot.mk Setoid.r a /-- The canonical quotient map into a `Quotient`. (This synthesizes the setoid by typeclass inference.) -/ protected def mk' {α : Sort u} [s : Setoid α] (a : α) : Quotient s := Quotient.mk s a /-- The analogue of `Quot.sound`: If `a` and `b` are related by the equivalence relation, then they have equal equivalence classes. -/ def sound {α : Sort u} {s : Setoid α} {a b : α} : a ≈ b → Quotient.mk s a = Quotient.mk s b := Quot.sound /-- The analogue of `Quot.lift`: if `f : α → β` respects the equivalence relation `≈`, then it lifts to a function on `Quotient s` such that `lift f h (mk a) = f a`. -/ protected abbrev lift {α : Sort u} {β : Sort v} {s : Setoid α} (f : α → β) : ((a b : α) → a ≈ b → f a = f b) → Quotient s → β := Quot.lift f /-- The analogue of `Quot.ind`: every element of `Quotient s` is of the form `Quotient.mk s a`. -/ protected theorem ind {α : Sort u} {s : Setoid α} {motive : Quotient s → Prop} : ((a : α) → motive (Quotient.mk s a)) → (q : Quotient s) → motive q := Quot.ind /-- The analogue of `Quot.liftOn`: if `f : α → β` respects the equivalence relation `≈`, then it lifts to a function on `Quotient s` such that `lift (mk a) f h = f a`. -/ protected abbrev liftOn {α : Sort u} {β : Sort v} {s : Setoid α} (q : Quotient s) (f : α → β) (c : (a b : α) → a ≈ b → f a = f b) : β := Quot.liftOn q f c /-- The analogue of `Quot.inductionOn`: every element of `Quotient s` is of the form `Quotient.mk s a`. -/ @[elab_as_elim] protected theorem inductionOn {α : Sort u} {s : Setoid α} {motive : Quotient s → Prop} (q : Quotient s) (h : (a : α) → motive (Quotient.mk s a)) : motive q := Quot.inductionOn q h theorem exists_rep {α : Sort u} {s : Setoid α} (q : Quotient s) : Exists (fun (a : α) => Quotient.mk s a = q) := Quot.exists_rep q section variable {α : Sort u} variable {s : Setoid α} variable {motive : Quotient s → Sort v} /-- The analogue of `Quot.rec` for `Quotient`. See `Quot.rec`. -/ @[inline, elab_as_elim] protected def rec (f : (a : α) → motive (Quotient.mk s a)) (h : (a b : α) → (p : a ≈ b) → Eq.ndrec (f a) (Quotient.sound p) = f b) (q : Quotient s) : motive q := Quot.rec f h q /-- The analogue of `Quot.recOn` for `Quotient`. See `Quot.recOn`. -/ @[elab_as_elim] protected abbrev recOn (q : Quotient s) (f : (a : α) → motive (Quotient.mk s a)) (h : (a b : α) → (p : a ≈ b) → Eq.ndrec (f a) (Quotient.sound p) = f b) : motive q := Quot.recOn q f h /-- The analogue of `Quot.recOnSubsingleton` for `Quotient`. See `Quot.recOnSubsingleton`. -/ @[elab_as_elim] protected abbrev recOnSubsingleton [h : (a : α) → Subsingleton (motive (Quotient.mk s a))] (q : Quotient s) (f : (a : α) → motive (Quotient.mk s a)) : motive q := Quot.recOnSubsingleton (h := h) q f /-- The analogue of `Quot.hrecOn` for `Quotient`. See `Quot.hrecOn`. -/ @[elab_as_elim] protected abbrev hrecOn (q : Quotient s) (f : (a : α) → motive (Quotient.mk s a)) (c : (a b : α) → (p : a ≈ b) → HEq (f a) (f b)) : motive q := Quot.hrecOn q f c end section universe uA uB uC variable {α : Sort uA} {β : Sort uB} {φ : Sort uC} variable {s₁ : Setoid α} {s₂ : Setoid β} /-- Lift a binary function to a quotient on both arguments. -/ protected abbrev lift₂ (f : α → β → φ) (c : (a₁ : α) → (b₁ : β) → (a₂ : α) → (b₂ : β) → a₁ ≈ a₂ → b₁ ≈ b₂ → f a₁ b₁ = f a₂ b₂) (q₁ : Quotient s₁) (q₂ : Quotient s₂) : φ := by apply Quotient.lift (fun (a₁ : α) => Quotient.lift (f a₁) (fun (a b : β) => c a₁ a a₁ b (Setoid.refl a₁)) q₂) _ q₁ intros induction q₂ using Quotient.ind apply c; assumption; apply Setoid.refl /-- Lift a binary function to a quotient on both arguments. -/ protected abbrev liftOn₂ (q₁ : Quotient s₁) (q₂ : Quotient s₂) (f : α → β → φ) (c : (a₁ : α) → (b₁ : β) → (a₂ : α) → (b₂ : β) → a₁ ≈ a₂ → b₁ ≈ b₂ → f a₁ b₁ = f a₂ b₂) : φ := Quotient.lift₂ f c q₁ q₂ @[elab_as_elim] protected theorem ind₂ {motive : Quotient s₁ → Quotient s₂ → Prop} (h : (a : α) → (b : β) → motive (Quotient.mk s₁ a) (Quotient.mk s₂ b)) (q₁ : Quotient s₁) (q₂ : Quotient s₂) : motive q₁ q₂ := by induction q₁ using Quotient.ind induction q₂ using Quotient.ind apply h @[elab_as_elim] protected theorem inductionOn₂ {motive : Quotient s₁ → Quotient s₂ → Prop} (q₁ : Quotient s₁) (q₂ : Quotient s₂) (h : (a : α) → (b : β) → motive (Quotient.mk s₁ a) (Quotient.mk s₂ b)) : motive q₁ q₂ := by induction q₁ using Quotient.ind induction q₂ using Quotient.ind apply h @[elab_as_elim] protected theorem inductionOn₃ {s₃ : Setoid φ} {motive : Quotient s₁ → Quotient s₂ → Quotient s₃ → Prop} (q₁ : Quotient s₁) (q₂ : Quotient s₂) (q₃ : Quotient s₃) (h : (a : α) → (b : β) → (c : φ) → motive (Quotient.mk s₁ a) (Quotient.mk s₂ b) (Quotient.mk s₃ c)) : motive q₁ q₂ q₃ := by induction q₁ using Quotient.ind induction q₂ using Quotient.ind induction q₃ using Quotient.ind apply h end section Exact variable {α : Sort u} private def rel {s : Setoid α} (q₁ q₂ : Quotient s) : Prop := Quotient.liftOn₂ q₁ q₂ (fun a₁ a₂ => a₁ ≈ a₂) (fun _ _ _ _ a₁b₁ a₂b₂ => propext (Iff.intro (fun a₁a₂ => Setoid.trans (Setoid.symm a₁b₁) (Setoid.trans a₁a₂ a₂b₂)) (fun b₁b₂ => Setoid.trans a₁b₁ (Setoid.trans b₁b₂ (Setoid.symm a₂b₂))))) private theorem rel.refl {s : Setoid α} (q : Quotient s) : rel q q := q.inductionOn Setoid.refl private theorem rel_of_eq {s : Setoid α} {q₁ q₂ : Quotient s} : q₁ = q₂ → rel q₁ q₂ := fun h => Eq.ndrecOn h (rel.refl q₁) theorem exact {s : Setoid α} {a b : α} : Quotient.mk s a = Quotient.mk s b → a ≈ b := fun h => rel_of_eq h end Exact section universe uA uB uC variable {α : Sort uA} {β : Sort uB} variable {s₁ : Setoid α} {s₂ : Setoid β} /-- Lift a binary function to a quotient on both arguments. -/ @[elab_as_elim] protected abbrev recOnSubsingleton₂ {motive : Quotient s₁ → Quotient s₂ → Sort uC} [s : (a : α) → (b : β) → Subsingleton (motive (Quotient.mk s₁ a) (Quotient.mk s₂ b))] (q₁ : Quotient s₁) (q₂ : Quotient s₂) (g : (a : α) → (b : β) → motive (Quotient.mk s₁ a) (Quotient.mk s₂ b)) : motive q₁ q₂ := by induction q₁ using Quot.recOnSubsingleton induction q₂ using Quot.recOnSubsingleton apply g intro a; apply s induction q₂ using Quot.recOnSubsingleton intro a; apply s infer_instance end end Quotient section variable {α : Type u} variable (r : α → α → Prop) instance {α : Sort u} {s : Setoid α} [d : ∀ (a b : α), Decidable (a ≈ b)] : DecidableEq (Quotient s) := fun (q₁ q₂ : Quotient s) => Quotient.recOnSubsingleton₂ q₁ q₂ fun a₁ a₂ => match d a₁ a₂ with | isTrue h₁ => isTrue (Quotient.sound h₁) | isFalse h₂ => isFalse fun h => absurd (Quotient.exact h) h₂ /-! # Function extensionality -/ /-- **Function extensionality** is the statement that if two functions take equal values every point, then the functions themselves are equal: `(∀ x, f x = g x) → f = g`. It is called "extensionality" because it talks about how to prove two objects are equal based on the properties of the object (compare with set extensionality, which is `(∀ x, x ∈ s ↔ x ∈ t) → s = t`). This is often an axiom in dependent type theory systems, because it cannot be proved from the core logic alone. However in lean's type theory this follows from the existence of quotient types (note the `Quot.sound` in the proof, as well as the `show` line which makes use of the definitional equality `Quot.lift f h (Quot.mk x) = f x`). -/ theorem funext {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x} (h : ∀ x, f x = g x) : f = g := by let eqv (f g : (x : α) → β x) := ∀ x, f x = g x let extfunApp (f : Quot eqv) (x : α) : β x := Quot.liftOn f (fun (f : ∀ (x : α), β x) => f x) (fun _ _ h => h x) show extfunApp (Quot.mk eqv f) = extfunApp (Quot.mk eqv g) exact congrArg extfunApp (Quot.sound h) instance {α : Sort u} {β : α → Sort v} [∀ a, Subsingleton (β a)] : Subsingleton (∀ a, β a) where allEq f g := funext fun a => Subsingleton.elim (f a) (g a) /-! # Squash -/ /-- `Squash α` is the quotient of `α` by the always true relation. It is empty if `α` is empty, otherwise it is a singleton. (Thus it is unconditionally a `Subsingleton`.) It is the "universal `Subsingleton`" mapped from `α`. It is similar to `Nonempty α`, which has the same properties, but unlike `Nonempty` this is a `Type u`, that is, it is "data", and the compiler represents an element of `Squash α` the same as `α` itself (as compared to `Nonempty α`, whose elements are represented by a dummy value). `Squash.lift` will extract a value in any subsingleton `β` from a function on `α`, while `Nonempty.rec` can only do the same when `β` is a proposition. -/ def Squash (α : Type u) := Quot (fun (_ _ : α) => True) /-- The canonical quotient map into `Squash α`. -/ def Squash.mk {α : Type u} (x : α) : Squash α := Quot.mk _ x theorem Squash.ind {α : Type u} {motive : Squash α → Prop} (h : ∀ (a : α), motive (Squash.mk a)) : ∀ (q : Squash α), motive q := Quot.ind h /-- If `β` is a subsingleton, then a function `α → β` lifts to `Squash α → β`. -/ @[inline] def Squash.lift {α β} [Subsingleton β] (s : Squash α) (f : α → β) : β := Quot.lift f (fun _ _ _ => Subsingleton.elim _ _) s instance : Subsingleton (Squash α) where allEq a b := by induction a using Squash.ind induction b using Squash.ind apply Quot.sound trivial /-! # Relations -/ /-- `Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`. -/ class Antisymm {α : Sort u} (r : α → α → Prop) where /-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/ antisymm {a b : α} : r a b → r b a → a = b namespace Lean /-! # Kernel reduction hints -/ /-- Depends on the correctness of the Lean compiler, interpreter, and all `[implemented_by ...]` and `[extern ...]` annotations. -/ axiom trustCompiler : True /-- When the kernel tries to reduce a term `Lean.reduceBool c`, it will invoke the Lean interpreter to evaluate `c`. The kernel will not use the interpreter if `c` is not a constant. This feature is useful for performing proofs by reflection. Remark: the Lean frontend allows terms of the from `Lean.reduceBool t` where `t` is a term not containing free variables. The frontend automatically declares a fresh auxiliary constant `c` and replaces the term with `Lean.reduceBool c`. The main motivation is that the code for `t` will be pre-compiled. Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base. This is extra 30k lines of code. More importantly, you will probably not be able to check your development using external type checkers (e.g., Trepplein) that do not implement this feature. Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter. So, you are mainly losing the capability of type checking your development using external checkers. Recall that the compiler trusts the correctness of all `[implemented_by ...]` and `[extern ...]` annotations. If an extern function is executed, then the trusted code base will also include the implementation of the associated foreign function. -/ opaque reduceBool (b : Bool) : Bool := -- This ensures that `#print axioms` will track use of `reduceBool`. have := trustCompiler b /-- Similar to `Lean.reduceBool` for closed `Nat` terms. Remark: we do not have plans for supporting a generic `reduceValue {α} (a : α) : α := a`. The main issue is that it is non-trivial to convert an arbitrary runtime object back into a Lean expression. We believe `Lean.reduceBool` enables most interesting applications (e.g., proof by reflection). -/ opaque reduceNat (n : Nat) : Nat := -- This ensures that `#print axioms` will track use of `reduceNat`. have := trustCompiler n /-- The axiom `ofReduceBool` is used to perform proofs by reflection. See `reduceBool`. This axiom is usually not used directly, because it has some syntactic restrictions. Instead, the `native_decide` tactic can be used to prove any proposition whose decidability instance can be evaluated to `true` using the lean compiler / interpreter. Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base. This is extra 30k lines of code. More importantly, you will probably not be able to check your development using external type checkers (e.g., Trepplein) that do not implement this feature. Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter. So, you are mainly losing the capability of type checking your development using external checkers. -/ axiom ofReduceBool (a b : Bool) (h : reduceBool a = b) : a = b /-- The axiom `ofReduceNat` is used to perform proofs by reflection. See `reduceBool`. Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base. This is extra 30k lines of code. More importantly, you will probably not be able to check your development using external type checkers (e.g., Trepplein) that do not implement this feature. Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter. So, you are mainly losing the capability of type checking your development using external checkers. -/ axiom ofReduceNat (a b : Nat) (h : reduceNat a = b) : a = b end Lean namespace Std variable {α : Sort u} /-- `Associative op` indicates `op` is an associative operation, i.e. `(a ∘ b) ∘ c = a ∘ (b ∘ c)`. -/ class Associative (op : α → α → α) : Prop where /-- An associative operation satisfies `(a ∘ b) ∘ c = a ∘ (b ∘ c)`. -/ assoc : (a b c : α) → op (op a b) c = op a (op b c) /-- `Commutative op` says that `op` is a commutative operation, i.e. `a ∘ b = b ∘ a`. -/ class Commutative (op : α → α → α) : Prop where /-- A commutative operation satisfies `a ∘ b = b ∘ a`. -/ comm : (a b : α) → op a b = op b a /-- `IdempotentOp op` indicates `op` is an idempotent binary operation. i.e. `a ∘ a = a`. -/ class IdempotentOp (op : α → α → α) : Prop where /-- An idempotent operation satisfies `a ∘ a = a`. -/ idempotent : (x : α) → op x x = x /-- `LeftIdentify op o` indicates `o` is a left identity of `op`. This class does not require a proof that `o` is an identity, and is used primarily for infering the identity using class resoluton. -/ class LeftIdentity (op : α → β → β) (o : outParam α) : Prop /-- `LawfulLeftIdentify op o` indicates `o` is a verified left identity of `op`. -/ class LawfulLeftIdentity (op : α → β → β) (o : outParam α) extends LeftIdentity op o : Prop where /-- Left identity `o` is an identity. -/ left_id : ∀ a, op o a = a /-- `RightIdentify op o` indicates `o` is a right identity `o` of `op`. This class does not require a proof that `o` is an identity, and is used primarily for infering the identity using class resoluton. -/ class RightIdentity (op : α → β → α) (o : outParam β) : Prop /-- `LawfulRightIdentify op o` indicates `o` is a verified right identity of `op`. -/ class LawfulRightIdentity (op : α → β → α) (o : outParam β) extends RightIdentity op o : Prop where /-- Right identity `o` is an identity. -/ right_id : ∀ a, op a o = a /-- `Identity op o` indicates `o` is a left and right identity of `op`. This class does not require a proof that `o` is an identity, and is used primarily for infering the identity using class resoluton. -/ class Identity (op : α → α → α) (o : outParam α) extends LeftIdentity op o, RightIdentity op o : Prop /-- `LawfulIdentity op o` indicates `o` is a verified left and right identity of `op`. -/ class LawfulIdentity (op : α → α → α) (o : outParam α) extends Identity op o, LawfulLeftIdentity op o, LawfulRightIdentity op o : Prop /-- `LawfulCommIdentity` can simplify defining instances of `LawfulIdentity` on commutative functions by requiring only a left or right identity proof. This class is intended for simplifying defining instances of `LawfulIdentity` and functions needed commutative operations with identity should just add a `LawfulIdentity` constraint. -/ class LawfulCommIdentity (op : α → α → α) (o : outParam α) [hc : Commutative op] extends LawfulIdentity op o : Prop where left_id a := Eq.trans (hc.comm o a) (right_id a) right_id a := Eq.trans (hc.comm a o) (left_id a) end Std