l3lab/ntp-mathlib huggingface dataset:
/-- Auxiliary definition for the `MonoidalCategory` instance on `Center C`. -/
def rightUnitor (X : Center C) : tensorObj X tensorUnit ≅ X :=
  isoMk
    ⟨(ρ_ X.1).hom, fun U => by
      dsimp
      simp only [tensor_id_comp_id_tensor_assoc, triangle_assoc, id_tensor_comp, Category.assoc]
      rw [← tensor_id_comp_id_tensor_assoc (ρ_ U).inv, cancel_epi, ← rightUnitor_tensor_inv_assoc,
        ← rightUnitor_inv_naturality_assoc]
      

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X : Center C
U : C
⊢ (HalfBraiding.β X.snd U).hom =
    (HalfBraiding.β X.snd U).hom ≫ (ρ_ (U ⊗ X.fst)).inv ≫ (α_ U X.fst (𝟙_ C)).hom ≫ (𝟙 U ⊗ (ρ_ X.fst).hom)

Next tactic:
simp
@[simp]
theorem associator_inv_f (X Y Z : Center C) : Hom.f (α_ X Y Z).inv = (α_ X.1 Y.1 Z.1).inv := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y Z : Center C
⊢ (α_ X Y Z).inv.f = (α_ X.fst Y.fst Z.fst).inv

Next tactic:
apply Iso.inv_ext'
@[simp]
theorem associator_inv_f (X Y Z : Center C) : Hom.f (α_ X Y Z).inv = (α_ X.1 Y.1 Z.1).inv := by
  apply Iso.inv_ext' -- Porting note: Originally `ext`
  

Proof state:
case hom_inv_id
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y Z : Center C
⊢ (α_ X.fst Y.fst Z.fst).hom ≫ (α_ X Y Z).inv.f = 𝟙 ((X ⊗ Y) ⊗ Z).fst

Next tactic:
rw [← associator_hom_f, ← comp_f, Iso.hom_inv_id]
@[simp]
theorem associator_inv_f (X Y Z : Center C) : Hom.f (α_ X Y Z).inv = (α_ X.1 Y.1 Z.1).inv := by
  apply Iso.inv_ext' -- Porting note: Originally `ext`
  rw [← associator_hom_f, ← comp_f, Iso.hom_inv_id]; 

Proof state:
case hom_inv_id
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y Z : Center C
⊢ (𝟙 ((X ⊗ Y) ⊗ Z)).f = 𝟙 ((X ⊗ Y) ⊗ Z).fst

Next tactic:
rfl
@[simp]
theorem leftUnitor_inv_f (X : Center C) : Hom.f (λ_ X).inv = (λ_ X.1).inv := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X : Center C
⊢ (λ_ X).inv.f = (λ_ X.fst).inv

Next tactic:
apply Iso.inv_ext'
@[simp]
theorem leftUnitor_inv_f (X : Center C) : Hom.f (λ_ X).inv = (λ_ X.1).inv := by
  apply Iso.inv_ext' -- Porting note: Originally `ext`
  

Proof state:
case hom_inv_id
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X : Center C
⊢ (λ_ X.fst).hom ≫ (λ_ X).inv.f = 𝟙 (𝟙_ (Center C) ⊗ X).fst

Next tactic:
rw [← leftUnitor_hom_f, ← comp_f, Iso.hom_inv_id]
@[simp]
theorem leftUnitor_inv_f (X : Center C) : Hom.f (λ_ X).inv = (λ_ X.1).inv := by
  apply Iso.inv_ext' -- Porting note: Originally `ext`
  rw [← leftUnitor_hom_f, ← comp_f, Iso.hom_inv_id]; 

Proof state:
case hom_inv_id
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X : Center C
⊢ (𝟙 (𝟙_ (Center C) ⊗ X)).f = 𝟙 (𝟙_ (Center C) ⊗ X).fst

Next tactic:
rfl
@[simp]
theorem rightUnitor_inv_f (X : Center C) : Hom.f (ρ_ X).inv = (ρ_ X.1).inv := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X : Center C
⊢ (ρ_ X).inv.f = (ρ_ X.fst).inv

Next tactic:
apply Iso.inv_ext'
@[simp]
theorem rightUnitor_inv_f (X : Center C) : Hom.f (ρ_ X).inv = (ρ_ X.1).inv := by
  apply Iso.inv_ext' -- Porting note: Originally `ext`
  

Proof state:
case hom_inv_id
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X : Center C
⊢ (ρ_ X.fst).hom ≫ (ρ_ X).inv.f = 𝟙 (X ⊗ 𝟙_ (Center C)).fst

Next tactic:
rw [← rightUnitor_hom_f, ← comp_f, Iso.hom_inv_id]
@[simp]
theorem rightUnitor_inv_f (X : Center C) : Hom.f (ρ_ X).inv = (ρ_ X.1).inv := by
  apply Iso.inv_ext' -- Porting note: Originally `ext`
  rw [← rightUnitor_hom_f, ← comp_f, Iso.hom_inv_id]; 

Proof state:
case hom_inv_id
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X : Center C
⊢ (𝟙 (X ⊗ 𝟙_ (Center C))).f = 𝟙 (X ⊗ 𝟙_ (Center C)).fst

Next tactic:
rfl
instance : ReflectsIsomorphisms (forget C).toFunctor where
  reflects f i := by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
A✝ B✝ : Center C
f : A✝ ⟶ B✝
i : IsIso ((forget C).toLaxMonoidalFunctor.toFunctor.map f)
⊢ IsIso f

Next tactic:
dsimp at i
instance : ReflectsIsomorphisms (forget C).toFunctor where
  reflects f i := by dsimp at i; 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
A✝ B✝ : Center C
f : A✝ ⟶ B✝
i : IsIso f.f
⊢ IsIso f

Next tactic:
change IsIso (isoMk f).hom
instance : ReflectsIsomorphisms (forget C).toFunctor where
  reflects f i := by dsimp at i; change IsIso (isoMk f).hom; 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
A✝ B✝ : Center C
f : A✝ ⟶ B✝
i : IsIso f.f
⊢ IsIso (isoMk f).hom

Next tactic:
infer_instance
/-- Auxiliary definition for the `BraidedCategory` instance on `Center C`. -/
@[simps!]
def braiding (X Y : Center C) : X ⊗ Y ≅ Y ⊗ X :=
  isoMk
    ⟨(X.2.β Y.1).hom, fun U => by
      

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y : Center C
U : C
⊢ ((HalfBraiding.β X.snd Y.fst).hom ⊗ 𝟙 U) ≫ (HalfBraiding.β (Y ⊗ X).snd U).hom =
    (HalfBraiding.β (X ⊗ Y).snd U).hom ≫ (𝟙 U ⊗ (HalfBraiding.β X.snd Y.fst).hom)

Next tactic:
dsimp
/-- Auxiliary definition for the `BraidedCategory` instance on `Center C`. -/
@[simps!]
def braiding (X Y : Center C) : X ⊗ Y ≅ Y ⊗ X :=
  isoMk
    ⟨(X.2.β Y.1).hom, fun U => by
      dsimp
      

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y : Center C
U : C
⊢ ((HalfBraiding.β X.snd Y.fst).hom ⊗ 𝟙 U) ≫
      (α_ Y.fst X.fst U).hom ≫
        (𝟙 Y.fst ⊗ (HalfBraiding.β X.snd U).hom) ≫
          (α_ Y.fst U X.fst).inv ≫ ((HalfBraiding.β Y.snd U).hom ⊗ 𝟙 X.fst) ≫ (α_ U Y.fst X.fst).hom =
    ((α_ X.fst Y.fst U).hom ≫
        (𝟙 X.fst ⊗ (HalfBraiding.β Y.snd U).hom) ≫
          (α_ X.fst U Y.fst).inv ≫ ((HalfBraiding.β X.snd U).hom ⊗ 𝟙 Y.fst) ≫ (α_ U X.fst Y.fst).hom) ≫
      (𝟙 U ⊗ (HalfBraiding.β X.snd Y.fst).hom)

Next tactic:
simp only [Category.assoc]
/-- Auxiliary definition for the `BraidedCategory` instance on `Center C`. -/
@[simps!]
def braiding (X Y : Center C) : X ⊗ Y ≅ Y ⊗ X :=
  isoMk
    ⟨(X.2.β Y.1).hom, fun U => by
      dsimp
      simp only [Category.assoc]
      

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y : Center C
U : C
⊢ ((HalfBraiding.β X.snd Y.fst).hom ⊗ 𝟙 U) ≫
      (α_ Y.fst X.fst U).hom ≫
        (𝟙 Y.fst ⊗ (HalfBraiding.β X.snd U).hom) ≫
          (α_ Y.fst U X.fst).inv ≫ ((HalfBraiding.β Y.snd U).hom ⊗ 𝟙 X.fst) ≫ (α_ U Y.fst X.fst).hom =
    (α_ X.fst Y.fst U).hom ≫
      (𝟙 X.fst ⊗ (HalfBraiding.β Y.snd U).hom) ≫
        (α_ X.fst U Y.fst).inv ≫
          ((HalfBraiding.β X.snd U).hom ⊗ 𝟙 Y.fst) ≫ (α_ U X.fst Y.fst).hom ≫ (𝟙 U ⊗ (HalfBraiding.β X.snd Y.fst).hom)

Next tactic:
rw [← IsIso.inv_comp_eq, IsIso.Iso.inv_hom, ← HalfBraiding.monoidal_assoc,
        ← HalfBraiding.naturality_assoc, HalfBraiding.monoidal]
/-- Auxiliary definition for the `BraidedCategory` instance on `Center C`. -/
@[simps!]
def braiding (X Y : Center C) : X ⊗ Y ≅ Y ⊗ X :=
  isoMk
    ⟨(X.2.β Y.1).hom, fun U => by
      dsimp
      simp only [Category.assoc]
      rw [← IsIso.inv_comp_eq, IsIso.Iso.inv_hom, ← HalfBraiding.monoidal_assoc,
        ← HalfBraiding.naturality_assoc, HalfBraiding.monoidal]
      

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X Y : Center C
U : C
⊢ (𝟙 X.fst ⊗ (HalfBraiding.β Y.snd U).hom) ≫
      ((α_ X.fst U Y.fst).inv ≫
          ((HalfBraiding.β X.snd U).hom ⊗ 𝟙 Y.fst) ≫
            (α_ U X.fst Y.fst).hom ≫ (𝟙 U ⊗ (HalfBraiding.β X.snd Y.fst).hom) ≫ (α_ U Y.fst X.fst).inv) ≫
        (α_ U Y.fst X.fst).hom =
    (𝟙 X.fst ⊗ (HalfBraiding.β Y.snd U).hom) ≫
      (α_ X.fst U Y.fst).inv ≫
        ((HalfBraiding.β X.snd U).hom ⊗ 𝟙 Y.fst) ≫ (α_ U X.fst Y.fst).hom ≫ (𝟙 U ⊗ (HalfBraiding.β X.snd Y.fst).hom)

Next tactic:
simp
instance braidedCategoryCenter : BraidedCategory (Center C) where
  braiding := braiding
  braiding_naturality f g := by
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X✝ X'✝ Y✝ Y'✝ : Center C
f : X✝ ⟶ Y✝
g : X'✝ ⟶ Y'✝
⊢ (f ⊗ g) ≫ (braiding Y✝ Y'✝).hom = (braiding X✝ X'✝).hom ≫ (g ⊗ f)

Next tactic:
ext
instance braidedCategoryCenter : BraidedCategory (Center C) where
  braiding := braiding
  braiding_naturality f g := by
    ext
    

Proof state:
case w
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X✝ X'✝ Y✝ Y'✝ : Center C
f : X✝ ⟶ Y✝
g : X'✝ ⟶ Y'✝
⊢ ((f ⊗ g) ≫ (braiding Y✝ Y'✝).hom).f = ((braiding X✝ X'✝).hom ≫ (g ⊗ f)).f

Next tactic:
dsimp
instance braidedCategoryCenter : BraidedCategory (Center C) where
  braiding := braiding
  braiding_naturality f g := by
    ext
    dsimp
    

Proof state:
case w
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
inst✝ : MonoidalCategory C
X✝ X'✝ Y✝ Y'✝ : Center C
f : X✝ ⟶ Y✝
g : X'✝ ⟶ Y'✝
⊢ (f.f ⊗ g.f) ≫ (HalfBraiding.β Y✝.snd Y'✝.fst).hom = (HalfBraiding.β X✝.snd X'✝.fst).hom ≫ (g.f ⊗ f.f)

Next tactic:
rw [← tensor_id_comp_id_tensor, Category.assoc, HalfBraiding.naturality, f.comm_assoc,
      id_tensor_comp_tensor_id]
/-- Auxiliary construction for `ofBraided`. -/
@[simps]
def ofBraidedObj (X : C) : Center C :=
  ⟨X, {
      β := fun Y => β_ X Y
      monoidal := fun U U' => by
        

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
inst✝ : BraidedCategory C
X U U' : C
⊢ ((fun Y => β_ X Y) (U ⊗ U')).hom =
    (α_ X U U').inv ≫
      (((fun Y => β_ X Y) U).hom ⊗ 𝟙 U') ≫ (α_ U X U').hom ≫ (𝟙 U ⊗ ((fun Y => β_ X Y) U').hom) ≫ (α_ U U' X).inv

Next tactic:
rw [Iso.eq_inv_comp, ← Category.assoc, ← Category.assoc, Iso.eq_comp_inv, Category.assoc,
          Category.assoc]
/-- Auxiliary construction for `ofBraided`. -/
@[simps]
def ofBraidedObj (X : C) : Center C :=
  ⟨X, {
      β := fun Y => β_ X Y
      monoidal := fun U U' => by
        rw [Iso.eq_inv_comp, ← Category.assoc, ← Category.assoc, Iso.eq_comp_inv, Category.assoc,
          Category.assoc]
        

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
inst✝ : BraidedCategory C
X U U' : C
⊢ (α_ X U U').hom ≫ ((fun Y => β_ X Y) (U ⊗ U')).hom ≫ (α_ U U' X).hom =
    (((fun Y => β_ X Y) U).hom ⊗ 𝟙 U') ≫ (α_ U X U').hom ≫ (𝟙 U ⊗ ((fun Y => β_ X Y) U').hom)

Next tactic:
exact hexagon_forward X U U'
/-- The functor lifting a braided category to its center, using the braiding as the half-braiding.
-/
@[simps]
def ofBraided : MonoidalFunctor C (Center C) where
  obj := ofBraidedObj
  map f :=
    { f
      comm := fun U => braiding_naturality _ _ }
  ε :=
    { f := 𝟙 _
      comm := fun U => by
        

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
inst✝ : BraidedCategory C
U : C
⊢ (𝟙 (𝟙_ (Center C)).fst ⊗ 𝟙 U) ≫
      (HalfBraiding.β ((Functor.mk { obj := ofBraidedObj, map := fun {X Y} f => Hom.mk f }).obj (𝟙_ C)).snd U).hom =
    (HalfBraiding.β (𝟙_ (Center C)).snd U).hom ≫ (𝟙 U ⊗ 𝟙 (𝟙_ (Center C)).fst)

Next tactic:
dsimp
/-- The functor lifting a braided category to its center, using the braiding as the half-braiding.
-/
@[simps]
def ofBraided : MonoidalFunctor C (Center C) where
  obj := ofBraidedObj
  map f :=
    { f
      comm := fun U => braiding_naturality _ _ }
  ε :=
    { f := 𝟙 _
      comm := fun U => by
        dsimp
        

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
inst✝ : BraidedCategory C
U : C
⊢ (𝟙 (𝟙_ (Center C)).fst ⊗ 𝟙 U) ≫ (β_ (𝟙_ C) U).hom = ((λ_ U).hom ≫ (ρ_ U).inv) ≫ (𝟙 U ⊗ 𝟙 (𝟙_ (Center C)).fst)

Next tactic:
rw [tensor_id, Category.id_comp, tensor_id, Category.comp_id, ← braiding_rightUnitor,
          Category.assoc, Iso.hom_inv_id, Category.comp_id]
/-- The functor lifting a braided category to its center, using the braiding as the half-braiding.
-/
@[simps]
def ofBraided : MonoidalFunctor C (Center C) where
  obj := ofBraidedObj
  map f :=
    { f
      comm := fun U => braiding_naturality _ _ }
  ε :=
    { f := 𝟙 _
      comm := fun U => by
        dsimp
        rw [tensor_id, Category.id_comp, tensor_id, Category.comp_id, ← braiding_rightUnitor,
          Category.assoc, Iso.hom_inv_id, Category.comp_id] }
  μ X Y :=
    { f := 𝟙 _
      comm := fun U => by
        

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
inst✝ : BraidedCategory C
X Y U : C
⊢ (𝟙
          ((Functor.mk { obj := ofBraidedObj, map := fun {X Y} f => Hom.mk f }).obj X ⊗
              (Functor.mk { obj := ofBraidedObj, map := fun {X Y} f => Hom.mk f }).obj Y).fst ⊗
        𝟙 U) ≫
      (HalfBraiding.β ((Functor.mk { obj := ofBraidedObj, map := fun {X Y} f => Hom.mk f }).obj (X ⊗ Y)).snd U).hom =
    (HalfBraiding.β
          ((Functor.mk { obj := ofBraidedObj, map := fun {X Y} f => Hom.mk f }).obj X ⊗
              (Functor.mk { obj := ofBraidedObj, map := fun {X Y} f => Hom.mk f }).obj Y).snd
          U).hom ≫
      (𝟙 U ⊗
        𝟙
          ((Functor.mk { obj := ofBraidedObj, map := fun {X Y} f => Hom.mk f }).obj X ⊗
              (Functor.mk { obj := ofBraidedObj, map := fun {X Y} f => Hom.mk f }).obj Y).fst)

Next tactic:
dsimp
/-- The functor lifting a braided category to its center, using the braiding as the half-braiding.
-/
@[simps]
def ofBraided : MonoidalFunctor C (Center C) where
  obj := ofBraidedObj
  map f :=
    { f
      comm := fun U => braiding_naturality _ _ }
  ε :=
    { f := 𝟙 _
      comm := fun U => by
        dsimp
        rw [tensor_id, Category.id_comp, tensor_id, Category.comp_id, ← braiding_rightUnitor,
          Category.assoc, Iso.hom_inv_id, Category.comp_id] }
  μ X Y :=
    { f := 𝟙 _
      comm := fun U => by
        dsimp
        

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
inst✝¹ : MonoidalCategory C
inst✝ : BraidedCategory C
X Y U : C
⊢ (𝟙 (X ⊗ Y) ⊗ 𝟙 U) ≫ (β_ (X ⊗ Y) U).hom =
    ((α_ X Y U).hom ≫ (𝟙 X ⊗ (β_ Y U).hom) ≫ (α_ X U Y).inv ≫ ((β_ X U).hom ⊗ 𝟙 Y) ≫ (α_ U X Y).hom) ≫ (𝟙 U ⊗ 𝟙 (X ⊗ Y))

Next tactic:
rw [tensor_id, tensor_id, Category.id_comp, Category.comp_id, ← Iso.inv_comp_eq,
          ← Category.assoc, ← Category.assoc, ← Iso.comp_inv_eq, Category.assoc, hexagon_reverse,
          Category.assoc]
@[simp]
theorem coe_toNat_eq_self : ENat.toNat (n : ℕ∞) = n ↔ n ≠ ⊤ :=
  ENat.recTopCoe (by 

Proof state:
m n : ℕ∞
⊢ ↑(toNat ⊤) = ⊤ ↔ ⊤ ≠ ⊤

Next tactic:
decide
@[simp]
theorem coe_toNat_eq_self : ENat.toNat (n : ℕ∞) = n ↔ n ≠ ⊤ :=
  ENat.recTopCoe (by decide) (fun _ => by 

Proof state:
m n : ℕ∞
x✝ : ℕ
⊢ ↑(toNat ↑x✝) = ↑x✝ ↔ ↑x✝ ≠ ⊤

Next tactic:
simp [toNat_coe]
theorem toNat_add {m n : ℕ∞} (hm : m ≠ ⊤) (hn : n ≠ ⊤) : toNat (m + n) = toNat m + toNat n := by
  

Proof state:
m✝ n✝ m n : ℕ∞
hm : m ≠ ⊤
hn : n ≠ ⊤
⊢ toNat (m + n) = toNat m + toNat n

Next tactic:
lift m to ℕ using hm
theorem toNat_add {m n : ℕ∞} (hm : m ≠ ⊤) (hn : n ≠ ⊤) : toNat (m + n) = toNat m + toNat n := by
  lift m to ℕ using hm
  

Proof state:
case intro
m✝ n✝ n : ℕ∞
hn : n ≠ ⊤
m : ℕ
⊢ toNat (↑m + n) = toNat ↑m + toNat n

Next tactic:
lift n to ℕ using hn
theorem toNat_add {m n : ℕ∞} (hm : m ≠ ⊤) (hn : n ≠ ⊤) : toNat (m + n) = toNat m + toNat n := by
  lift m to ℕ using hm
  lift n to ℕ using hn
  

Proof state:
case intro.intro
m✝ n✝ : ℕ∞
m n : ℕ
⊢ toNat (↑m + ↑n) = toNat ↑m + toNat ↑n

Next tactic:
rfl
theorem toNat_sub {n : ℕ∞} (hn : n ≠ ⊤) (m : ℕ∞) : toNat (m - n) = toNat m - toNat n := by
  

Proof state:
m✝ n✝ n : ℕ∞
hn : n ≠ ⊤
m : ℕ∞
⊢ toNat (m - n) = toNat m - toNat n

Next tactic:
lift n to ℕ using hn
theorem toNat_sub {n : ℕ∞} (hn : n ≠ ⊤) (m : ℕ∞) : toNat (m - n) = toNat m - toNat n := by
  lift n to ℕ using hn
  

Proof state:
case intro
m✝ n✝ m : ℕ∞
n : ℕ
⊢ toNat (m - ↑n) = toNat m - toNat ↑n

Next tactic:
induction m using ENat.recTopCoe
theorem toNat_sub {n : ℕ∞} (hn : n ≠ ⊤) (m : ℕ∞) : toNat (m - n) = toNat m - toNat n := by
  lift n to ℕ using hn
  induction m using ENat.recTopCoe
  · 

Proof state:
case intro.h₁
m n✝ : ℕ∞
n : ℕ
⊢ toNat (⊤ - ↑n) = toNat ⊤ - toNat ↑n

Next tactic:
rw [top_sub_coe, toNat_top, zero_tsub]
theorem toNat_sub {n : ℕ∞} (hn : n ≠ ⊤) (m : ℕ∞) : toNat (m - n) = toNat m - toNat n := by
  lift n to ℕ using hn
  induction m using ENat.recTopCoe
  · rw [top_sub_coe, toNat_top, zero_tsub]
  · 

Proof state:
case intro.h₂
m n✝ : ℕ∞
n a✝ : ℕ
⊢ toNat (↑a✝ - ↑n) = toNat ↑a✝ - toNat ↑n

Next tactic:
rw [← coe_sub, toNat_coe, toNat_coe, toNat_coe]
theorem toNat_eq_iff {m : ℕ∞} {n : ℕ} (hn : n ≠ 0) : toNat m = n ↔ m = n := by
  

Proof state:
m✝ n✝ m : ℕ∞
n : ℕ
hn : n ≠ 0
⊢ toNat m = n ↔ m = ↑n

Next tactic:
induction m using ENat.recTopCoe
theorem toNat_eq_iff {m : ℕ∞} {n : ℕ} (hn : n ≠ 0) : toNat m = n ↔ m = n := by
  induction m using ENat.recTopCoe <;> 

Proof state:
case h₁
m n✝ : ℕ∞
n : ℕ
hn : n ≠ 0
⊢ toNat ⊤ = n ↔ ⊤ = ↑n

Next tactic:
simp [hn.symm]
theorem toNat_eq_iff {m : ℕ∞} {n : ℕ} (hn : n ≠ 0) : toNat m = n ↔ m = n := by
  induction m using ENat.recTopCoe <;> 

Proof state:
case h₂
m n✝ : ℕ∞
n : ℕ
hn : n ≠ 0
a✝ : ℕ
⊢ toNat ↑a✝ = n ↔ ↑a✝ = ↑n

Next tactic:
simp [hn.symm]
@[simp]
theorem succ_def (m : ℕ∞) : Order.succ m = m + 1 := by 

Proof state:
m✝ n m : ℕ∞
⊢ Order.succ m = m + 1

Next tactic:
cases m
@[simp]
theorem succ_def (m : ℕ∞) : Order.succ m = m + 1 := by cases m <;> 

Proof state:
case none
m n : ℕ∞
⊢ Order.succ none = none + 1

Next tactic:
rfl
@[simp]
theorem succ_def (m : ℕ∞) : Order.succ m = m + 1 := by cases m <;> 

Proof state:
case some
m n : ℕ∞
val✝ : ℕ
⊢ Order.succ (some val✝) = some val✝ + 1

Next tactic:
rfl
theorem add_one_le_iff (hm : m ≠ ⊤) : m + 1 ≤ n ↔ m < n :=
  m.succ_def ▸ (Order.succ_le_iff_of_not_isMax <| by 

Proof state:
m n : ℕ∞
hm : m ≠ ⊤
⊢ ¬IsMax m

Next tactic:
rwa [isMax_iff_eq_top]
@[elab_as_elim]
theorem nat_induction {P : ℕ∞ → Prop} (a : ℕ∞) (h0 : P 0) (hsuc : ∀ n : ℕ, P n → P n.succ)
    (htop : (∀ n : ℕ, P n) → P ⊤) : P a := by
  

Proof state:
m n : ℕ∞
P : ℕ∞ → Prop
a : ℕ∞
h0 : P 0
hsuc : ∀ (n : ℕ), P ↑n → P ↑(Nat.succ n)
htop : (∀ (n : ℕ), P ↑n) → P ⊤
⊢ P a

Next tactic:
have A : ∀ n : ℕ, P n := fun n => Nat.recOn n h0 hsuc
@[elab_as_elim]
theorem nat_induction {P : ℕ∞ → Prop} (a : ℕ∞) (h0 : P 0) (hsuc : ∀ n : ℕ, P n → P n.succ)
    (htop : (∀ n : ℕ, P n) → P ⊤) : P a := by
  have A : ∀ n : ℕ, P n := fun n => Nat.recOn n h0 hsuc
  

Proof state:
m n : ℕ∞
P : ℕ∞ → Prop
a : ℕ∞
h0 : P 0
hsuc : ∀ (n : ℕ), P ↑n → P ↑(Nat.succ n)
htop : (∀ (n : ℕ), P ↑n) → P ⊤
A : ∀ (n : ℕ), P ↑n
⊢ P a

Next tactic:
cases a
@[elab_as_elim]
theorem nat_induction {P : ℕ∞ → Prop} (a : ℕ∞) (h0 : P 0) (hsuc : ∀ n : ℕ, P n → P n.succ)
    (htop : (∀ n : ℕ, P n) → P ⊤) : P a := by
  have A : ∀ n : ℕ, P n := fun n => Nat.recOn n h0 hsuc
  cases a
  · 

Proof state:
case none
m n : ℕ∞
P : ℕ∞ → Prop
h0 : P 0
hsuc : ∀ (n : ℕ), P ↑n → P ↑(Nat.succ n)
htop : (∀ (n : ℕ), P ↑n) → P ⊤
A : ∀ (n : ℕ), P ↑n
⊢ P none

Next tactic:
exact htop A
@[elab_as_elim]
theorem nat_induction {P : ℕ∞ → Prop} (a : ℕ∞) (h0 : P 0) (hsuc : ∀ n : ℕ, P n → P n.succ)
    (htop : (∀ n : ℕ, P n) → P ⊤) : P a := by
  have A : ∀ n : ℕ, P n := fun n => Nat.recOn n h0 hsuc
  cases a
  · exact htop A
  · 

Proof state:
case some
m n : ℕ∞
P : ℕ∞ → Prop
h0 : P 0
hsuc : ∀ (n : ℕ), P ↑n → P ↑(Nat.succ n)
htop : (∀ (n : ℕ), P ↑n) → P ⊤
A : ∀ (n : ℕ), P ↑n
val✝ : ℕ
⊢ P (some val✝)

Next tactic:
exact A _
theorem distrib_three_right [Mul R] [Add R] [RightDistribClass R] (a b c d : R) :
    (a + b + c) * d = a * d + b * d + c * d := by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝² : Mul R
inst✝¹ : Add R
inst✝ : RightDistribClass R
a b c d : R
⊢ (a + b + c) * d = a * d + b * d + c * d

Next tactic:
simp [right_distrib]
theorem add_one_mul [RightDistribClass α] (a b : α) : (a + 1) * b = a * b + b := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝² : Add α
inst✝¹ : MulOneClass α
inst✝ : RightDistribClass α
a b : α
⊢ (a + 1) * b = a * b + b

Next tactic:
rw [add_mul, one_mul]
theorem mul_add_one [LeftDistribClass α] (a b : α) : a * (b + 1) = a * b + a := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝² : Add α
inst✝¹ : MulOneClass α
inst✝ : LeftDistribClass α
a b : α
⊢ a * (b + 1) = a * b + a

Next tactic:
rw [mul_add, mul_one]
theorem one_add_mul [RightDistribClass α] (a b : α) : (1 + a) * b = b + a * b := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝² : Add α
inst✝¹ : MulOneClass α
inst✝ : RightDistribClass α
a b : α
⊢ (1 + a) * b = b + a * b

Next tactic:
rw [add_mul, one_mul]
theorem mul_one_add [LeftDistribClass α] (a b : α) : a * (1 + b) = a + a * b := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝² : Add α
inst✝¹ : MulOneClass α
inst✝ : LeftDistribClass α
a b : α
⊢ a * (1 + b) = a + a * b

Next tactic:
rw [mul_add, mul_one]
theorem two_mul (n : α) : 2 * n = n + n :=
  (congrArg₂ _ one_add_one_eq_two.symm rfl).trans <| (right_distrib 1 1 n).trans (by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝ : NonAssocSemiring α
n : α
⊢ 1 * n + 1 * n = n + n

Next tactic:
rw [one_mul]
theorem mul_two (n : α) : n * 2 = n + n :=
  (congrArg₂ _ rfl one_add_one_eq_two.symm).trans <| (left_distrib n 1 1).trans (by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝ : NonAssocSemiring α
n : α
⊢ n * 1 + n * 1 = n + n

Next tactic:
rw [mul_one]
@[to_additive]
theorem mul_ite {α} [Mul α] (P : Prop) [Decidable P] (a b c : α) :
    (a * if P then b else c) = if P then a * b else a * c := by 

Proof state:
α✝ : Type u
β : Type v
γ : Type w
R : Type x
α : Type u_1
inst✝¹ : Mul α
P : Prop
inst✝ : Decidable P
a b c : α
⊢ (a * if P then b else c) = if P then a * b else a * c

Next tactic:
split_ifs
@[to_additive]
theorem mul_ite {α} [Mul α] (P : Prop) [Decidable P] (a b c : α) :
    (a * if P then b else c) = if P then a * b else a * c := by split_ifs <;> 

Proof state:
case pos
α✝ : Type u
β : Type v
γ : Type w
R : Type x
α : Type u_1
inst✝¹ : Mul α
P : Prop
inst✝ : Decidable P
a b c : α
h✝ : P
⊢ a * b = a * b

Next tactic:
rfl
@[to_additive]
theorem mul_ite {α} [Mul α] (P : Prop) [Decidable P] (a b c : α) :
    (a * if P then b else c) = if P then a * b else a * c := by split_ifs <;> 

Proof state:
case neg
α✝ : Type u
β : Type v
γ : Type w
R : Type x
α : Type u_1
inst✝¹ : Mul α
P : Prop
inst✝ : Decidable P
a b c : α
h✝ : ¬P
⊢ a * c = a * c

Next tactic:
rfl
@[to_additive]
theorem ite_mul {α} [Mul α] (P : Prop) [Decidable P] (a b c : α) :
    (if P then a else b) * c = if P then a * c else b * c := by 

Proof state:
α✝ : Type u
β : Type v
γ : Type w
R : Type x
α : Type u_1
inst✝¹ : Mul α
P : Prop
inst✝ : Decidable P
a b c : α
⊢ (if P then a else b) * c = if P then a * c else b * c

Next tactic:
split_ifs
@[to_additive]
theorem ite_mul {α} [Mul α] (P : Prop) [Decidable P] (a b c : α) :
    (if P then a else b) * c = if P then a * c else b * c := by split_ifs <;> 

Proof state:
case pos
α✝ : Type u
β : Type v
γ : Type w
R : Type x
α : Type u_1
inst✝¹ : Mul α
P : Prop
inst✝ : Decidable P
a b c : α
h✝ : P
⊢ a * c = a * c

Next tactic:
rfl
@[to_additive]
theorem ite_mul {α} [Mul α] (P : Prop) [Decidable P] (a b c : α) :
    (if P then a else b) * c = if P then a * c else b * c := by split_ifs <;> 

Proof state:
case neg
α✝ : Type u
β : Type v
γ : Type w
R : Type x
α : Type u_1
inst✝¹ : Mul α
P : Prop
inst✝ : Decidable P
a b c : α
h✝ : ¬P
⊢ b * c = b * c

Next tactic:
rfl
lemma ite_zero_mul : ite P a 0 * b = ite P (a * b) 0 := by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝² : MulZeroClass α
P Q : Prop
inst✝¹ : Decidable P
inst✝ : Decidable Q
a b : α
⊢ (if P then a else 0) * b = if P then a * b else 0

Next tactic:
simp
lemma mul_ite_zero : a * ite P b 0 = ite P (a * b) 0 := by 

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝² : MulZeroClass α
P Q : Prop
inst✝¹ : Decidable P
inst✝ : Decidable Q
a b : α
⊢ (a * if P then b else 0) = if P then a * b else 0

Next tactic:
simp
lemma ite_zero_mul_ite_zero : ite P a 0 * ite Q b 0 = ite (P ∧ Q) (a * b) 0 := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
R : Type x
inst✝² : MulZeroClass α
P Q : Prop
inst✝¹ : Decidable P
inst✝ : Decidable Q
a b : α
⊢ ((if P then a else 0) * if Q then b else 0) = if P ∧ Q then a * b else 0

Next tactic:
simp only [← ite_and, ite_mul, mul_ite, mul_zero, zero_mul, and_comm]