/-
Copyright (c) 2020 Aaron Anderson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Aaron Anderson

! This file was ported from Lean 3 source module order.atoms
! leanprover-community/mathlib commit 422e70f7ce183d2900c586a8cda8381e788a0c62
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Order.ModularLattice
import Mathlib.Order.WellFounded

/-!
# Atoms, Coatoms, and Simple Lattices

This module defines atoms, which are minimal non-`⊥` elements in bounded lattices, simple lattices,
which are lattices with only two elements, and related ideas.

## Main definitions

### Atoms and Coatoms
  * `IsAtom a` indicates that the only element below `a` is `⊥`.
  * `IsCoatom a` indicates that the only element above `a` is `⊤`.

### Atomic and Atomistic Lattices
  * `IsAtomic` indicates that every element other than `⊥` is above an atom.
  * `IsCoatomic` indicates that every element other than `⊤` is below a coatom.
  * `IsAtomistic` indicates that every element is the `supₛ` of a set of atoms.
  * `IsCoatomistic` indicates that every element is the `infₛ` of a set of coatoms.

### Simple Lattices
  * `IsSimpleOrder` indicates that an order has only two unique elements, `⊥` and `⊤`.
  * `IsSimpleOrder.boundedOrder`
  * `IsSimpleOrder.distribLattice`
  * Given an instance of `IsSimpleOrder`, we provide the following definitions. These are not
    made global instances as they contain data :
    * `IsSimpleOrder.booleanAlgebra`
    * `IsSimpleOrder.completeLattice`
    * `IsSimpleOrder.completeBooleanAlgebra`

## Main results
  * `isAtom_dual_iff_isCoatom` and `isCoatom_dual_iff_isAtom` express the (definitional) duality
   of `IsAtom` and `IsCoatom`.
  * `isSimpleOrder_iff_isAtom_top` and `isSimpleOrder_iff_isCoatom_bot` express the
  connection between atoms, coatoms, and simple lattices
  * `IsCompl.isAtom_iff_isCoatom` and `IsCompl.isCoatom_if_isAtom`: In a modular
  bounded lattice, a complement of an atom is a coatom and vice versa.
  * `isAtomic_iff_isCoatomic`: A modular complemented lattice is atomic iff it is coatomic.

-/

variable {α β : Type _}

section Atoms

section IsAtom

section Preorder

variable [Preorder α] [OrderBot α] {a b x : α}

/-- An atom of an `OrderBot` is an element with no other element between it and `⊥`,
  which is not `⊥`. -/
def IsAtom (a : α) : Prop :=
  a ≠ ⊥ ∧ ∀ b, b < a → b = ⊥
#align is_atom IsAtom

theorem IsAtom.Iic (ha : IsAtom a) (hax : a ≤ x) : IsAtom (⟨a, hax⟩ : Set.Iic x) :=
  ⟨fun con => ha.1 (Subtype.mk_eq_mk.1 con), fun ⟨b, _⟩ hba => Subtype.mk_eq_mk.2 (ha.2 b hba)⟩
#align is_atom.Iic IsAtom.Iic

theorem IsAtom.of_isAtom_coe_Iic {a : Set.Iic x} (ha : IsAtom a) : IsAtom (a : α) :=
  ⟨fun con => ha.1 (Subtype.ext con), fun b hba =>
    Subtype.mk_eq_mk.1 (ha.2 ⟨b, hba.le.trans a.prop⟩ hba)⟩
#align is_atom.of_is_atom_coe_Iic IsAtom.of_isAtom_coe_Iic

theorem isAtom_iff {a : α} : IsAtom a ↔ a ≠ ⊥ ∧ ∀ (b) (_ : b ≠ ⊥), b ≤ a → a ≤ b :=
  and_congr Iff.rfl <|
    forall_congr' fun b => by simp only [Ne.def, @not_imp_comm (b = ⊥), not_imp, lt_iff_le_not_le]
#align is_atom_iff isAtom_iff

end Preorder

variable [PartialOrder α] [OrderBot α] {a b x : α}

theorem IsAtom.lt_iff (h : IsAtom a) : x < a ↔ x = ⊥ :=
  ⟨h.2 x, fun hx => hx.symm ▸ h.1.bot_lt⟩
#align is_atom.lt_iff IsAtom.lt_iff

theorem IsAtom.le_iff (h : IsAtom a) : x ≤ a ↔ x = ⊥ ∨ x = a := by rw [le_iff_lt_or_eq, h.lt_iff]
#align is_atom.le_iff IsAtom.le_iff

theorem IsAtom.Iic_eq (h : IsAtom a) : Set.Iic a = {⊥, a} :=
  Set.ext fun _ => h.le_iff
#align is_atom.Iic_eq IsAtom.Iic_eq

@[simp]
theorem bot_covby_iff : ⊥ ⋖ a ↔ IsAtom a := by
  simp only [Covby, bot_lt_iff_ne_bot, IsAtom, not_imp_not]
#align bot_covby_iff bot_covby_iff

alias bot_covby_iff ↔ Covby.is_atom IsAtom.bot_covby
#align covby.is_atom Covby.is_atom
#align is_atom.bot_covby IsAtom.bot_covby

end IsAtom

section IsCoatom

section Preorder

variable [Preorder α]

/-- A coatom of an `OrderTop` is an element with no other element between it and `⊤`,
  which is not `⊤`. -/
def IsCoatom [OrderTop α] (a : α) : Prop :=
  a ≠ ⊤ ∧ ∀ b, a < b → b = ⊤
#align is_coatom IsCoatom

@[simp]
theorem isCoatom_dual_iff_isAtom [OrderBot α] {a : α} :
    IsCoatom (OrderDual.toDual a) ↔ IsAtom a :=
  Iff.rfl
#align is_coatom_dual_iff_is_atom isCoatom_dual_iff_isAtom

@[simp]
theorem isAtom_dual_iff_isCoatom [OrderTop α] {a : α} :
    IsAtom (OrderDual.toDual a) ↔ IsCoatom a :=
  Iff.rfl
#align is_atom_dual_iff_is_coatom isAtom_dual_iff_isCoatom

alias isCoatom_dual_iff_isAtom ↔ _ IsAtom.dual
#align is_atom.dual IsAtom.dual

alias isAtom_dual_iff_isCoatom ↔ _ IsCoatom.dual
#align is_coatom.dual IsCoatom.dual

variable [OrderTop α] {a x : α}

theorem IsCoatom.Ici (ha : IsCoatom a) (hax : x ≤ a) : IsCoatom (⟨a, hax⟩ : Set.Ici x) :=
  ha.dual.Iic hax
#align is_coatom.Ici IsCoatom.Ici

theorem IsCoatom.of_isCoatom_coe_Ici {a : Set.Ici x} (ha : IsCoatom a) : IsCoatom (a : α) :=
  @IsAtom.of_isAtom_coe_Iic αᵒᵈ _ _ x a ha
#align is_coatom.of_is_coatom_coe_Ici IsCoatom.of_isCoatom_coe_Ici

theorem isCoatom_iff {a : α} : IsCoatom a ↔ a ≠ ⊤ ∧ ∀ (b) (_ : b ≠ ⊤), a ≤ b → b ≤ a :=
  @isAtom_iff αᵒᵈ _ _ _
#align is_coatom_iff isCoatom_iff

end Preorder

variable [PartialOrder α] [OrderTop α] {a b x : α}

theorem IsCoatom.lt_iff (h : IsCoatom a) : a < x ↔ x = ⊤ :=
  h.dual.lt_iff
#align is_coatom.lt_iff IsCoatom.lt_iff

theorem IsCoatom.le_iff (h : IsCoatom a) : a ≤ x ↔ x = ⊤ ∨ x = a :=
  h.dual.le_iff
#align is_coatom.le_iff IsCoatom.le_iff

theorem IsCoatom.Ici_eq (h : IsCoatom a) : Set.Ici a = {⊤, a} :=
  h.dual.Iic_eq
#align is_coatom.Ici_eq IsCoatom.Ici_eq

@[simp]
theorem covby_top_iff : a ⋖ ⊤ ↔ IsCoatom a :=
  toDual_covby_toDual_iff.symm.trans bot_covby_iff
#align covby_top_iff covby_top_iff

alias covby_top_iff ↔ Covby.is_coatom IsCoatom.covby_top
#align covby.is_coatom Covby.is_coatom
#align is_coatom.covby_top IsCoatom.covby_top

end IsCoatom

section PartialOrder

variable [PartialOrder α] {a b : α}

@[simp]
theorem Set.Ici.isAtom_iff {b : Set.Ici a} : IsAtom b ↔ a ⋖ b := by
  rw [← bot_covby_iff]
  refine' (Set.OrdConnected.apply_covby_apply_iff (OrderEmbedding.subtype fun c => a ≤ c) _).symm
  simpa only [OrderEmbedding.subtype_apply, Subtype.range_coe_subtype] using Set.ordConnected_Ici
#align set.Ici.is_atom_iff Set.Ici.isAtom_iff

@[simp]
theorem Set.Iic.isCoatom_iff {a : Set.Iic b} : IsCoatom a ↔ ↑a ⋖ b := by
  rw [← covby_top_iff]
  refine' (Set.OrdConnected.apply_covby_apply_iff (OrderEmbedding.subtype fun c => c ≤ b) _).symm
  simpa only [OrderEmbedding.subtype_apply, Subtype.range_coe_subtype] using Set.ordConnected_Iic
#align set.Iic.is_coatom_iff Set.Iic.isCoatom_iff

theorem covby_iff_atom_Ici (h : a ≤ b) : a ⋖ b ↔ IsAtom (⟨b, h⟩ : Set.Ici a) := by simp
#align covby_iff_atom_Ici covby_iff_atom_Ici

theorem covby_iff_coatom_Iic (h : a ≤ b) : a ⋖ b ↔ IsCoatom (⟨a, h⟩ : Set.Iic b) := by simp
#align covby_iff_coatom_Iic covby_iff_coatom_Iic

end PartialOrder

section Pairwise

theorem IsAtom.inf_eq_bot_of_ne [SemilatticeInf α] [OrderBot α] {a b : α} (ha : IsAtom a)
    (hb : IsAtom b) (hab : a ≠ b) : a ⊓ b = ⊥ :=
  hab.not_le_or_not_le.elim (ha.lt_iff.1 ∘ inf_lt_left.2) (hb.lt_iff.1 ∘ inf_lt_right.2)
#align is_atom.inf_eq_bot_of_ne IsAtom.inf_eq_bot_of_ne

theorem IsAtom.disjoint_of_ne [SemilatticeInf α] [OrderBot α] {a b : α} (ha : IsAtom a)
    (hb : IsAtom b) (hab : a ≠ b) : Disjoint a b :=
  disjoint_iff.mpr (IsAtom.inf_eq_bot_of_ne ha hb hab)
#align is_atom.disjoint_of_ne IsAtom.disjoint_of_ne

theorem IsCoatom.sup_eq_top_of_ne [SemilatticeSup α] [OrderTop α] {a b : α} (ha : IsCoatom a)
    (hb : IsCoatom b) (hab : a ≠ b) : a ⊔ b = ⊤ :=
  ha.dual.inf_eq_bot_of_ne hb.dual hab
#align is_coatom.sup_eq_top_of_ne IsCoatom.sup_eq_top_of_ne

end Pairwise

end Atoms

section Atomic

variable [PartialOrder α] (α)

/-- A lattice is atomic iff every element other than `⊥` has an atom below it. -/
@[mk_iff]
class IsAtomic [OrderBot α] : Prop where
  /--Every element other than `⊥` has an atom below it. -/
  eq_bot_or_exists_atom_le : ∀ b : α, b = ⊥ ∨ ∃ a : α, IsAtom a ∧ a ≤ b
#align is_atomic IsAtomic
#align is_atomic_iff IsAtomic_iff

/-- A lattice is coatomic iff every element other than `⊤` has a coatom above it. -/
@[mk_iff]
class IsCoatomic [OrderTop α] : Prop where
  /--Every element other than `⊤` has an atom above it. -/
  eq_top_or_exists_le_coatom : ∀ b : α, b = ⊤ ∨ ∃ a : α, IsCoatom a ∧ b ≤ a
#align is_coatomic IsCoatomic
#align is_coatomic_iff IsCoatomic_iff

export IsAtomic (eq_bot_or_exists_atom_le)

export IsCoatomic (eq_top_or_exists_le_coatom)

variable {α}

@[simp]
theorem isCoatomic_dual_iff_isAtomic [OrderBot α] : IsCoatomic αᵒᵈ ↔ IsAtomic α :=
  ⟨fun h => ⟨fun b => by apply h.eq_top_or_exists_le_coatom⟩, fun h =>
    ⟨fun b => by apply h.eq_bot_or_exists_atom_le⟩⟩
#align is_coatomic_dual_iff_is_atomic isCoatomic_dual_iff_isAtomic

@[simp]
theorem isAtomic_dual_iff_isCoatomic [OrderTop α] : IsAtomic αᵒᵈ ↔ IsCoatomic α :=
  ⟨fun h => ⟨fun b => by apply h.eq_bot_or_exists_atom_le⟩, fun h =>
    ⟨fun b => by apply h.eq_top_or_exists_le_coatom⟩⟩
#align is_atomic_dual_iff_is_coatomic isAtomic_dual_iff_isCoatomic

namespace IsAtomic

variable [OrderBot α] [IsAtomic α]

instance isCoatomic_dual : IsCoatomic αᵒᵈ :=
  isCoatomic_dual_iff_isAtomic.2 ‹IsAtomic α›
#align is_atomic.is_coatomic_dual IsAtomic.isCoatomic_dual

instance Set.Iic.isAtomic {x : α} : IsAtomic (Set.Iic x) :=
  ⟨fun ⟨y, hy⟩ =>
    (eq_bot_or_exists_atom_le y).imp Subtype.mk_eq_mk.2 fun ⟨a, ha, hay⟩ =>
      ⟨⟨a, hay.trans hy⟩, ha.Iic (hay.trans hy), hay⟩⟩
#align is_atomic.set.Iic.is_atomic IsAtomic.Set.Iic.isAtomic

end IsAtomic

namespace IsCoatomic

variable [OrderTop α] [IsCoatomic α]

instance isCoatomic : IsAtomic αᵒᵈ :=
  isAtomic_dual_iff_isCoatomic.2 ‹IsCoatomic α›
#align is_coatomic.is_coatomic IsCoatomic.isCoatomic

instance Set.Ici.isCoatomic {x : α} : IsCoatomic (Set.Ici x) :=
  ⟨fun ⟨y, hy⟩ =>
    (eq_top_or_exists_le_coatom y).imp Subtype.mk_eq_mk.2 fun ⟨a, ha, hay⟩ =>
      ⟨⟨a, le_trans hy hay⟩, ha.Ici (le_trans hy hay), hay⟩⟩
#align is_coatomic.set.Ici.is_coatomic IsCoatomic.Set.Ici.isCoatomic

end IsCoatomic

theorem isAtomic_iff_forall_isAtomic_Iic [OrderBot α] :
    IsAtomic α ↔ ∀ x : α, IsAtomic (Set.Iic x) :=
  ⟨@IsAtomic.Set.Iic.isAtomic _ _ _, fun h =>
    ⟨fun x =>
      ((@eq_bot_or_exists_atom_le _ _ _ (h x)) (⊤ : Set.Iic x)).imp Subtype.mk_eq_mk.1
        (Exists.imp' (↑) fun ⟨_, _⟩ => And.imp_left IsAtom.of_isAtom_coe_Iic)⟩⟩
#align is_atomic_iff_forall_is_atomic_Iic isAtomic_iff_forall_isAtomic_Iic

theorem isCoatomic_iff_forall_isCoatomic_Ici [OrderTop α] :
    IsCoatomic α ↔ ∀ x : α, IsCoatomic (Set.Ici x) :=
  isAtomic_dual_iff_isCoatomic.symm.trans <|
    isAtomic_iff_forall_isAtomic_Iic.trans <|
      forall_congr' fun _ => isCoatomic_dual_iff_isAtomic.symm.trans Iff.rfl
#align is_coatomic_iff_forall_is_coatomic_Ici isCoatomic_iff_forall_isCoatomic_Ici

section WellFounded

theorem isAtomic_of_orderBot_wellFounded_lt [OrderBot α]
    (h : WellFounded ((· < ·) : α → α → Prop)) : IsAtomic α :=
  ⟨fun a =>
    or_iff_not_imp_left.2 fun ha =>
      let ⟨b, hb, hm⟩ := h.has_min { b | b ≠ ⊥ ∧ b ≤ a } ⟨a, ha, le_rfl⟩
      ⟨b, ⟨hb.1, fun c => not_imp_not.1 fun hc hl => hm c ⟨hc, hl.le.trans hb.2⟩ hl⟩, hb.2⟩⟩
#align is_atomic_of_order_bot_well_founded_lt isAtomic_of_orderBot_wellFounded_lt

theorem isCoatomic_of_orderTop_gt_wellFounded [OrderTop α]
    (h : WellFounded ((· > ·) : α → α → Prop)) : IsCoatomic α :=
  isAtomic_dual_iff_isCoatomic.1 (@isAtomic_of_orderBot_wellFounded_lt αᵒᵈ _ _ h)
#align is_coatomic_of_order_top_gt_well_founded isCoatomic_of_orderTop_gt_wellFounded

end WellFounded

end Atomic

section Atomistic

variable (α) [CompleteLattice α]

/-- A lattice is atomistic iff every element is a `supₛ` of a set of atoms. -/
class IsAtomistic : Prop where
  /--Every element is a `supₛ` of a set of atoms. -/
  eq_supₛ_atoms : ∀ b : α, ∃ s : Set α, b = supₛ s ∧ ∀ a, a ∈ s → IsAtom a
#align is_atomistic IsAtomistic
#align is_atomistic.eq_Sup_atoms IsAtomistic.eq_supₛ_atoms

/-- A lattice is coatomistic iff every element is an `infₛ` of a set of coatoms. -/
class IsCoatomistic : Prop where
  /--Every element is a `infₛ` of a set of coatoms. -/
  eq_infₛ_coatoms : ∀ b : α, ∃ s : Set α, b = infₛ s ∧ ∀ a, a ∈ s → IsCoatom a
#align is_coatomistic IsCoatomistic
#align is_coatomistic.eq_Inf_coatoms IsCoatomistic.eq_infₛ_coatoms

export IsAtomistic (eq_supₛ_atoms)

export IsCoatomistic (eq_infₛ_coatoms)

variable {α}

@[simp]
theorem isCoatomistic_dual_iff_isAtomistic : IsCoatomistic αᵒᵈ ↔ IsAtomistic α :=
  ⟨fun h => ⟨fun b => by apply h.eq_infₛ_coatoms⟩, fun h => ⟨fun b => by apply h.eq_supₛ_atoms⟩⟩
#align is_coatomistic_dual_iff_is_atomistic isCoatomistic_dual_iff_isAtomistic

@[simp]
theorem isAtomistic_dual_iff_isCoatomistic : IsAtomistic αᵒᵈ ↔ IsCoatomistic α :=
  ⟨fun h => ⟨fun b => by apply h.eq_supₛ_atoms⟩, fun h => ⟨fun b => by apply h.eq_infₛ_coatoms⟩⟩
#align is_atomistic_dual_iff_is_coatomistic isAtomistic_dual_iff_isCoatomistic

namespace IsAtomistic

instance isCoatomistic_dual [h : IsAtomistic α] : IsCoatomistic αᵒᵈ :=
  isCoatomistic_dual_iff_isAtomistic.2 h
#align is_atomistic.is_coatomistic_dual IsAtomistic.isCoatomistic_dual

variable [IsAtomistic α]

instance (priority := 100) : IsAtomic α :=
  ⟨fun b => by
    rcases eq_supₛ_atoms b with ⟨s, rfl, hs⟩
    cases' s.eq_empty_or_nonempty with h h
    · simp [h]
    · exact Or.intro_right _ ⟨h.some, hs _ h.choose_spec, le_supₛ h.choose_spec⟩⟩

end IsAtomistic

section IsAtomistic

variable [IsAtomistic α]

@[simp]
theorem supₛ_atoms_le_eq (b : α) : supₛ { a : α | IsAtom a ∧ a ≤ b } = b := by
  rcases eq_supₛ_atoms b with ⟨s, rfl, hs⟩
  exact le_antisymm (supₛ_le fun _ => And.right) (supₛ_le_supₛ fun a ha => ⟨hs a ha, le_supₛ ha⟩)
#align Sup_atoms_le_eq supₛ_atoms_le_eq

@[simp]
theorem supₛ_atoms_eq_top : supₛ { a : α | IsAtom a } = ⊤ := by
  refine' Eq.trans (congr rfl (Set.ext fun x => _)) (supₛ_atoms_le_eq ⊤)
  exact (and_iff_left le_top).symm
#align Sup_atoms_eq_top supₛ_atoms_eq_top

theorem le_iff_atom_le_imp {a b : α} : a ≤ b ↔ ∀ c : α, IsAtom c → c ≤ a → c ≤ b :=
  ⟨fun ab c _ ca => le_trans ca ab, fun h =>
    by
    rw [← supₛ_atoms_le_eq a, ← supₛ_atoms_le_eq b]
    exact supₛ_le_supₛ fun c hc => ⟨hc.1, h c hc.1 hc.2⟩⟩
#align le_iff_atom_le_imp le_iff_atom_le_imp

end IsAtomistic

namespace IsCoatomistic

instance isAtomistic_dual [h : IsCoatomistic α] : IsAtomistic αᵒᵈ :=
  isAtomistic_dual_iff_isCoatomistic.2 h
#align is_coatomistic.is_atomistic_dual IsCoatomistic.isAtomistic_dual

variable [IsCoatomistic α]

instance (priority := 100) : IsCoatomic α :=
  ⟨fun b => by
    rcases eq_infₛ_coatoms b with ⟨s, rfl, hs⟩
    cases' s.eq_empty_or_nonempty with h h
    · simp [h]
    · exact Or.intro_right _ ⟨h.some, hs _ h.choose_spec, infₛ_le h.choose_spec⟩⟩

end IsCoatomistic

end Atomistic

/-- An order is simple iff it has exactly two elements, `⊥` and `⊤`. -/
class IsSimpleOrder (α : Type _) [LE α] [BoundedOrder α] extends Nontrivial α : Prop where
  /-- Every element is either `⊥` or `⊤` -/
  eq_bot_or_eq_top : ∀ a : α, a = ⊥ ∨ a = ⊤
#align is_simple_order IsSimpleOrder

export IsSimpleOrder (eq_bot_or_eq_top)

theorem isSimpleOrder_iff_isSimpleOrder_orderDual [LE α] [BoundedOrder α] :
    IsSimpleOrder α ↔ IsSimpleOrder αᵒᵈ := by
  constructor <;> intro i <;> haveI := i
  · exact
      { exists_pair_ne := @exists_pair_ne α _
        eq_bot_or_eq_top := fun a => Or.symm (eq_bot_or_eq_top (OrderDual.ofDual a) : _ ∨ _) }
  · exact
      { exists_pair_ne := @exists_pair_ne αᵒᵈ _
        eq_bot_or_eq_top := fun a => Or.symm (eq_bot_or_eq_top (OrderDual.toDual a)) }
#align is_simple_order_iff_is_simple_order_order_dual isSimpleOrder_iff_isSimpleOrder_orderDual

theorem IsSimpleOrder.bot_ne_top [LE α] [BoundedOrder α] [IsSimpleOrder α] : (⊥ : α) ≠ (⊤ : α) := by
  obtain ⟨a, b, h⟩ := exists_pair_ne α
  rcases eq_bot_or_eq_top a with (rfl | rfl) <;> rcases eq_bot_or_eq_top b with (rfl | rfl) <;>
    first |simpa|simpa using h.symm
#align is_simple_order.bot_ne_top IsSimpleOrder.bot_ne_top

section IsSimpleOrder

variable [PartialOrder α] [BoundedOrder α] [IsSimpleOrder α]

instance {α} [LE α] [BoundedOrder α] [IsSimpleOrder α] : IsSimpleOrder αᵒᵈ :=
  isSimpleOrder_iff_isSimpleOrder_orderDual.1 (by infer_instance)

/-- A simple `BoundedOrder` induces a preorder. This is not an instance to prevent loops. -/
protected def IsSimpleOrder.preorder {α} [LE α] [BoundedOrder α] [IsSimpleOrder α] : Preorder α
    where
  le := (· ≤ ·)
  le_refl a := by rcases eq_bot_or_eq_top a with (rfl | rfl) <;> simp
  le_trans a b c := by
    rcases eq_bot_or_eq_top a with (rfl | rfl)
    · simp
    · rcases eq_bot_or_eq_top b with (rfl | rfl)
      · rcases eq_bot_or_eq_top c with (rfl | rfl) <;> simp
      · simp
#align is_simple_order.preorder IsSimpleOrder.preorder

/-- A simple partial ordered `BoundedOrder` induces a linear order.
This is not an instance to prevent loops. -/
protected def IsSimpleOrder.linearOrder [DecidableEq α] : LinearOrder α :=
  { (inferInstance : PartialOrder α) with
    le_total := fun a b => by rcases eq_bot_or_eq_top a with (rfl | rfl) <;> simp
    decidable_le := fun a b =>
      if ha : a = ⊥ then isTrue (ha.le.trans bot_le)
      else
        if hb : b = ⊤ then isTrue (le_top.trans hb.ge)
        else
          isFalse fun H =>
            hb (top_unique (le_trans (top_le_iff.mpr (Or.resolve_left
              (eq_bot_or_eq_top a) ha)) H)) }
#align is_simple_order.linear_order IsSimpleOrder.linearOrder

@[simp]
theorem isAtom_top : IsAtom (⊤ : α) :=
  ⟨top_ne_bot, fun a ha => Or.resolve_right (eq_bot_or_eq_top a) (ne_of_lt ha)⟩
#align is_atom_top isAtom_top

@[simp]
theorem isCoatom_bot : IsCoatom (⊥ : α) :=
  isAtom_dual_iff_isCoatom.1 isAtom_top
#align is_coatom_bot isCoatom_bot

theorem bot_covby_top : (⊥ : α) ⋖ ⊤ :=
  isAtom_top.bot_covby
#align bot_covby_top bot_covby_top

end IsSimpleOrder

namespace IsSimpleOrder

section Preorder

variable [Preorder α] [BoundedOrder α] [IsSimpleOrder α] {a b : α} (h : a < b)

theorem eq_bot_of_lt : a = ⊥ :=
  (IsSimpleOrder.eq_bot_or_eq_top _).resolve_right h.ne_top
#align is_simple_order.eq_bot_of_lt IsSimpleOrder.eq_bot_of_lt

theorem eq_top_of_lt : b = ⊤ :=
  (IsSimpleOrder.eq_bot_or_eq_top _).resolve_left h.ne_bot
#align is_simple_order.eq_top_of_lt IsSimpleOrder.eq_top_of_lt

alias eq_bot_of_lt ← LT.lt.eq_bot

alias eq_top_of_lt ← LT.lt.eq_top

end Preorder

section BoundedOrder

variable [Lattice α] [BoundedOrder α] [IsSimpleOrder α]

/-- A simple partial ordered `BoundedOrder` induces a lattice.
This is not an instance to prevent loops -/
protected def lattice {α} [DecidableEq α] [PartialOrder α] [BoundedOrder α] [IsSimpleOrder α] :
    Lattice α :=
  @LinearOrder.toLattice α IsSimpleOrder.linearOrder
#align is_simple_order.lattice IsSimpleOrder.lattice

/-- A lattice that is a `BoundedOrder` is a distributive lattice.
This is not an instance to prevent loops -/
protected def distribLattice : DistribLattice α :=
  { (inferInstance : Lattice α) with
    le_sup_inf := fun x y z => by rcases eq_bot_or_eq_top x with (rfl | rfl) <;> simp }
#align is_simple_order.distrib_lattice IsSimpleOrder.distribLattice

-- see Note [lower instance priority]
instance (priority := 100) : IsAtomic α :=
  ⟨fun b => (eq_bot_or_eq_top b).imp_right fun h => ⟨⊤, ⟨isAtom_top, ge_of_eq h⟩⟩⟩

-- see Note [lower instance priority]
instance (priority := 100) : IsCoatomic α :=
  isAtomic_dual_iff_isCoatomic.1 (by infer_instance)

end BoundedOrder

-- It is important that in this section `IsSimpleOrder` is the last type-class argument.
section DecidableEq

variable [DecidableEq α] [PartialOrder α] [BoundedOrder α] [IsSimpleOrder α]

/-- Every simple lattice is isomorphic to `Bool`, regardless of order. -/
@[simps]
def equivBool {α} [DecidableEq α] [LE α] [BoundedOrder α] [IsSimpleOrder α] : α ≃ Bool
    where
  toFun x := x = ⊤
  invFun x := cond x ⊤ ⊥
  left_inv x := by rcases eq_bot_or_eq_top x with (rfl | rfl) <;> simp [bot_ne_top]
  right_inv x := by cases x <;> simp [bot_ne_top]
#align is_simple_order.equiv_bool IsSimpleOrder.equivBool
#align is_simple_order.equiv_bool_symm_apply IsSimpleOrder.equivBool_symm_apply
#align is_simple_order.equiv_bool_apply IsSimpleOrder.equivBool_apply

/-- Every simple lattice over a partial order is order-isomorphic to `Bool`. -/
def orderIsoBool : α ≃o Bool :=
  { equivBool with
    map_rel_iff' := @fun a b => by
      rcases eq_bot_or_eq_top a with (rfl | rfl)
      · simp [bot_ne_top]
      · rcases eq_bot_or_eq_top b with (rfl | rfl)
        · simp [bot_ne_top.symm, bot_ne_top, Bool.false_lt_true]
        · simp [bot_ne_top] }
#align is_simple_order.order_iso_bool IsSimpleOrder.orderIsoBool

/-- A simple `BoundedOrder` is also a `BooleanAlgebra`. -/
protected def booleanAlgebra {α} [DecidableEq α] [Lattice α] [BoundedOrder α] [IsSimpleOrder α] :
    BooleanAlgebra α :=
  { inferInstanceAs (BoundedOrder α), IsSimpleOrder.distribLattice with
    compl := fun x => if x = ⊥ then ⊤ else ⊥
    sdiff := fun x y => if x = ⊤ ∧ y = ⊥ then ⊤ else ⊥
    sdiff_eq := fun x y => by
      rcases eq_bot_or_eq_top x with (rfl | rfl) <;> simp [bot_ne_top, SDiff.sdiff, compl]
    inf_compl_le_bot := fun x =>
      by
      rcases eq_bot_or_eq_top x with (rfl | rfl)
      · simp
      . simp
    top_le_sup_compl := fun x => by rcases eq_bot_or_eq_top x with (rfl | rfl) <;> simp }
#align is_simple_order.boolean_algebra IsSimpleOrder.booleanAlgebra

end DecidableEq

variable [Lattice α] [BoundedOrder α] [IsSimpleOrder α]

open Classical

/-- A simple `BoundedOrder` is also complete. -/
protected noncomputable def completeLattice : CompleteLattice α :=
  { (inferInstance : Lattice α),
    (inferInstance : BoundedOrder α) with
    supₛ := fun s => if ⊤ ∈ s then ⊤ else ⊥
    infₛ := fun s => if ⊥ ∈ s then ⊥ else ⊤
    le_supₛ := fun s x h => by
      rcases eq_bot_or_eq_top x with (rfl | rfl)
      · exact bot_le
      · dsimp; rw [if_pos h]
    supₛ_le := fun s x h => by
      rcases eq_bot_or_eq_top x with (rfl | rfl)
      · dsimp; rw [if_neg]
        intro con
        exact bot_ne_top (eq_top_iff.2 (h ⊤ con))
      · exact le_top
    infₛ_le := fun s x h => by
      rcases eq_bot_or_eq_top x with (rfl | rfl)
      · dsimp; rw [if_pos h]
      · exact le_top
    le_infₛ := fun s x h => by
      rcases eq_bot_or_eq_top x with (rfl | rfl)
      · exact bot_le
      · dsimp; rw [if_neg]
        intro con
        exact top_ne_bot (eq_bot_iff.2 (h ⊥ con)) }
#align is_simple_order.complete_lattice IsSimpleOrder.completeLattice

/-- A simple `BoundedOrder` is also a `CompleteBooleanAlgebra`. -/
protected noncomputable def completeBooleanAlgebra : CompleteBooleanAlgebra α :=
  { IsSimpleOrder.completeLattice,
    IsSimpleOrder.booleanAlgebra with
    infᵢ_sup_le_sup_infₛ := fun x s =>
      by
      rcases eq_bot_or_eq_top x with (rfl | rfl)
      · simp only [bot_sup_eq, ← infₛ_eq_infᵢ]
        exact le_rfl
      · simp only [top_le_iff, top_sup_eq, infᵢ_top, le_infₛ_iff, le_refl]
    inf_supₛ_le_supᵢ_inf := fun x s =>
      by
      rcases eq_bot_or_eq_top x with (rfl | rfl)
      · simp only [le_bot_iff, supₛ_eq_bot, bot_inf_eq, supᵢ_bot, le_refl]
      · simp only [top_inf_eq, ← supₛ_eq_supᵢ]
        exact le_rfl }
#align is_simple_order.complete_boolean_algebra IsSimpleOrder.completeBooleanAlgebra

end IsSimpleOrder

namespace IsSimpleOrder

variable [CompleteLattice α] [IsSimpleOrder α]

--set_option default_priority 100 --Porting note: not supported, done for each instance individually

instance (priority := 100) : IsAtomistic α :=
  ⟨fun b =>
    (eq_bot_or_eq_top b).elim
      (fun h => ⟨∅, ⟨h.trans supₛ_empty.symm, fun _ ha => False.elim (Set.not_mem_empty _ ha)⟩⟩)
      fun h =>
      ⟨{⊤}, h.trans supₛ_singleton.symm, fun _ ha =>
        (Set.mem_singleton_iff.1 ha).symm ▸ isAtom_top⟩⟩

instance : IsCoatomistic α :=
  isAtomistic_dual_iff_isCoatomistic.1 (by infer_instance)

end IsSimpleOrder

theorem isSimpleOrder_iff_isAtom_top [PartialOrder α] [BoundedOrder α] :
    IsSimpleOrder α ↔ IsAtom (⊤ : α) :=
  ⟨fun h => @isAtom_top _ _ _ h, fun h =>
    { exists_pair_ne := ⟨⊤, ⊥, h.1⟩
      eq_bot_or_eq_top := fun a => ((eq_or_lt_of_le le_top).imp_right (h.2 a)).symm }⟩
#align is_simple_order_iff_is_atom_top isSimpleOrder_iff_isAtom_top

theorem isSimpleOrder_iff_isCoatom_bot [PartialOrder α] [BoundedOrder α] :
    IsSimpleOrder α ↔ IsCoatom (⊥ : α) :=
  isSimpleOrder_iff_isSimpleOrder_orderDual.trans isSimpleOrder_iff_isAtom_top
#align is_simple_order_iff_is_coatom_bot isSimpleOrder_iff_isCoatom_bot

namespace Set

theorem isSimpleOrder_Iic_iff_isAtom [PartialOrder α] [OrderBot α] {a : α} :
    IsSimpleOrder (Iic a) ↔ IsAtom a :=
  isSimpleOrder_iff_isAtom_top.trans <|
    and_congr (not_congr Subtype.mk_eq_mk)
      ⟨fun h b ab => Subtype.mk_eq_mk.1 (h ⟨b, le_of_lt ab⟩ ab), fun h ⟨b, _⟩ hbotb =>
        Subtype.mk_eq_mk.2 (h b (Subtype.mk_lt_mk.1 hbotb))⟩
#align set.is_simple_order_Iic_iff_is_atom Set.isSimpleOrder_Iic_iff_isAtom

theorem isSimpleOrder_Ici_iff_isCoatom [PartialOrder α] [OrderTop α] {a : α} :
    IsSimpleOrder (Ici a) ↔ IsCoatom a :=
  isSimpleOrder_iff_isCoatom_bot.trans <|
    and_congr (not_congr Subtype.mk_eq_mk)
      ⟨fun h b ab => Subtype.mk_eq_mk.1 (h ⟨b, le_of_lt ab⟩ ab), fun h ⟨b, _⟩ hbotb =>
        Subtype.mk_eq_mk.2 (h b (Subtype.mk_lt_mk.1 hbotb))⟩
#align set.is_simple_order_Ici_iff_is_coatom Set.isSimpleOrder_Ici_iff_isCoatom

end Set

namespace OrderEmbedding

variable [PartialOrder α] [PartialOrder β]

theorem isAtom_of_map_bot_of_image [OrderBot α] [OrderBot β] (f : β ↪o α) (hbot : f ⊥ = ⊥) {b : β}
    (hb : IsAtom (f b)) : IsAtom b := by
  simp only [← bot_covby_iff] at hb ⊢
  exact Covby.of_image f (hbot.symm ▸ hb)
#align order_embedding.is_atom_of_map_bot_of_image OrderEmbedding.isAtom_of_map_bot_of_image

theorem isCoatom_of_map_top_of_image [OrderTop α] [OrderTop β] (f : β ↪o α) (htop : f ⊤ = ⊤)
    {b : β} (hb : IsCoatom (f b)) : IsCoatom b :=
  f.dual.isAtom_of_map_bot_of_image htop hb
#align order_embedding.is_coatom_of_map_top_of_image OrderEmbedding.isCoatom_of_map_top_of_image

end OrderEmbedding

namespace GaloisInsertion

variable [PartialOrder α] [PartialOrder β]

theorem isAtom_of_u_bot [OrderBot α] [OrderBot β] {l : α → β} {u : β → α}
    (gi : GaloisInsertion l u) (hbot : u ⊥ = ⊥) {b : β} (hb : IsAtom (u b)) : IsAtom b :=
  OrderEmbedding.isAtom_of_map_bot_of_image
    ⟨⟨u, gi.u_injective⟩, @GaloisInsertion.u_le_u_iff _ _ _ _ _ _ gi⟩ hbot hb
#align galois_insertion.is_atom_of_u_bot GaloisInsertion.isAtom_of_u_bot

theorem isAtom_iff [OrderBot α] [IsAtomic α] [OrderBot β] {l : α → β} {u : β → α}
    (gi : GaloisInsertion l u) (hbot : u ⊥ = ⊥) (h_atom : ∀ a, IsAtom a → u (l a) = a) (a : α) :
    IsAtom (l a) ↔ IsAtom a := by
  refine' ⟨fun hla => _, fun ha => gi.isAtom_of_u_bot hbot ((h_atom a ha).symm ▸ ha)⟩
  obtain ⟨a', ha', hab'⟩ :=
    (eq_bot_or_exists_atom_le (u (l a))).resolve_left (hbot ▸ fun h => hla.1 (gi.u_injective h))
  have :=
    (hla.le_iff.mp <| (gi.l_u_eq (l a) ▸ gi.gc.monotone_l hab' : l a' ≤ l a)).resolve_left fun h =>
      ha'.1 (hbot ▸ h_atom a' ha' ▸ congr_arg u h)
  have haa' : a = a' :=
    (ha'.le_iff.mp <|
          (gi.gc.le_u_l a).trans_eq (h_atom a' ha' ▸ congr_arg u this.symm)).resolve_left
      (mt (congr_arg l) (gi.gc.l_bot.symm ▸ hla.1))
  exact haa'.symm ▸ ha'
#align galois_insertion.is_atom_iff GaloisInsertion.isAtom_iff

theorem isAtom_iff' [OrderBot α] [IsAtomic α] [OrderBot β] {l : α → β} {u : β → α}
    (gi : GaloisInsertion l u) (hbot : u ⊥ = ⊥) (h_atom : ∀ a, IsAtom a → u (l a) = a) (b : β) :
    IsAtom (u b) ↔ IsAtom b := by rw [← gi.isAtom_iff hbot h_atom, gi.l_u_eq]
#align galois_insertion.is_atom_iff' GaloisInsertion.isAtom_iff'

theorem isCoatom_of_image [OrderTop α] [OrderTop β] {l : α → β} {u : β → α}
    (gi : GaloisInsertion l u) {b : β} (hb : IsCoatom (u b)) : IsCoatom b :=
  OrderEmbedding.isCoatom_of_map_top_of_image
    ⟨⟨u, gi.u_injective⟩, @GaloisInsertion.u_le_u_iff _ _ _ _ _ _ gi⟩ gi.gc.u_top hb
#align galois_insertion.is_coatom_of_image GaloisInsertion.isCoatom_of_image

theorem isCoatom_iff [OrderTop α] [IsCoatomic α] [OrderTop β] {l : α → β} {u : β → α}
    (gi : GaloisInsertion l u) (h_coatom : ∀ a : α, IsCoatom a → u (l a) = a) (b : β) :
    IsCoatom (u b) ↔ IsCoatom b := by
  refine' ⟨fun hb => gi.isCoatom_of_image hb, fun hb => _⟩
  obtain ⟨a, ha, hab⟩ :=
    (eq_top_or_exists_le_coatom (u b)).resolve_left fun h =>
      hb.1 <| (gi.gc.u_top ▸ gi.l_u_eq ⊤ : l ⊤ = ⊤) ▸ gi.l_u_eq b ▸ congr_arg l h
  have : l a = b :=
    (hb.le_iff.mp (gi.l_u_eq b ▸ gi.gc.monotone_l hab : b ≤ l a)).resolve_left fun hla =>
      ha.1 (gi.gc.u_top ▸ h_coatom a ha ▸ congr_arg u hla)
  exact this ▸ (h_coatom a ha).symm ▸ ha
#align galois_insertion.is_coatom_iff GaloisInsertion.isCoatom_iff

end GaloisInsertion

namespace GaloisCoinsertion

variable [PartialOrder α] [PartialOrder β]

theorem isCoatom_of_l_top [OrderTop α] [OrderTop β] {l : α → β} {u : β → α}
    (gi : GaloisCoinsertion l u) (hbot : l ⊤ = ⊤) {a : α} (hb : IsCoatom (l a)) : IsCoatom a :=
  gi.dual.isAtom_of_u_bot hbot hb.dual
#align galois_coinsertion.is_coatom_of_l_top GaloisCoinsertion.isCoatom_of_l_top

theorem isCoatom_iff [OrderTop α] [OrderTop β] [IsCoatomic β] {l : α → β} {u : β → α}
    (gi : GaloisCoinsertion l u) (htop : l ⊤ = ⊤) (h_coatom : ∀ b, IsCoatom b → l (u b) = b)
    (b : β) : IsCoatom (u b) ↔ IsCoatom b :=
  gi.dual.isAtom_iff htop h_coatom b
#align galois_coinsertion.is_coatom_iff GaloisCoinsertion.isCoatom_iff

theorem isCoatom_iff' [OrderTop α] [OrderTop β] [IsCoatomic β] {l : α → β} {u : β → α}
    (gi : GaloisCoinsertion l u) (htop : l ⊤ = ⊤) (h_coatom : ∀ b, IsCoatom b → l (u b) = b)
    (a : α) : IsCoatom (l a) ↔ IsCoatom a :=
  gi.dual.isAtom_iff' htop h_coatom a
#align galois_coinsertion.is_coatom_iff' GaloisCoinsertion.isCoatom_iff'

theorem isAtom_of_image [OrderBot α] [OrderBot β] {l : α → β} {u : β → α}
    (gi : GaloisCoinsertion l u) {a : α} (hb : IsAtom (l a)) : IsAtom a :=
  gi.dual.isCoatom_of_image hb.dual
#align galois_coinsertion.is_atom_of_image GaloisCoinsertion.isAtom_of_image

theorem isAtom_iff [OrderBot α] [OrderBot β] [IsAtomic β] {l : α → β} {u : β → α}
    (gi : GaloisCoinsertion l u) (h_atom : ∀ b, IsAtom b → l (u b) = b) (a : α) :
    IsAtom (l a) ↔ IsAtom a :=
  gi.dual.isCoatom_iff h_atom a
#align galois_coinsertion.is_atom_iff GaloisCoinsertion.isAtom_iff

end GaloisCoinsertion

namespace OrderIso

variable [PartialOrder α] [PartialOrder β]

@[simp]
theorem isAtom_iff [OrderBot α] [OrderBot β] (f : α ≃o β) (a : α) : IsAtom (f a) ↔ IsAtom a :=
  ⟨f.toGaloisCoinsertion.isAtom_of_image, fun ha =>
    f.toGaloisInsertion.isAtom_of_u_bot (map_bot f.symm) <| (f.symm_apply_apply a).symm ▸ ha⟩
#align order_iso.is_atom_iff OrderIso.isAtom_iff

@[simp]
theorem isCoatom_iff [OrderTop α] [OrderTop β] (f : α ≃o β) (a : α) :
    IsCoatom (f a) ↔ IsCoatom a :=
  f.dual.isAtom_iff a
#align order_iso.is_coatom_iff OrderIso.isCoatom_iff

theorem isSimpleOrder_iff [BoundedOrder α] [BoundedOrder β] (f : α ≃o β) :
    IsSimpleOrder α ↔ IsSimpleOrder β := by
  rw [isSimpleOrder_iff_isAtom_top, isSimpleOrder_iff_isAtom_top, ← f.isAtom_iff ⊤,
    f.map_top]
#align order_iso.is_simple_order_iff OrderIso.isSimpleOrder_iff

theorem isSimpleOrder [BoundedOrder α] [BoundedOrder β] [h : IsSimpleOrder β] (f : α ≃o β) :
    IsSimpleOrder α :=
  f.isSimpleOrder_iff.mpr h
#align order_iso.is_simple_order OrderIso.isSimpleOrder

protected theorem isAtomic_iff [OrderBot α] [OrderBot β] (f : α ≃o β) :
    IsAtomic α ↔ IsAtomic β := by
  simp only [IsAtomic_iff, f.surjective.forall, f.surjective.exists, ← map_bot f, f.eq_iff_eq,
    f.le_iff_le, f.isAtom_iff]
#align order_iso.is_atomic_iff OrderIso.isAtomic_iff

protected theorem isCoatomic_iff [OrderTop α] [OrderTop β] (f : α ≃o β) :
    IsCoatomic α ↔ IsCoatomic β := by
  simp only [← isAtomic_dual_iff_isCoatomic, f.dual.isAtomic_iff]
#align order_iso.is_coatomic_iff OrderIso.isCoatomic_iff

end OrderIso

section IsModularLattice

variable [Lattice α] [BoundedOrder α] [IsModularLattice α]

namespace IsCompl

variable {a b : α} (hc : IsCompl a b)

theorem isAtom_iff_isCoatom : IsAtom a ↔ IsCoatom b :=
  Set.isSimpleOrder_Iic_iff_isAtom.symm.trans <|
    hc.IicOrderIsoIci.isSimpleOrder_iff.trans Set.isSimpleOrder_Ici_iff_isCoatom
#align is_compl.is_atom_iff_is_coatom IsCompl.isAtom_iff_isCoatom

theorem isCoatom_iff_isAtom : IsCoatom a ↔ IsAtom b :=
  hc.symm.isAtom_iff_isCoatom.symm
#align is_compl.is_coatom_iff_is_atom IsCompl.isCoatom_iff_isAtom

end IsCompl

variable [ComplementedLattice α]

theorem isCoatomic_of_isAtomic_of_complementedLattice_of_isModular [IsAtomic α] :
    IsCoatomic α :=
  ⟨fun x => by
    rcases exists_isCompl x with ⟨y, xy⟩
    apply (eq_bot_or_exists_atom_le y).imp _ _
    · rintro rfl
      exact eq_top_of_isCompl_bot xy
    · rintro ⟨a, ha, ay⟩
      rcases exists_isCompl (xy.symm.IicOrderIsoIci ⟨a, ay⟩) with ⟨⟨b, xb⟩, hb⟩
      refine' ⟨↑(⟨b, xb⟩ : Set.Ici x), IsCoatom.of_isCoatom_coe_Ici _, xb⟩
      rw [← hb.isAtom_iff_isCoatom, OrderIso.isAtom_iff]
      apply ha.Iic⟩
#align is_coatomic_of_is_atomic_of_complemented_lattice_of_is_modular isCoatomic_of_isAtomic_of_complementedLattice_of_isModular

theorem isAtomic_of_isCoatomic_of_complementedLattice_of_isModular [IsCoatomic α] :
    IsAtomic α :=
  isCoatomic_dual_iff_isAtomic.1 isCoatomic_of_isAtomic_of_complementedLattice_of_isModular
#align is_atomic_of_is_coatomic_of_complemented_lattice_of_is_modular isAtomic_of_isCoatomic_of_complementedLattice_of_isModular

theorem isAtomic_iff_isCoatomic : IsAtomic α ↔ IsCoatomic α :=
  ⟨fun h => @isCoatomic_of_isAtomic_of_complementedLattice_of_isModular _ _ _ _ _ h, fun h =>
    @isAtomic_of_isCoatomic_of_complementedLattice_of_isModular _ _ _ _ _ h⟩
#align is_atomic_iff_is_coatomic isAtomic_iff_isCoatomic

end IsModularLattice

namespace Set

theorem isAtom_singleton (x : α) : IsAtom ({x} : Set α) :=
  ⟨singleton_ne_empty _, fun _ hs => ssubset_singleton_iff.mp hs⟩
#align set.is_atom_singleton Set.isAtom_singleton

theorem isAtom_iff (s : Set α) : IsAtom s ↔ ∃ x, s = {x} := by
  refine'
    ⟨_, by
      rintro ⟨x, rfl⟩
      exact isAtom_singleton x⟩
  rw [_root_.isAtom_iff, bot_eq_empty, ← nonempty_iff_ne_empty]
  rintro ⟨⟨x, hx⟩, hs⟩
  exact
    ⟨x, eq_singleton_iff_unique_mem.2
        ⟨hx, fun y hy => (hs {y} (singleton_ne_empty _) (singleton_subset_iff.2 hy) hx).symm⟩⟩
#align set.is_atom_iff Set.isAtom_iff

theorem isCoatom_iff (s : Set α) : IsCoatom s ↔ ∃ x, s = {x}ᶜ := by
  rw [isCompl_compl.isCoatom_iff_isAtom, isAtom_iff]
  simp_rw [@eq_comm _ s, compl_eq_comm]

#align set.is_coatom_iff Set.isCoatom_iff

theorem isCoatom_singleton_compl (x : α) : IsCoatom ({x}ᶜ : Set α) :=
  (isCoatom_iff ({x}ᶜ)).mpr ⟨x, rfl⟩
#align set.is_coatom_singleton_compl Set.isCoatom_singleton_compl

instance : IsAtomistic (Set α) where
  eq_supₛ_atoms s :=
    ⟨(fun x => {x}) '' s, by rw [supₛ_eq_unionₛ, unionₛ_image, bunionᵢ_of_singleton],
      by { rintro _ ⟨x, _, rfl⟩
           exact isAtom_singleton x }⟩

instance : IsCoatomistic (Set α) where
  eq_infₛ_coatoms s :=
    ⟨(fun x => {x}ᶜ) '' sᶜ,
      by { rw [infₛ_eq_interₛ, interₛ_image, ← compl_unionᵢ₂, bunionᵢ_of_singleton, compl_compl] },
      by { rintro _ ⟨x, _, rfl⟩
           exact isCoatom_singleton_compl x }⟩

end Set


/-
Copyright (c) 2021 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes
-/
import data.mv_polynomial.variables

/-!
# Polynomials supported by a set of variables

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

This file contains the definition and lemmas about `mv_polynomial.supported`.

## Main definitions

* `mv_polynomial.supported` : Given a set `s : set σ`, `supported R s` is the subalgebra of
  `mv_polynomial σ R` consisting of polynomials whose set of variables is contained in `s`.
  This subalgebra is isomorphic to `mv_polynomial s R`

## Tags
variables, polynomial, vars
-/
universes u v w

namespace mv_polynomial
variables {σ τ : Type*} {R : Type u} {S : Type v} {r : R} {e : ℕ} {n m : σ}

section comm_semiring
variables [comm_semiring R] {p q : mv_polynomial σ R}

variables (R)

/-- The set of polynomials whose variables are contained in `s` as a `subalgebra` over `R`. -/
noncomputable def supported (s : set σ) : subalgebra R (mv_polynomial σ R) :=
algebra.adjoin R (X '' s)

variables {σ R}

open_locale classical
open algebra

lemma supported_eq_range_rename (s : set σ) :
  supported R s = (rename (coe : s → σ)).range :=
by rw [supported, set.image_eq_range, adjoin_range_eq_range_aeval, rename]

/--The isomorphism between the subalgebra of polynomials supported by `s` and `mv_polynomial s R`-/
noncomputable def supported_equiv_mv_polynomial (s : set σ) :
  supported R s ≃ₐ[R] mv_polynomial s R :=
(subalgebra.equiv_of_eq _ _ (supported_eq_range_rename s)).trans
(alg_equiv.of_injective (rename (coe : s → σ))
  (rename_injective _ subtype.val_injective)).symm

@[simp] lemma supported_equiv_mv_polynomial_symm_C (s : set σ) (x : R) :
  (supported_equiv_mv_polynomial s).symm (C x) = algebra_map R (supported R s) x :=
begin
  ext1,
  simp [supported_equiv_mv_polynomial, mv_polynomial.algebra_map_eq],
end

@[simp] lemma supported_equiv_mv_polynomial_symm_X (s : set σ) (i : s) :
  (↑((supported_equiv_mv_polynomial s).symm (X i : mv_polynomial s R)) : mv_polynomial σ R) = X i :=
by simp [supported_equiv_mv_polynomial]

variables {s t : set σ}

lemma mem_supported : p ∈ (supported R s) ↔ ↑p.vars ⊆ s :=
begin
  rw [supported_eq_range_rename, alg_hom.mem_range],
  split,
  { rintros ⟨p, rfl⟩,
    refine trans (finset.coe_subset.2 (vars_rename _ _)) _,
    simp },
  { intros hs,
    exact exists_rename_eq_of_vars_subset_range p (coe : s → σ) subtype.val_injective (by simpa) }
end

lemma supported_eq_vars_subset : (supported R s : set (mv_polynomial σ R)) = {p | ↑p.vars ⊆ s} :=
set.ext $ λ _, mem_supported

@[simp] lemma mem_supported_vars (p : mv_polynomial σ R) : p ∈ supported R (↑p.vars : set σ) :=
by rw [mem_supported]

variable (s)

lemma supported_eq_adjoin_X : supported R s = algebra.adjoin R (X '' s) := rfl

@[simp] lemma supported_univ : supported R (set.univ : set σ) = ⊤ :=
by simp [algebra.eq_top_iff, mem_supported]

@[simp] lemma supported_empty : supported R (∅ : set σ) = ⊥ :=
by simp [supported_eq_adjoin_X]

variables {s}

lemma supported_mono (st : s ⊆ t) : supported R s ≤ supported R t :=
algebra.adjoin_mono (set.image_subset _ st)

@[simp] lemma X_mem_supported [nontrivial R] {i : σ} : (X i) ∈ supported R s ↔ i ∈ s :=
by simp [mem_supported]

@[simp] lemma supported_le_supported_iff [nontrivial R] :
  supported R s ≤ supported R t ↔ s ⊆ t :=
begin
  split,
  { intros h i,
    simpa using @h (X i) },
  { exact supported_mono }
end

lemma supported_strict_mono [nontrivial R] :
  strict_mono (supported R : set σ → subalgebra R (mv_polynomial σ R)) :=
strict_mono_of_le_iff_le (λ _ _, supported_le_supported_iff.symm)

lemma exists_restrict_to_vars (R : Type*) [comm_ring R] {F : mv_polynomial σ ℤ} (hF : ↑F.vars ⊆ s) :
  ∃ f : (s → R) → R, ∀ x : σ → R, f (x ∘ coe : s → R) = aeval x F :=
begin
  classical,
  rw [← mem_supported, supported_eq_range_rename, alg_hom.mem_range] at hF,
  cases hF with F' hF',
  use λ z, aeval z F',
  intro x,
  simp only [←hF', aeval_rename],
end

end comm_semiring

end mv_polynomial


/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Johan Commelin, Mario Carneiro
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.data.mv_polynomial.monad
import Mathlib.data.set.disjointed
import Mathlib.PostPort

universes u u_1 u_2 v u_3

namespace Mathlib

/-!
# Degrees and variables of polynomials

This file establishes many results about the degree and variable sets of a multivariate polynomial.

The *variable set* of a polynomial $P \in R[X]$ is a `finset` containing each $x \in X$
that appears in a monomial in $P$.

The *degree set* of a polynomial $P \in R[X]$ is a `multiset` containing, for each $x$ in the
variable set, $n$ copies of $x$, where $n$ is the maximum number of copies of $x$ appearing in a
monomial of $P$.

## Main declarations

* `mv_polynomial.degrees p` : the multiset of variables representing the union of the multisets corresponding
  to each non-zero monomial in `p`. For example if `7 ≠ 0` in `R` and `p = x²y+7y³` then
  `degrees p = {x, x, y, y, y}`

* `mv_polynomial.vars p` : the finset of variables occurring in `p`. For example if `p = x⁴y+yz` then
  `vars p = {x, y, z}`

* `mv_polynomial.degree_of n p : ℕ` -- the total degree of `p` with respect to the variable `n`. For example
  if `p = x⁴y+yz` then `degree_of y p = 1`.

* `mv_polynomial.total_degree p : ℕ` -- the max of the sizes of the multisets `s` whose monomials `X^s` occur
  in `p`. For example if `p = x⁴y+yz` then `total_degree p = 5`.

## Notation

As in other polynomial files, we typically use the notation:

+ `σ τ : Type*` (indexing the variables)

+ `R : Type*` `[comm_semiring R]` (the coefficients)

+ `s : σ →₀ ℕ`, a function from `σ` to `ℕ` which is zero away from a finite set.
This will give rise to a monomial in `mv_polynomial σ R` which mathematicians might call `X^s`

+ `r : R`

+ `i : σ`, with corresponding monomial `X i`, often denoted `X_i` by mathematicians

+ `p : mv_polynomial σ R`

-/

namespace mv_polynomial

/-! ### `degrees` -/

/--
The maximal degrees of each variable in a multi-variable polynomial, expressed as a multiset.

(For example, `degrees (x^2 * y + y^3)` would be `{x, x, y, y, y}`.)
-/
def degrees {R : Type u} {σ : Type u_1} [comm_semiring R] (p : mv_polynomial σ R) : multiset σ :=
  finset.sup (finsupp.support p) fun (s : σ →₀ ℕ) => coe_fn finsupp.to_multiset s

theorem degrees_monomial {R : Type u} {σ : Type u_1} [comm_semiring R] (s : σ →₀ ℕ) (a : R) :
    degrees (monomial s a) ≤ coe_fn finsupp.to_multiset s :=
  sorry

theorem degrees_monomial_eq {R : Type u} {σ : Type u_1} [comm_semiring R] (s : σ →₀ ℕ) (a : R)
    (ha : a ≠ 0) : degrees (monomial s a) = coe_fn finsupp.to_multiset s :=
  sorry

theorem degrees_C {R : Type u} {σ : Type u_1} [comm_semiring R] (a : R) :
    degrees (coe_fn C a) = 0 :=
  iff.mp multiset.le_zero (degrees_monomial 0 a)

theorem degrees_X' {R : Type u} {σ : Type u_1} [comm_semiring R] (n : σ) :
    degrees (X n) ≤ singleton n :=
  le_trans (degrees_monomial (finsupp.single n 1) 1) (le_of_eq (finsupp.to_multiset_single n 1))

@[simp] theorem degrees_X {R : Type u} {σ : Type u_1} [comm_semiring R] [nontrivial R] (n : σ) :
    degrees (X n) = singleton n :=
  Eq.trans (degrees_monomial_eq (finsupp.single n 1) 1 one_ne_zero) (finsupp.to_multiset_single n 1)

@[simp] theorem degrees_zero {R : Type u} {σ : Type u_1} [comm_semiring R] : degrees 0 = 0 :=
  eq.mpr (id (Eq._oldrec (Eq.refl (degrees 0 = 0)) (Eq.symm C_0))) (degrees_C 0)

@[simp] theorem degrees_one {R : Type u} {σ : Type u_1} [comm_semiring R] : degrees 1 = 0 :=
  degrees_C 1

theorem degrees_add {R : Type u} {σ : Type u_1} [comm_semiring R] (p : mv_polynomial σ R)
    (q : mv_polynomial σ R) : degrees (p + q) ≤ degrees p ⊔ degrees q :=
  sorry

theorem degrees_sum {R : Type u} {σ : Type u_1} [comm_semiring R] {ι : Type u_2} (s : finset ι)
    (f : ι → mv_polynomial σ R) :
    degrees (finset.sum s fun (i : ι) => f i) ≤ finset.sup s fun (i : ι) => degrees (f i) :=
  sorry

theorem degrees_mul {R : Type u} {σ : Type u_1} [comm_semiring R] (p : mv_polynomial σ R)
    (q : mv_polynomial σ R) : degrees (p * q) ≤ degrees p + degrees q :=
  sorry

theorem degrees_prod {R : Type u} {σ : Type u_1} [comm_semiring R] {ι : Type u_2} (s : finset ι)
    (f : ι → mv_polynomial σ R) :
    degrees (finset.prod s fun (i : ι) => f i) ≤ finset.sum s fun (i : ι) => degrees (f i) :=
  sorry

theorem degrees_pow {R : Type u} {σ : Type u_1} [comm_semiring R] (p : mv_polynomial σ R) (n : ℕ) :
    degrees (p ^ n) ≤ n •ℕ degrees p :=
  sorry

theorem mem_degrees {R : Type u} {σ : Type u_1} [comm_semiring R] {p : mv_polynomial σ R} {i : σ} :
    i ∈ degrees p ↔ ∃ (d : σ →₀ ℕ), coeff d p ≠ 0 ∧ i ∈ finsupp.support d :=
  sorry

theorem le_degrees_add {R : Type u} {σ : Type u_1} [comm_semiring R] {p : mv_polynomial σ R}
    {q : mv_polynomial σ R} (h : multiset.disjoint (degrees p) (degrees q)) :
    degrees p ≤ degrees (p + q) :=
  sorry

theorem degrees_add_of_disjoint {R : Type u} {σ : Type u_1} [comm_semiring R]
    {p : mv_polynomial σ R} {q : mv_polynomial σ R}
    (h : multiset.disjoint (degrees p) (degrees q)) : degrees (p + q) = degrees p ∪ degrees q :=
  sorry

theorem degrees_map {R : Type u} {S : Type v} {σ : Type u_1} [comm_semiring R] [comm_semiring S]
    (p : mv_polynomial σ R) (f : R →+* S) : degrees (coe_fn (map f) p) ⊆ degrees p :=
  sorry

theorem degrees_rename {R : Type u} {σ : Type u_1} {τ : Type u_2} [comm_semiring R] (f : σ → τ)
    (φ : mv_polynomial σ R) : degrees (coe_fn (rename f) φ) ⊆ multiset.map f (degrees φ) :=
  sorry

theorem degrees_map_of_injective {R : Type u} {S : Type v} {σ : Type u_1} [comm_semiring R]
    [comm_semiring S] (p : mv_polynomial σ R) {f : R →+* S} (hf : function.injective ⇑f) :
    degrees (coe_fn (map f) p) = degrees p :=
  sorry

/-! ### `vars` -/

/-- `vars p` is the set of variables appearing in the polynomial `p` -/
def vars {R : Type u} {σ : Type u_1} [comm_semiring R] (p : mv_polynomial σ R) : finset σ :=
  multiset.to_finset (degrees p)

@[simp] theorem vars_0 {R : Type u} {σ : Type u_1} [comm_semiring R] : vars 0 = ∅ :=
  eq.mpr (id (Eq._oldrec (Eq.refl (vars 0 = ∅)) (vars.equations._eqn_1 0)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (multiset.to_finset (degrees 0) = ∅)) degrees_zero))
      (eq.mpr (id (Eq._oldrec (Eq.refl (multiset.to_finset 0 = ∅)) multiset.to_finset_zero))
        (Eq.refl ∅)))

@[simp] theorem vars_monomial {R : Type u} {σ : Type u_1} {r : R} {s : σ →₀ ℕ} [comm_semiring R]
    (h : r ≠ 0) : vars (monomial s r) = finsupp.support s :=
  sorry

@[simp] theorem vars_C {R : Type u} {σ : Type u_1} {r : R} [comm_semiring R] :
    vars (coe_fn C r) = ∅ :=
  eq.mpr (id (Eq._oldrec (Eq.refl (vars (coe_fn C r) = ∅)) (vars.equations._eqn_1 (coe_fn C r))))
    (eq.mpr
      (id (Eq._oldrec (Eq.refl (multiset.to_finset (degrees (coe_fn C r)) = ∅)) (degrees_C r)))
      (eq.mpr (id (Eq._oldrec (Eq.refl (multiset.to_finset 0 = ∅)) multiset.to_finset_zero))
        (Eq.refl ∅)))

@[simp] theorem vars_X {R : Type u} {σ : Type u_1} {n : σ} [comm_semiring R] [nontrivial R] :
    vars (X n) = singleton n :=
  sorry

theorem mem_vars {R : Type u} {σ : Type u_1} [comm_semiring R] {p : mv_polynomial σ R} (i : σ) :
    i ∈ vars p ↔ ∃ (d : σ →₀ ℕ), ∃ (H : d ∈ finsupp.support p), i ∈ finsupp.support d :=
  sorry

theorem mem_support_not_mem_vars_zero {R : Type u} {σ : Type u_1} [comm_semiring R]
    {f : mv_polynomial σ R} {x : σ →₀ ℕ} (H : x ∈ finsupp.support f) {v : σ} (h : ¬v ∈ vars f) :
    coe_fn x v = 0 :=
  sorry

theorem vars_add_subset {R : Type u} {σ : Type u_1} [comm_semiring R] (p : mv_polynomial σ R)
    (q : mv_polynomial σ R) : vars (p + q) ⊆ vars p ∪ vars q :=
  sorry

theorem vars_add_of_disjoint {R : Type u} {σ : Type u_1} [comm_semiring R] {p : mv_polynomial σ R}
    {q : mv_polynomial σ R} (h : disjoint (vars p) (vars q)) : vars (p + q) = vars p ∪ vars q :=
  sorry

theorem vars_mul {R : Type u} {σ : Type u_1} [comm_semiring R] (φ : mv_polynomial σ R)
    (ψ : mv_polynomial σ R) : vars (φ * ψ) ⊆ vars φ ∪ vars ψ :=
  sorry

@[simp] theorem vars_one {R : Type u} {σ : Type u_1} [comm_semiring R] : vars 1 = ∅ := vars_C

theorem vars_pow {R : Type u} {σ : Type u_1} [comm_semiring R] (φ : mv_polynomial σ R) (n : ℕ) :
    vars (φ ^ n) ⊆ vars φ :=
  sorry

/--
The variables of the product of a family of polynomials
are a subset of the union of the sets of variables of each polynomial.
-/
theorem vars_prod {R : Type u} {σ : Type u_1} [comm_semiring R] {ι : Type u_2} {s : finset ι}
    (f : ι → mv_polynomial σ R) :
    vars (finset.prod s fun (i : ι) => f i) ⊆ finset.bUnion s fun (i : ι) => vars (f i) :=
  sorry

theorem vars_C_mul {σ : Type u_1} {A : Type u_3} [integral_domain A] (a : A) (ha : a ≠ 0)
    (φ : mv_polynomial σ A) : vars (coe_fn C a * φ) = vars φ :=
  sorry

theorem vars_sum_subset {R : Type u} {σ : Type u_1} [comm_semiring R] {ι : Type u_3} (t : finset ι)
    (φ : ι → mv_polynomial σ R) :
    vars (finset.sum t fun (i : ι) => φ i) ⊆ finset.bUnion t fun (i : ι) => vars (φ i) :=
  sorry

theorem vars_sum_of_disjoint {R : Type u} {σ : Type u_1} [comm_semiring R] {ι : Type u_3}
    (t : finset ι) (φ : ι → mv_polynomial σ R)
    (h : pairwise (disjoint on fun (i : ι) => vars (φ i))) :
    vars (finset.sum t fun (i : ι) => φ i) = finset.bUnion t fun (i : ι) => vars (φ i) :=
  sorry

theorem vars_map {R : Type u} {S : Type v} {σ : Type u_1} [comm_semiring R] (p : mv_polynomial σ R)
    [comm_semiring S] (f : R →+* S) : vars (coe_fn (map f) p) ⊆ vars p :=
  sorry

theorem vars_map_of_injective {R : Type u} {S : Type v} {σ : Type u_1} [comm_semiring R]
    (p : mv_polynomial σ R) [comm_semiring S] {f : R →+* S} (hf : function.injective ⇑f) :
    vars (coe_fn (map f) p) = vars p :=
  sorry

theorem vars_monomial_single {R : Type u} {σ : Type u_1} [comm_semiring R] (i : σ) {e : ℕ} {r : R}
    (he : e ≠ 0) (hr : r ≠ 0) : vars (monomial (finsupp.single i e) r) = singleton i :=
  sorry

theorem vars_eq_support_bUnion_support {R : Type u} {σ : Type u_1} [comm_semiring R]
    (p : mv_polynomial σ R) : vars p = finset.bUnion (finsupp.support p) finsupp.support :=
  sorry

/-! ### `degree_of` -/

/-- `degree_of n p` gives the highest power of X_n that appears in `p` -/
def degree_of {R : Type u} {σ : Type u_1} [comm_semiring R] (n : σ) (p : mv_polynomial σ R) : ℕ :=
  multiset.count n (degrees p)

/-! ### `total_degree` -/

/-- `total_degree p` gives the maximum |s| over the monomials X^s in `p` -/
def total_degree {R : Type u} {σ : Type u_1} [comm_semiring R] (p : mv_polynomial σ R) : ℕ :=
  finset.sup (finsupp.support p) fun (s : σ →₀ ℕ) => finsupp.sum s fun (n : σ) (e : ℕ) => e

theorem total_degree_eq {R : Type u} {σ : Type u_1} [comm_semiring R] (p : mv_polynomial σ R) :
    total_degree p =
        finset.sup (finsupp.support p)
          fun (m : σ →₀ ℕ) => coe_fn multiset.card (coe_fn finsupp.to_multiset m) :=
  sorry

theorem total_degree_le_degrees_card {R : Type u} {σ : Type u_1} [comm_semiring R]
    (p : mv_polynomial σ R) : total_degree p ≤ coe_fn multiset.card (degrees p) :=
  eq.mpr
    (id
      (Eq._oldrec (Eq.refl (total_degree p ≤ coe_fn multiset.card (degrees p)))
        (total_degree_eq p)))
    (finset.sup_le
      fun (s : σ →₀ ℕ) (hs : s ∈ finsupp.support p) => multiset.card_le_of_le (finset.le_sup hs))

@[simp] theorem total_degree_C {R : Type u} {σ : Type u_1} [comm_semiring R] (a : R) :
    total_degree (coe_fn C a) = 0 :=
  sorry

@[simp] theorem total_degree_zero {R : Type u} {σ : Type u_1} [comm_semiring R] :
    total_degree 0 = 0 :=
  eq.mpr (id (Eq._oldrec (Eq.refl (total_degree 0 = 0)) (Eq.symm C_0))) (total_degree_C 0)

@[simp] theorem total_degree_one {R : Type u} {σ : Type u_1} [comm_semiring R] :
    total_degree 1 = 0 :=
  total_degree_C 1

@[simp] theorem total_degree_X {σ : Type u_1} {R : Type u_2} [comm_semiring R] [nontrivial R]
    (s : σ) : total_degree (X s) = 1 :=
  sorry

theorem total_degree_add {R : Type u} {σ : Type u_1} [comm_semiring R] (a : mv_polynomial σ R)
    (b : mv_polynomial σ R) : total_degree (a + b) ≤ max (total_degree a) (total_degree b) :=
  sorry

theorem total_degree_mul {R : Type u} {σ : Type u_1} [comm_semiring R] (a : mv_polynomial σ R)
    (b : mv_polynomial σ R) : total_degree (a * b) ≤ total_degree a + total_degree b :=
  sorry

theorem total_degree_pow {R : Type u} {σ : Type u_1} [comm_semiring R] (a : mv_polynomial σ R)
    (n : ℕ) : total_degree (a ^ n) ≤ n * total_degree a :=
  sorry

theorem total_degree_list_prod {R : Type u} {σ : Type u_1} [comm_semiring R]
    (s : List (mv_polynomial σ R)) :
    total_degree (list.prod s) ≤ list.sum (list.map total_degree s) :=
  sorry

theorem total_degree_multiset_prod {R : Type u} {σ : Type u_1} [comm_semiring R]
    (s : multiset (mv_polynomial σ R)) :
    total_degree (multiset.prod s) ≤ multiset.sum (multiset.map total_degree s) :=
  sorry

theorem total_degree_finset_prod {R : Type u} {σ : Type u_1} [comm_semiring R] {ι : Type u_2}
    (s : finset ι) (f : ι → mv_polynomial σ R) :
    total_degree (finset.prod s f) ≤ finset.sum s fun (i : ι) => total_degree (f i) :=
  sorry

theorem exists_degree_lt {R : Type u} {σ : Type u_1} [comm_semiring R] [fintype σ]
    (f : mv_polynomial σ R) (n : ℕ) (h : total_degree f < n * fintype.card σ) {d : σ →₀ ℕ}
    (hd : d ∈ finsupp.support f) : ∃ (i : σ), coe_fn d i < n :=
  sorry

theorem coeff_eq_zero_of_total_degree_lt {R : Type u} {σ : Type u_1} [comm_semiring R]
    {f : mv_polynomial σ R} {d : σ →₀ ℕ}
    (h : total_degree f < finset.sum (finsupp.support d) fun (i : σ) => coe_fn d i) :
    coeff d f = 0 :=
  sorry

theorem total_degree_rename_le {R : Type u} {σ : Type u_1} {τ : Type u_2} [comm_semiring R]
    (f : σ → τ) (p : mv_polynomial σ R) : total_degree (coe_fn (rename f) p) ≤ total_degree p :=
  sorry

/-! ### `vars` and `eval` -/

theorem eval₂_hom_eq_constant_coeff_of_vars {R : Type u} {S : Type v} {σ : Type u_1}
    [comm_semiring R] [comm_semiring S] (f : R →+* S) {g : σ → S} {p : mv_polynomial σ R}
    (hp : ∀ (i : σ), i ∈ vars p → g i = 0) :
    coe_fn (eval₂_hom f g) p = coe_fn f (coe_fn constant_coeff p) :=
  sorry

theorem aeval_eq_constant_coeff_of_vars {R : Type u} {S : Type v} {σ : Type u_1} [comm_semiring R]
    [comm_semiring S] [algebra R S] {g : σ → S} {p : mv_polynomial σ R}
    (hp : ∀ (i : σ), i ∈ vars p → g i = 0) :
    coe_fn (aeval g) p = coe_fn (algebra_map R S) (coe_fn constant_coeff p) :=
  eval₂_hom_eq_constant_coeff_of_vars (algebra_map R S) hp

theorem eval₂_hom_congr' {R : Type u} {S : Type v} {σ : Type u_1} [comm_semiring R]
    [comm_semiring S] {f₁ : R →+* S} {f₂ : R →+* S} {g₁ : σ → S} {g₂ : σ → S}
    {p₁ : mv_polynomial σ R} {p₂ : mv_polynomial σ R} :
    f₁ = f₂ →
        (∀ (i : σ), i ∈ vars p₁ → i ∈ vars p₂ → g₁ i = g₂ i) →
          p₁ = p₂ → coe_fn (eval₂_hom f₁ g₁) p₁ = coe_fn (eval₂_hom f₂ g₂) p₂ :=
  sorry

theorem vars_bind₁ {R : Type u} {σ : Type u_1} {τ : Type u_2} [comm_semiring R]
    (f : σ → mv_polynomial τ R) (φ : mv_polynomial σ R) :
    vars (coe_fn (bind₁ f) φ) ⊆ finset.bUnion (vars φ) fun (i : σ) => vars (f i) :=
  sorry

theorem mem_vars_bind₁ {R : Type u} {σ : Type u_1} {τ : Type u_2} [comm_semiring R]
    (f : σ → mv_polynomial τ R) (φ : mv_polynomial σ R) {j : τ}
    (h : j ∈ vars (coe_fn (bind₁ f) φ)) : ∃ (i : σ), i ∈ vars φ ∧ j ∈ vars (f i) :=
  sorry

theorem vars_rename {R : Type u} {σ : Type u_1} {τ : Type u_2} [comm_semiring R] (f : σ → τ)
    (φ : mv_polynomial σ R) : vars (coe_fn (rename f) φ) ⊆ finset.image f (vars φ) :=
  sorry

theorem mem_vars_rename {R : Type u} {σ : Type u_1} {τ : Type u_2} [comm_semiring R] (f : σ → τ)
    (φ : mv_polynomial σ R) {j : τ} (h : j ∈ vars (coe_fn (rename f) φ)) :
    ∃ (i : σ), i ∈ vars φ ∧ f i = j :=
  sorry

end Mathlib