l3lab/ntp-mathlib huggingface dataset:
/-- The product in `CommRingCat` is the cartesian product. -/
def prodFanIsLimit : IsLimit (prodFan A B) where
  lift c := RingHom.prod (c.π.app ⟨WalkingPair.left⟩) (c.π.app ⟨WalkingPair.right⟩)
  fac c j := by
    ext
    rcases j with ⟨⟨⟩⟩ <;>
    simp only [pair_obj_left, prodFan_pt, BinaryFan.π_app_left, BinaryFan.π_app_right,
      FunctorToTypes.map_comp_apply, forget_map, coe_of, RingHom.prod_apply] <;>
    rfl
  uniq s m h := by
    ext x
    change m x = (BinaryFan.fst s x, BinaryFan.snd s x)
    have eq1 := congr_hom (h ⟨WalkingPair.left⟩) x
    

Proof state:
case w
A B : CommRingCat
s : Cone (pair A B)
m : s.pt ⟶ (prodFan A B).pt
h : ∀ (j : Discrete WalkingPair), m ≫ (prodFan A B).π.app j = s.π.app j
x : (forget CommRingCat).obj s.pt
eq1 : (m ≫ (prodFan A B).π.app { as := WalkingPair.left }) x = (s.π.app { as := WalkingPair.left }) x
⊢ m x = ((BinaryFan.fst s) x, (BinaryFan.snd s) x)

Next tactic:
have eq2 := congr_hom (h ⟨WalkingPair.right⟩) x
/-- The product in `CommRingCat` is the cartesian product. -/
def prodFanIsLimit : IsLimit (prodFan A B) where
  lift c := RingHom.prod (c.π.app ⟨WalkingPair.left⟩) (c.π.app ⟨WalkingPair.right⟩)
  fac c j := by
    ext
    rcases j with ⟨⟨⟩⟩ <;>
    simp only [pair_obj_left, prodFan_pt, BinaryFan.π_app_left, BinaryFan.π_app_right,
      FunctorToTypes.map_comp_apply, forget_map, coe_of, RingHom.prod_apply] <;>
    rfl
  uniq s m h := by
    ext x
    change m x = (BinaryFan.fst s x, BinaryFan.snd s x)
    have eq1 := congr_hom (h ⟨WalkingPair.left⟩) x
    have eq2 := congr_hom (h ⟨WalkingPair.right⟩) x
    

Proof state:
case w
A B : CommRingCat
s : Cone (pair A B)
m : s.pt ⟶ (prodFan A B).pt
h : ∀ (j : Discrete WalkingPair), m ≫ (prodFan A B).π.app j = s.π.app j
x : (forget CommRingCat).obj s.pt
eq1 : (m ≫ (prodFan A B).π.app { as := WalkingPair.left }) x = (s.π.app { as := WalkingPair.left }) x
eq2 : (m ≫ (prodFan A B).π.app { as := WalkingPair.right }) x = (s.π.app { as := WalkingPair.right }) x
⊢ m x = ((BinaryFan.fst s) x, (BinaryFan.snd s) x)

Next tactic:
dsimp at eq1 eq2
/-- The product in `CommRingCat` is the cartesian product. -/
def prodFanIsLimit : IsLimit (prodFan A B) where
  lift c := RingHom.prod (c.π.app ⟨WalkingPair.left⟩) (c.π.app ⟨WalkingPair.right⟩)
  fac c j := by
    ext
    rcases j with ⟨⟨⟩⟩ <;>
    simp only [pair_obj_left, prodFan_pt, BinaryFan.π_app_left, BinaryFan.π_app_right,
      FunctorToTypes.map_comp_apply, forget_map, coe_of, RingHom.prod_apply] <;>
    rfl
  uniq s m h := by
    ext x
    change m x = (BinaryFan.fst s x, BinaryFan.snd s x)
    have eq1 := congr_hom (h ⟨WalkingPair.left⟩) x
    have eq2 := congr_hom (h ⟨WalkingPair.right⟩) x
    dsimp at eq1 eq2
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    

Proof state:
case w
A B : CommRingCat
s : Cone (pair A B)
m : s.pt ⟶ (prodFan A B).pt
h : ∀ (j : Discrete WalkingPair), m ≫ (prodFan A B).π.app j = s.π.app j
x : (forget CommRingCat).obj s.pt
eq1 : (m ≫ BinaryFan.fst (prodFan A B)) x = (BinaryFan.fst s) x
eq2 : (m ≫ BinaryFan.snd (prodFan A B)) x = (BinaryFan.snd s) x
⊢ m x = ((BinaryFan.fst s) x, (BinaryFan.snd s) x)

Next tactic:
erw [← eq1, ← eq2]
/-- The product in `CommRingCat` is the cartesian product. -/
def prodFanIsLimit : IsLimit (prodFan A B) where
  lift c := RingHom.prod (c.π.app ⟨WalkingPair.left⟩) (c.π.app ⟨WalkingPair.right⟩)
  fac c j := by
    ext
    rcases j with ⟨⟨⟩⟩ <;>
    simp only [pair_obj_left, prodFan_pt, BinaryFan.π_app_left, BinaryFan.π_app_right,
      FunctorToTypes.map_comp_apply, forget_map, coe_of, RingHom.prod_apply] <;>
    rfl
  uniq s m h := by
    ext x
    change m x = (BinaryFan.fst s x, BinaryFan.snd s x)
    have eq1 := congr_hom (h ⟨WalkingPair.left⟩) x
    have eq2 := congr_hom (h ⟨WalkingPair.right⟩) x
    dsimp at eq1 eq2
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    erw [← eq1, ← eq2]
    

Proof state:
case w
A B : CommRingCat
s : Cone (pair A B)
m : s.pt ⟶ (prodFan A B).pt
h : ∀ (j : Discrete WalkingPair), m ≫ (prodFan A B).π.app j = s.π.app j
x : (forget CommRingCat).obj s.pt
eq1 : (m ≫ BinaryFan.fst (prodFan A B)) x = (BinaryFan.fst s) x
eq2 : (m ≫ BinaryFan.snd (prodFan A B)) x = (BinaryFan.snd s) x
⊢ m x = ((m ≫ BinaryFan.fst (prodFan A B)) x, (m ≫ BinaryFan.snd (prodFan A B)) x)

Next tactic:
rfl
/-- The equalizer in `CommRingCat` is the equalizer as sets. This is the equalizer fork. -/
def equalizerFork : Fork f g :=
  Fork.ofι (CommRingCat.ofHom (RingHom.eqLocus f g).subtype) <| by
      

Proof state:
A B : CommRingCat
f g : A ⟶ B
⊢ ofHom (Subring.subtype (RingHom.eqLocus f g)) ≫ f = ofHom (Subring.subtype (RingHom.eqLocus f g)) ≫ g

Next tactic:
ext ⟨x, e⟩
/-- The equalizer in `CommRingCat` is the equalizer as sets. This is the equalizer fork. -/
def equalizerFork : Fork f g :=
  Fork.ofι (CommRingCat.ofHom (RingHom.eqLocus f g).subtype) <| by
      ext ⟨x, e⟩
      

Proof state:
case w.mk
A B : CommRingCat
f g : A ⟶ B
x : ↑A
e : x ∈ RingHom.eqLocus f g
⊢ (ofHom (Subring.subtype (RingHom.eqLocus f g)) ≫ f) { val := x, property := e } =
    (ofHom (Subring.subtype (RingHom.eqLocus f g)) ≫ g) { val := x, property := e }

Next tactic:
simpa using e
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  

Proof state:
A B : CommRingCat
f g : A ⟶ B
⊢ IsLimit (equalizerFork f g)

Next tactic:
fapply Fork.IsLimit.mk'
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  fapply Fork.IsLimit.mk'
  

Proof state:
case create
A B : CommRingCat
f g : A ⟶ B
⊢ (s : Fork f g) →
    { l //
      l ≫ Fork.ι (equalizerFork f g) = Fork.ι s ∧
        ∀
          {m :
            ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
              ((Functor.const WalkingParallelPair).obj (equalizerFork f g).pt).obj WalkingParallelPair.zero},
          m ≫ Fork.ι (equalizerFork f g) = Fork.ι s → m = l }

Next tactic:
intro s
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  fapply Fork.IsLimit.mk'
  intro s
  -- Porting note : Lean can't see through `(parallelPair f g).obj zero`
  

Proof state:
case create
A B : CommRingCat
f g : A ⟶ B
s : Fork f g
⊢ { l //
    l ≫ Fork.ι (equalizerFork f g) = Fork.ι s ∧
      ∀
        {m :
          ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
            ((Functor.const WalkingParallelPair).obj (equalizerFork f g).pt).obj WalkingParallelPair.zero},
        m ≫ Fork.ι (equalizerFork f g) = Fork.ι s → m = l }

Next tactic:
haveI : SubsemiringClass (Subring A) ((parallelPair f g).obj WalkingParallelPair.zero) :=
    show SubsemiringClass (Subring A) A by infer_instance
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  fapply Fork.IsLimit.mk'
  intro s
  -- Porting note : Lean can't see through `(parallelPair f g).obj zero`
  haveI : SubsemiringClass (Subring A) ((parallelPair f g).obj WalkingParallelPair.zero) :=
    show SubsemiringClass (Subring A) A by 

Proof state:
A B : CommRingCat
f g : A ⟶ B
s : Fork f g
⊢ SubsemiringClass (Subring ↑A) ↑A

Next tactic:
infer_instance
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  fapply Fork.IsLimit.mk'
  intro s
  -- Porting note : Lean can't see through `(parallelPair f g).obj zero`
  haveI : SubsemiringClass (Subring A) ((parallelPair f g).obj WalkingParallelPair.zero) :=
    show SubsemiringClass (Subring A) A by infer_instance
  

Proof state:
case create
A B : CommRingCat
f g : A ⟶ B
s : Fork f g
this : SubsemiringClass (Subring ↑A) ↑((parallelPair f g).obj WalkingParallelPair.zero)
⊢ { l //
    l ≫ Fork.ι (equalizerFork f g) = Fork.ι s ∧
      ∀
        {m :
          ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
            ((Functor.const WalkingParallelPair).obj (equalizerFork f g).pt).obj WalkingParallelPair.zero},
        m ≫ Fork.ι (equalizerFork f g) = Fork.ι s → m = l }

Next tactic:
use s.ι.codRestrict _ fun x => (ConcreteCategory.congr_hom s.condition x : _)
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  fapply Fork.IsLimit.mk'
  intro s
  -- Porting note : Lean can't see through `(parallelPair f g).obj zero`
  haveI : SubsemiringClass (Subring A) ((parallelPair f g).obj WalkingParallelPair.zero) :=
    show SubsemiringClass (Subring A) A by infer_instance
  use s.ι.codRestrict _ fun x => (ConcreteCategory.congr_hom s.condition x : _)
  

Proof state:
case property
A B : CommRingCat
f g : A ⟶ B
s : Fork f g
this : SubsemiringClass (Subring ↑A) ↑((parallelPair f g).obj WalkingParallelPair.zero)
⊢ RingHom.codRestrict (Fork.ι s) (RingHom.eqLocus f g)
          (_ :
            ∀ (x : ↑(((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero)),
              (Fork.ι s ≫ f) x = (Fork.ι s ≫ g) x) ≫
        Fork.ι (equalizerFork f g) =
      Fork.ι s ∧
    ∀
      {m :
        ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
          ((Functor.const WalkingParallelPair).obj (equalizerFork f g).pt).obj WalkingParallelPair.zero},
      m ≫ Fork.ι (equalizerFork f g) = Fork.ι s →
        m =
          RingHom.codRestrict (Fork.ι s) (RingHom.eqLocus f g)
            (_ :
              ∀ (x : ↑(((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero)),
                (Fork.ι s ≫ f) x = (Fork.ι s ≫ g) x)

Next tactic:
constructor
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  fapply Fork.IsLimit.mk'
  intro s
  -- Porting note : Lean can't see through `(parallelPair f g).obj zero`
  haveI : SubsemiringClass (Subring A) ((parallelPair f g).obj WalkingParallelPair.zero) :=
    show SubsemiringClass (Subring A) A by infer_instance
  use s.ι.codRestrict _ fun x => (ConcreteCategory.congr_hom s.condition x : _)
  constructor
  · 

Proof state:
case property.left
A B : CommRingCat
f g : A ⟶ B
s : Fork f g
this : SubsemiringClass (Subring ↑A) ↑((parallelPair f g).obj WalkingParallelPair.zero)
⊢ RingHom.codRestrict (Fork.ι s) (RingHom.eqLocus f g)
        (_ :
          ∀ (x : ↑(((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero)),
            (Fork.ι s ≫ f) x = (Fork.ι s ≫ g) x) ≫
      Fork.ι (equalizerFork f g) =
    Fork.ι s

Next tactic:
ext
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  fapply Fork.IsLimit.mk'
  intro s
  -- Porting note : Lean can't see through `(parallelPair f g).obj zero`
  haveI : SubsemiringClass (Subring A) ((parallelPair f g).obj WalkingParallelPair.zero) :=
    show SubsemiringClass (Subring A) A by infer_instance
  use s.ι.codRestrict _ fun x => (ConcreteCategory.congr_hom s.condition x : _)
  constructor
  · ext
    

Proof state:
case property.left.w
A B : CommRingCat
f g : A ⟶ B
s : Fork f g
this : SubsemiringClass (Subring ↑A) ↑((parallelPair f g).obj WalkingParallelPair.zero)
x✝ : (forget CommRingCat).obj (((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero)
⊢ (RingHom.codRestrict (Fork.ι s) (RingHom.eqLocus f g)
          (_ :
            ∀ (x : ↑(((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero)),
              (Fork.ι s ≫ f) x = (Fork.ι s ≫ g) x) ≫
        Fork.ι (equalizerFork f g))
      x✝ =
    (Fork.ι s) x✝

Next tactic:
rfl
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  fapply Fork.IsLimit.mk'
  intro s
  -- Porting note : Lean can't see through `(parallelPair f g).obj zero`
  haveI : SubsemiringClass (Subring A) ((parallelPair f g).obj WalkingParallelPair.zero) :=
    show SubsemiringClass (Subring A) A by infer_instance
  use s.ι.codRestrict _ fun x => (ConcreteCategory.congr_hom s.condition x : _)
  constructor
  · ext
    rfl
  · 

Proof state:
case property.right
A B : CommRingCat
f g : A ⟶ B
s : Fork f g
this : SubsemiringClass (Subring ↑A) ↑((parallelPair f g).obj WalkingParallelPair.zero)
⊢ ∀
    {m :
      ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
        ((Functor.const WalkingParallelPair).obj (equalizerFork f g).pt).obj WalkingParallelPair.zero},
    m ≫ Fork.ι (equalizerFork f g) = Fork.ι s →
      m =
        RingHom.codRestrict (Fork.ι s) (RingHom.eqLocus f g)
          (_ :
            ∀ (x : ↑(((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero)),
              (Fork.ι s ≫ f) x = (Fork.ι s ≫ g) x)

Next tactic:
intro m hm
/-- The equalizer in `CommRingCat` is the equalizer as sets. -/
def equalizerForkIsLimit : IsLimit (equalizerFork f g) := by
  fapply Fork.IsLimit.mk'
  intro s
  -- Porting note : Lean can't see through `(parallelPair f g).obj zero`
  haveI : SubsemiringClass (Subring A) ((parallelPair f g).obj WalkingParallelPair.zero) :=
    show SubsemiringClass (Subring A) A by infer_instance
  use s.ι.codRestrict _ fun x => (ConcreteCategory.congr_hom s.condition x : _)
  constructor
  · ext
    rfl
  · intro m hm
    

Proof state:
case property.right
A B : CommRingCat
f g : A ⟶ B
s : Fork f g
this : SubsemiringClass (Subring ↑A) ↑((parallelPair f g).obj WalkingParallelPair.zero)
m :
  ((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero ⟶
    ((Functor.const WalkingParallelPair).obj (equalizerFork f g).pt).obj WalkingParallelPair.zero
hm : m ≫ Fork.ι (equalizerFork f g) = Fork.ι s
⊢ m =
    RingHom.codRestrict (Fork.ι s) (RingHom.eqLocus f g)
      (_ :
        ∀ (x : ↑(((Functor.const WalkingParallelPair).obj s.pt).obj WalkingParallelPair.zero)),
          (Fork.ι s ≫ f) x = (Fork.ι s ≫ g) x)

Next tactic:
exact RingHom.ext fun x => Subtype.ext <| ConcreteCategory.congr_hom hm x
instance : IsLocalRingHom (equalizerFork f g).ι := by
  

Proof state:
A B : CommRingCat
f g : A ⟶ B
⊢ IsLocalRingHom (Fork.ι (equalizerFork f g))

Next tactic:
constructor
instance : IsLocalRingHom (equalizerFork f g).ι := by
  constructor
  

Proof state:
case map_nonunit
A B : CommRingCat
f g : A ⟶ B
⊢ ∀ (a : ↑(((Functor.const WalkingParallelPair).obj (equalizerFork f g).pt).obj WalkingParallelPair.zero)),
    IsUnit ((Fork.ι (equalizerFork f g)) a) → IsUnit a

Next tactic:
rintro ⟨a, h₁ : _ = _⟩ (⟨⟨x, y, h₃, h₄⟩, rfl : x = _⟩ : IsUnit a)
instance : IsLocalRingHom (equalizerFork f g).ι := by
  constructor
  rintro ⟨a, h₁ : _ = _⟩ (⟨⟨x, y, h₃, h₄⟩, rfl : x = _⟩ : IsUnit a)
  

Proof state:
case map_nonunit.mk.intro.mk
A B : CommRingCat
f g : A ⟶ B
x y : ↑A
h₃ : x * y = 1
h₄ : y * x = 1
h₁ : f x = g x
⊢ IsUnit { val := x, property := h₁ }

Next tactic:
have : y ∈ RingHom.eqLocus f g := by
    apply (f.isUnit_map ⟨⟨x, y, h₃, h₄⟩, rfl⟩ : IsUnit (f x)).mul_left_inj.mp
    conv_rhs => rw [h₁]
    rw [← f.map_mul, ← g.map_mul, h₄, f.map_one, g.map_one]
instance : IsLocalRingHom (equalizerFork f g).ι := by
  constructor
  rintro ⟨a, h₁ : _ = _⟩ (⟨⟨x, y, h₃, h₄⟩, rfl : x = _⟩ : IsUnit a)
  have : y ∈ RingHom.eqLocus f g := by
    

Proof state:
A B : CommRingCat
f g : A ⟶ B
x y : ↑A
h₃ : x * y = 1
h₄ : y * x = 1
h₁ : f x = g x
⊢ y ∈ RingHom.eqLocus f g

Next tactic:
apply (f.isUnit_map ⟨⟨x, y, h₃, h₄⟩, rfl⟩ : IsUnit (f x)).mul_left_inj.mp
instance : IsLocalRingHom (equalizerFork f g).ι := by
  constructor
  rintro ⟨a, h₁ : _ = _⟩ (⟨⟨x, y, h₃, h₄⟩, rfl : x = _⟩ : IsUnit a)
  have : y ∈ RingHom.eqLocus f g := by
    apply (f.isUnit_map ⟨⟨x, y, h₃, h₄⟩, rfl⟩ : IsUnit (f x)).mul_left_inj.mp
    

Proof state:
A B : CommRingCat
f g : A ⟶ B
x y : ↑A
h₃ : x * y = 1
h₄ : y * x = 1
h₁ : f x = g x
⊢ f y * f x = g y * f x

Next tactic:
conv_rhs => rw [h₁]
instance : IsLocalRingHom (equalizerFork f g).ι := by
  constructor
  rintro ⟨a, h₁ : _ = _⟩ (⟨⟨x, y, h₃, h₄⟩, rfl : x = _⟩ : IsUnit a)
  have : y ∈ RingHom.eqLocus f g := by
    apply (f.isUnit_map ⟨⟨x, y, h₃, h₄⟩, rfl⟩ : IsUnit (f x)).mul_left_inj.mp
    conv_rhs => 

Proof state:
A B : CommRingCat
f g : A ⟶ B
x y : ↑A
h₃ : x * y = 1
h₄ : y * x = 1
h₁ : f x = g x
| g y * f x

Next tactic:
rw [h₁]
instance : IsLocalRingHom (equalizerFork f g).ι := by
  constructor
  rintro ⟨a, h₁ : _ = _⟩ (⟨⟨x, y, h₃, h₄⟩, rfl : x = _⟩ : IsUnit a)
  have : y ∈ RingHom.eqLocus f g := by
    apply (f.isUnit_map ⟨⟨x, y, h₃, h₄⟩, rfl⟩ : IsUnit (f x)).mul_left_inj.mp
    conv_rhs => rw [h₁]
    

Proof state:
A B : CommRingCat
f g : A ⟶ B
x y : ↑A
h₃ : x * y = 1
h₄ : y * x = 1
h₁ : f x = g x
⊢ f y * f x = g y * g x

Next tactic:
rw [← f.map_mul, ← g.map_mul, h₄, f.map_one, g.map_one]
instance : IsLocalRingHom (equalizerFork f g).ι := by
  constructor
  rintro ⟨a, h₁ : _ = _⟩ (⟨⟨x, y, h₃, h₄⟩, rfl : x = _⟩ : IsUnit a)
  have : y ∈ RingHom.eqLocus f g := by
    apply (f.isUnit_map ⟨⟨x, y, h₃, h₄⟩, rfl⟩ : IsUnit (f x)).mul_left_inj.mp
    conv_rhs => rw [h₁]
    rw [← f.map_mul, ← g.map_mul, h₄, f.map_one, g.map_one]
  

Proof state:
case map_nonunit.mk.intro.mk
A B : CommRingCat
f g : A ⟶ B
x y : ↑A
h₃ : x * y = 1
h₄ : y * x = 1
h₁ : f x = g x
this : y ∈ RingHom.eqLocus f g
⊢ IsUnit { val := x, property := h₁ }

Next tactic:
rw [isUnit_iff_exists_inv]
instance : IsLocalRingHom (equalizerFork f g).ι := by
  constructor
  rintro ⟨a, h₁ : _ = _⟩ (⟨⟨x, y, h₃, h₄⟩, rfl : x = _⟩ : IsUnit a)
  have : y ∈ RingHom.eqLocus f g := by
    apply (f.isUnit_map ⟨⟨x, y, h₃, h₄⟩, rfl⟩ : IsUnit (f x)).mul_left_inj.mp
    conv_rhs => rw [h₁]
    rw [← f.map_mul, ← g.map_mul, h₄, f.map_one, g.map_one]
  rw [isUnit_iff_exists_inv]
  

Proof state:
case map_nonunit.mk.intro.mk
A B : CommRingCat
f g : A ⟶ B
x y : ↑A
h₃ : x * y = 1
h₄ : y * x = 1
h₁ : f x = g x
this : y ∈ RingHom.eqLocus f g
⊢ ∃ b, { val := x, property := h₁ } * b = 1

Next tactic:
exact ⟨⟨y, this⟩, Subtype.eq h₃⟩
instance equalizer_ι_isLocalRingHom (F : WalkingParallelPair ⥤ CommRingCat.{u}) :
    IsLocalRingHom (limit.π F WalkingParallelPair.zero) := by
  

Proof state:
A B : CommRingCat
f g : A ⟶ B
F : WalkingParallelPair ⥤ CommRingCat
⊢ IsLocalRingHom (limit.π F WalkingParallelPair.zero)

Next tactic:
have := limMap_π (diagramIsoParallelPair F).hom WalkingParallelPair.zero
instance equalizer_ι_isLocalRingHom (F : WalkingParallelPair ⥤ CommRingCat.{u}) :
    IsLocalRingHom (limit.π F WalkingParallelPair.zero) := by
  have := limMap_π (diagramIsoParallelPair F).hom WalkingParallelPair.zero
  

Proof state:
A B : CommRingCat
f g : A ⟶ B
F : WalkingParallelPair ⥤ CommRingCat
this :
  limMap (diagramIsoParallelPair F).hom ≫
      limit.π (parallelPair (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right))
        WalkingParallelPair.zero =
    limit.π F WalkingParallelPair.zero ≫ (diagramIsoParallelPair F).hom.app WalkingParallelPair.zero
⊢ IsLocalRingHom (limit.π F WalkingParallelPair.zero)

Next tactic:
rw [← IsIso.comp_inv_eq] at this
instance equalizer_ι_isLocalRingHom (F : WalkingParallelPair ⥤ CommRingCat.{u}) :
    IsLocalRingHom (limit.π F WalkingParallelPair.zero) := by
  have := limMap_π (diagramIsoParallelPair F).hom WalkingParallelPair.zero
  rw [← IsIso.comp_inv_eq] at this
  

Proof state:
A B : CommRingCat
f g : A ⟶ B
F : WalkingParallelPair ⥤ CommRingCat
this :
  (limMap (diagramIsoParallelPair F).hom ≫
        limit.π (parallelPair (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right))
          WalkingParallelPair.zero) ≫
      inv ((diagramIsoParallelPair F).hom.app WalkingParallelPair.zero) =
    limit.π F WalkingParallelPair.zero
⊢ IsLocalRingHom (limit.π F WalkingParallelPair.zero)

Next tactic:
rw [← this]
instance equalizer_ι_isLocalRingHom (F : WalkingParallelPair ⥤ CommRingCat.{u}) :
    IsLocalRingHom (limit.π F WalkingParallelPair.zero) := by
  have := limMap_π (diagramIsoParallelPair F).hom WalkingParallelPair.zero
  rw [← IsIso.comp_inv_eq] at this
  rw [← this]
  

Proof state:
A B : CommRingCat
f g : A ⟶ B
F : WalkingParallelPair ⥤ CommRingCat
this :
  (limMap (diagramIsoParallelPair F).hom ≫
        limit.π (parallelPair (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right))
          WalkingParallelPair.zero) ≫
      inv ((diagramIsoParallelPair F).hom.app WalkingParallelPair.zero) =
    limit.π F WalkingParallelPair.zero
⊢ IsLocalRingHom
    ((limMap (diagramIsoParallelPair F).hom ≫
        limit.π (parallelPair (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right))
          WalkingParallelPair.zero) ≫
      inv ((diagramIsoParallelPair F).hom.app WalkingParallelPair.zero))

Next tactic:
rw [← limit.isoLimitCone_hom_π
      ⟨_,
        equalizerForkIsLimit (F.map WalkingParallelPairHom.left)
          (F.map WalkingParallelPairHom.right)⟩
      WalkingParallelPair.zero]
instance equalizer_ι_isLocalRingHom (F : WalkingParallelPair ⥤ CommRingCat.{u}) :
    IsLocalRingHom (limit.π F WalkingParallelPair.zero) := by
  have := limMap_π (diagramIsoParallelPair F).hom WalkingParallelPair.zero
  rw [← IsIso.comp_inv_eq] at this
  rw [← this]
  rw [← limit.isoLimitCone_hom_π
      ⟨_,
        equalizerForkIsLimit (F.map WalkingParallelPairHom.left)
          (F.map WalkingParallelPairHom.right)⟩
      WalkingParallelPair.zero]
  

Proof state:
A B : CommRingCat
f g : A ⟶ B
F : WalkingParallelPair ⥤ CommRingCat
this :
  (limMap (diagramIsoParallelPair F).hom ≫
        limit.π (parallelPair (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right))
          WalkingParallelPair.zero) ≫
      inv ((diagramIsoParallelPair F).hom.app WalkingParallelPair.zero) =
    limit.π F WalkingParallelPair.zero
⊢ IsLocalRingHom
    ((limMap (diagramIsoParallelPair F).hom ≫
        (limit.isoLimitCone
              { cone := equalizerFork (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right),
                isLimit :=
                  equalizerForkIsLimit (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right) }).hom ≫
          { cone := equalizerFork (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right),
                    isLimit :=
                      equalizerForkIsLimit (F.map WalkingParallelPairHom.left)
                        (F.map WalkingParallelPairHom.right) }.cone.π.app
            WalkingParallelPair.zero) ≫
      inv ((diagramIsoParallelPair F).hom.app WalkingParallelPair.zero))

Next tactic:
change IsLocalRingHom ((lim.map _ ≫ _ ≫ (equalizerFork _ _).ι) ≫ _)
instance equalizer_ι_isLocalRingHom (F : WalkingParallelPair ⥤ CommRingCat.{u}) :
    IsLocalRingHom (limit.π F WalkingParallelPair.zero) := by
  have := limMap_π (diagramIsoParallelPair F).hom WalkingParallelPair.zero
  rw [← IsIso.comp_inv_eq] at this
  rw [← this]
  rw [← limit.isoLimitCone_hom_π
      ⟨_,
        equalizerForkIsLimit (F.map WalkingParallelPairHom.left)
          (F.map WalkingParallelPairHom.right)⟩
      WalkingParallelPair.zero]
  change IsLocalRingHom ((lim.map _ ≫ _ ≫ (equalizerFork _ _).ι) ≫ _)
  

Proof state:
A B : CommRingCat
f g : A ⟶ B
F : WalkingParallelPair ⥤ CommRingCat
this :
  (limMap (diagramIsoParallelPair F).hom ≫
        limit.π (parallelPair (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right))
          WalkingParallelPair.zero) ≫
      inv ((diagramIsoParallelPair F).hom.app WalkingParallelPair.zero) =
    limit.π F WalkingParallelPair.zero
⊢ IsLocalRingHom
    ((lim.map (diagramIsoParallelPair F).hom ≫
        (limit.isoLimitCone
              { cone := equalizerFork (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right),
                isLimit :=
                  equalizerForkIsLimit (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right) }).hom ≫
          Fork.ι (equalizerFork (F.map WalkingParallelPairHom.left) (F.map WalkingParallelPairHom.right))) ≫
      inv ((diagramIsoParallelPair F).hom.app WalkingParallelPair.zero))

Next tactic:
infer_instance