/-
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Jeremy Avigad, Floris van Doorn
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.core

universes u v w l u_1 r s

namespace Mathlib

@[simp] theorem opt_param_eq (α : Sort u) (default : α) : optParam α default = α := rfl

def id {α : Sort u} (a : α) : α := a

def flip {α : Sort u} {β : Sort v} {φ : Sort w} (f : α → β → φ) : β → α → φ :=
  fun (b : β) (a : α) => f a b

/- implication -/

def implies (a : Prop) (b : Prop) := a → b

/-- Implication `→` is transitive. If `P → Q` and `Q → R` then `P → R`. -/
theorem implies.trans {p : Prop} {q : Prop} {r : Prop} (h₁ : implies p q) (h₂ : implies q r) :
    implies p r :=
  fun (hp : p) => h₂ (h₁ hp)

def trivial : True := True.intro

/-- We can't have `a` and `¬a`, that would be absurd!-/
def absurd {a : Prop} {b : Sort v} (h₁ : a) (h₂ : ¬a) : b := False._oldrec (h₂ h₁)

theorem not.intro {a : Prop} (h : a → False) : ¬a := h

/-- Modus tollens. If an implication is true, then so is its contrapositive. -/
theorem mt {a : Prop} {b : Prop} (h₁ : a → b) (h₂ : ¬b) : ¬a := fun (ha : a) => h₂ (h₁ ha)

/- not -/

theorem not_false : ¬False := id

def non_contradictory (a : Prop) := ¬¬a

theorem non_contradictory_intro {a : Prop} (ha : a) : ¬¬a := fun (hna : ¬a) => absurd ha hna

/- false -/

def false.elim {C : Sort u} (h : False) : C := False._oldrec h

/- eq -/

-- proof irrelevance is built in

theorem proof_irrel {a : Prop} (h₁ : a) (h₂ : a) : h₁ = h₂ := rfl

@[simp] theorem id.def {α : Sort u} (a : α) : id a = a := rfl

def eq.mp {α : Sort u} {β : Sort u} : α = β → α → β := eq.rec_on

def eq.mpr {α : Sort u} {β : Sort u} : α = β → β → α :=
  fun (h₁ : α = β) (h₂ : β) => eq.rec_on sorry h₂

theorem eq.substr {α : Sort u} {p : α → Prop} {a : α} {b : α} (h₁ : b = a) : p a → p b :=
  Eq.subst (Eq.symm h₁)

theorem congr {α : Sort u} {β : Sort v} {f₁ : α → β} {f₂ : α → β} {a₁ : α} {a₂ : α} (h₁ : f₁ = f₂)
    (h₂ : a₁ = a₂) : f₁ a₁ = f₂ a₂ :=
  h₁ ▸ h₂ ▸ rfl

theorem congr_fun {α : Sort u} {β : α → Sort v} {f : (x : α) → β x} {g : (x : α) → β x} (h : f = g)
    (a : α) : f a = g a :=
  h ▸ Eq.refl (f a)

theorem congr_arg {α : Sort u} {β : Sort v} {a₁ : α} {a₂ : α} (f : α → β) : a₁ = a₂ → f a₁ = f a₂ :=
  congr rfl

theorem trans_rel_left {α : Sort u} {a : α} {b : α} {c : α} (r : α → α → Prop) (h₁ : r a b)
    (h₂ : b = c) : r a c :=
  h₂ ▸ h₁

theorem trans_rel_right {α : Sort u} {a : α} {b : α} {c : α} (r : α → α → Prop) (h₁ : a = b)
    (h₂ : r b c) : r a c :=
  Eq.symm h₁ ▸ h₂

theorem of_eq_true {p : Prop} (h : p = True) : p := Eq.symm h ▸ trivial

theorem not_of_eq_false {p : Prop} (h : p = False) : ¬p := fun (hp : p) => h ▸ hp

def cast {α : Sort u} {β : Sort u} (h : α = β) (a : α) : β := Eq._oldrec a h

theorem cast_proof_irrel {α : Sort u} {β : Sort u} (h₁ : α = β) (h₂ : α = β) (a : α) :
    cast h₁ a = cast h₂ a :=
  rfl

theorem cast_eq {α : Sort u} (h : α = α) (a : α) : cast h a = a := rfl

/- ne -/

def ne {α : Sort u} (a : α) (b : α) := ¬a = b

infixl:50 " ≠ " => Mathlib.ne

@[simp] theorem ne.def {α : Sort u} (a : α) (b : α) : a ≠ b = (¬a = b) := rfl

namespace ne

theorem intro {α : Sort u} {a : α} {b : α} (h : a = b → False) : a ≠ b := h

theorem elim {α : Sort u} {a : α} {b : α} (h : a ≠ b) : a = b → False := h

theorem irrefl {α : Sort u} {a : α} (h : a ≠ a) : False := h rfl

theorem symm {α : Sort u} {a : α} {b : α} (h : a ≠ b) : b ≠ a := fun (h₁ : b = a) => h (Eq.symm h₁)

end ne

theorem false_of_ne {α : Sort u} {a : α} : a ≠ a → False := ne.irrefl

theorem ne_false_of_self {p : Prop} : p → p ≠ False := fun (hp : p) (heq : p = False) => heq ▸ hp

theorem ne_true_of_not {p : Prop} : ¬p → p ≠ True :=
  fun (hnp : ¬p) (heq : p = True) => Eq.subst heq hnp trivial

theorem true_ne_false : ¬True = False := ne_false_of_self trivial

theorem heq.elim {α : Sort u} {a : α} {p : α → Sort v} {b : α} (h₁ : a == b) : p a → p b :=
  eq.rec_on (eq_of_heq h₁)

theorem heq.subst {α : Sort u} {β : Sort u} {a : α} {b : β} {p : (T : Sort u) → T → Prop} :
    a == b → p α a → p β b :=
  heq.rec_on

theorem heq.symm {α : Sort u} {β : Sort u} {a : α} {b : β} (h : a == b) : b == a :=
  heq.rec_on h (HEq.refl a)

theorem heq_of_eq {α : Sort u} {a : α} {a' : α} (h : a = a') : a == a' := h ▸ HEq.refl a

theorem heq.trans {α : Sort u} {β : Sort u} {φ : Sort u} {a : α} {b : β} {c : φ} (h₁ : a == b)
    (h₂ : b == c) : a == c :=
  HEq.subst h₂ h₁

theorem heq_of_heq_of_eq {α : Sort u} {β : Sort u} {a : α} {b : β} {b' : β} (h₁ : a == b)
    (h₂ : b = b') : a == b' :=
  HEq.trans h₁ (heq_of_eq h₂)

theorem heq_of_eq_of_heq {α : Sort u} {β : Sort u} {a : α} {a' : α} {b : β} (h₁ : a = a')
    (h₂ : a' == b) : a == b :=
  HEq.trans (heq_of_eq h₁) h₂

def type_eq_of_heq {α : Sort u} {β : Sort u} {a : α} {b : β} (h : a == b) : α = β :=
  heq.rec_on h (Eq.refl α)

theorem eq_rec_heq {α : Sort u} {φ : α → Sort v} {a : α} {a' : α} (h : a = a') (p : φ a) :
    eq.rec_on h p == p :=
  sorry

theorem heq_of_eq_rec_left {α : Sort u} {φ : α → Sort v} {a : α} {a' : α} {p₁ : φ a} {p₂ : φ a'}
    (e : a = a') (h₂ : eq.rec_on e p₁ = p₂) : p₁ == p₂ :=
  sorry

theorem heq_of_eq_rec_right {α : Sort u} {φ : α → Sort v} {a : α} {a' : α} {p₁ : φ a} {p₂ : φ a'}
    (e : a' = a) (h₂ : p₁ = eq.rec_on e p₂) : p₁ == p₂ :=
  sorry

theorem of_heq_true {a : Prop} (h : a == True) : a := of_eq_true (eq_of_heq h)

theorem eq_rec_compose {α : Sort u} {β : Sort u} {φ : Sort u} (p₁ : β = φ) (p₂ : α = β) (a : α) :
    eq.rec_on p₁ (eq.rec_on p₂ a) = eq.rec_on (Eq.trans p₂ p₁) a :=
  sorry

theorem cast_heq {α : Sort u} {β : Sort u} (h : α = β) (a : α) : cast h a == a := sorry

infixr:35 " /\ " => Mathlib.and

infixr:35 " ∧ " => Mathlib.and

/- and -/

theorem and.elim {a : Prop} {b : Prop} {c : Prop} (h₁ : a ∧ b) (h₂ : a → b → c) : c :=
  And._oldrec h₂ h₁

theorem and.swap {a : Prop} {b : Prop} : a ∧ b → b ∧ a :=
  fun (_x : a ∧ b) =>
    (fun (_a : a ∧ b) =>
        and.dcases_on _a
          fun (left : a) (right : b) => idRhs (b ∧ a) { left := right, right := left })
      _x

def and.symm {a : Prop} {b : Prop} : a ∧ b → b ∧ a := and.swap

infixr:30 " \/ " => Mathlib.or

infixr:30 " ∨ " => Mathlib.or

/- or -/

namespace or

theorem elim {a : Prop} {b : Prop} {c : Prop} (h₁ : a ∨ b) (h₂ : a → c) (h₃ : b → c) : c :=
  Or._oldrec h₂ h₃ h₁

end or

theorem non_contradictory_em (a : Prop) : ¬¬(a ∨ ¬a) :=
  fun (not_em : ¬(a ∨ ¬a)) =>
    (fun (neg_a : ¬a) => absurd (Or.inr neg_a) not_em)
      fun (pos_a : a) => absurd (Or.inl pos_a) not_em

def not_not_em (a : Prop) : ¬¬(a ∨ ¬a) := non_contradictory_em

theorem or.swap {a : Prop} {b : Prop} : a ∨ b → b ∨ a := Or._oldrec Or.inr Or.inl

def or.symm {a : Prop} {b : Prop} : a ∨ b → b ∨ a := or.swap

/- xor -/

def xor (a : Prop) (b : Prop) := a ∧ ¬b ∨ b ∧ ¬a

/- iff -/

/-- `iff P Q`, with notation `P ↔ Q`, is the proposition asserting that `P` and `Q` are equivalent,
that is, have the same truth value. -/
not found

infixl:20 " <-> " => Mathlib.iff

infixl:20 " ↔ " => Mathlib.iff

theorem iff.elim {a : Prop} {b : Prop} {c : Prop} : ((a → b) → (b → a) → c) → (a ↔ b) → c :=
  Iff._oldrec

theorem iff.elim_left {a : Prop} {b : Prop} : (a ↔ b) → a → b := iff.mp

theorem iff.elim_right {a : Prop} {b : Prop} : (a ↔ b) → b → a := iff.mpr

theorem iff_iff_implies_and_implies (a : Prop) (b : Prop) : a ↔ b ↔ (a → b) ∧ (b → a) :=
  { mp := fun (h : a ↔ b) => { left := iff.mp h, right := iff.mpr h },
    mpr := fun (h : (a → b) ∧ (b → a)) => { mp := and.left h, mpr := and.right h } }

theorem iff.refl (a : Prop) : a ↔ a := { mp := fun (h : a) => h, mpr := fun (h : a) => h }

theorem iff.rfl {a : Prop} : a ↔ a := iff.refl a

theorem iff.trans {a : Prop} {b : Prop} {c : Prop} (h₁ : a ↔ b) (h₂ : b ↔ c) : a ↔ c :=
  { mp := fun (ha : a) => iff.mp h₂ (iff.mp h₁ ha),
    mpr := fun (hc : c) => iff.mpr h₁ (iff.mpr h₂ hc) }

theorem iff.symm {a : Prop} {b : Prop} (h : a ↔ b) : b ↔ a :=
  { mp := iff.elim_right h, mpr := iff.elim_left h }

theorem iff.comm {a : Prop} {b : Prop} : a ↔ b ↔ (b ↔ a) := { mp := iff.symm, mpr := iff.symm }

theorem eq.to_iff {a : Prop} {b : Prop} (h : a = b) : a ↔ b := eq.rec_on h iff.rfl

theorem neq_of_not_iff {a : Prop} {b : Prop} : ¬(a ↔ b) → a ≠ b :=
  fun (h₁ : ¬(a ↔ b)) (h₂ : a = b) => (fun (this : a ↔ b) => absurd this h₁) (h₂ ▸ iff.refl a)

theorem not_iff_not_of_iff {a : Prop} {b : Prop} (h₁ : a ↔ b) : ¬a ↔ ¬b :=
  { mp := fun (hna : ¬a) (hb : b) => hna (iff.elim_right h₁ hb),
    mpr := fun (hnb : ¬b) (ha : a) => hnb (iff.elim_left h₁ ha) }

theorem of_iff_true {a : Prop} (h : a ↔ True) : a := iff.mp (iff.symm h) trivial

theorem not_of_iff_false {a : Prop} : (a ↔ False) → ¬a := iff.mp

theorem iff_true_intro {a : Prop} (h : a) : a ↔ True :=
  { mp := fun (hl : a) => trivial, mpr := fun (hr : True) => h }

theorem iff_false_intro {a : Prop} (h : ¬a) : a ↔ False := { mp := h, mpr := False._oldrec }

theorem not_non_contradictory_iff_absurd (a : Prop) : ¬¬¬a ↔ ¬a :=
  { mp := fun (hl : ¬¬¬a) (ha : a) => hl (non_contradictory_intro ha), mpr := absurd }

def not_not_not_iff (a : Prop) : ¬¬¬a ↔ ¬a := not_non_contradictory_iff_absurd

theorem imp_congr {a : Prop} {b : Prop} {c : Prop} {d : Prop} (h₁ : a ↔ c) (h₂ : b ↔ d) :
    a → b ↔ c → d :=
  { mp := fun (hab : a → b) (hc : c) => iff.mp h₂ (hab (iff.mpr h₁ hc)),
    mpr := fun (hcd : c → d) (ha : a) => iff.mpr h₂ (hcd (iff.mp h₁ ha)) }

theorem imp_congr_ctx {a : Prop} {b : Prop} {c : Prop} {d : Prop} (h₁ : a ↔ c) (h₂ : c → (b ↔ d)) :
    a → b ↔ c → d :=
  { mp :=
      fun (hab : a → b) (hc : c) =>
        (fun (ha : a) => (fun (hb : b) => iff.mp (h₂ hc) hb) (hab ha)) (iff.mpr h₁ hc),
    mpr :=
      fun (hcd : c → d) (ha : a) =>
        (fun (hc : c) => (fun (hd : d) => iff.mpr (h₂ hc) hd) (hcd hc)) (iff.mp h₁ ha) }

theorem imp_congr_right {a : Prop} {b : Prop} {c : Prop} (h : a → (b ↔ c)) : a → b ↔ a → c :=
  { mp := fun (hab : a → b) (ha : a) => iff.elim_left (h ha) (hab ha),
    mpr := fun (hab : a → c) (ha : a) => iff.elim_right (h ha) (hab ha) }

theorem not_not_intro {a : Prop} (ha : a) : ¬¬a := fun (hna : ¬a) => hna ha

theorem not_of_not_not_not {a : Prop} (h : ¬¬¬a) : ¬a := fun (ha : a) => absurd (not_not_intro ha) h

@[simp] theorem not_true : ¬True ↔ False := iff_false_intro (not_not_intro trivial)

def not_true_iff : ¬True ↔ False := not_true

@[simp] theorem not_false_iff : ¬False ↔ True := iff_true_intro not_false

theorem not_congr {a : Prop} {b : Prop} (h : a ↔ b) : ¬a ↔ ¬b :=
  { mp := fun (h₁ : ¬a) (h₂ : b) => h₁ (iff.mpr h h₂),
    mpr := fun (h₁ : ¬b) (h₂ : a) => h₁ (iff.mp h h₂) }

@[simp] theorem ne_self_iff_false {α : Sort u} (a : α) : ¬a = a ↔ False :=
  { mp := false_of_ne, mpr := false.elim }

@[simp] theorem eq_self_iff_true {α : Sort u} (a : α) : a = a ↔ True := iff_true_intro rfl

@[simp] theorem heq_self_iff_true {α : Sort u} (a : α) : a == a ↔ True :=
  iff_true_intro (HEq.refl a)

@[simp] theorem iff_not_self (a : Prop) : a ↔ ¬a ↔ False :=
  iff_false_intro
    fun (h : a ↔ ¬a) => (fun (h' : ¬a) => h' (iff.mpr h h')) fun (ha : a) => iff.mp h ha ha

@[simp] theorem not_iff_self (a : Prop) : ¬a ↔ a ↔ False :=
  iff_false_intro
    fun (h : ¬a ↔ a) => (fun (h' : ¬a) => h' (iff.mp h h')) fun (ha : a) => iff.mpr h ha ha

@[simp] theorem true_iff_false : True ↔ False ↔ False :=
  iff_false_intro fun (h : True ↔ False) => iff.mp h trivial

@[simp] theorem false_iff_true : False ↔ True ↔ False :=
  iff_false_intro fun (h : False ↔ True) => iff.mpr h trivial

theorem false_of_true_iff_false : (True ↔ False) → False :=
  fun (h : True ↔ False) => iff.mp h trivial

theorem false_of_true_eq_false : True = False → False := fun (h : True = False) => h ▸ trivial

theorem true_eq_false_of_false : False → True = False := false.elim

theorem eq_comm {α : Sort u} {a : α} {b : α} : a = b ↔ b = a := { mp := Eq.symm, mpr := Eq.symm }

/- and simp rules -/

theorem and.imp {a : Prop} {b : Prop} {c : Prop} {d : Prop} (hac : a → c) (hbd : b → d) :
    a ∧ b → c ∧ d :=
  sorry

def and_implies {a : Prop} {b : Prop} {c : Prop} {d : Prop} (hac : a → c) (hbd : b → d) :
    a ∧ b → c ∧ d :=
  and.imp

theorem and_congr {a : Prop} {b : Prop} {c : Prop} {d : Prop} (h₁ : a ↔ c) (h₂ : b ↔ d) :
    a ∧ b ↔ c ∧ d :=
  { mp := and.imp (iff.mp h₁) (iff.mp h₂), mpr := and.imp (iff.mpr h₁) (iff.mpr h₂) }

theorem and_congr_right {a : Prop} {b : Prop} {c : Prop} (h : a → (b ↔ c)) : a ∧ b ↔ a ∧ c := sorry

theorem and.comm {a : Prop} {b : Prop} : a ∧ b ↔ b ∧ a := { mp := and.swap, mpr := and.swap }

theorem and_comm (a : Prop) (b : Prop) : a ∧ b ↔ b ∧ a := and.comm

theorem and.assoc {a : Prop} {b : Prop} {c : Prop} : (a ∧ b) ∧ c ↔ a ∧ b ∧ c := sorry

theorem and_assoc {c : Prop} (a : Prop) (b : Prop) : (a ∧ b) ∧ c ↔ a ∧ b ∧ c := and.assoc

theorem and.left_comm {a : Prop} {b : Prop} {c : Prop} : a ∧ b ∧ c ↔ b ∧ a ∧ c :=
  iff.trans (iff.symm and.assoc) (iff.trans (and_congr and.comm (iff.refl c)) and.assoc)

theorem and_iff_left {a : Prop} {b : Prop} (hb : b) : a ∧ b ↔ a :=
  { mp := and.left, mpr := fun (ha : a) => { left := ha, right := hb } }

theorem and_iff_right {a : Prop} {b : Prop} (ha : a) : a ∧ b ↔ b :=
  { mp := and.right, mpr := And.intro ha }

@[simp] theorem and_true (a : Prop) : a ∧ True ↔ a := and_iff_left trivial

@[simp] theorem true_and (a : Prop) : True ∧ a ↔ a := and_iff_right trivial

@[simp] theorem and_false (a : Prop) : a ∧ False ↔ False := iff_false_intro and.right

@[simp] theorem false_and (a : Prop) : False ∧ a ↔ False := iff_false_intro and.left

@[simp] theorem not_and_self (a : Prop) : ¬a ∧ a ↔ False :=
  iff_false_intro fun (h : ¬a ∧ a) => and.elim h fun (h₁ : ¬a) (h₂ : a) => absurd h₂ h₁

@[simp] theorem and_not_self (a : Prop) : a ∧ ¬a ↔ False :=
  iff_false_intro
    fun (_x : a ∧ ¬a) =>
      (fun (_a : a ∧ ¬a) =>
          and.dcases_on _a fun (left : a) (right : ¬a) => idRhs False (absurd left right))
        _x

@[simp] theorem and_self (a : Prop) : a ∧ a ↔ a :=
  { mp := and.left, mpr := fun (h : a) => { left := h, right := h } }

/- or simp rules -/

theorem or.imp {a : Prop} {b : Prop} {c : Prop} {d : Prop} (h₂ : a → c) (h₃ : b → d) :
    a ∨ b → c ∨ d :=
  Or._oldrec (fun (h : a) => Or.inl (h₂ h)) fun (h : b) => Or.inr (h₃ h)

theorem or.imp_left {a : Prop} {b : Prop} {c : Prop} (h : a → b) : a ∨ c → b ∨ c := or.imp h id

theorem or.imp_right {a : Prop} {b : Prop} {c : Prop} (h : a → b) : c ∨ a → c ∨ b := or.imp id h

theorem or_congr {a : Prop} {b : Prop} {c : Prop} {d : Prop} (h₁ : a ↔ c) (h₂ : b ↔ d) :
    a ∨ b ↔ c ∨ d :=
  { mp := or.imp (iff.mp h₁) (iff.mp h₂), mpr := or.imp (iff.mpr h₁) (iff.mpr h₂) }

theorem or.comm {a : Prop} {b : Prop} : a ∨ b ↔ b ∨ a := { mp := or.swap, mpr := or.swap }

theorem or_comm (a : Prop) (b : Prop) : a ∨ b ↔ b ∨ a := or.comm

theorem or.assoc {a : Prop} {b : Prop} {c : Prop} : (a ∨ b) ∨ c ↔ a ∨ b ∨ c :=
  { mp := Or._oldrec (or.imp_right Or.inl) fun (h : c) => Or.inr (Or.inr h),
    mpr := Or._oldrec (fun (h : a) => Or.inl (Or.inl h)) (or.imp_left Or.inr) }

theorem or_assoc {c : Prop} (a : Prop) (b : Prop) : (a ∨ b) ∨ c ↔ a ∨ b ∨ c := or.assoc

theorem or.left_comm {a : Prop} {b : Prop} {c : Prop} : a ∨ b ∨ c ↔ b ∨ a ∨ c :=
  iff.trans (iff.symm or.assoc) (iff.trans (or_congr or.comm (iff.refl c)) or.assoc)

theorem or_iff_right_of_imp {a : Prop} {b : Prop} (ha : a → b) : a ∨ b ↔ b :=
  { mp := Or._oldrec ha id, mpr := Or.inr }

theorem or_iff_left_of_imp {a : Prop} {b : Prop} (hb : b → a) : a ∨ b ↔ a :=
  { mp := Or._oldrec id hb, mpr := Or.inl }

@[simp] theorem or_true (a : Prop) : a ∨ True ↔ True := iff_true_intro (Or.inr trivial)

@[simp] theorem true_or (a : Prop) : True ∨ a ↔ True := iff_true_intro (Or.inl trivial)

@[simp] theorem or_false (a : Prop) : a ∨ False ↔ a :=
  { mp := Or._oldrec id false.elim, mpr := Or.inl }

@[simp] theorem false_or (a : Prop) : False ∨ a ↔ a := iff.trans or.comm (or_false a)

@[simp] theorem or_self (a : Prop) : a ∨ a ↔ a := { mp := Or._oldrec id id, mpr := Or.inl }

theorem not_or {a : Prop} {b : Prop} : ¬a → ¬b → ¬(a ∨ b) :=
  fun (ᾰ : ¬a) (ᾰ_1 : ¬b) (ᾰ_2 : a ∨ b) =>
    or.dcases_on ᾰ_2 (fun (ᾰ_1 : a) => idRhs False (absurd ᾰ_1 ᾰ))
      fun (ᾰ_1_1 : b) => idRhs False (absurd ᾰ_1_1 ᾰ_1)

/- or resolution rulse -/

def or.resolve_left {a : Prop} {b : Prop} (h : a ∨ b) (na : ¬a) : b :=
  or.elim h (fun (ha : a) => absurd ha na) id

def or.neg_resolve_left {a : Prop} {b : Prop} (h : ¬a ∨ b) (ha : a) : b :=
  or.elim h (fun (na : ¬a) => absurd ha na) id

def or.resolve_right {a : Prop} {b : Prop} (h : a ∨ b) (nb : ¬b) : a :=
  or.elim h id fun (hb : b) => absurd hb nb

def or.neg_resolve_right {a : Prop} {b : Prop} (h : a ∨ ¬b) (hb : b) : a :=
  or.elim h id fun (nb : ¬b) => absurd hb nb

/- iff simp rules -/

@[simp] theorem iff_true (a : Prop) : a ↔ True ↔ a :=
  { mp := fun (h : a ↔ True) => iff.mpr h trivial, mpr := iff_true_intro }

@[simp] theorem true_iff (a : Prop) : True ↔ a ↔ a := iff.trans iff.comm (iff_true a)

@[simp] theorem iff_false (a : Prop) : a ↔ False ↔ ¬a := { mp := iff.mp, mpr := iff_false_intro }

@[simp] theorem false_iff (a : Prop) : False ↔ a ↔ ¬a := iff.trans iff.comm (iff_false a)

@[simp] theorem iff_self (a : Prop) : a ↔ a ↔ True := iff_true_intro iff.rfl

theorem iff_congr {a : Prop} {b : Prop} {c : Prop} {d : Prop} (h₁ : a ↔ c) (h₂ : b ↔ d) :
    a ↔ b ↔ (c ↔ d) :=
  iff.trans (iff_iff_implies_and_implies a b)
    (iff.trans (and_congr (imp_congr h₁ h₂) (imp_congr h₂ h₁))
      (iff.symm (iff_iff_implies_and_implies c d)))

/- implies simp rule -/

@[simp] theorem implies_true_iff (α : Sort u) : α → True ↔ True :=
  { mp := fun (h : α → True) => trivial, mpr := fun (ha : True) (h : α) => trivial }

@[simp] theorem false_implies_iff (a : Prop) : False → a ↔ True :=
  { mp := fun (h : False → a) => trivial, mpr := fun (ha : True) (h : False) => false.elim h }

@[simp] theorem true_implies_iff (α : Prop) : True → α ↔ α :=
  { mp := fun (h : True → α) => h trivial, mpr := fun (h : α) (h' : True) => h }

/--
The existential quantifier.

To prove a goal of the form `⊢ ∃ x, p x`, you can provide a witness `y` with the tactic `existsi y`.
If you are working in a project that depends on mathlib, then we recommend the `use` tactic
instead.
You'll then be left with the goal `⊢ p y`.

To extract a witness `x` and proof `hx : p x` from a hypothesis `h : ∃ x, p x`,
use the tactic `cases h with x hx`. See also the mathlib tactics `obtain` and `rcases`.
-/
not found

def exists.intro {α : Sort u_1} {p : α → Prop} (w : α) (h : p w) : Exists p := Exists.intro

theorem exists.elim {α : Sort u} {p : α → Prop} {b : Prop} (h₁ : ∃ (x : α), p x)
    (h₂ : ∀ (a : α), p a → b) : b :=
  Exists._oldrec h₂ h₁

/- exists unique -/

def exists_unique {α : Sort u} (p : α → Prop) := ∃ (x : α), p x ∧ ∀ (y : α), p y → y = x

theorem exists_unique.intro {α : Sort u} {p : α → Prop} (w : α) (h₁ : p w)
    (h₂ : ∀ (y : α), p y → y = w) : exists_unique fun (x : α) => p x :=
  exists.intro w { left := h₁, right := h₂ }

theorem exists_unique.elim {α : Sort u} {p : α → Prop} {b : Prop}
    (h₂ : exists_unique fun (x : α) => p x) (h₁ : ∀ (x : α), p x → (∀ (y : α), p y → y = x) → b) :
    b :=
  exists.elim h₂
    fun (w : α) (hw : (fun (x : α) => p x) w ∧ ∀ (y : α), p y → y = w) =>
      h₁ w (and.left hw) (and.right hw)

theorem exists_unique_of_exists_of_unique {α : Type u} {p : α → Prop} (hex : ∃ (x : α), p x)
    (hunique : ∀ (y₁ y₂ : α), p y₁ → p y₂ → y₁ = y₂) : exists_unique fun (x : α) => p x :=
  exists.elim hex
    fun (x : α) (px : p x) =>
      exists_unique.intro x px fun (y : α) (this : p y) => hunique y x this px

theorem exists_of_exists_unique {α : Sort u} {p : α → Prop} (h : exists_unique fun (x : α) => p x) :
    ∃ (x : α), p x :=
  exists.elim h
    fun (x : α) (hx : (fun (x : α) => p x) x ∧ ∀ (y : α), p y → y = x) =>
      Exists.intro x (and.left hx)

theorem unique_of_exists_unique {α : Sort u} {p : α → Prop} (h : exists_unique fun (x : α) => p x)
    {y₁ : α} {y₂ : α} (py₁ : p y₁) (py₂ : p y₂) : y₁ = y₂ :=
  exists_unique.elim h
    fun (x : α) (this : p x) (unique : ∀ (y : α), p y → y = x) =>
      (fun (this : y₁ = y₂) => this) (Eq.trans (unique y₁ py₁) (Eq.symm (unique y₂ py₂)))

/- exists, forall, exists unique congruences -/

theorem forall_congr {α : Sort u} {p : α → Prop} {q : α → Prop} (h : ∀ (a : α), p a ↔ q a) :
    (∀ (a : α), p a) ↔ ∀ (a : α), q a :=
  { mp := fun (p_1 : ∀ (a : α), p a) (a : α) => iff.mp (h a) (p_1 a),
    mpr := fun (q_1 : ∀ (a : α), q a) (a : α) => iff.mpr (h a) (q_1 a) }

theorem exists_imp_exists {α : Sort u} {p : α → Prop} {q : α → Prop} (h : ∀ (a : α), p a → q a) :
    (∃ (a : α), p a) → ∃ (a : α), q a :=
  fun (p_1 : ∃ (a : α), p a) => exists.elim p_1 fun (a : α) (hp : p a) => Exists.intro a (h a hp)

theorem exists_congr {α : Sort u} {p : α → Prop} {q : α → Prop} (h : ∀ (a : α), p a ↔ q a) :
    Exists p ↔ ∃ (a : α), q a :=
  { mp := exists_imp_exists fun (a : α) => iff.mp (h a),
    mpr := exists_imp_exists fun (a : α) => iff.mpr (h a) }

theorem exists_unique_congr {α : Sort u} {p₁ : α → Prop} {p₂ : α → Prop}
    (h : ∀ (x : α), p₁ x ↔ p₂ x) : exists_unique p₁ ↔ exists_unique fun (x : α) => p₂ x :=
  exists_congr fun (x : α) => and_congr (h x) (forall_congr fun (y : α) => imp_congr (h y) iff.rfl)

theorem forall_not_of_not_exists {α : Sort u} {p : α → Prop} :
    (¬∃ (x : α), p x) → ∀ (x : α), ¬p x :=
  fun (hne : ¬∃ (x : α), p x) (x : α) (hp : p x) => hne (Exists.intro x hp)

/- decidable -/

def decidable.to_bool (p : Prop) [h : Decidable p] : Bool :=
  decidable.cases_on h (fun (h₁ : ¬p) => false) fun (h₂ : p) => tt

@[simp] theorem to_bool_true_eq_tt (h : Decidable True) : to_bool True = tt :=
  decidable.cases_on h (fun (h : ¬True) => false.elim (iff.mp not_true h)) fun (_x : True) => rfl

@[simp] theorem to_bool_false_eq_ff (h : Decidable False) : to_bool False = false :=
  decidable.cases_on h (fun (h : ¬False) => rfl) fun (h : False) => false.elim h

protected instance decidable.true : Decidable True := is_true trivial

protected instance decidable.false : Decidable False := is_false not_false

-- We use "dependent" if-then-else to be able to communicate the if-then-else condition

-- to the branches

def dite (c : Prop) [h : Decidable c] {α : Sort u} : (c → α) → (¬c → α) → α :=
  fun (t : c → α) (e : ¬c → α) => decidable.rec_on h e t

/- if-then-else -/

def ite (c : Prop) [h : Decidable c] {α : Sort u} (t : α) (e : α) : α :=
  decidable.rec_on h (fun (hnc : ¬c) => e) fun (hc : c) => t

namespace decidable

def rec_on_true {p : Prop} [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u} (h₃ : p)
    (h₄ : h₁ h₃) : decidable.rec_on h h₂ h₁ :=
  decidable.rec_on h (fun (h : ¬p) => False._oldrec (h h₃)) fun (h : p) => h₄

def rec_on_false {p : Prop} [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u} (h₃ : ¬p)
    (h₄ : h₂ h₃) : decidable.rec_on h h₂ h₁ :=
  decidable.rec_on h (fun (h : ¬p) => h₄) fun (h : p) => False._oldrec (h₃ h)

def by_cases {p : Prop} {q : Sort u} [φ : Decidable p] : (p → q) → (¬p → q) → q := dite p

theorem em (p : Prop) [Decidable p] : p ∨ ¬p := by_cases Or.inl Or.inr

theorem by_contradiction {p : Prop} [Decidable p] (h : ¬p → False) : p :=
  dite p (fun (h₁ : p) => h₁) fun (h₁ : ¬p) => False._oldrec (h h₁)

theorem of_not_not {p : Prop} [Decidable p] : ¬¬p → p :=
  fun (hnn : ¬¬p) => by_contradiction fun (hn : ¬p) => absurd hn hnn

theorem not_not_iff (p : Prop) [Decidable p] : ¬¬p ↔ p := { mp := of_not_not, mpr := not_not_intro }

theorem not_and_iff_or_not (p : Prop) (q : Prop) [d₁ : Decidable p] [d₂ : Decidable q] :
    ¬(p ∧ q) ↔ ¬p ∨ ¬q :=
  sorry

theorem not_or_iff_and_not (p : Prop) (q : Prop) [d₁ : Decidable p] [d₂ : Decidable q] :
    ¬(p ∨ q) ↔ ¬p ∧ ¬q :=
  sorry

end decidable

def decidable_of_decidable_of_iff {p : Prop} {q : Prop} (hp : Decidable p) (h : p ↔ q) :
    Decidable q :=
  dite p (fun (hp : p) => is_true (iff.mp h hp)) fun (hp : ¬p) => is_false sorry

def decidable_of_decidable_of_eq {p : Prop} {q : Prop} (hp : Decidable p) (h : p = q) :
    Decidable q :=
  decidable_of_decidable_of_iff hp (eq.to_iff h)

protected def or.by_cases {p : Prop} {q : Prop} [Decidable p] [Decidable q] {α : Sort u} (h : p ∨ q)
    (h₁ : p → α) (h₂ : q → α) : α :=
  dite p (fun (hp : p) => h₁ hp)
    fun (hp : ¬p) => dite q (fun (hq : q) => h₂ hq) fun (hq : ¬q) => False._oldrec (or.elim h hp hq)

protected instance and.decidable {p : Prop} {q : Prop} [Decidable p] [Decidable q] :
    Decidable (p ∧ q) :=
  dite p
    (fun (hp : p) =>
      dite q (fun (hq : q) => is_true { left := hp, right := hq }) fun (hq : ¬q) => is_false sorry)
    fun (hp : ¬p) => is_false sorry

protected instance or.decidable {p : Prop} {q : Prop} [Decidable p] [Decidable q] :
    Decidable (p ∨ q) :=
  dite p (fun (hp : p) => is_true (Or.inl hp))
    fun (hp : ¬p) =>
      dite q (fun (hq : q) => is_true (Or.inr hq)) fun (hq : ¬q) => is_false (Or._oldrec hp hq)

protected instance not.decidable {p : Prop} [Decidable p] : Decidable (¬p) :=
  dite p (fun (hp : p) => is_false (absurd hp)) fun (hp : ¬p) => is_true hp

protected instance implies.decidable {p : Prop} {q : Prop} [Decidable p] [Decidable q] :
    Decidable (p → q) :=
  dite p (fun (hp : p) => dite q (fun (hq : q) => is_true sorry) fun (hq : ¬q) => is_false sorry)
    fun (hp : ¬p) => is_true sorry

protected instance iff.decidable {p : Prop} {q : Prop} [Decidable p] [Decidable q] :
    Decidable (p ↔ q) :=
  dite p (fun (hp : p) => dite q (fun (hq : q) => is_true sorry) fun (hq : ¬q) => is_false sorry)
    fun (hp : ¬p) => dite q (fun (hq : q) => is_false sorry) fun (hq : ¬q) => is_true sorry

protected instance xor.decidable {p : Prop} {q : Prop} [Decidable p] [Decidable q] :
    Decidable (xor p q) :=
  dite p (fun (hp : p) => dite q (fun (hq : q) => is_false sorry) fun (hq : ¬q) => is_true sorry)
    fun (hp : ¬p) => dite q (fun (hq : q) => is_true sorry) fun (hq : ¬q) => is_false sorry

protected instance exists_prop_decidable {p : Prop} (P : p → Prop) [Dp : Decidable p]
    [DP : (h : p) → Decidable (P h)] : Decidable (∃ (h : p), P h) :=
  dite p (fun (h : p) => decidable_of_decidable_of_iff (DP h) sorry) fun (h : ¬p) => is_false sorry

protected instance forall_prop_decidable {p : Prop} (P : p → Prop) [Dp : Decidable p]
    [DP : (h : p) → Decidable (P h)] : Decidable (∀ (h : p), P h) :=
  dite p (fun (h : p) => decidable_of_decidable_of_iff (DP h) sorry) fun (h : ¬p) => is_true sorry

protected instance ne.decidable {α : Sort u} [DecidableEq α] (a : α) (b : α) : Decidable (a ≠ b) :=
  implies.decidable

theorem bool.ff_ne_tt : false = tt → False :=
  fun (ᾰ : false = tt) =>
    eq.dcases_on ᾰ (fun (H_1 : tt = false) => bool.no_confusion H_1) (Eq.refl tt) (HEq.refl ᾰ)

def is_dec_eq {α : Sort u} (p : α → α → Bool) := ∀ {x y : α}, p x y = tt → x = y

def is_dec_refl {α : Sort u} (p : α → α → Bool) := ∀ (x : α), p x x = tt

protected instance bool.decidable_eq : DecidableEq Bool := sorry

def decidable_eq_of_bool_pred {α : Sort u} {p : α → α → Bool} (h₁ : is_dec_eq p)
    (h₂ : is_dec_refl p) : DecidableEq α :=
  fun (x y : α) =>
    dite (p x y = tt) (fun (hp : p x y = tt) => is_true (h₁ hp))
      fun (hp : ¬p x y = tt) => is_false sorry

theorem decidable_eq_inl_refl {α : Sort u} [h : DecidableEq α] (a : α) :
    h a a = is_true (Eq.refl a) :=
  sorry

theorem decidable_eq_inr_neg {α : Sort u} [h : DecidableEq α] {a : α} {b : α} (n : a ≠ b) :
    h a b = is_false n :=
  sorry

/- inhabited -/

not found

def arbitrary (α : Sort u) [Inhabited α] : α := Inhabited.default

protected instance prop.inhabited : Inhabited Prop := { default := True }

protected instance pi.inhabited (α : Sort u) {β : α → Sort v} [(x : α) → Inhabited (β x)] :
    Inhabited ((x : α) → β x) :=
  { default := fun (a : α) => Inhabited.default }

protected instance bool.inhabited : Inhabited Bool := { default := false }

protected instance true.inhabited : Inhabited True := { default := trivial }

not found

protected def nonempty.elim {α : Sort u} {p : Prop} (h₁ : Nonempty α) (h₂ : α → p) : p :=
  Nonempty._oldrec h₂ h₁

protected instance nonempty_of_inhabited {α : Sort u} [Inhabited α] : Nonempty α :=
  Nonempty.intro Inhabited.default

theorem nonempty_of_exists {α : Sort u} {p : α → Prop} : (∃ (x : α), p x) → Nonempty α :=
  fun (ᾰ : ∃ (x : α), p x) =>
    Exists.dcases_on ᾰ fun (ᾰ_w : α) (ᾰ_h : p ᾰ_w) => idRhs (Nonempty α) (Nonempty.intro ᾰ_w)

/- subsingleton -/

class inductive subsingleton (α : Sort u) where
| intro : (∀ (a b : α), a = b) → subsingleton α

protected def subsingleton.elim {α : Sort u} [h : subsingleton α] (a : α) (b : α) : a = b :=
  subsingleton._oldrec (fun (p : ∀ (a b : α), a = b) => p) h

protected def subsingleton.helim {α : Sort u} {β : Sort u} [h : subsingleton α] :
    α = β → ∀ (a : α) (b : β), a == b :=
  fun (h_1 : α = β) => eq.rec_on h_1 fun (a b : α) => heq_of_eq (subsingleton.elim a b)

protected instance subsingleton_prop (p : Prop) : subsingleton p :=
  subsingleton.intro fun (a b : p) => proof_irrel a b

protected instance decidable.subsingleton (p : Prop) : subsingleton (Decidable p) :=
  subsingleton.intro fun (d₁ : Decidable p) => sorry

protected theorem rec_subsingleton {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 (decidable.rec_on h h₂ h₁) :=
  sorry

theorem if_pos {c : Prop} [h : Decidable c] (hc : c) {α : Sort u} {t : α} {e : α} : ite c t e = t :=
  sorry

theorem if_neg {c : Prop} [h : Decidable c] (hnc : ¬c) {α : Sort u} {t : α} {e : α} :
    ite c t e = e :=
  sorry

@[simp] theorem if_t_t (c : Prop) [h : Decidable c] {α : Sort u} (t : α) : ite c t t = t := sorry

theorem implies_of_if_pos {c : Prop} {t : Prop} {e : Prop} [Decidable c] (h : ite c t e) : c → t :=
  fun (hc : c) => eq.rec_on (if_pos hc) h

theorem implies_of_if_neg {c : Prop} {t : Prop} {e : Prop} [Decidable c] (h : ite c t e) : ¬c → e :=
  fun (hnc : ¬c) => eq.rec_on (if_neg hnc) h

theorem if_ctx_congr {α : Sort u} {b : Prop} {c : Prop} [dec_b : Decidable b] [dec_c : Decidable c]
    {x : α} {y : α} {u : α} {v : α} (h_c : b ↔ c) (h_t : c → x = u) (h_e : ¬c → y = v) :
    ite b x y = ite c u v :=
  sorry

theorem if_congr {α : Sort u} {b : Prop} {c : Prop} [dec_b : Decidable b] [dec_c : Decidable c]
    {x : α} {y : α} {u : α} {v : α} (h_c : b ↔ c) (h_t : x = u) (h_e : y = v) :
    ite b x y = ite c u v :=
  if_ctx_congr h_c (fun (h : c) => h_t) fun (h : ¬c) => h_e

@[simp] theorem if_true {α : Sort u} {h : Decidable True} (t : α) (e : α) : ite True t e = t :=
  if_pos trivial

@[simp] theorem if_false {α : Sort u} {h : Decidable False} (t : α) (e : α) : ite False t e = e :=
  if_neg not_false

theorem if_ctx_congr_prop {b : Prop} {c : Prop} {x : Prop} {y : Prop} {u : Prop} {v : Prop}
    [dec_b : Decidable b] [dec_c : Decidable c] (h_c : b ↔ c) (h_t : c → (x ↔ u))
    (h_e : ¬c → (y ↔ v)) : ite b x y ↔ ite c u v :=
  sorry

theorem if_congr_prop {b : Prop} {c : Prop} {x : Prop} {y : Prop} {u : Prop} {v : Prop}
    [dec_b : Decidable b] [dec_c : Decidable c] (h_c : b ↔ c) (h_t : x ↔ u) (h_e : y ↔ v) :
    ite b x y ↔ ite c u v :=
  if_ctx_congr_prop h_c (fun (h : c) => h_t) fun (h : ¬c) => h_e

theorem if_ctx_simp_congr_prop {b : Prop} {c : Prop} {x : Prop} {y : Prop} {u : Prop} {v : Prop}
    [dec_b : Decidable b] (h_c : b ↔ c) (h_t : c → (x ↔ u)) (h_e : ¬c → (y ↔ v)) :
    ite b x y ↔ ite c u v :=
  if_ctx_congr_prop h_c h_t h_e

theorem if_simp_congr_prop {b : Prop} {c : Prop} {x : Prop} {y : Prop} {u : Prop} {v : Prop}
    [dec_b : Decidable b] (h_c : b ↔ c) (h_t : x ↔ u) (h_e : y ↔ v) : ite b x y ↔ ite c u v :=
  if_ctx_simp_congr_prop h_c (fun (h : c) => h_t) fun (h : ¬c) => h_e

@[simp] theorem dif_pos {c : Prop} [h : Decidable c] (hc : c) {α : Sort u} {t : c → α}
    {e : ¬c → α} : dite c t e = t hc :=
  sorry

@[simp] theorem dif_neg {c : Prop} [h : Decidable c] (hnc : ¬c) {α : Sort u} {t : c → α}
    {e : ¬c → α} : dite c t e = e hnc :=
  sorry

theorem dif_ctx_congr {α : Sort u} {b : Prop} {c : Prop} [dec_b : Decidable b] [dec_c : Decidable c]
    {x : b → α} {u : c → α} {y : ¬b → α} {v : ¬c → α} (h_c : b ↔ c)
    (h_t : ∀ (h : c), x (iff.mpr h_c h) = u h)
    (h_e : ∀ (h : ¬c), y (iff.mpr (not_iff_not_of_iff h_c) h) = v h) : dite b x y = dite c u v :=
  sorry

theorem dif_ctx_simp_congr {α : Sort u} {b : Prop} {c : Prop} [dec_b : Decidable b] {x : b → α}
    {u : c → α} {y : ¬b → α} {v : ¬c → α} (h_c : b ↔ c) (h_t : ∀ (h : c), x (iff.mpr h_c h) = u h)
    (h_e : ∀ (h : ¬c), y (iff.mpr (not_iff_not_of_iff h_c) h) = v h) : dite b x y = dite c u v :=
  dif_ctx_congr h_c h_t h_e

-- 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 (h : c) => t) fun (h : ¬c) => e) = ite c t e :=
  sorry

protected instance ite.decidable {c : Prop} {t : Prop} {e : Prop} [d_c : Decidable c]
    [d_t : Decidable t] [d_e : Decidable e] : Decidable (ite c t e) :=
  sorry

protected instance dite.decidable {c : Prop} {t : c → Prop} {e : ¬c → Prop} [d_c : Decidable c]
    [d_t : (h : c) → Decidable (t h)] [d_e : (h : ¬c) → Decidable (e h)] :
    Decidable (dite c (fun (h : c) => t h) fun (h : ¬c) => e h) :=
  sorry

def as_true (c : Prop) [Decidable c] := ite c True False

def as_false (c : Prop) [Decidable c] := ite c False True

def of_as_true {c : Prop} [h₁ : Decidable c] (h₂ : as_true c) : c := sorry

/-- Universe lifting operation -/
structure ulift (α : Type s) where
  up :: (down : α)

namespace ulift

/- Bijection between α and ulift.{v} α -/

theorem up_down {α : Type u} (b : ulift α) : up (down b) = b :=
  cases_on b fun (b : α) => idRhs (up (down (up b)) = up (down (up b))) rfl

end ulift

theorem ulift.down_up {α : Type u} (a : α) : ulift.down (ulift.up a) = a := rfl

/-- Universe lifting operation from Sort to Type -/
structure plift (α : Sort u) where
  up :: (down : α)

namespace plift

/- Bijection between α and plift α -/

theorem up_down {α : Sort u} (b : plift α) : up (down b) = b :=
  cases_on b fun (b : α) => idRhs (up (down (up b)) = up (down (up b))) rfl

end plift

theorem plift.down_up {α : Sort u} (a : α) : plift.down (plift.up a) = a := rfl

/- Equalities for rewriting let-expressions -/

theorem let_value_eq {α : Sort u} {β : Sort v} {a₁ : α} {a₂ : α} (b : α → β) :
    a₁ = a₂ →
        (let x : α := a₁;
          b x) =
          let x : α := a₂;
          b x :=
  fun (h : a₁ = a₂) => eq.rec_on h rfl

theorem let_value_heq {α : Sort v} {β : α → Sort u} {a₁ : α} {a₂ : α} (b : (x : α) → β x) :
    a₁ = a₂ →
        (let x : α := a₁;
          b x) ==
          let x : α := a₂;
          b x :=
  fun (h : a₁ = a₂) => eq.rec_on h (HEq.refl (b a₁))

theorem let_body_eq {α : Sort v} {β : α → Sort u} (a : α) {b₁ : (x : α) → β x}
    {b₂ : (x : α) → β x} :
    (∀ (x : α), b₁ x = b₂ x) →
        (let x : α := a;
          b₁ x) =
          let x : α := a;
          b₂ x :=
  fun (h : ∀ (x : α), b₁ x = b₂ x) => h a

theorem let_eq {α : Sort v} {β : Sort u} {a₁ : α} {a₂ : α} {b₁ : α → β} {b₂ : α → β} :
    a₁ = a₂ →
        (∀ (x : α), b₁ x = b₂ x) →
          (let x : α := a₁;
            b₁ x) =
            let x : α := a₂;
            b₂ x :=
  fun (h₁ : a₁ = a₂) (h₂ : ∀ (x : α), b₁ x = b₂ x) => eq.rec_on h₁ (h₂ a₁)

def reflexive {β : Sort v} (r : β → β → Prop) := ∀ (x : β), r x x

def symmetric {β : Sort v} (r : β → β → Prop) := ∀ {x y : β}, r x y → r y x

def transitive {β : Sort v} (r : β → β → Prop) := ∀ {x y z : β}, r x y → r y z → r x z

def equivalence {β : Sort v} (r : β → β → Prop) := reflexive r ∧ symmetric r ∧ transitive r

def total {β : Sort v} (r : β → β → Prop) := ∀ (x y : β), r x y ∨ r y x

def mk_equivalence {β : Sort v} (r : β → β → Prop) (rfl : reflexive r) (symm : symmetric r)
    (trans : transitive r) : equivalence r :=
  { left := rfl, right := { left := symm, right := trans } }

def irreflexive {β : Sort v} (r : β → β → Prop) := ∀ (x : β), ¬r x x

def anti_symmetric {β : Sort v} (r : β → β → Prop) := ∀ {x y : β}, r x y → r y x → x = y

def empty_relation {α : Sort u} (a₁ : α) (a₂ : α) := False

def subrelation {β : Sort v} (q : β → β → Prop) (r : β → β → Prop) := ∀ {x y : β}, q x y → r x y

def inv_image {α : Sort u} {β : Sort v} (r : β → β → Prop) (f : α → β) : α → α → Prop :=
  fun (a₁ a₂ : α) => r (f a₁) (f a₂)

theorem inv_image.trans {α : Sort u} {β : Sort v} (r : β → β → Prop) (f : α → β)
    (h : transitive r) : transitive (inv_image r f) :=
  fun (a₁ a₂ a₃ : α) (h₁ : inv_image r f a₁ a₂) (h₂ : inv_image r f a₂ a₃) => h h₁ h₂

theorem inv_image.irreflexive {α : Sort u} {β : Sort v} (r : β → β → Prop) (f : α → β)
    (h : irreflexive r) : irreflexive (inv_image r f) :=
  fun (a : α) (h₁ : inv_image r f a a) => h (f a) h₁

inductive tc {α : Sort u} (r : α → α → Prop) : α → α → Prop where
| base : ∀ (a b : α), r a b → tc r a b
| trans : ∀ (a b c : α), tc r a b → tc r b c → tc r a c

def commutative {α : Type u} (f : α → α → α) := ∀ (a b : α), f a b = f b a

def associative {α : Type u} (f : α → α → α) := ∀ (a b c : α), f (f a b) c = f a (f b c)

def left_identity {α : Type u} (f : α → α → α) (one : α) := ∀ (a : α), f one a = a

def right_identity {α : Type u} (f : α → α → α) (one : α) := ∀ (a : α), f a one = a

def right_inverse {α : Type u} (f : α → α → α) (inv : α → α) (one : α) :=
  ∀ (a : α), f a (inv a) = one

def left_cancelative {α : Type u} (f : α → α → α) := ∀ (a b c : α), f a b = f a c → b = c

def right_cancelative {α : Type u} (f : α → α → α) := ∀ (a b c : α), f a b = f c b → a = c

def left_distributive {α : Type u} (f : α → α → α) (g : α → α → α) :=
  ∀ (a b c : α), f a (g b c) = g (f a b) (f a c)

def right_distributive {α : Type u} (f : α → α → α) (g : α → α → α) :=
  ∀ (a b c : α), f (g a b) c = g (f a c) (f b c)

def right_commutative {α : Type u} {β : Type v} (h : β → α → β) :=
  ∀ (b : β) (a₁ a₂ : α), h (h b a₁) a₂ = h (h b a₂) a₁

def left_commutative {α : Type u} {β : Type v} (h : α → β → β) :=
  ∀ (a₁ a₂ : α) (b : β), h a₁ (h a₂ b) = h a₂ (h a₁ b)

theorem left_comm {α : Type u} (f : α → α → α) :
    commutative f → associative f → left_commutative f :=
  fun (hcomm : commutative f) (hassoc : associative f) (a b c : α) =>
    Eq.trans (Eq.trans (Eq.symm (hassoc a b c)) (hcomm a b ▸ rfl)) (hassoc b a c)

theorem right_comm {α : Type u} (f : α → α → α) :
    commutative f → associative f → right_commutative f :=
  fun (hcomm : commutative f) (hassoc : associative f) (a b c : α) =>
    Eq.trans (Eq.trans (hassoc a b c) (hcomm b c ▸ rfl)) (Eq.symm (hassoc a c b))

end Mathlib


/-
Copyright (c) 2018 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Patrick Massot, Johannes Hölzl

! This file was ported from Lean 3 source module analysis.normed.field.basic
! leanprover-community/mathlib commit f06058e64b7e8397234455038f3f8aec83aaba5a
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Algebra.Algebra.Subalgebra.Basic
import Mathlib.Analysis.Normed.Group.Basic
import Mathlib.Topology.Instances.ENNReal

/-!
# Normed fields

In this file we define (semi)normed rings and fields. We also prove some theorems about these
definitions.
-/

variable {α : Type _} {β : Type _} {γ : Type _} {ι : Type _}

open Filter Metric

open Topology BigOperators NNReal ENNReal uniformity Pointwise

/-- A non-unital seminormed ring is a not-necessarily-unital ring
endowed with a seminorm which satisfies the inequality `‖x y‖ ≤ ‖x‖ ‖y‖`. -/
class NonUnitalSeminormedRing (α : Type _) extends Norm α, NonUnitalRing α,
  PseudoMetricSpace α where
  /-- The distance is induced by the norm. -/
  dist_eq : ∀ x y, dist x y = norm (x - y)
  /-- The norm is submultiplicative. -/
  norm_mul : ∀ a b, norm (a * b) ≤ norm a * norm b
#align non_unital_semi_normed_ring NonUnitalSeminormedRing

/-- A seminormed ring is a ring endowed with a seminorm which satisfies the inequality
`‖x y‖ ≤ ‖x‖ ‖y‖`. -/
class SeminormedRing (α : Type _) extends Norm α, Ring α, PseudoMetricSpace α where
  /-- The distance is induced by the norm. -/
  dist_eq : ∀ x y, dist x y = norm (x - y)
  /-- The norm is submultiplicative. -/
  norm_mul : ∀ a b, norm (a * b) ≤ norm a * norm b
#align semi_normed_ring SeminormedRing

-- see Note [lower instance priority]
/-- A seminormed ring is a non-unital seminormed ring. -/
instance (priority := 100) SeminormedRing.toNonUnitalSeminormedRing [β : SeminormedRing α] :
    NonUnitalSeminormedRing α :=
  { β with }
#align semi_normed_ring.to_non_unital_semi_normed_ring SeminormedRing.toNonUnitalSeminormedRing

/-- A non-unital normed ring is a not-necessarily-unital ring
endowed with a norm which satisfies the inequality `‖x y‖ ≤ ‖x‖ ‖y‖`. -/
class NonUnitalNormedRing (α : Type _) extends Norm α, NonUnitalRing α, MetricSpace α where
  /-- The distance is induced by the norm. -/
  dist_eq : ∀ x y, dist x y = norm (x - y)
  /-- The norm is submultiplicative. -/
  norm_mul : ∀ a b, norm (a * b) ≤ norm a * norm b
#align non_unital_normed_ring NonUnitalNormedRing

-- see Note [lower instance priority]
/-- A non-unital normed ring is a non-unital seminormed ring. -/
instance (priority := 100) NonUnitalNormedRing.toNonUnitalSeminormedRing
    [β : NonUnitalNormedRing α] : NonUnitalSeminormedRing α :=
  { β with }
#align non_unital_normed_ring.to_non_unital_semi_normed_ring NonUnitalNormedRing.toNonUnitalSeminormedRing

/-- A normed ring is a ring endowed with a norm which satisfies the inequality `‖x y‖ ≤ ‖x‖ ‖y‖`. -/
class NormedRing (α : Type _) extends Norm α, Ring α, MetricSpace α where
  /-- The distance is induced by the norm. -/
  dist_eq : ∀ x y, dist x y = norm (x - y)
  /-- The norm is submultiplicative. -/
  norm_mul : ∀ a b, norm (a * b) ≤ norm a * norm b
#align normed_ring NormedRing

/-- A normed division ring is a division ring endowed with a seminorm which satisfies the equality
`‖x y‖ = ‖x‖ ‖y‖`. -/
class NormedDivisionRing (α : Type _) extends Norm α, DivisionRing α, MetricSpace α where
  /-- The distance is induced by the norm. -/
  dist_eq : ∀ x y, dist x y = norm (x - y)
  /-- The norm is multiplicative. -/
  norm_mul' : ∀ a b, norm (a * b) = norm a * norm b
#align normed_division_ring NormedDivisionRing

-- see Note [lower instance priority]
/-- A normed division ring is a normed ring. -/
instance (priority := 100) NormedDivisionRing.toNormedRing [β : NormedDivisionRing α] :
    NormedRing α :=
  { β with norm_mul := fun a b => (NormedDivisionRing.norm_mul' a b).le }
#align normed_division_ring.to_normed_ring NormedDivisionRing.toNormedRing

-- see Note [lower instance priority]
/-- A normed ring is a seminormed ring. -/
instance (priority := 100) NormedRing.toSeminormedRing [β : NormedRing α] : SeminormedRing α :=
  { β with }
#align normed_ring.to_semi_normed_ring NormedRing.toSeminormedRing

-- see Note [lower instance priority]
/-- A normed ring is a non-unital normed ring. -/
instance (priority := 100) NormedRing.toNonUnitalNormedRing [β : NormedRing α] :
    NonUnitalNormedRing α :=
  { β with }
#align normed_ring.to_non_unital_normed_ring NormedRing.toNonUnitalNormedRing

/-- A seminormed commutative ring is a commutative ring endowed with a seminorm which satisfies
the inequality `‖x y‖ ≤ ‖x‖ ‖y‖`. -/
class SeminormedCommRing (α : Type _) extends SeminormedRing α where
  /-- Multiplication is commutative. -/
  mul_comm : ∀ x y : α, x * y = y * x
#align semi_normed_comm_ring SeminormedCommRing

/-- A normed commutative ring is a commutative ring endowed with a norm which satisfies
the inequality `‖x y‖ ≤ ‖x‖ ‖y‖`. -/
class NormedCommRing (α : Type _) extends NormedRing α where
  /-- Multiplication is commutative. -/
  mul_comm : ∀ x y : α, x * y = y * x
#align normed_comm_ring NormedCommRing

-- see Note [lower instance priority]
/-- A normed commutative ring is a seminormed commutative ring. -/
instance (priority := 100) NormedCommRing.toSeminormedCommRing [β : NormedCommRing α] :
    SeminormedCommRing α :=
  { β with }
#align normed_comm_ring.to_semi_normed_comm_ring NormedCommRing.toSeminormedCommRing

instance PUnit.normedCommRing : NormedCommRing PUnit :=
  { PUnit.normedAddCommGroup, PUnit.commRing with
    norm_mul := fun _ _ => by simp }

/-- A mixin class with the axiom `‖1‖ = 1`. Many `NormedRing`s and all `NormedField`s satisfy this
axiom. -/
class NormOneClass (α : Type _) [Norm α] [One α] : Prop where
  /-- The norm of the multiplicative identity is 1. -/
  norm_one : ‖(1 : α)‖ = 1
#align norm_one_class NormOneClass

export NormOneClass (norm_one)

attribute [simp] norm_one

@[simp]
theorem nnnorm_one [SeminormedAddCommGroup α] [One α] [NormOneClass α] : ‖(1 : α)‖₊ = 1 :=
  NNReal.eq norm_one
#align nnnorm_one nnnorm_one

theorem NormOneClass.nontrivial (α : Type _) [SeminormedAddCommGroup α] [One α] [NormOneClass α] :
    Nontrivial α :=
  nontrivial_of_ne 0 1 <| ne_of_apply_ne norm <| by simp
#align norm_one_class.nontrivial NormOneClass.nontrivial

-- see Note [lower instance priority]
instance (priority := 100) SeminormedCommRing.toCommRing [β : SeminormedCommRing α] : CommRing α :=
  { β with }
#align semi_normed_comm_ring.to_comm_ring SeminormedCommRing.toCommRing

-- see Note [lower instance priority]
instance (priority := 100) NonUnitalNormedRing.toNormedAddCommGroup [β : NonUnitalNormedRing α] :
    NormedAddCommGroup α :=
  { β with }
#align non_unital_normed_ring.to_normed_add_comm_group NonUnitalNormedRing.toNormedAddCommGroup

-- see Note [lower instance priority]
instance (priority := 100) NonUnitalSeminormedRing.toSeminormedAddCommGroup
    [NonUnitalSeminormedRing α] : SeminormedAddCommGroup α :=
  { ‹NonUnitalSeminormedRing α› with }
#align non_unital_semi_normed_ring.to_seminormed_add_comm_group NonUnitalSeminormedRing.toSeminormedAddCommGroup

instance ULift.normOneClass [SeminormedAddCommGroup α] [One α] [NormOneClass α] :
    NormOneClass (ULift α) :=
  ⟨by simp [ULift.norm_def]⟩

instance Prod.normOneClass [SeminormedAddCommGroup α] [One α] [NormOneClass α]
    [SeminormedAddCommGroup β] [One β] [NormOneClass β] : NormOneClass (α × β) :=
  ⟨by simp [Prod.norm_def]⟩
#align prod.norm_one_class Prod.normOneClass

instance Pi.normOneClass {ι : Type _} {α : ι → Type _} [Nonempty ι] [Fintype ι]
    [∀ i, SeminormedAddCommGroup (α i)] [∀ i, One (α i)] [∀ i, NormOneClass (α i)] :
    NormOneClass (∀ i, α i) :=
  ⟨by simp [Pi.norm_def]; exact Finset.sup_const Finset.univ_nonempty 1⟩
#align pi.norm_one_class Pi.normOneClass

instance MulOpposite.normOneClass [SeminormedAddCommGroup α] [One α] [NormOneClass α] :
    NormOneClass αᵐᵒᵖ :=
  ⟨@norm_one α _ _ _⟩
#align mul_opposite.norm_one_class MulOpposite.normOneClass

section NonUnitalSeminormedRing

variable [NonUnitalSeminormedRing α]

theorem norm_mul_le (a b : α) : ‖a * b‖ ≤ ‖a‖ * ‖b‖ :=
  NonUnitalSeminormedRing.norm_mul _ _
#align norm_mul_le norm_mul_le

theorem nnnorm_mul_le (a b : α) : ‖a * b‖₊ ≤ ‖a‖₊ * ‖b‖₊ := by
  simpa only [← norm_toNNReal, ← Real.toNNReal_mul (norm_nonneg _)] using
    Real.toNNReal_mono (norm_mul_le _ _)
#align nnnorm_mul_le nnnorm_mul_le

theorem one_le_norm_one (β) [NormedRing β] [Nontrivial β] : 1 ≤ ‖(1 : β)‖ :=
  (le_mul_iff_one_le_left <| norm_pos_iff.mpr (one_ne_zero : (1 : β) ≠ 0)).mp
    (by simpa only [mul_one] using norm_mul_le (1 : β) 1)
#align one_le_norm_one one_le_norm_one

theorem one_le_nnnorm_one (β) [NormedRing β] [Nontrivial β] : 1 ≤ ‖(1 : β)‖₊ :=
  one_le_norm_one β
#align one_le_nnnorm_one one_le_nnnorm_one

theorem Filter.Tendsto.zero_mul_isBoundedUnder_le {f g : ι → α} {l : Filter ι}
    (hf : Tendsto f l (𝓝 0)) (hg : IsBoundedUnder (· ≤ ·) l ((‖·‖) ∘ g)) :
    Tendsto (fun x => f x * g x) l (𝓝 0) :=
  hf.op_zero_isBoundedUnder_le hg (· * ·) norm_mul_le
#align filter.tendsto.zero_mul_is_bounded_under_le Filter.Tendsto.zero_mul_isBoundedUnder_le

theorem Filter.isBoundedUnder_le_mul_tendsto_zero {f g : ι → α} {l : Filter ι}
    (hf : IsBoundedUnder (· ≤ ·) l (norm ∘ f)) (hg : Tendsto g l (𝓝 0)) :
    Tendsto (fun x => f x * g x) l (𝓝 0) :=
  hg.op_zero_isBoundedUnder_le hf (flip (· * ·)) fun x y =>
    (norm_mul_le y x).trans_eq (mul_comm _ _)
#align filter.is_bounded_under_le.mul_tendsto_zero Filter.isBoundedUnder_le_mul_tendsto_zero

/-- In a seminormed ring, the left-multiplication `AddMonoidHom` is bounded. -/
theorem mulLeft_bound (x : α) : ∀ y : α, ‖AddMonoidHom.mulLeft x y‖ ≤ ‖x‖ * ‖y‖ :=
  norm_mul_le x
#align mul_left_bound mulLeft_bound

/-- In a seminormed ring, the right-multiplication `AddMonoidHom` is bounded. -/
theorem mulRight_bound (x : α) : ∀ y : α, ‖AddMonoidHom.mulRight x y‖ ≤ ‖x‖ * ‖y‖ := fun y => by
  rw [mul_comm]
  exact norm_mul_le y x
#align mul_right_bound mulRight_bound

instance ULift.nonUnitalSeminormedRing : NonUnitalSeminormedRing (ULift α) :=
  { ULift.seminormedAddCommGroup, ULift.nonUnitalRing with
    norm_mul := fun x y => (norm_mul_le x.down y.down : _) }

/-- Non-unital seminormed ring structure on the product of two non-unital seminormed rings,
  using the sup norm. -/
instance Prod.nonUnitalSeminormedRing [NonUnitalSeminormedRing β] :
    NonUnitalSeminormedRing (α × β) :=
  { Prod.seminormedAddCommGroup, instNonUnitalRingProd with
    norm_mul := fun x y =>
      calc
        ‖x * y‖ = ‖(x.1 * y.1, x.2 * y.2)‖ := rfl
        _ = max ‖x.1 * y.1‖ ‖x.2 * y.2‖ := rfl
        _ ≤ max (‖x.1‖ * ‖y.1‖) (‖x.2‖ * ‖y.2‖) :=
          (max_le_max (norm_mul_le x.1 y.1) (norm_mul_le x.2 y.2))
        _ = max (‖x.1‖ * ‖y.1‖) (‖y.2‖ * ‖x.2‖) := by simp [mul_comm]
        _ ≤ max ‖x.1‖ ‖x.2‖ * max ‖y.2‖ ‖y.1‖ := by
          apply max_mul_mul_le_max_mul_max <;> simp [norm_nonneg]
        _ = max ‖x.1‖ ‖x.2‖ * max ‖y.1‖ ‖y.2‖ := by simp [max_comm]
        _ = ‖x‖ * ‖y‖ := rfl
         }
#align prod.non_unital_semi_normed_ring Prod.nonUnitalSeminormedRing

/-- Non-unital seminormed ring structure on the product of finitely many non-unital seminormed
rings, using the sup norm. -/
instance Pi.nonUnitalSeminormedRing {π : ι → Type _} [Fintype ι]
    [∀ i, NonUnitalSeminormedRing (π i)] : NonUnitalSeminormedRing (∀ i, π i) :=
  { Pi.seminormedAddCommGroup, Pi.nonUnitalRing with
    norm_mul := fun x y =>
      NNReal.coe_mono <|
        calc
          (Finset.univ.sup fun i => ‖x i * y i‖₊) ≤
              Finset.univ.sup ((fun i => ‖x i‖₊) * fun i => ‖y i‖₊) :=
            Finset.sup_mono_fun fun _ _ => norm_mul_le _ _
          _ ≤ (Finset.univ.sup fun i => ‖x i‖₊) * Finset.univ.sup fun i => ‖y i‖₊ :=
            Finset.sup_mul_le_mul_sup_of_nonneg _ (fun _ _ => zero_le _) fun _ _ => zero_le _
           }
#align pi.non_unital_semi_normed_ring Pi.nonUnitalSeminormedRing

instance MulOpposite.nonUnitalSeminormedRing : NonUnitalSeminormedRing αᵐᵒᵖ :=
  { MulOpposite.seminormedAddCommGroup, MulOpposite.nonUnitalRing α with
    norm_mul :=
      MulOpposite.rec' fun x =>
        MulOpposite.rec' fun y => (norm_mul_le y x).trans_eq (mul_comm _ _) }
#align mul_opposite.non_unital_semi_normed_ring MulOpposite.nonUnitalSeminormedRing

end NonUnitalSeminormedRing

section SeminormedRing

variable [SeminormedRing α]

/-- A subalgebra of a seminormed ring is also a seminormed ring, with the restriction of the norm.

See note [implicit instance arguments]. -/
instance Subalgebra.seminormedRing {𝕜 : Type _} {_ : CommRing 𝕜} {E : Type _} [SeminormedRing E]
    {_ : Algebra 𝕜 E} (s : Subalgebra 𝕜 E) : SeminormedRing s :=
  { s.toSubmodule.seminormedAddCommGroup, s.toRing with
    norm_mul := fun a b => norm_mul_le a.1 b.1 }
#align subalgebra.semi_normed_ring Subalgebra.seminormedRing

/-- A subalgebra of a normed ring is also a normed ring, with the restriction of the norm.

See note [implicit instance arguments]. -/
instance Subalgebra.normedRing {𝕜 : Type _} {_ : CommRing 𝕜} {E : Type _} [NormedRing E]
    {_ : Algebra 𝕜 E} (s : Subalgebra 𝕜 E) : NormedRing s :=
  { s.seminormedRing with
    eq_of_dist_eq_zero := eq_of_dist_eq_zero }
#align subalgebra.normed_ring Subalgebra.normedRing

theorem Nat.norm_cast_le : ∀ n : ℕ, ‖(n : α)‖ ≤ n * ‖(1 : α)‖
  | 0 => by simp
  | n + 1 => by
    rw [n.cast_succ, n.cast_succ, add_mul, one_mul]
    exact norm_add_le_of_le (Nat.norm_cast_le n) le_rfl
#align nat.norm_cast_le Nat.norm_cast_le

theorem List.norm_prod_le' : ∀ {l : List α}, l ≠ [] → ‖l.prod‖ ≤ (l.map norm).prod
  | [], h => (h rfl).elim
  | [a], _ => by simp
  | a::b::l, _ => by
    rw [List.map_cons, List.prod_cons, @List.prod_cons _ _ _ ‖a‖]
    refine' le_trans (norm_mul_le _ _) (mul_le_mul_of_nonneg_left _ (norm_nonneg _))
    exact List.norm_prod_le' (List.cons_ne_nil b l)
#align list.norm_prod_le' List.norm_prod_le'

theorem List.nnnorm_prod_le' {l : List α} (hl : l ≠ []) : ‖l.prod‖₊ ≤ (l.map nnnorm).prod :=
  (List.norm_prod_le' hl).trans_eq <| by simp [NNReal.coe_list_prod, List.map_map]
#align list.nnnorm_prod_le' List.nnnorm_prod_le'

theorem List.norm_prod_le [NormOneClass α] : ∀ l : List α, ‖l.prod‖ ≤ (l.map norm).prod
  | [] => by simp
  | a::l => List.norm_prod_le' (List.cons_ne_nil a l)
#align list.norm_prod_le List.norm_prod_le

theorem List.nnnorm_prod_le [NormOneClass α] (l : List α) : ‖l.prod‖₊ ≤ (l.map nnnorm).prod :=
  l.norm_prod_le.trans_eq <| by simp [NNReal.coe_list_prod, List.map_map]
#align list.nnnorm_prod_le List.nnnorm_prod_le

theorem Finset.norm_prod_le' {α : Type _} [NormedCommRing α] (s : Finset ι) (hs : s.Nonempty)
    (f : ι → α) : ‖∏ i in s, f i‖ ≤ ∏ i in s, ‖f i‖ := by
  rcases s with ⟨⟨l⟩, hl⟩
  have : l.map f ≠ [] := by simpa using hs
  simpa using List.norm_prod_le' this
#align finset.norm_prod_le' Finset.norm_prod_le'

theorem Finset.nnnorm_prod_le' {α : Type _} [NormedCommRing α] (s : Finset ι) (hs : s.Nonempty)
    (f : ι → α) : ‖∏ i in s, f i‖₊ ≤ ∏ i in s, ‖f i‖₊ :=
  (s.norm_prod_le' hs f).trans_eq <| by simp [NNReal.coe_prod]
#align finset.nnnorm_prod_le' Finset.nnnorm_prod_le'

theorem Finset.norm_prod_le {α : Type _} [NormedCommRing α] [NormOneClass α] (s : Finset ι)
    (f : ι → α) : ‖∏ i in s, f i‖ ≤ ∏ i in s, ‖f i‖ := by
  rcases s with ⟨⟨l⟩, hl⟩
  simpa using (l.map f).norm_prod_le
#align finset.norm_prod_le Finset.norm_prod_le

theorem Finset.nnnorm_prod_le {α : Type _} [NormedCommRing α] [NormOneClass α] (s : Finset ι)
    (f : ι → α) : ‖∏ i in s, f i‖₊ ≤ ∏ i in s, ‖f i‖₊ :=
  (s.norm_prod_le f).trans_eq <| by simp [NNReal.coe_prod]
#align finset.nnnorm_prod_le Finset.nnnorm_prod_le

/-- If `α` is a seminormed ring, then `‖a ^ n‖₊ ≤ ‖a‖₊ ^ n` for `n > 0`.
See also `nnnorm_pow_le`. -/
theorem nnnorm_pow_le' (a : α) : ∀ {n : ℕ}, 0 < n → ‖a ^ n‖₊ ≤ ‖a‖₊ ^ n
  | 1, _ => by simp only [pow_one, le_rfl]
  | n + 2, _ => by
    simpa only [pow_succ _ (n + 1)] using
      le_trans (nnnorm_mul_le _ _) (mul_le_mul_left' (nnnorm_pow_le' a n.succ_pos) _)
#align nnnorm_pow_le' nnnorm_pow_le'

/-- If `α` is a seminormed ring with `‖1‖₊ = 1`, then `‖a ^ n‖₊ ≤ ‖a‖₊ ^ n`.
See also `nnnorm_pow_le'`.-/
theorem nnnorm_pow_le [NormOneClass α] (a : α) (n : ℕ) : ‖a ^ n‖₊ ≤ ‖a‖₊ ^ n :=
  Nat.recOn n (by simp only [Nat.zero_eq, pow_zero, nnnorm_one, le_rfl])
    fun k _hk => nnnorm_pow_le' a k.succ_pos
#align nnnorm_pow_le nnnorm_pow_le

/-- If `α` is a seminormed ring, then `‖a ^ n‖ ≤ ‖a‖ ^ n` for `n > 0`. See also `norm_pow_le`. -/
theorem norm_pow_le' (a : α) {n : ℕ} (h : 0 < n) : ‖a ^ n‖ ≤ ‖a‖ ^ n := by
  simpa only [NNReal.coe_pow, coe_nnnorm] using NNReal.coe_mono (nnnorm_pow_le' a h)
#align norm_pow_le' norm_pow_le'

/-- If `α` is a seminormed ring with `‖1‖ = 1`, then `‖a ^ n‖ ≤ ‖a‖ ^ n`. See also `norm_pow_le'`.-/
theorem norm_pow_le [NormOneClass α] (a : α) (n : ℕ) : ‖a ^ n‖ ≤ ‖a‖ ^ n :=
  Nat.recOn n (by simp only [Nat.zero_eq, pow_zero, norm_one, le_rfl])
    fun n _hn => norm_pow_le' a n.succ_pos
#align norm_pow_le norm_pow_le

theorem eventually_norm_pow_le (a : α) : ∀ᶠ n : ℕ in atTop, ‖a ^ n‖ ≤ ‖a‖ ^ n :=
  eventually_atTop.mpr ⟨1, fun _b h => norm_pow_le' a (Nat.succ_le_iff.mp h)⟩
#align eventually_norm_pow_le eventually_norm_pow_le

instance ULift.seminormedRing : SeminormedRing (ULift α) :=
  { ULift.nonUnitalSeminormedRing, ULift.ring with }

/-- Seminormed ring structure on the product of two seminormed rings,
  using the sup norm. -/
instance Prod.seminormedRing [SeminormedRing β] : SeminormedRing (α × β) :=
  { Prod.nonUnitalSeminormedRing, instRingProd with }
#align prod.semi_normed_ring Prod.seminormedRing

/-- Seminormed ring structure on the product of finitely many seminormed rings,
  using the sup norm. -/
instance Pi.seminormedRing {π : ι → Type _} [Fintype ι] [∀ i, SeminormedRing (π i)] :
    SeminormedRing (∀ i, π i) :=
  { Pi.nonUnitalSeminormedRing, Pi.ring with }
#align pi.semi_normed_ring Pi.seminormedRing

instance MulOpposite.seminormedRing : SeminormedRing αᵐᵒᵖ :=
  { MulOpposite.nonUnitalSeminormedRing, MulOpposite.ring α with }
#align mul_opposite.semi_normed_ring MulOpposite.seminormedRing

end SeminormedRing

section NonUnitalNormedRing

variable [NonUnitalNormedRing α]

instance ULift.nonUnitalNormedRing : NonUnitalNormedRing (ULift α) :=
  { ULift.nonUnitalSeminormedRing, ULift.normedAddCommGroup with }

/-- Non-unital normed ring structure on the product of two non-unital normed rings,
using the sup norm. -/
instance Prod.nonUnitalNormedRing [NonUnitalNormedRing β] : NonUnitalNormedRing (α × β) :=
  { Prod.nonUnitalSeminormedRing, Prod.normedAddCommGroup with }
#align prod.non_unital_normed_ring Prod.nonUnitalNormedRing

/-- Normed ring structure on the product of finitely many non-unital normed rings, using the sup
norm. -/
instance Pi.nonUnitalNormedRing {π : ι → Type _} [Fintype ι] [∀ i, NonUnitalNormedRing (π i)] :
    NonUnitalNormedRing (∀ i, π i) :=
  { Pi.nonUnitalSeminormedRing, Pi.normedAddCommGroup with }
#align pi.non_unital_normed_ring Pi.nonUnitalNormedRing

instance MulOpposite.nonUnitalNormedRing : NonUnitalNormedRing αᵐᵒᵖ :=
  { MulOpposite.nonUnitalSeminormedRing, MulOpposite.normedAddCommGroup with }
#align mul_opposite.non_unital_normed_ring MulOpposite.nonUnitalNormedRing

end NonUnitalNormedRing

section NormedRing

variable [NormedRing α]

theorem Units.norm_pos [Nontrivial α] (x : αˣ) : 0 < ‖(x : α)‖ :=
  norm_pos_iff.mpr (Units.ne_zero x)
#align units.norm_pos Units.norm_pos

theorem Units.nnnorm_pos [Nontrivial α] (x : αˣ) : 0 < ‖(x : α)‖₊ :=
  x.norm_pos
#align units.nnnorm_pos Units.nnnorm_pos

instance ULift.normedRing : NormedRing (ULift α) :=
  { ULift.seminormedRing, ULift.normedAddCommGroup with }

/-- Normed ring structure on the product of two normed rings, using the sup norm. -/
instance Prod.normedRing [NormedRing β] : NormedRing (α × β) :=
  { Prod.nonUnitalNormedRing, instRingProd with }
#align prod.normed_ring Prod.normedRing

/-- Normed ring structure on the product of finitely many normed rings, using the sup norm. -/
instance Pi.normedRing {π : ι → Type _} [Fintype ι] [∀ i, NormedRing (π i)] :
    NormedRing (∀ i, π i) :=
  { Pi.seminormedRing, Pi.normedAddCommGroup with }
#align pi.normed_ring Pi.normedRing

instance MulOpposite.normedRing : NormedRing αᵐᵒᵖ :=
  { MulOpposite.seminormedRing, MulOpposite.normedAddCommGroup with }
#align mul_opposite.normed_ring MulOpposite.normedRing

end NormedRing

-- see Note [lower instance priority]
instance (priority := 100) semi_normed_ring_top_monoid [NonUnitalSeminormedRing α] :
    ContinuousMul α :=
  ⟨continuous_iff_continuousAt.2 fun x =>
      tendsto_iff_norm_tendsto_zero.2 <| by
        have : ∀ e : α × α, ‖e.1 * e.2 - x.1 * x.2‖ ≤ ‖e.1‖ * ‖e.2 - x.2‖ + ‖e.1 - x.1‖ * ‖x.2‖ :=
          by
          intro e
          calc
            ‖e.1 * e.2 - x.1 * x.2‖ ≤ ‖e.1 * (e.2 - x.2) + (e.1 - x.1) * x.2‖ := by
              rw [_root_.mul_sub, _root_.sub_mul, sub_add_sub_cancel]
            -- porting note: `ENNReal.{mul_sub, sub_mul}` should be protected
            _ ≤ ‖e.1‖ * ‖e.2 - x.2‖ + ‖e.1 - x.1‖ * ‖x.2‖ :=
              norm_add_le_of_le (norm_mul_le _ _) (norm_mul_le _ _)
        refine squeeze_zero (fun e => norm_nonneg _) this ?_
        -- porting note: the new `convert` sucks, it's way too dumb without using the type
        -- of the goal to figure out how to match things up. The rest of this proof was:
        /- convert
          ((continuous_fst.tendsto x).norm.mul
                ((continuous_snd.tendsto x).sub tendsto_const_nhds).norm).add
            (((continuous_fst.tendsto x).sub tendsto_const_nhds).norm.mul _)
        show tendsto _ _ _
        exact tendsto_const_nhds
        simp -/
        rw [←zero_add 0]
        refine Tendsto.add ?_ ?_
        · rw [←mul_zero (‖x.fst‖)]
          refine Filter.Tendsto.mul ?_ ?_
          · exact (continuous_fst.tendsto x).norm
          · rw [←norm_zero (E := α), ←sub_self x.snd]
            exact ((continuous_snd.tendsto x).sub tendsto_const_nhds).norm
        · rw [←zero_mul (‖x.snd‖)]
          refine' Filter.Tendsto.mul _ tendsto_const_nhds
          rw [←norm_zero (E := α), ←sub_self x.fst]
          exact ((continuous_fst.tendsto x).sub tendsto_const_nhds).norm⟩
#align semi_normed_ring_top_monoid semi_normed_ring_top_monoid

-- see Note [lower instance priority]
/-- A seminormed ring is a topological ring. -/
instance (priority := 100) semi_normed_top_ring [NonUnitalSeminormedRing α] : TopologicalRing α
    where
#align semi_normed_top_ring semi_normed_top_ring

section NormedDivisionRing

variable [NormedDivisionRing α]

@[simp]
theorem norm_mul (a b : α) : ‖a * b‖ = ‖a‖ * ‖b‖ :=
  NormedDivisionRing.norm_mul' a b
#align norm_mul norm_mul

instance (priority := 900) NormedDivisionRing.to_normOneClass : NormOneClass α :=
  ⟨mul_left_cancel₀ (mt norm_eq_zero.1 (one_ne_zero' α)) <| by rw [← norm_mul, mul_one, mul_one]⟩
#align normed_division_ring.to_norm_one_class NormedDivisionRing.to_normOneClass

instance isAbsoluteValue_norm : IsAbsoluteValue (norm : α → ℝ)
    where
  abv_nonneg' := norm_nonneg
  abv_eq_zero' := norm_eq_zero
  abv_add' := norm_add_le
  abv_mul' := norm_mul
#align is_absolute_value_norm isAbsoluteValue_norm

@[simp]
theorem nnnorm_mul (a b : α) : ‖a * b‖₊ = ‖a‖₊ * ‖b‖₊ :=
  NNReal.eq <| norm_mul a b
#align nnnorm_mul nnnorm_mul

/-- `norm` as a `MonoidWithZeroHom`. -/
@[simps]
def normHom : α →*₀ ℝ where
  toFun := (‖·‖)
  map_zero' := norm_zero
  map_one' := norm_one
  map_mul' := norm_mul
#align norm_hom normHom

/-- `nnnorm` as a `MonoidWithZeroHom`. -/
@[simps]
def nnnormHom : α →*₀ ℝ≥0 where
  toFun := (‖·‖₊)
  map_zero' := nnnorm_zero
  map_one' := nnnorm_one
  map_mul' := nnnorm_mul
#align nnnorm_hom nnnormHom

@[simp]
theorem norm_pow (a : α) : ∀ n : ℕ, ‖a ^ n‖ = ‖a‖ ^ n :=
  (normHom.toMonoidHom : α →* ℝ).map_pow a
#align norm_pow norm_pow

@[simp]
theorem nnnorm_pow (a : α) (n : ℕ) : ‖a ^ n‖₊ = ‖a‖₊ ^ n :=
  (nnnormHom.toMonoidHom : α →* ℝ≥0).map_pow a n
#align nnnorm_pow nnnorm_pow

protected theorem List.norm_prod (l : List α) : ‖l.prod‖ = (l.map norm).prod :=
  (normHom.toMonoidHom : α →* ℝ).map_list_prod _
#align list.norm_prod List.norm_prod

protected theorem List.nnnorm_prod (l : List α) : ‖l.prod‖₊ = (l.map nnnorm).prod :=
  (nnnormHom.toMonoidHom : α →* ℝ≥0).map_list_prod _
#align list.nnnorm_prod List.nnnorm_prod

@[simp]
theorem norm_div (a b : α) : ‖a / b‖ = ‖a‖ / ‖b‖ :=
  map_div₀ (normHom : α →*₀ ℝ) a b
#align norm_div norm_div

@[simp]
theorem nnnorm_div (a b : α) : ‖a / b‖₊ = ‖a‖₊ / ‖b‖₊ :=
  map_div₀ (nnnormHom : α →*₀ ℝ≥0) a b
#align nnnorm_div nnnorm_div

@[simp]
theorem norm_inv (a : α) : ‖a⁻¹‖ = ‖a‖⁻¹ :=
  map_inv₀ (normHom : α →*₀ ℝ) a
#align norm_inv norm_inv

@[simp]
theorem nnnorm_inv (a : α) : ‖a⁻¹‖₊ = ‖a‖₊⁻¹ :=
  NNReal.eq <| by simp
#align nnnorm_inv nnnorm_inv

@[simp]
theorem norm_zpow : ∀ (a : α) (n : ℤ), ‖a ^ n‖ = ‖a‖ ^ n :=
  map_zpow₀ (normHom : α →*₀ ℝ)
#align norm_zpow norm_zpow

@[simp]
theorem nnnorm_zpow : ∀ (a : α) (n : ℤ), ‖a ^ n‖₊ = ‖a‖₊ ^ n :=
  map_zpow₀ (nnnormHom : α →*₀ ℝ≥0)
#align nnnorm_zpow nnnorm_zpow

theorem dist_inv_inv₀ {z w : α} (hz : z ≠ 0) (hw : w ≠ 0) : dist z⁻¹ w⁻¹ = dist z w / (‖z‖ * ‖w‖) :=
  by
  rw [dist_eq_norm, inv_sub_inv' hz hw, norm_mul, norm_mul, norm_inv, norm_inv, mul_comm ‖z‖⁻¹,
    mul_assoc, dist_eq_norm', div_eq_mul_inv, mul_inv]
#align dist_inv_inv₀ dist_inv_inv₀

theorem nndist_inv_inv₀ {z w : α} (hz : z ≠ 0) (hw : w ≠ 0) :
    nndist z⁻¹ w⁻¹ = nndist z w / (‖z‖₊ * ‖w‖₊) := by
  rw [← NNReal.coe_eq]
  simp [-NNReal.coe_eq, dist_inv_inv₀ hz hw]
#align nndist_inv_inv₀ nndist_inv_inv₀

/-- Multiplication on the left by a nonzero element of a normed division ring tends to infinity at
infinity. TODO: use `Bornology.cobounded` instead of `Filter.comap Norm.norm Filter.atTop`. -/
theorem Filter.tendsto_mul_left_cobounded {a : α} (ha : a ≠ 0) :
    Tendsto ((· * ·) a) (comap norm atTop) (comap norm atTop) := by
  simpa only [tendsto_comap_iff, (· ∘ ·), norm_mul] using
    tendsto_const_nhds.mul_atTop (norm_pos_iff.2 ha) tendsto_comap
#align filter.tendsto_mul_left_cobounded Filter.tendsto_mul_left_cobounded

/-- Multiplication on the right by a nonzero element of a normed division ring tends to infinity at
infinity. TODO: use `Bornology.cobounded` instead of `Filter.comap Norm.norm Filter.atTop`. -/
theorem Filter.tendsto_mul_right_cobounded {a : α} (ha : a ≠ 0) :
    Tendsto (fun x => x * a) (comap norm atTop) (comap norm atTop) := by
  simpa only [tendsto_comap_iff, (· ∘ ·), norm_mul] using
    tendsto_comap.atTop_mul (norm_pos_iff.2 ha) tendsto_const_nhds
#align filter.tendsto_mul_right_cobounded Filter.tendsto_mul_right_cobounded

-- see Note [lower instance priority]
instance (priority := 100) NormedDivisionRing.to_hasContinuousInv₀ : HasContinuousInv₀ α := by
  refine' ⟨fun r r0 => tendsto_iff_norm_tendsto_zero.2 _⟩
  have r0' : 0 < ‖r‖ := norm_pos_iff.2 r0
  rcases exists_between r0' with ⟨ε, ε0, εr⟩
  have : ∀ᶠ e in 𝓝 r, ‖e⁻¹ - r⁻¹‖ ≤ ‖r - e‖ / ‖r‖ / ε :=
    by
    filter_upwards [(isOpen_lt continuous_const continuous_norm).eventually_mem εr]with e he
    have e0 : e ≠ 0 := norm_pos_iff.1 (ε0.trans he)
    calc
      ‖e⁻¹ - r⁻¹‖ = ‖r‖⁻¹ * ‖r - e‖ * ‖e‖⁻¹ := by
        rw [← norm_inv, ← norm_inv, ← norm_mul, ← norm_mul, _root_.mul_sub, _root_.sub_mul,
          mul_assoc _ e, inv_mul_cancel r0, mul_inv_cancel e0, one_mul, mul_one]
      -- porting note: `ENNReal.{mul_sub, sub_mul}` should be `protected`
      _ = ‖r - e‖ / ‖r‖ / ‖e‖ := by field_simp [mul_comm]
      _ ≤ ‖r - e‖ / ‖r‖ / ε :=
        div_le_div_of_le_left (div_nonneg (norm_nonneg _) (norm_nonneg _)) ε0 he.le

  refine' squeeze_zero' (eventually_of_forall fun _ => norm_nonneg _) this _
  refine' (((continuous_const.sub continuous_id).norm.div_const _).div_const _).tendsto' _ _ _
  simp
#align normed_division_ring.to_has_continuous_inv₀ NormedDivisionRing.to_hasContinuousInv₀

-- see Note [lower instance priority]
/-- A normed division ring is a topological division ring. -/
instance (priority := 100) NormedDivisionRing.to_topologicalDivisionRing : TopologicalDivisionRing α
    where
#align normed_division_ring.to_topological_division_ring NormedDivisionRing.to_topologicalDivisionRing

theorem norm_map_one_of_pow_eq_one [Monoid β] (φ : β →* α) {x : β} {k : ℕ+} (h : x ^ (k : ℕ) = 1) :
    ‖φ x‖ = 1 := by
  rw [← pow_left_inj, ← norm_pow, ← map_pow, h, map_one, norm_one, one_pow]
  exacts[norm_nonneg _, zero_le_one, k.pos]
#align norm_map_one_of_pow_eq_one norm_map_one_of_pow_eq_one

theorem norm_one_of_pow_eq_one {x : α} {k : ℕ+} (h : x ^ (k : ℕ) = 1) : ‖x‖ = 1 :=
  norm_map_one_of_pow_eq_one (MonoidHom.id α) h
#align norm_one_of_pow_eq_one norm_one_of_pow_eq_one

end NormedDivisionRing

/-- A normed field is a field with a norm satisfying ‖x y‖ = ‖x‖ ‖y‖. -/
class NormedField (α : Type _) extends Norm α, Field α, MetricSpace α where
  /-- The distance is induced by the norm. -/
  dist_eq : ∀ x y, dist x y = norm (x - y)
  /-- The norm is multiplicative. -/
  norm_mul' : ∀ a b, norm (a * b) = norm a * norm b
#align normed_field NormedField

/-- A nontrivially normed field is a normed field in which there is an element of norm different
from `0` and `1`. This makes it possible to bring any element arbitrarily close to `0` by
multiplication by the powers of any element, and thus to relate algebra and topology. -/
class NontriviallyNormedField (α : Type _) extends NormedField α where
  /-- The norm attains a value exceeding 1. -/
  non_trivial : ∃ x : α, 1 < ‖x‖
#align nontrivially_normed_field NontriviallyNormedField

/-- A densely normed field is a normed field for which the image of the norm is dense in `ℝ≥0`,
which means it is also nontrivially normed. However, not all nontrivally normed fields are densely
normed; in particular, the `padic`s exhibit this fact. -/
class DenselyNormedField (α : Type _) extends NormedField α where
  /-- The range of the norm is dense in the collection of nonnegative real numbers. -/
  lt_norm_lt : ∀ x y : ℝ, 0 ≤ x → x < y → ∃ a : α, x < ‖a‖ ∧ ‖a‖ < y
#align densely_normed_field DenselyNormedField

section NormedField

/-- A densely normed field is always a nontrivially normed field.
See note [lower instance priority]. -/
instance (priority := 100) DenselyNormedField.toNontriviallyNormedField [DenselyNormedField α] :
    NontriviallyNormedField α where
  non_trivial :=
    let ⟨a, h, _⟩ := DenselyNormedField.lt_norm_lt 1 2 zero_le_one one_lt_two
    ⟨a, h⟩
#align densely_normed_field.to_nontrivially_normed_field DenselyNormedField.toNontriviallyNormedField

variable [NormedField α]

-- see Note [lower instance priority]
instance (priority := 100) NormedField.toNormedDivisionRing : NormedDivisionRing α :=
  { ‹NormedField α› with }
#align normed_field.to_normed_division_ring NormedField.toNormedDivisionRing

-- see Note [lower instance priority]
instance (priority := 100) NormedField.toNormedCommRing : NormedCommRing α :=
  { ‹NormedField α› with norm_mul := fun a b => (norm_mul a b).le }
#align normed_field.to_normed_comm_ring NormedField.toNormedCommRing

@[simp]
theorem norm_prod (s : Finset β) (f : β → α) : ‖∏ b in s, f b‖ = ∏ b in s, ‖f b‖ :=
  (normHom.toMonoidHom : α →* ℝ).map_prod f s
#align norm_prod norm_prod

@[simp]
theorem nnnorm_prod (s : Finset β) (f : β → α) : ‖∏ b in s, f b‖₊ = ∏ b in s, ‖f b‖₊ :=
  (nnnormHom.toMonoidHom : α →* ℝ≥0).map_prod f s
#align nnnorm_prod nnnorm_prod

end NormedField

namespace NormedField

section Nontrivially

variable (α) [NontriviallyNormedField α]

theorem exists_one_lt_norm : ∃ x : α, 1 < ‖x‖ :=
  ‹NontriviallyNormedField α›.non_trivial
#align normed_field.exists_one_lt_norm NormedField.exists_one_lt_norm

theorem exists_lt_norm (r : ℝ) : ∃ x : α, r < ‖x‖ :=
  let ⟨w, hw⟩ := exists_one_lt_norm α
  let ⟨n, hn⟩ := pow_unbounded_of_one_lt r hw
  ⟨w ^ n, by rwa [norm_pow]⟩
#align normed_field.exists_lt_norm NormedField.exists_lt_norm

theorem exists_norm_lt {r : ℝ} (hr : 0 < r) : ∃ x : α, 0 < ‖x‖ ∧ ‖x‖ < r :=
  let ⟨w, hw⟩ := exists_lt_norm α r⁻¹
  ⟨w⁻¹, by rwa [← Set.mem_Ioo, norm_inv, ← Set.mem_inv, Set.inv_Ioo_0_left hr]⟩
#align normed_field.exists_norm_lt NormedField.exists_norm_lt

theorem exists_norm_lt_one : ∃ x : α, 0 < ‖x‖ ∧ ‖x‖ < 1 :=
  exists_norm_lt α one_pos
#align normed_field.exists_norm_lt_one NormedField.exists_norm_lt_one

variable {α}

@[instance]
theorem punctured_nhds_neBot (x : α) : NeBot (𝓝[≠] x) := by
  rw [← mem_closure_iff_nhdsWithin_neBot, Metric.mem_closure_iff]
  rintro ε ε0
  rcases exists_norm_lt α ε0 with ⟨b, hb0, hbε⟩
  refine' ⟨x + b, mt (Set.mem_singleton_iff.trans add_right_eq_self).1 <| norm_pos_iff.1 hb0, _⟩
  rwa [dist_comm, dist_eq_norm, add_sub_cancel']
#align normed_field.punctured_nhds_ne_bot NormedField.punctured_nhds_neBot

@[instance]
theorem nhdsWithin_isUnit_neBot : NeBot (𝓝[{ x : α | IsUnit x }] 0) := by
  simpa only [isUnit_iff_ne_zero] using punctured_nhds_neBot (0 : α)
#align normed_field.nhds_within_is_unit_ne_bot NormedField.nhdsWithin_isUnit_neBot

end Nontrivially

section Densely

variable (α) [DenselyNormedField α]

theorem exists_lt_norm_lt {r₁ r₂ : ℝ} (h₀ : 0 ≤ r₁) (h : r₁ < r₂) : ∃ x : α, r₁ < ‖x‖ ∧ ‖x‖ < r₂ :=
  DenselyNormedField.lt_norm_lt r₁ r₂ h₀ h
#align normed_field.exists_lt_norm_lt NormedField.exists_lt_norm_lt

theorem exists_lt_nnnorm_lt {r₁ r₂ : ℝ≥0} (h : r₁ < r₂) : ∃ x : α, r₁ < ‖x‖₊ ∧ ‖x‖₊ < r₂ := by
  exact_mod_cast exists_lt_norm_lt α r₁.prop h
#align normed_field.exists_lt_nnnorm_lt NormedField.exists_lt_nnnorm_lt

instance denselyOrdered_range_norm : DenselyOrdered (Set.range (norm : α → ℝ)) where
  dense := by
    rintro ⟨-, x, rfl⟩ ⟨-, y, rfl⟩ hxy
    let ⟨z, h⟩ := exists_lt_norm_lt α (norm_nonneg _) hxy
    exact ⟨⟨‖z‖, z, rfl⟩, h⟩
#align normed_field.densely_ordered_range_norm NormedField.denselyOrdered_range_norm

instance denselyOrdered_range_nnnorm : DenselyOrdered (Set.range (nnnorm : α → ℝ≥0)) where
  dense := by
    rintro ⟨-, x, rfl⟩ ⟨-, y, rfl⟩ hxy
    let ⟨z, h⟩ := exists_lt_nnnorm_lt α hxy
    exact ⟨⟨‖z‖₊, z, rfl⟩, h⟩
#align normed_field.densely_ordered_range_nnnorm NormedField.denselyOrdered_range_nnnorm

theorem denseRange_nnnorm : DenseRange (nnnorm : α → ℝ≥0) :=
  dense_of_exists_between fun _ _ hr =>
    let ⟨x, h⟩ := exists_lt_nnnorm_lt α hr
    ⟨‖x‖₊, ⟨x, rfl⟩, h⟩
#align normed_field.dense_range_nnnorm NormedField.denseRange_nnnorm

end Densely

end NormedField

instance Real.normedCommRing : NormedCommRing ℝ :=
  { Real.normedAddCommGroup, Real.commRing with norm_mul := fun x y => (abs_mul x y).le }

noncomputable instance Real.normedField : NormedField ℝ :=
  { Real.normedAddCommGroup, Real.field with
    norm_mul' := abs_mul }

noncomputable instance Real.denselyNormedField : DenselyNormedField ℝ where
  lt_norm_lt _ _ h₀ hr :=
    let ⟨x, h⟩ := exists_between hr
    ⟨x, by rwa [Real.norm_eq_abs, abs_of_nonneg (h₀.trans h.1.le)]⟩

namespace Real

theorem toNNReal_mul_nnnorm {x : ℝ} (y : ℝ) (hx : 0 ≤ x) : x.toNNReal * ‖y‖₊ = ‖x * y‖₊ := by
  ext
  simp only [NNReal.coe_mul, nnnorm_mul, coe_nnnorm, Real.toNNReal_of_nonneg, norm_of_nonneg, hx,
    coe_mk]
#align real.to_nnreal_mul_nnnorm Real.toNNReal_mul_nnnorm

theorem nnnorm_mul_toNNReal (x : ℝ) {y : ℝ} (hy : 0 ≤ y) : ‖x‖₊ * y.toNNReal = ‖x * y‖₊ := by
  rw [mul_comm, mul_comm x, toNNReal_mul_nnnorm x hy]
#align real.nnnorm_mul_to_nnreal Real.nnnorm_mul_toNNReal

end Real

namespace NNReal

open NNReal

-- porting note: removed `@[simp]` because `simp` can prove this
theorem norm_eq (x : ℝ≥0) : ‖(x : ℝ)‖ = x := by rw [Real.norm_eq_abs, x.abs_eq]
#align nnreal.norm_eq NNReal.norm_eq

@[simp]
theorem nnnorm_eq (x : ℝ≥0) : ‖(x : ℝ)‖₊ = x :=
  NNReal.eq <| Real.norm_of_nonneg x.2
#align nnreal.nnnorm_eq NNReal.nnnorm_eq

end NNReal

@[simp 1001] -- porting note: increase priority so that the LHS doesn't simplify
theorem norm_norm [SeminormedAddCommGroup α] (x : α) : ‖‖x‖‖ = ‖x‖ :=
  Real.norm_of_nonneg (norm_nonneg _)
#align norm_norm norm_norm

@[simp]
theorem nnnorm_norm [SeminormedAddCommGroup α] (a : α) : ‖‖a‖‖₊ = ‖a‖₊ := by
  rw [Real.nnnorm_of_nonneg (norm_nonneg a)]; rfl
#align nnnorm_norm nnnorm_norm

/-- A restatement of `MetricSpace.tendsto_atTop` in terms of the norm. -/
theorem NormedAddCommGroup.tendsto_atTop [Nonempty α] [SemilatticeSup α] {β : Type _}
    [SeminormedAddCommGroup β] {f : α → β} {b : β} :
    Tendsto f atTop (𝓝 b) ↔ ∀ ε, 0 < ε → ∃ N, ∀ n, N ≤ n → ‖f n - b‖ < ε :=
  (atTop_basis.tendsto_iff Metric.nhds_basis_ball).trans (by simp [dist_eq_norm])
#align normed_add_comm_group.tendsto_at_top NormedAddCommGroup.tendsto_atTop

/-- A variant of `NormedAddCommGroup.tendsto_atTop` that
uses `∃ N, ∀ n > N, ...` rather than `∃ N, ∀ n ≥ N, ...`
-/
theorem NormedAddCommGroup.tendsto_atTop' [Nonempty α] [SemilatticeSup α] [NoMaxOrder α]
    {β : Type _} [SeminormedAddCommGroup β] {f : α → β} {b : β} :
    Tendsto f atTop (𝓝 b) ↔ ∀ ε, 0 < ε → ∃ N, ∀ n, N < n → ‖f n - b‖ < ε :=
  (atTop_basis_Ioi.tendsto_iff Metric.nhds_basis_ball).trans (by simp [dist_eq_norm])
#align normed_add_comm_group.tendsto_at_top' NormedAddCommGroup.tendsto_atTop'

instance Int.normedCommRing : NormedCommRing ℤ :=
  { Int.normedAddCommGroup, Int.instRingInt with
    norm_mul := fun m n => le_of_eq <| by simp only [norm, Int.cast_mul, abs_mul]
    mul_comm := mul_comm }

instance Int.normOneClass : NormOneClass ℤ :=
  ⟨by simp [← Int.norm_cast_real]⟩

instance Rat.normedField : NormedField ℚ :=
  { Rat.normedAddCommGroup, Rat.field with
    norm_mul' := fun r₁ r₂ => by simp only [norm, Rat.cast_mul, abs_mul] }

instance Rat.denselyNormedField : DenselyNormedField ℚ where
  lt_norm_lt r₁ r₂ h₀ hr :=
    let ⟨q, h⟩ := exists_rat_btwn hr
    ⟨q, by rwa [←Rat.norm_cast_real, Real.norm_eq_abs, abs_of_pos (h₀.trans_lt h.1)]⟩
section RingHomIsometric

variable {R₁ : Type _} {R₂ : Type _} {R₃ : Type _}

/-- This class states that a ring homomorphism is isometric. This is a sufficient assumption
for a continuous semilinear map to be bounded and this is the main use for this typeclass. -/
class RingHomIsometric [Semiring R₁] [Semiring R₂] [Norm R₁] [Norm R₂] (σ : R₁ →+* R₂) : Prop where
  /-- The ring homomorphism is an isometry. -/
  is_iso : ∀ {x : R₁}, ‖σ x‖ = ‖x‖
#align ring_hom_isometric RingHomIsometric

attribute [simp] RingHomIsometric.is_iso

variable [SeminormedRing R₁] [SeminormedRing R₂] [SeminormedRing R₃]

instance RingHomIsometric.ids : RingHomIsometric (RingHom.id R₁) :=
  ⟨rfl⟩
#align ring_hom_isometric.ids RingHomIsometric.ids

end RingHomIsometric

/-! ### Induced normed structures -/

section Induced

variable {F : Type _} (R S : Type _)

/-- A non-unital ring homomorphism from an `NonUnitalRing` to a `NonUnitalSeminormedRing`
induces a `NonUnitalSeminormedRing` structure on the domain.

See note [reducible non-instances] -/
@[reducible]
def NonUnitalSeminormedRing.induced [NonUnitalRing R] [NonUnitalSeminormedRing S]
    [NonUnitalRingHomClass F R S] (f : F) : NonUnitalSeminormedRing R :=
  { SeminormedAddCommGroup.induced R S f, ‹NonUnitalRing R› with
    norm_mul := fun x y => by
      show ‖f (x * y)‖ ≤ ‖f x‖ * ‖f y‖
      exact (map_mul f x y).symm ▸ norm_mul_le (f x) (f y) }
#align non_unital_semi_normed_ring.induced NonUnitalSeminormedRing.induced

/-- An injective non-unital ring homomorphism from an `NonUnitalRing` to a
`NonUnitalNormedRing` induces a `NonUnitalNormedRing` structure on the domain.

See note [reducible non-instances] -/
@[reducible]
def NonUnitalNormedRing.induced [NonUnitalRing R] [NonUnitalNormedRing S]
    [NonUnitalRingHomClass F R S] (f : F) (hf : Function.Injective f) : NonUnitalNormedRing R :=
  { NonUnitalSeminormedRing.induced R S f, NormedAddCommGroup.induced R S f hf with }
#align non_unital_normed_ring.induced NonUnitalNormedRing.induced

/-- A non-unital ring homomorphism from an `Ring` to a `SeminormedRing` induces a
`SeminormedRing` structure on the domain.

See note [reducible non-instances] -/
@[reducible]
def SeminormedRing.induced [Ring R] [SeminormedRing S] [NonUnitalRingHomClass F R S] (f : F) :
    SeminormedRing R :=
  { NonUnitalSeminormedRing.induced R S f, SeminormedAddCommGroup.induced R S f, ‹Ring R› with }
#align semi_normed_ring.induced SeminormedRing.induced

/-- An injective non-unital ring homomorphism from an `Ring` to a `NormedRing` induces a
`NormedRing` structure on the domain.

See note [reducible non-instances] -/
@[reducible]
def NormedRing.induced [Ring R] [NormedRing S] [NonUnitalRingHomClass F R S] (f : F)
    (hf : Function.Injective f) : NormedRing R :=
  { NonUnitalSeminormedRing.induced R S f, NormedAddCommGroup.induced R S f hf, ‹Ring R› with }
#align normed_ring.induced NormedRing.induced

/-- A non-unital ring homomorphism from a `CommRing` to a `SeminormedRing` induces a
`SeminormedCommRing` structure on the domain.

See note [reducible non-instances] -/
@[reducible]
def SeminormedCommRing.induced [CommRing R] [SeminormedRing S] [NonUnitalRingHomClass F R S]
    (f : F) : SeminormedCommRing R :=
  { NonUnitalSeminormedRing.induced R S f, SeminormedAddCommGroup.induced R S f, ‹CommRing R› with }
#align semi_normed_comm_ring.induced SeminormedCommRing.induced

/-- An injective non-unital ring homomorphism from an `CommRing` to a `NormedRing` induces a
`NormedCommRing` structure on the domain.

See note [reducible non-instances] -/
@[reducible]
def NormedCommRing.induced [CommRing R] [NormedRing S] [NonUnitalRingHomClass F R S] (f : F)
    (hf : Function.Injective f) : NormedCommRing R :=
  { SeminormedCommRing.induced R S f, NormedAddCommGroup.induced R S f hf with }
#align normed_comm_ring.induced NormedCommRing.induced

/-- An injective non-unital ring homomorphism from an `DivisionRing` to a `NormedRing` induces a
`NormedDivisionRing` structure on the domain.

See note [reducible non-instances] -/
@[reducible]
def NormedDivisionRing.induced [DivisionRing R] [NormedDivisionRing S] [NonUnitalRingHomClass F R S]
    (f : F) (hf : Function.Injective f) : NormedDivisionRing R :=
  { NormedAddCommGroup.induced R S f hf, ‹DivisionRing R› with
    norm_mul' := fun x y => by
      show ‖f (x * y)‖ = ‖f x‖ * ‖f y‖
      exact (map_mul f x y).symm ▸ norm_mul (f x) (f y) }
#align normed_division_ring.induced NormedDivisionRing.induced

/-- An injective non-unital ring homomorphism from an `Field` to a `NormedRing` induces a
`NormedField` structure on the domain.

See note [reducible non-instances] -/
@[reducible]
def NormedField.induced [Field R] [NormedField S] [NonUnitalRingHomClass F R S] (f : F)
    (hf : Function.Injective f) : NormedField R :=
  { NormedDivisionRing.induced R S f hf with
    mul_comm := mul_comm }
#align normed_field.induced NormedField.induced

/-- A ring homomorphism from a `Ring R` to a `SeminormedRing S` which induces the norm structure
`SeminormedRing.induced` makes `R` satisfy `‖(1 : R)‖ = 1` whenever `‖(1 : S)‖ = 1`. -/
theorem NormOneClass.induced {F : Type _} (R S : Type _) [Ring R] [SeminormedRing S]
    [NormOneClass S] [RingHomClass F R S] (f : F) :
    @NormOneClass R (SeminormedRing.induced R S f).toNorm _ :=
  -- porting note: is this `let` a bad idea somehow?
  let _ : SeminormedRing R := SeminormedRing.induced R S f
  { norm_one := (congr_arg norm (map_one f)).trans norm_one }
#align norm_one_class.induced NormOneClass.induced

end Induced

namespace SubringClass

variable {S R : Type _} [SetLike S R]

instance toSeminormedRing [SeminormedRing R] [SubringClass S R] (s : S) : SeminormedRing s :=
  SeminormedRing.induced s R (SubringClass.subtype s)
#align subring_class.to_semi_normed_ring SubringClass.toSeminormedRing

instance toNormedRing [NormedRing R] [SubringClass S R] (s : S) : NormedRing s :=
  NormedRing.induced s R (SubringClass.subtype s) Subtype.val_injective
#align subring_class.to_normed_ring SubringClass.toNormedRing

instance toSeminormedCommRing [SeminormedCommRing R] [_h : SubringClass S R] (s : S) :
    SeminormedCommRing s :=
  { SubringClass.toSeminormedRing s with mul_comm := mul_comm }
#align subring_class.to_semi_normed_comm_ring SubringClass.toSeminormedCommRing

instance toNormedCommRing [NormedCommRing R] [SubringClass S R] (s : S) : NormedCommRing s :=
  { SubringClass.toNormedRing s with mul_comm := mul_comm }
#align subring_class.to_normed_comm_ring SubringClass.toNormedCommRing

end SubringClass

-- porting note: add this back in once `assert_not_exists` is ported
/-
-- Guard again import creep.
assert_not_exists RestrictScalars
-/


lemma add_comm (a b : mynat) : a + b = b + a :=
begin
induction b with c hc,
rw add_zero,
rw zero_add,
refl,
rw add_succ,
rw succ_add,
rw hc,
refl,
end