lean4-htt/src/Init/PropLemmas.lean
Kim Morrison efe2ab4c04
chore: remove duplicate instances (#8397)
This PR cleans up many duplicate instances (or, in some cases,
needlessly duplicated `def X := ...; instance Y := X`).
2025-05-19 04:36:06 +00:00

751 lines
34 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Jeremy Avigad, Floris van Doorn, Mario Carneiro
This provides additional lemmas about propositional types beyond what is
needed for Core and SimpLemmas.
-/
module
prelude
import Init.Core
import Init.NotationExtra
set_option linter.missingDocs true -- keep it documented
/-! ## cast and equality -/
@[simp] theorem eq_mp_eq_cast (h : α = β) : Eq.mp h = cast h := rfl
@[simp] theorem eq_mpr_eq_cast (h : α = β) : Eq.mpr h = cast h.symm := rfl
@[simp] theorem cast_cast : ∀ (ha : α = β) (hb : β = γ) (a : α),
cast hb (cast ha a) = cast (ha.trans hb) a
| rfl, rfl, _ => rfl
@[simp] theorem eq_true_eq_id : Eq True = id := by
funext _; simp only [true_iff, id_def, eq_iff_iff]
theorem proof_irrel_heq {p q : Prop} (hp : p) (hq : q) : HEq hp hq := by
cases propext (iff_of_true hp hq); rfl
/-! ## not -/
theorem not_not_em (a : Prop) : ¬¬(a ¬a) := fun h => h (.inr (h ∘ .inl))
/-! ## and -/
theorem and_self_iff : a ∧ a ↔ a := Iff.of_eq (and_self a)
theorem and_not_self_iff (a : Prop) : a ∧ ¬a ↔ False := iff_false_intro and_not_self
theorem not_and_self_iff (a : Prop) : ¬a ∧ a ↔ False := iff_false_intro not_and_self
theorem And.imp (f : a → c) (g : b → d) (h : a ∧ b) : c ∧ d := And.intro (f h.left) (g h.right)
theorem And.imp_left (h : a → b) : a ∧ c → b ∧ c := .imp h id
theorem And.imp_right (h : a → b) : c ∧ a → c ∧ b := .imp id h
theorem and_congr (h₁ : a ↔ c) (h₂ : b ↔ d) : a ∧ b ↔ c ∧ d :=
Iff.intro (And.imp h₁.mp h₂.mp) (And.imp h₁.mpr h₂.mpr)
theorem and_congr_left' (h : a ↔ b) : a ∧ c ↔ b ∧ c := and_congr h .rfl
theorem and_congr_right' (h : b ↔ c) : a ∧ b ↔ a ∧ c := and_congr .rfl h
theorem not_and_of_not_left (b : Prop) : ¬a → ¬(a ∧ b) := mt And.left
theorem not_and_of_not_right (a : Prop) {b : Prop} : ¬b → ¬(a ∧ b) := mt And.right
theorem and_congr_right_eq (h : a → b = c) : (a ∧ b) = (a ∧ c) :=
propext (and_congr_right (Iff.of_eq ∘ h))
theorem and_congr_left_eq (h : c → a = b) : (a ∧ c) = (b ∧ c) :=
propext (and_congr_left (Iff.of_eq ∘ h))
theorem and_left_comm : a ∧ b ∧ c ↔ b ∧ a ∧ c :=
Iff.intro (fun ⟨ha, hb, hc⟩ => ⟨hb, ha, hc⟩)
(fun ⟨hb, ha, hc⟩ => ⟨ha, hb, hc⟩)
theorem and_right_comm : (a ∧ b) ∧ c ↔ (a ∧ c) ∧ b :=
Iff.intro (fun ⟨⟨ha, hb⟩, hc⟩ => ⟨⟨ha, hc⟩, hb⟩)
(fun ⟨⟨ha, hc⟩, hb⟩ => ⟨⟨ha, hb⟩, hc⟩)
theorem and_rotate : a ∧ b ∧ c ↔ b ∧ c ∧ a := by rw [and_left_comm, @and_comm a c]
theorem and_and_and_comm : (a ∧ b) ∧ c ∧ d ↔ (a ∧ c) ∧ b ∧ d := by rw [← and_assoc, @and_right_comm a, and_assoc]
theorem and_and_left : a ∧ (b ∧ c) ↔ (a ∧ b) ∧ a ∧ c := by rw [and_and_and_comm, and_self]
theorem and_and_right : (a ∧ b) ∧ c ↔ (a ∧ c) ∧ b ∧ c := by rw [and_and_and_comm, and_self]
theorem and_iff_left (hb : b) : a ∧ b ↔ a := Iff.intro And.left (And.intro · hb)
theorem and_iff_right (ha : a) : a ∧ b ↔ b := Iff.intro And.right (And.intro ha ·)
/-! ## or -/
theorem or_self_iff : a a ↔ a := or_self _ ▸ .rfl
theorem not_or_intro {a b : Prop} (ha : ¬a) (hb : ¬b) : ¬(a b) := (·.elim ha hb)
theorem or_congr (h₁ : a ↔ c) (h₂ : b ↔ d) : (a b) ↔ (c d) := ⟨.imp h₁.mp h₂.mp, .imp h₁.mpr h₂.mpr⟩
theorem or_congr_left (h : a ↔ b) : a c ↔ b c := or_congr h .rfl
theorem or_congr_right (h : b ↔ c) : a b ↔ a c := or_congr .rfl h
theorem or_left_comm : a (b c) ↔ b (a c) := by rw [← or_assoc, ← or_assoc, @or_comm a b]
theorem or_right_comm : (a b) c ↔ (a c) b := by rw [or_assoc, or_assoc, @or_comm b]
theorem or_or_or_comm : (a b) c d ↔ (a c) b d := by rw [← or_assoc, @or_right_comm a, or_assoc]
theorem or_or_distrib_left : a b c ↔ (a b) a c := by rw [or_or_or_comm, or_self]
theorem or_or_distrib_right : (a b) c ↔ (a c) b c := by rw [or_or_or_comm, or_self]
theorem or_rotate : a b c ↔ b c a := by simp only [or_left_comm, Or.comm]
theorem or_iff_left (hb : ¬b) : a b ↔ a := or_iff_left_iff_imp.mpr hb.elim
theorem or_iff_right (ha : ¬a) : a b ↔ b := or_iff_right_iff_imp.mpr ha.elim
/-! ## distributivity -/
theorem not_imp_of_and_not : a ∧ ¬b → ¬(a → b)
| ⟨ha, hb⟩, h => hb <| h ha
theorem imp_and {α} : (α → b ∧ c) ↔ (α → b) ∧ (α → c) :=
⟨fun h => ⟨fun ha => (h ha).1, fun ha => (h ha).2⟩, fun h ha => ⟨h.1 ha, h.2 ha⟩⟩
theorem not_and' : ¬(a ∧ b) ↔ b → ¬a := Iff.trans not_and imp_not_comm
/-- `∧` distributes over `` (on the left). -/
theorem and_or_left : a ∧ (b c) ↔ (a ∧ b) (a ∧ c) :=
Iff.intro (fun ⟨ha, hbc⟩ => hbc.imp (.intro ha) (.intro ha))
(Or.rec (.imp_right .inl) (.imp_right .inr))
/-- `∧` distributes over `` (on the right). -/
theorem or_and_right : (a b) ∧ c ↔ (a ∧ c) (b ∧ c) := by rw [@and_comm (a b), and_or_left, @and_comm c, @and_comm c]
/-- `` distributes over `∧` (on the left). -/
theorem or_and_left : a (b ∧ c) ↔ (a b) ∧ (a c) :=
Iff.intro (Or.rec (fun ha => ⟨.inl ha, .inl ha⟩) (.imp .inr .inr))
(And.rec <| .rec (fun _ => .inl ·) (.imp_right ∘ .intro))
/-- `` distributes over `∧` (on the right). -/
theorem and_or_right : (a ∧ b) c ↔ (a c) ∧ (b c) := by rw [@or_comm (a ∧ b), or_and_left, @or_comm c, @or_comm c]
theorem or_imp : (a b → c) ↔ (a → c) ∧ (b → c) :=
Iff.intro (fun h => ⟨h ∘ .inl, h ∘ .inr⟩) (fun ⟨ha, hb⟩ => Or.rec ha hb)
/-
`not_or` is made simp for confluence with `¬((b || c) = true)`:
Critical pair:
1. `¬(b = true c = true)` via `Bool.or_eq_true`.
2. `(b || c = false)` via `Bool.not_eq_true` which then
reduces to `b = false ∧ c = false` via Mathlib simp lemma
`Bool.or_eq_false_eq_eq_false_and_eq_false`.
Both reduce to `b = false ∧ c = false` via `not_or`.
-/
@[simp] theorem not_or : ¬(p q) ↔ ¬p ∧ ¬q := or_imp
theorem not_and_of_not_or_not (h : ¬a ¬b) : ¬(a ∧ b) := h.elim (mt (·.1)) (mt (·.2))
/-! ## not equal -/
theorem ne_of_apply_ne {α β : Sort _} (f : α → β) {x y : α} : f x ≠ f y → x ≠ y :=
mt <| congrArg _
/-! ## Ite -/
@[simp]
theorem if_false_left [h : Decidable p] :
ite p False q ↔ ¬p ∧ q := by cases h <;> (rename_i g; simp [g])
@[simp]
theorem if_false_right [h : Decidable p] :
ite p q False ↔ p ∧ q := by cases h <;> (rename_i g; simp [g])
/-
`if_true_left` and `if_true_right` are lower priority because
they introduce disjunctions and we prefer `if_false_left` and
`if_false_right` if they overlap.
-/
@[simp low]
theorem if_true_left [h : Decidable p] :
ite p True q ↔ ¬p → q := by cases h <;> (rename_i g; simp [g])
@[simp low]
theorem if_true_right [h : Decidable p] :
ite p q True ↔ p → q := by cases h <;> (rename_i g; simp [g])
/-- Negation of the condition `P : Prop` in a `dite` is the same as swapping the branches. -/
@[simp] theorem dite_not [hn : Decidable (¬p)] [h : Decidable p] (x : ¬p → α) (y : ¬¬p → α) :
dite (¬p) x y = dite p (fun h => y (not_not_intro h)) x := by
cases h <;> (rename_i g; simp [g])
/-- Negation of the condition `P : Prop` in a `ite` is the same as swapping the branches. -/
@[simp] theorem ite_not (p : Prop) [Decidable p] (x y : α) : ite (¬p) x y = ite p y x :=
dite_not (fun _ => x) (fun _ => y)
@[simp] theorem ite_then_self {p q : Prop} [h : Decidable p] : (if p then p else q) ↔ (¬p → q) := by
cases h <;> (rename_i g; simp [g])
@[simp] theorem ite_else_self {p q : Prop} [h : Decidable p] : (if p then q else p) ↔ (p ∧ q) := by
cases h <;> (rename_i g; simp [g])
@[simp] theorem ite_then_not_self {p : Prop} [Decidable p] {q : Prop} : (if p then ¬p else q) ↔ ¬p ∧ q := by
split <;> simp_all
@[simp] theorem ite_else_not_self {p : Prop} [Decidable p] {q : Prop} : (if p then q else ¬p) ↔ p → q := by
split <;> simp_all
/-- If two if-then-else statements only differ by the `Decidable` instances, they are equal. -/
-- This is useful for ensuring confluence, but rarely otherwise.
@[simp] theorem ite_eq_ite (p : Prop) {h h' : Decidable p} (x y : α) :
(@ite _ p h x y = @ite _ p h' x y) ↔ True := by
simp
congr
/-- If two if-then-else statements only differ by the `Decidable` instances, they are equal. -/
-- This is useful for ensuring confluence, but rarely otherwise.
@[simp] theorem ite_iff_ite (p : Prop) {h h' : Decidable p} (x y : Prop) :
(@ite _ p h x y ↔ @ite _ p h' x y) ↔ True := by
rw [iff_true]
suffices @ite _ p h x y = @ite _ p h' x y by simp [this]
congr
/-! ## exists and forall -/
section quantifiers
variable {p q : α → Prop} {b : Prop}
theorem forall_imp (h : ∀ a, p a → q a) : (∀ a, p a) → ∀ a, q a := fun h' a => h a (h' a)
/--
As `simp` does not index foralls, this `@[simp]` lemma is tried on every `forall` expression.
This is not ideal, and likely a performance issue, but it is difficult to remove this attribute at this time.
-/
@[simp] theorem forall_exists_index {q : (∃ x, p x) → Prop} :
(∀ h, q h) ↔ ∀ x (h : p x), q ⟨x, h⟩ :=
⟨fun h x hpx => h ⟨x, hpx⟩, fun h ⟨x, hpx⟩ => h x hpx⟩
theorem Exists.imp (h : ∀ a, p a → q a) : (∃ a, p a) → ∃ a, q a
| ⟨a, hp⟩ => ⟨a, h a hp⟩
theorem Exists.imp' {β} {q : β → Prop} (f : α → β) (hpq : ∀ a, p a → q (f a)) :
(∃ a, p a) → ∃ b, q b
| ⟨_, hp⟩ => ⟨_, hpq _ hp⟩
theorem exists_imp : ((∃ x, p x) → b) ↔ ∀ x, p x → b := forall_exists_index
theorem exists₂_imp {P : (x : α) → p x → Prop} : (∃ x h, P x h) → b ↔ ∀ x h, P x h → b := by simp
@[simp] theorem exists_const (α) [i : Nonempty α] : (∃ _ : α, b) ↔ b :=
⟨fun ⟨_, h⟩ => h, i.elim Exists.intro⟩
@[congr]
theorem exists_prop_congr {p p' : Prop} {q q' : p → Prop} (hq : ∀ h, q h ↔ q' h) (hp : p ↔ p') :
Exists q ↔ ∃ h : p', q' (hp.2 h) :=
⟨fun ⟨_, _⟩ ↦ ⟨hp.1 _, (hq _).1 _⟩, fun ⟨_, _⟩ ↦ ⟨_, (hq _).2 _⟩⟩
theorem exists_prop_of_true {p : Prop} {q : p → Prop} (h : p) : (Exists fun h' : p => q h') ↔ q h :=
@exists_const (q h) p ⟨h⟩
@[simp] theorem exists_true_left {p : True → Prop} : Exists p ↔ p True.intro :=
exists_prop_of_true _
section forall_congr
theorem forall_congr' (h : ∀ a, p a ↔ q a) : (∀ a, p a) ↔ ∀ a, q a :=
⟨fun H a => (h a).1 (H a), fun H a => (h a).2 (H a)⟩
theorem exists_congr (h : ∀ a, p a ↔ q a) : (∃ a, p a) ↔ ∃ a, q a :=
⟨Exists.imp fun x => (h x).1, Exists.imp fun x => (h x).2⟩
variable {β : α → Sort _}
theorem forall₂_congr {p q : ∀ a, β a → Prop} (h : ∀ a b, p a b ↔ q a b) :
(∀ a b, p a b) ↔ ∀ a b, q a b :=
forall_congr' fun a => forall_congr' <| h a
theorem exists₂_congr {p q : ∀ a, β a → Prop} (h : ∀ a b, p a b ↔ q a b) :
(∃ a b, p a b) ↔ ∃ a b, q a b :=
exists_congr fun a => exists_congr <| h a
variable {γ : ∀ a, β a → Sort _}
theorem forall₃_congr {p q : ∀ a b, γ a b → Prop} (h : ∀ a b c, p a b c ↔ q a b c) :
(∀ a b c, p a b c) ↔ ∀ a b c, q a b c :=
forall_congr' fun a => forall₂_congr <| h a
theorem exists₃_congr {p q : ∀ a b, γ a b → Prop} (h : ∀ a b c, p a b c ↔ q a b c) :
(∃ a b c, p a b c) ↔ ∃ a b c, q a b c :=
exists_congr fun a => exists₂_congr <| h a
variable {δ : ∀ a b, γ a b → Sort _}
theorem forall₄_congr {p q : ∀ a b c, δ a b c → Prop} (h : ∀ a b c d, p a b c d ↔ q a b c d) :
(∀ a b c d, p a b c d) ↔ ∀ a b c d, q a b c d :=
forall_congr' fun a => forall₃_congr <| h a
theorem exists₄_congr {p q : ∀ a b c, δ a b c → Prop} (h : ∀ a b c d, p a b c d ↔ q a b c d) :
(∃ a b c d, p a b c d) ↔ ∃ a b c d, q a b c d :=
exists_congr fun a => exists₃_congr <| h a
variable {ε : ∀ a b c, δ a b c → Sort _}
theorem forall₅_congr {p q : ∀ a b c d, ε a b c d → Prop}
(h : ∀ a b c d e, p a b c d e ↔ q a b c d e) :
(∀ a b c d e, p a b c d e) ↔ ∀ a b c d e, q a b c d e :=
forall_congr' fun a => forall₄_congr <| h a
theorem exists₅_congr {p q : ∀ a b c d, ε a b c d → Prop}
(h : ∀ a b c d e, p a b c d e ↔ q a b c d e) :
(∃ a b c d e, p a b c d e) ↔ ∃ a b c d e, q a b c d e :=
exists_congr fun a => exists₄_congr <| h a
end forall_congr
@[simp] theorem not_exists : (¬∃ x, p x) ↔ ∀ x, ¬p x := exists_imp
theorem forall_not_of_not_exists (h : ¬∃ x, p x) : ∀ x, ¬p x := not_exists.mp h
theorem not_exists_of_forall_not (h : ∀ x, ¬p x) : ¬∃ x, p x := not_exists.mpr h
theorem forall_and : (∀ x, p x ∧ q x) ↔ (∀ x, p x) ∧ (∀ x, q x) :=
⟨fun h => ⟨fun x => (h x).1, fun x => (h x).2⟩, fun ⟨h₁, h₂⟩ x => ⟨h₁ x, h₂ x⟩⟩
theorem exists_or : (∃ x, p x q x) ↔ (∃ x, p x) ∃ x, q x :=
⟨fun | ⟨x, .inl h⟩ => .inl ⟨x, h⟩ | ⟨x, .inr h⟩ => .inr ⟨x, h⟩,
fun | .inl ⟨x, h⟩ => ⟨x, .inl h⟩ | .inr ⟨x, h⟩ => ⟨x, .inr h⟩⟩
@[simp] theorem exists_false : ¬(∃ _a : α, False) := fun ⟨_, h⟩ => h
@[simp] theorem forall_const (α : Sort _) [i : Nonempty α] : (α → b) ↔ b :=
⟨i.elim, fun hb _ => hb⟩
theorem Exists.nonempty : (∃ x, p x) → Nonempty α | ⟨x, _⟩ => ⟨x⟩
@[deprecated Exists.nonempty (since := "2025-05-19")]
theorem nonempty_of_exists {α : Sort u} {p : α → Prop} : Exists (fun x => p x) → Nonempty α
| ⟨w, _⟩ => ⟨w⟩
theorem not_forall_of_exists_not {p : α → Prop} : (∃ x, ¬p x) → ¬∀ x, p x
| ⟨x, hn⟩, h => hn (h x)
@[simp] theorem forall_eq {p : α → Prop} {a' : α} : (∀ a, a = a' → p a) ↔ p a' :=
⟨fun h => h a' rfl, fun h _ e => e.symm ▸ h⟩
@[simp] theorem forall_eq' {a' : α} : (∀ a, a' = a → p a) ↔ p a' := by simp [@eq_comm _ a']
@[simp] theorem exists_eq : ∃ a, a = a' := ⟨_, rfl⟩
@[simp] theorem exists_eq' : ∃ a, a' = a := ⟨_, rfl⟩
@[simp] theorem exists_eq_left : (∃ a, a = a' ∧ p a) ↔ p a' :=
⟨fun ⟨_, e, h⟩ => e ▸ h, fun h => ⟨_, rfl, h⟩⟩
@[simp] theorem exists_eq_right : (∃ a, p a ∧ a = a') ↔ p a' :=
(exists_congr <| by exact fun a => And.comm).trans exists_eq_left
@[simp] theorem exists_and_left : (∃ x, b ∧ p x) ↔ b ∧ (∃ x, p x) :=
⟨fun ⟨x, h, hp⟩ => ⟨h, x, hp⟩, fun ⟨h, x, hp⟩ => ⟨x, h, hp⟩⟩
@[simp] theorem exists_and_right : (∃ x, p x ∧ b) ↔ (∃ x, p x) ∧ b := by simp [And.comm]
@[simp] theorem exists_eq_left' : (∃ a, a' = a ∧ p a) ↔ p a' := by simp [@eq_comm _ a']
@[simp] theorem exists_eq_right' : (∃ a, p a ∧ a' = a) ↔ p a' := by simp [@eq_comm _ a']
@[simp] theorem exists_prop_eq {p : (a : α) → a = a' → Prop} :
(∃ (a : α) (h : a = a'), p a h) ↔ p a' rfl :=
⟨fun ⟨_, e, h⟩ => e ▸ h, fun h => ⟨_, rfl, h⟩⟩
@[simp] theorem exists_prop_eq' {p : (a : α) → a' = a → Prop} :
(∃ (a : α) (h : a' = a), p a h) ↔ p a' rfl := by simp [@eq_comm _ a']
@[simp] theorem forall_eq_or_imp : (∀ a, a = a' q a → p a) ↔ p a' ∧ ∀ a, q a → p a := by
simp only [or_imp, forall_and, forall_eq]
@[simp] theorem exists_eq_or_imp : (∃ a, (a = a' q a) ∧ p a) ↔ p a' ∃ a, q a ∧ p a := by
simp only [or_and_right, exists_or, exists_eq_left]
@[simp] theorem exists_eq_right_right : (∃ (a : α), p a ∧ q a ∧ a = a') ↔ p a' ∧ q a' := by
simp [← and_assoc]
@[simp] theorem exists_eq_right_right' : (∃ (a : α), p a ∧ q a ∧ a' = a) ↔ p a' ∧ q a' := by
simp [@eq_comm _ a']
@[simp] theorem exists_or_eq_left (y : α) (p : α → Prop) : ∃ x : α, x = y p x := ⟨y, .inl rfl⟩
@[simp] theorem exists_or_eq_right (y : α) (p : α → Prop) : ∃ x : α, p x x = y := ⟨y, .inr rfl⟩
@[simp] theorem exists_or_eq_left' (y : α) (p : α → Prop) : ∃ x : α, y = x p x := ⟨y, .inl rfl⟩
@[simp] theorem exists_or_eq_right' (y : α) (p : α → Prop) : ∃ x : α, p x y = x := ⟨y, .inr rfl⟩
theorem exists_prop' {p : Prop} : (∃ _ : α, p) ↔ Nonempty α ∧ p :=
⟨fun ⟨a, h⟩ => ⟨⟨a⟩, h⟩, fun ⟨⟨a⟩, h⟩ => ⟨a, h⟩⟩
@[simp] theorem exists_prop : (∃ _h : a, b) ↔ a ∧ b :=
⟨fun ⟨hp, hq⟩ => ⟨hp, hq⟩, fun ⟨hp, hq⟩ => ⟨hp, hq⟩⟩
@[simp] theorem exists_idem {P : Prop} (f : P → P → Sort _) :
(∃ (p₁ : P), ∃ (p₂ : P), f p₁ p₂) ↔ ∃ (p : P), f p p :=
⟨fun ⟨p, _, h⟩ => ⟨p, h⟩, fun ⟨p, h⟩ => ⟨p, p, h⟩⟩
@[simp] theorem exists_apply_eq_apply (f : α → β) (a' : α) : ∃ a, f a = f a' := ⟨a', rfl⟩
theorem forall_prop_of_true {p : Prop} {q : p → Prop} (h : p) : (∀ h' : p, q h') ↔ q h :=
@forall_const (q h) p ⟨h⟩
theorem forall_comm {p : α → β → Prop} : (∀ a b, p a b) ↔ (∀ b a, p a b) :=
⟨fun h b a => h a b, fun h a b => h b a⟩
theorem exists_comm {p : α → β → Prop} : (∃ a b, p a b) ↔ (∃ b a, p a b) :=
⟨fun ⟨a, b, h⟩ => ⟨b, a, h⟩, fun ⟨b, a, h⟩ => ⟨a, b, h⟩⟩
@[simp] theorem forall_apply_eq_imp_iff {f : α → β} {p : β → Prop} :
(∀ b a, f a = b → p b) ↔ ∀ a, p (f a) := by simp [forall_comm]
@[simp] theorem forall_eq_apply_imp_iff {f : α → β} {p : β → Prop} :
(∀ b a, b = f a → p b) ↔ ∀ a, p (f a) := by simp [forall_comm]
@[simp] theorem forall_apply_eq_imp_iff₂ {f : α → β} {p : α → Prop} {q : β → Prop} :
(∀ b a, p a → f a = b → q b) ↔ ∀ a, p a → q (f a) :=
⟨fun h a ha => h (f a) a ha rfl, fun h _ a ha hb => hb ▸ h a ha⟩
theorem forall_prop_of_false {p : Prop} {q : p → Prop} (hn : ¬p) : (∀ h' : p, q h') ↔ True :=
iff_true_intro fun h => hn.elim h
@[simp] theorem and_exists_self (P : Prop) (Q : P → Prop) : (P ∧ ∃ p, Q p) ↔ ∃ p, Q p :=
⟨fun ⟨_, h⟩ => h, fun ⟨p, q⟩ => ⟨p, ⟨p, q⟩⟩⟩
@[simp] theorem exists_and_self (P : Prop) (Q : P → Prop) : ((∃ p, Q p) ∧ P) ↔ ∃ p, Q p :=
⟨fun ⟨h, _⟩ => h, fun ⟨p, q⟩ => ⟨⟨p, q⟩, p⟩⟩
@[simp] theorem forall_self_imp (P : Prop) (Q : P → Prop) : (∀ p : P, P → Q p) ↔ ∀ p, Q p :=
⟨fun h p => h p p, fun h _ p => h p⟩
end quantifiers
/-! ## membership -/
section Mem
variable [Membership α β] {s t : β} {a b : α}
theorem ne_of_mem_of_not_mem (h : a ∈ s) : b ∉ s → a ≠ b := mt fun e => e ▸ h
theorem ne_of_mem_of_not_mem' (h : a ∈ s) : a ∉ t → s ≠ t := mt fun e => e ▸ h
end Mem
/-! ## Nonempty -/
@[simp] theorem nonempty_prop {p : Prop} : Nonempty p ↔ p :=
⟨fun ⟨h⟩ => h, fun h => ⟨h⟩⟩
/-! ## decidable -/
@[simp] theorem Decidable.not_not [Decidable p] : ¬¬p ↔ p := ⟨of_not_not, not_not_intro⟩
/-- Excluded middle. Added as alias for Decidable.em -/
abbrev Decidable.or_not_self := em
/-- Excluded middle commuted. Added as alias for Decidable.em -/
theorem Decidable.not_or_self (p : Prop) [h : Decidable p] : ¬p p := by
cases h <;> simp [*]
theorem Decidable.by_contra [Decidable p] : (¬p → False) → p := of_not_not
/-- Construct a non-Prop by cases on an `Or`, when the left conjunct is decidable. -/
protected def Or.by_cases [Decidable p] {α : Sort u} (h : p q) (h₁ : p → α) (h₂ : q → α) : α :=
if hp : p then h₁ hp else h₂ (h.resolve_left hp)
/-- Construct a non-Prop by cases on an `Or`, when the right conjunct is decidable. -/
protected def Or.by_cases' [Decidable q] {α : Sort u} (h : p q) (h₁ : p → α) (h₂ : q → α) : α :=
if hq : q then h₂ hq else h₁ (h.resolve_right hq)
instance exists_prop_decidable {p} (P : p → Prop)
[Decidable p] [∀ h, Decidable (P h)] : Decidable (∃ h, P h) :=
if h : p then
decidable_of_decidable_of_iff ⟨fun h2 => ⟨h, h2⟩, fun ⟨_, h2⟩ => h2⟩
else isFalse fun ⟨h', _⟩ => h h'
instance forall_prop_decidable {p} (P : p → Prop)
[Decidable p] [∀ h, Decidable (P h)] : Decidable (∀ h, P h) :=
if h : p then
decidable_of_decidable_of_iff ⟨fun h2 _ => h2, fun al => al h⟩
else isTrue fun h2 => absurd h2 h
@[bool_to_prop] theorem decide_eq_true_iff {p : Prop} [Decidable p] : (decide p = true) ↔ p := by simp
@[simp, bool_to_prop] theorem decide_eq_decide {p q : Prop} {_ : Decidable p} {_ : Decidable q} :
decide p = decide q ↔ (p ↔ q) :=
⟨fun h => by rw [← decide_eq_true_iff (p := p), h, decide_eq_true_iff], fun h => by simp [h]⟩
theorem Decidable.of_not_imp [Decidable a] (h : ¬(a → b)) : a :=
byContradiction (not_not_of_not_imp h)
theorem Decidable.not_imp_symm [Decidable a] (h : ¬a → b) (hb : ¬b) : a :=
byContradiction <| hb ∘ h
theorem Decidable.not_imp_comm [Decidable a] [Decidable b] : (¬a → b) ↔ (¬b → a) :=
⟨not_imp_symm, not_imp_symm⟩
theorem Decidable.not_imp_self [Decidable a] : (¬a → a) ↔ a := by
have := @imp_not_self (¬a); rwa [not_not] at this
theorem Decidable.or_iff_not_imp_left [Decidable a] : a b ↔ (¬a → b) :=
⟨Or.resolve_left, fun h => dite _ .inl (.inr ∘ h)⟩
theorem Decidable.or_iff_not_imp_right [Decidable b] : a b ↔ (¬b → a) :=
or_comm.trans or_iff_not_imp_left
theorem Decidable.not_imp_not [Decidable a] : (¬a → ¬b) ↔ (b → a) :=
⟨fun h hb => byContradiction (h · hb), mt⟩
theorem Decidable.not_or_of_imp [Decidable a] (h : a → b) : ¬a b :=
if ha : a then .inr (h ha) else .inl ha
theorem Decidable.imp_iff_not_or [Decidable a] : (a → b) ↔ (¬a b) :=
⟨not_or_of_imp, Or.neg_resolve_left⟩
theorem Decidable.imp_iff_or_not [Decidable b] : b → a ↔ a ¬b :=
Decidable.imp_iff_not_or.trans or_comm
theorem Decidable.imp_or [Decidable a] : (a → b c) ↔ (a → b) (a → c) :=
if h : a then by
rw [imp_iff_right h, imp_iff_right h, imp_iff_right h]
else by
rw [iff_false_intro h, false_imp_iff, false_imp_iff, true_or]
theorem Decidable.imp_or' [Decidable b] : (a → b c) ↔ (a → b) (a → c) :=
if h : b then by simp [h] else by
rw [eq_false h, false_or]; exact (or_iff_right_of_imp fun hx x => (hx x).elim).symm
theorem Decidable.not_imp_iff_and_not [Decidable a] : ¬(a → b) ↔ a ∧ ¬b :=
⟨fun h => ⟨of_not_imp h, not_of_not_imp h⟩, not_imp_of_and_not⟩
theorem Decidable.peirce (a b : Prop) [Decidable a] : ((a → b) → a) → a :=
if ha : a then fun _ => ha else fun h => h ha.elim
theorem peirce' {a : Prop} (H : ∀ b : Prop, (a → b) → a) : a := H _ id
theorem Decidable.not_iff_not [Decidable a] [Decidable b] : (¬a ↔ ¬b) ↔ (a ↔ b) := by
rw [@iff_def (¬a), @iff_def' a]; exact and_congr not_imp_not not_imp_not
theorem Decidable.not_iff_comm [Decidable a] [Decidable b] : (¬a ↔ b) ↔ (¬b ↔ a) := by
rw [@iff_def (¬a), @iff_def (¬b)]; exact and_congr not_imp_comm imp_not_comm
theorem Decidable.not_iff [Decidable b] : ¬(a ↔ b) ↔ (¬a ↔ b) :=
if h : b then by
rw [iff_true_right h, iff_true_right h]
else by
rw [iff_false_right h, iff_false_right h]
theorem Decidable.iff_not_comm [Decidable a] [Decidable b] : (a ↔ ¬b) ↔ (b ↔ ¬a) := by
rw [@iff_def a, @iff_def b]; exact and_congr imp_not_comm not_imp_comm
theorem Decidable.iff_iff_and_or_not_and_not {a b : Prop} [Decidable b] :
(a ↔ b) ↔ (a ∧ b) (¬a ∧ ¬b) :=
⟨fun e => if h : b then .inl ⟨e.2 h, h⟩ else .inr ⟨mt e.1 h, h⟩,
Or.rec (And.rec iff_of_true) (And.rec iff_of_false)⟩
theorem Decidable.iff_iff_not_or_and_or_not [Decidable a] [Decidable b] :
(a ↔ b) ↔ (¬a b) ∧ (a ¬b) := by
rw [iff_iff_implies_and_implies (a := a) (b := b)]; simp only [imp_iff_not_or, Or.comm]
theorem Decidable.not_and_not_right [Decidable b] : ¬(a ∧ ¬b) ↔ (a → b) :=
⟨fun h ha => not_imp_symm (And.intro ha) h, fun h ⟨ha, hb⟩ => hb <| h ha⟩
theorem Decidable.not_and_iff_not_or_not [Decidable a] : ¬(a ∧ b) ↔ ¬a ¬b :=
⟨fun h => if ha : a then .inr (h ⟨ha, ·⟩) else .inl ha, not_and_of_not_or_not⟩
set_option linter.missingDocs false in
@[deprecated Decidable.not_and_iff_not_or_not (since := "2025-03-18")]
abbrev Decidable.not_and_iff_or_not_not := @Decidable.not_and_iff_not_or_not
theorem Decidable.not_and_iff_not_or_not' [Decidable b] : ¬(a ∧ b) ↔ ¬a ¬b :=
⟨fun h => if hb : b then .inl (h ⟨·, hb⟩) else .inr hb, not_and_of_not_or_not⟩
set_option linter.missingDocs false in
@[deprecated Decidable.not_and_iff_not_or_not' (since := "2025-03-18")]
abbrev Decidable.not_and_iff_or_not_not' := @Decidable.not_and_iff_not_or_not'
theorem Decidable.or_iff_not_not_and_not [Decidable a] [Decidable b] : a b ↔ ¬(¬a ∧ ¬b) := by
rw [← not_or, not_not]
set_option linter.missingDocs false in
@[deprecated Decidable.or_iff_not_not_and_not (since := "2025-03-18")]
abbrev Decidable.or_iff_not_and_not := @Decidable.or_iff_not_not_and_not
theorem Decidable.and_iff_not_not_or_not [Decidable a] [Decidable b] : a ∧ b ↔ ¬(¬a ¬b) := by
rw [← not_and_iff_not_or_not, not_not]
set_option linter.missingDocs false in
@[deprecated Decidable.and_iff_not_not_or_not (since := "2025-03-18")]
abbrev Decidable.and_iff_not_or_not := @Decidable.and_iff_not_not_or_not
theorem Decidable.imp_iff_right_iff [Decidable a] : (a → b ↔ b) ↔ a b :=
Iff.intro
(fun h => (Decidable.em a).imp_right fun ha' => h.mp fun ha => (ha' ha).elim)
(fun ab => ab.elim imp_iff_right fun hb => iff_of_true (fun _ => hb) hb)
theorem Decidable.imp_iff_left_iff [Decidable a] : (b ↔ a → b) ↔ a b :=
propext (@Iff.comm (a → b) b) ▸ (@Decidable.imp_iff_right_iff a b _)
theorem Decidable.and_or_imp [Decidable a] : a ∧ b (a → c) ↔ a → b c :=
if ha : a then by simp only [ha, true_and, true_imp_iff]
else by simp only [ha, false_or, false_and, false_imp_iff]
theorem Decidable.or_congr_left' [Decidable c] (h : ¬c → (a ↔ b)) : a c ↔ b c := by
rw [or_iff_not_imp_right, or_iff_not_imp_right]; exact imp_congr_right h
theorem Decidable.or_congr_right' [Decidable a] (h : ¬a → (b ↔ c)) : a b ↔ a c := by
rw [or_iff_not_imp_left, or_iff_not_imp_left]; exact imp_congr_right h
@[simp] theorem Decidable.iff_congr_left {P Q R : Prop} [Decidable P] [Decidable Q] [Decidable R] :
((P ↔ R) ↔ (Q ↔ R)) ↔ (P ↔ Q) :=
if h : R then by simp_all [Decidable.not_iff_not] else by simp_all [Decidable.not_iff_not]
@[simp] theorem Decidable.iff_congr_right {P Q R : Prop} [Decidable P] [Decidable Q] [Decidable R] :
((P ↔ Q) ↔ (P ↔ R)) ↔ (Q ↔ R) :=
if h : P then by simp_all [Decidable.not_iff_not] else by simp_all [Decidable.not_iff_not]
/-- Transfer decidability of `a` to decidability of `b`, if the propositions are equivalent.
**Important**: this function should be used instead of `rw` on `Decidable b`, because the
kernel will get stuck reducing the usage of `propext` otherwise,
and `decide` will not work. -/
@[inline] def decidable_of_iff (a : Prop) (h : a ↔ b) [Decidable a] : Decidable b :=
decidable_of_decidable_of_iff h
/-- Transfer decidability of `b` to decidability of `a`, if the propositions are equivalent.
This is the same as `decidable_of_iff` but the iff is flipped. -/
@[inline, expose] def decidable_of_iff' (b : Prop) (h : a ↔ b) [Decidable b] : Decidable a :=
decidable_of_decidable_of_iff h.symm
instance Decidable.predToBool (p : α → Prop) [DecidablePred p] :
CoeDep (α → Prop) p (α → Bool) := ⟨fun b => decide <| p b⟩
instance [DecidablePred p] : DecidablePred (p ∘ f) :=
fun x => inferInstanceAs (Decidable (p (f x)))
/-- Prove that `a` is decidable by constructing a boolean `b` and a proof that `b ↔ a`.
(This is sometimes taken as an alternate definition of decidability.) -/
def decidable_of_bool : ∀ (b : Bool), (b ↔ a) → Decidable a
| true, h => isTrue (h.1 rfl)
| false, h => isFalse (mt h.2 Bool.noConfusion)
protected theorem Decidable.not_forall {p : α → Prop} [Decidable (∃ x, ¬p x)]
[∀ x, Decidable (p x)] : (¬∀ x, p x) ↔ ∃ x, ¬p x :=
⟨Decidable.not_imp_symm fun nx x => Decidable.not_imp_symm (fun h => ⟨x, h⟩) nx,
not_forall_of_exists_not⟩
protected theorem Decidable.not_forall_not {p : α → Prop} [Decidable (∃ x, p x)] :
(¬∀ x, ¬p x) ↔ ∃ x, p x :=
(@Decidable.not_iff_comm _ _ _ (decidable_of_iff (¬∃ x, p x) not_exists)).1 not_exists
protected theorem Decidable.not_exists_not {p : α → Prop} [∀ x, Decidable (p x)] :
(¬∃ x, ¬p x) ↔ ∀ x, p x := by
simp only [not_exists, Decidable.not_not]
export Decidable (not_imp_self)
/-
`decide_implies` simp justification.
We have a critical pair from `decide (¬(p ∧ q))`:
1. `decide (p → ¬q)` via `not_and`
2. `!decide (p ∧ q)` via `decide_not` This further refines to
`!(decide p) || !(decide q)` via `Bool.decide_and` (in Mathlib) and
`Bool.not_and` (made simp in Mathlib).
We introduce `decide_implies` below and then both normalize to
`!(decide p) || !(decide q)`.
-/
@[simp]
theorem decide_implies (u v : Prop)
[duv : Decidable (u → v)] [du : Decidable u] {dv : u → Decidable v}
: decide (u → v) = dite u (fun h => @decide v (dv h)) (fun _ => true) :=
if h : u then by
simp [h]
else by
simp [h]
/-
`decide_ite` is needed to resolve critical pair with
We have a critical pair from `decide (ite p b c = true)`:
1. `ite p b c` via `decide_coe`
2. `decide (ite p (b = true) (c = true))` via `Bool.ite_eq_true_distrib`.
We introduce `decide_ite` so both normalize to `ite p b c`.
-/
@[simp]
theorem decide_ite (u : Prop) [du : Decidable u] (p q : Prop)
[dpq : Decidable (ite u p q)] [dp : Decidable p] [dq : Decidable q] :
decide (ite u p q) = ite u (decide p) (decide q) := by
cases du <;> simp [*]
/- Confluence for `ite_then_self` and `decide_ite`. -/
@[simp] theorem ite_then_decide_self (p : Prop) [h : Decidable p] {w : Decidable p} (q : Bool) :
(@ite _ p h (decide p) q) = (decide p || q) := by
split <;> simp_all
/- Confluence for `ite_else_self` and `decide_ite`. -/
@[simp] theorem ite_else_decide_self (p : Prop) [h : Decidable p] {w : Decidable p} (q : Bool) :
(@ite _ p h q (decide p)) = (decide p && q) := by
split <;> simp_all
@[simp] theorem ite_then_decide_not_self (p : Prop) [h : Decidable p] {w : Decidable p} (q : Bool) :
(@ite _ p h (!decide p) q) = (!decide p && q) := by
split <;> simp_all
@[simp] theorem ite_else_decide_not_self (p : Prop) [h : Decidable p] {w : Decidable p} (q : Bool) :
(@ite _ p h q (!decide p)) = (!decide p || q) := by
split <;> simp_all
attribute [local simp] Decidable.imp_iff_left_iff
@[simp] theorem dite_eq_left_iff {p : Prop} [Decidable p] {x : α} {y : ¬ p → α} : (if h : p then x else y h) = x ↔ ∀ h : ¬ p, y h = x := by
split <;> simp_all
@[simp] theorem dite_eq_right_iff {p : Prop} [Decidable p] {x : p → α} {y : α} : (if h : p then x h else y) = y ↔ ∀ h : p, x h = y := by
split <;> simp_all
@[simp] theorem left_eq_dite_iff {p : Prop} [Decidable p] {x : α} {y : ¬ p → α} : x = (if h : p then x else y h) ↔ ∀ h : ¬ p, x = y h := by
split <;> simp_all
@[simp] theorem right_eq_dite_iff {p : Prop} [Decidable p] {x : p → α} {y : α} : y = (if h : p then x h else y) ↔ ∀ h : p, y = x h := by
split <;> simp_all
@[simp] theorem dite_iff_left_iff {p : Prop} [Decidable p] {x : Prop} {y : ¬ p → Prop} : ((if h : p then x else y h) ↔ x) ↔ ∀ h : ¬ p, y h ↔ x := by
split <;> simp_all
@[simp] theorem dite_iff_right_iff {p : Prop} [Decidable p] {x : p → Prop} {y : Prop} : ((if h : p then x h else y) ↔ y) ↔ ∀ h : p, x h ↔ y := by
split <;> simp_all
@[simp] theorem left_iff_dite_iff {p : Prop} [Decidable p] {x : Prop} {y : ¬ p → Prop} : (x ↔ (if h : p then x else y h)) ↔ ∀ h : ¬ p, x ↔ y h := by
split <;> simp_all
@[simp] theorem right_iff_dite_iff {p : Prop} [Decidable p] {x : p → Prop} {y : Prop} : (y ↔ (if h : p then x h else y)) ↔ ∀ h : p, y ↔ x h := by
split <;> simp_all
@[simp] theorem ite_eq_left_iff {p : Prop} [Decidable p] {x y : α} : (if p then x else y) = x ↔ ¬ p → y = x := by
split <;> simp_all
@[simp] theorem ite_eq_right_iff {p : Prop} [Decidable p] {x y : α} : (if p then x else y) = y ↔ p → x = y := by
split <;> simp_all
@[simp] theorem left_eq_ite_iff {p : Prop} [Decidable p] {x y : α} : x = (if p then x else y) ↔ ¬ p → x = y := by
split <;> simp_all
@[simp] theorem right_eq_ite_iff {p : Prop} [Decidable p] {x y : α} : y = (if p then x else y) ↔ p → y = x := by
split <;> simp_all
@[simp] theorem ite_iff_left_iff {p : Prop} [Decidable p] {x y : Prop} : ((if p then x else y) ↔ x) ↔ ¬ p → y = x := by
split <;> simp_all
@[simp] theorem ite_iff_right_iff {p : Prop} [Decidable p] {x y : Prop} : ((if p then x else y) ↔ y) ↔ p → x = y := by
split <;> simp_all
@[simp] theorem left_iff_ite_iff {p : Prop} [Decidable p] {x y : Prop} : (x ↔ (if p then x else y)) ↔ ¬ p → x = y := by
split <;> simp_all
@[simp] theorem right_iff_ite_iff {p : Prop} [Decidable p] {x y : Prop} : (y ↔ (if p then x else y)) ↔ p → y = x := by
split <;> simp_all
@[simp] theorem dite_then_false {p : Prop} [Decidable p] {x : ¬ p → Prop} : (if h : p then False else x h) ↔ ∃ h : ¬ p, x h := by
split <;> simp_all
@[simp] theorem dite_else_false {p : Prop} [Decidable p] {x : p → Prop} : (if h : p then x h else False) ↔ ∃ h : p, x h := by
split <;> simp_all
@[simp] theorem dite_then_true {p : Prop} [Decidable p] {x : ¬ p → Prop} : (if h : p then True else x h) ↔ ∀ h : ¬ p, x h := by
split <;> simp_all
@[simp] theorem dite_else_true {p : Prop} [Decidable p] {x : p → Prop} : (if h : p then x h else True) ↔ ∀ h : p, x h := by
split <;> simp_all