l3lab/ntp-mathlib huggingface dataset:
theorem isSheafFor_arrows_iff : (ofArrows X π).IsSheafFor P ↔
    (∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x →
    ∃! t, ∀ i, P.map (π i).op t = x i) := by
  refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩
  · obtain ⟨t, ht₁, ht₂⟩ := h _ hx.familyOfElements_compatible
    refine ⟨t, fun i ↦ ?_, fun t' ht' ↦ ht₂ _ fun _ _ ⟨i⟩ ↦ ?_⟩
    · 

Proof state:
case refine_1.intro.intro.refine_1
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
h : IsSheafFor P (ofArrows X π)
x : (i : I) → P.obj (op (X i))
hx : Arrows.Compatible P π x
t : P.obj (op B)
ht₁ : FamilyOfElements.IsAmalgamation (Arrows.Compatible.familyOfElements hx) t
ht₂ :
  ∀ (y : P.obj (op B)), (fun t => FamilyOfElements.IsAmalgamation (Arrows.Compatible.familyOfElements hx) t) y → y = t
i : I
⊢ P.map (π i).op t = x i

Next tactic:
rw [ht₁ _ (ofArrows.mk i), hx.familyOfElements_ofArrows_mk]
theorem isSheafFor_arrows_iff : (ofArrows X π).IsSheafFor P ↔
    (∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x →
    ∃! t, ∀ i, P.map (π i).op t = x i) := by
  refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩
  · obtain ⟨t, ht₁, ht₂⟩ := h _ hx.familyOfElements_compatible
    refine ⟨t, fun i ↦ ?_, fun t' ht' ↦ ht₂ _ fun _ _ ⟨i⟩ ↦ ?_⟩
    · rw [ht₁ _ (ofArrows.mk i), hx.familyOfElements_ofArrows_mk]
    · 

Proof state:
case refine_1.intro.intro.refine_2
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
h : IsSheafFor P (ofArrows X π)
x : (i : I) → P.obj (op (X i))
hx : Arrows.Compatible P π x
t : P.obj (op B)
ht₁ : FamilyOfElements.IsAmalgamation (Arrows.Compatible.familyOfElements hx) t
ht₂ :
  ∀ (y : P.obj (op B)), (fun t => FamilyOfElements.IsAmalgamation (Arrows.Compatible.familyOfElements hx) t) y → y = t
t' : P.obj (op B)
ht' : (fun t => ∀ (i : I), P.map (π i).op t = x i) t'
x✝² : C
x✝¹ : x✝² ⟶ B
x✝ : ofArrows X π x✝¹
i : I
⊢ P.map (π i).op t' = Arrows.Compatible.familyOfElements hx (π i) (_ : ofArrows X π (π i))

Next tactic:
rw [ht', hx.familyOfElements_ofArrows_mk]
theorem isSheafFor_arrows_iff : (ofArrows X π).IsSheafFor P ↔
    (∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x →
    ∃! t, ∀ i, P.map (π i).op t = x i) := by
  refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩
  · obtain ⟨t, ht₁, ht₂⟩ := h _ hx.familyOfElements_compatible
    refine ⟨t, fun i ↦ ?_, fun t' ht' ↦ ht₂ _ fun _ _ ⟨i⟩ ↦ ?_⟩
    · rw [ht₁ _ (ofArrows.mk i), hx.familyOfElements_ofArrows_mk]
    · rw [ht', hx.familyOfElements_ofArrows_mk]
  · 

Proof state:
case refine_2
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
h : ∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x → ∃! t, ∀ (i : I), P.map (π i).op t = x i
x : FamilyOfElements P (ofArrows X π)
hx : FamilyOfElements.Compatible x
⊢ ∃! t, FamilyOfElements.IsAmalgamation x t

Next tactic:
obtain ⟨t, hA, ht⟩ := h (fun i ↦ x (π i) (ofArrows.mk _))
      (fun i j Z gi gj ↦ hx gi gj (ofArrows.mk _) (ofArrows.mk _))
theorem isSheafFor_arrows_iff : (ofArrows X π).IsSheafFor P ↔
    (∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x →
    ∃! t, ∀ i, P.map (π i).op t = x i) := by
  refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩
  · obtain ⟨t, ht₁, ht₂⟩ := h _ hx.familyOfElements_compatible
    refine ⟨t, fun i ↦ ?_, fun t' ht' ↦ ht₂ _ fun _ _ ⟨i⟩ ↦ ?_⟩
    · rw [ht₁ _ (ofArrows.mk i), hx.familyOfElements_ofArrows_mk]
    · rw [ht', hx.familyOfElements_ofArrows_mk]
  · obtain ⟨t, hA, ht⟩ := h (fun i ↦ x (π i) (ofArrows.mk _))
      (fun i j Z gi gj ↦ hx gi gj (ofArrows.mk _) (ofArrows.mk _))
    

Proof state:
case refine_2.intro.intro
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
h : ∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x → ∃! t, ∀ (i : I), P.map (π i).op t = x i
x : FamilyOfElements P (ofArrows X π)
hx : FamilyOfElements.Compatible x
t : P.obj (op B)
hA : ∀ (i : I), P.map (π i).op t = x (π i) (_ : ofArrows X π (π i))
ht : ∀ (y : P.obj (op B)), (fun t => ∀ (i : I), P.map (π i).op t = x (π i) (_ : ofArrows X π (π i))) y → y = t
⊢ ∃! t, FamilyOfElements.IsAmalgamation x t

Next tactic:
exact ⟨t, fun Y f ⟨i⟩ ↦ hA i, fun y hy ↦ ht y (fun i ↦ hy (π i) (ofArrows.mk _))⟩
theorem Arrows.pullbackCompatible_iff (x : (i : I) → P.obj (op (X i))) :
    Compatible P π x ↔ PullbackCompatible P π x := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
inst✝ : hasPullbacks (ofArrows X π)
x : (i : I) → P.obj (op (X i))
⊢ Compatible P π x ↔ PullbackCompatible P π x

Next tactic:
refine ⟨fun t i j ↦ ?_, fun t i j Z gi gj comm ↦ ?_⟩
theorem Arrows.pullbackCompatible_iff (x : (i : I) → P.obj (op (X i))) :
    Compatible P π x ↔ PullbackCompatible P π x := by
  refine ⟨fun t i j ↦ ?_, fun t i j Z gi gj comm ↦ ?_⟩
  · 

Proof state:
case refine_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
inst✝ : hasPullbacks (ofArrows X π)
x : (i : I) → P.obj (op (X i))
t : Compatible P π x
i j : I
⊢ P.map pullback.fst.op (x i) = P.map pullback.snd.op (x j)

Next tactic:
apply t
theorem Arrows.pullbackCompatible_iff (x : (i : I) → P.obj (op (X i))) :
    Compatible P π x ↔ PullbackCompatible P π x := by
  refine ⟨fun t i j ↦ ?_, fun t i j Z gi gj comm ↦ ?_⟩
  · apply t
    

Proof state:
case refine_1.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
inst✝ : hasPullbacks (ofArrows X π)
x : (i : I) → P.obj (op (X i))
t : Compatible P π x
i j : I
⊢ pullback.fst ≫ π i = pullback.snd ≫ π j

Next tactic:
exact pullback.condition
theorem Arrows.pullbackCompatible_iff (x : (i : I) → P.obj (op (X i))) :
    Compatible P π x ↔ PullbackCompatible P π x := by
  refine ⟨fun t i j ↦ ?_, fun t i j Z gi gj comm ↦ ?_⟩
  · apply t
    exact pullback.condition
  · 

Proof state:
case refine_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
inst✝ : hasPullbacks (ofArrows X π)
x : (i : I) → P.obj (op (X i))
t : PullbackCompatible P π x
i j : I
Z : C
gi : Z ⟶ (fun i => X i) i
gj : Z ⟶ (fun i => X i) j
comm : gi ≫ π i = gj ≫ π j
⊢ P.map gi.op (x i) = P.map gj.op (x j)

Next tactic:
rw [← pullback.lift_fst _ _ comm, op_comp, FunctorToTypes.map_comp_apply, t i j,
      ← FunctorToTypes.map_comp_apply, ← op_comp, pullback.lift_snd]
theorem isSheafFor_arrows_iff_pullbacks : (ofArrows X π).IsSheafFor P ↔
    (∀ (x : (i : I) → P.obj (op (X i))), Arrows.PullbackCompatible P π x →
    ∃! t, ∀ i, P.map (π i).op t = x i) := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
inst✝ : hasPullbacks (ofArrows X π)
⊢ IsSheafFor P (ofArrows X π) ↔
    ∀ (x : (i : I) → P.obj (op (X i))), Arrows.PullbackCompatible P π x → ∃! t, ∀ (i : I), P.map (π i).op t = x i

Next tactic:
simp_rw [← Arrows.pullbackCompatible_iff, isSheafFor_arrows_iff]
/-- The induced map from the quotient by the kernel is injective. -/
theorem kerLift_injective (f : R →+* S) : Function.Injective (kerLift f) := fun a b =>
  Quotient.inductionOn₂' a b fun a b (h : f a = f b) =>
    Ideal.Quotient.eq.2 <| show a - b ∈ ker f by 

Proof state:
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f✝ f : R →+* S
a✝ b✝ : R ⧸ ker f
a b : R
h : f a = f b
⊢ a - b ∈ ker f

Next tactic:
rw [mem_ker, map_sub, h, sub_self]
theorem lift_injective_of_ker_le_ideal (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0)
    (hI : ker f ≤ I) : Function.Injective (Ideal.Quotient.lift I f H) := by
  

Proof state:
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f✝ : R →+* S
I : Ideal R
f : R →+* S
H : ∀ a ∈ I, f a = 0
hI : ker f ≤ I
⊢ Function.Injective ⇑(Ideal.Quotient.lift I f H)

Next tactic:
rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero]
theorem lift_injective_of_ker_le_ideal (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0)
    (hI : ker f ≤ I) : Function.Injective (Ideal.Quotient.lift I f H) := by
  rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero]
  

Proof state:
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f✝ : R →+* S
I : Ideal R
f : R →+* S
H : ∀ a ∈ I, f a = 0
hI : ker f ≤ I
⊢ ∀ (x : R ⧸ I), (Ideal.Quotient.lift I f H) x = 0 → x = 0

Next tactic:
intro u hu
theorem lift_injective_of_ker_le_ideal (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0)
    (hI : ker f ≤ I) : Function.Injective (Ideal.Quotient.lift I f H) := by
  rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero]
  intro u hu
  

Proof state:
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f✝ : R →+* S
I : Ideal R
f : R →+* S
H : ∀ a ∈ I, f a = 0
hI : ker f ≤ I
u : R ⧸ I
hu : (Ideal.Quotient.lift I f H) u = 0
⊢ u = 0

Next tactic:
obtain ⟨v, rfl⟩ := Ideal.Quotient.mk_surjective u
theorem lift_injective_of_ker_le_ideal (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0)
    (hI : ker f ≤ I) : Function.Injective (Ideal.Quotient.lift I f H) := by
  rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero]
  intro u hu
  obtain ⟨v, rfl⟩ := Ideal.Quotient.mk_surjective u
  

Proof state:
case intro
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f✝ : R →+* S
I : Ideal R
f : R →+* S
H : ∀ a ∈ I, f a = 0
hI : ker f ≤ I
v : R
hu : (Ideal.Quotient.lift I f H) ((Ideal.Quotient.mk I) v) = 0
⊢ (Ideal.Quotient.mk I) v = 0

Next tactic:
rw [Ideal.Quotient.lift_mk] at hu
theorem lift_injective_of_ker_le_ideal (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0)
    (hI : ker f ≤ I) : Function.Injective (Ideal.Quotient.lift I f H) := by
  rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero]
  intro u hu
  obtain ⟨v, rfl⟩ := Ideal.Quotient.mk_surjective u
  rw [Ideal.Quotient.lift_mk] at hu
  

Proof state:
case intro
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f✝ : R →+* S
I : Ideal R
f : R →+* S
H : ∀ a ∈ I, f a = 0
hI : ker f ≤ I
v : R
hu : f v = 0
⊢ (Ideal.Quotient.mk I) v = 0

Next tactic:
rw [Ideal.Quotient.eq_zero_iff_mem]
theorem lift_injective_of_ker_le_ideal (I : Ideal R) {f : R →+* S} (H : ∀ a : R, a ∈ I → f a = 0)
    (hI : ker f ≤ I) : Function.Injective (Ideal.Quotient.lift I f H) := by
  rw [RingHom.injective_iff_ker_eq_bot, RingHom.ker_eq_bot_iff_eq_zero]
  intro u hu
  obtain ⟨v, rfl⟩ := Ideal.Quotient.mk_surjective u
  rw [Ideal.Quotient.lift_mk] at hu
  rw [Ideal.Quotient.eq_zero_iff_mem]
  

Proof state:
case intro
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f✝ : R →+* S
I : Ideal R
f : R →+* S
H : ∀ a ∈ I, f a = 0
hI : ker f ≤ I
v : R
hu : f v = 0
⊢ v ∈ I

Next tactic:
exact hI ((RingHom.mem_ker f).mpr hu)
/-- The **first isomorphism theorem for commutative rings**, computable version. -/
def quotientKerEquivOfRightInverse {g : S → R} (hf : Function.RightInverse g f) :
    R ⧸ ker f ≃+* S :=
  { kerLift f with
    toFun := kerLift f
    invFun := Ideal.Quotient.mk (ker f) ∘ g
    left_inv := by
      

Proof state:
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f : R →+* S
g : S → R
hf : Function.RightInverse g ⇑f
src✝ : R ⧸ ker f →+* S := kerLift f
⊢ Function.LeftInverse (⇑(Ideal.Quotient.mk (ker f)) ∘ g) ⇑(kerLift f)

Next tactic:
rintro ⟨x⟩
/-- The **first isomorphism theorem for commutative rings**, computable version. -/
def quotientKerEquivOfRightInverse {g : S → R} (hf : Function.RightInverse g f) :
    R ⧸ ker f ≃+* S :=
  { kerLift f with
    toFun := kerLift f
    invFun := Ideal.Quotient.mk (ker f) ∘ g
    left_inv := by
      rintro ⟨x⟩
      

Proof state:
case mk
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f : R →+* S
g : S → R
hf : Function.RightInverse g ⇑f
src✝ : R ⧸ ker f →+* S := kerLift f
x✝ : R ⧸ ker f
x : R
⊢ (⇑(Ideal.Quotient.mk (ker f)) ∘ g) ((kerLift f) (Quot.mk Setoid.r x)) = Quot.mk Setoid.r x

Next tactic:
apply kerLift_injective
/-- The **first isomorphism theorem for commutative rings**, computable version. -/
def quotientKerEquivOfRightInverse {g : S → R} (hf : Function.RightInverse g f) :
    R ⧸ ker f ≃+* S :=
  { kerLift f with
    toFun := kerLift f
    invFun := Ideal.Quotient.mk (ker f) ∘ g
    left_inv := by
      rintro ⟨x⟩
      apply kerLift_injective
      

Proof state:
case mk.a
R : Type u
S : Type v
inst✝¹ : CommRing R
inst✝ : CommRing S
f : R →+* S
g : S → R
hf : Function.RightInverse g ⇑f
src✝ : R ⧸ ker f →+* S := kerLift f
x✝ : R ⧸ ker f
x : R
⊢ (kerLift f) ((⇑(Ideal.Quotient.mk (ker f)) ∘ g) ((kerLift f) (Quot.mk Setoid.r x))) = (kerLift f) (Quot.mk Setoid.r x)

Next tactic:
simp only [Submodule.Quotient.quot_mk_eq_mk, Ideal.Quotient.mk_eq_mk, kerLift_mk,
        Function.comp_apply, hf (f x)]
@[simp]
theorem mk_ker {I : Ideal R} : ker (Quotient.mk I) = I := by
  

Proof state:
R : Type u
S : Type v
F : Type w
inst✝¹ : CommRing R
inst✝ : CommRing S
I : Ideal R
⊢ ker (Quotient.mk I) = I

Next tactic:
ext
@[simp]
theorem mk_ker {I : Ideal R} : ker (Quotient.mk I) = I := by
  ext
  

Proof state:
case h
R : Type u
S : Type v
F : Type w
inst✝¹ : CommRing R
inst✝ : CommRing S
I : Ideal R
x✝ : R
⊢ x✝ ∈ ker (Quotient.mk I) ↔ x✝ ∈ I

Next tactic:
rw [ker, mem_comap, @Submodule.mem_bot _ _ _ _ Semiring.toModule _,
    Quotient.eq_zero_iff_mem]
theorem map_mk_eq_bot_of_le {I J : Ideal R} (h : I ≤ J) : I.map (Quotient.mk J) = ⊥ := by
  

Proof state:
R : Type u
S : Type v
F : Type w
inst✝¹ : CommRing R
inst✝ : CommRing S
I J : Ideal R
h : I ≤ J
⊢ map (Quotient.mk J) I = ⊥

Next tactic:
rw [map_eq_bot_iff_le_ker, mk_ker]
theorem map_mk_eq_bot_of_le {I J : Ideal R} (h : I ≤ J) : I.map (Quotient.mk J) = ⊥ := by
  rw [map_eq_bot_iff_le_ker, mk_ker]
  

Proof state:
R : Type u
S : Type v
F : Type w
inst✝¹ : CommRing R
inst✝ : CommRing S
I J : Ideal R
h : I ≤ J
⊢ I ≤ J

Next tactic:
exact h
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  

Proof state:
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
⊢ ker (Quotient.lift I f H) = map (Quotient.mk I) (ker f)

Next tactic:
apply Ideal.ext
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  

Proof state:
case h
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
⊢ ∀ (x : R ⧸ I), x ∈ ker (Quotient.lift I f H) ↔ x ∈ map (Quotient.mk I) (ker f)

Next tactic:
intro x
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  

Proof state:
case h
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
⊢ x ∈ ker (Quotient.lift I f H) ↔ x ∈ map (Quotient.mk I) (ker f)

Next tactic:
constructor
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · 

Proof state:
case h.mp
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
⊢ x ∈ ker (Quotient.lift I f H) → x ∈ map (Quotient.mk I) (ker f)

Next tactic:
intro hx
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · intro hx
    

Proof state:
case h.mp
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
hx : x ∈ ker (Quotient.lift I f H)
⊢ x ∈ map (Quotient.mk I) (ker f)

Next tactic:
obtain ⟨y, hy⟩ := Quotient.mk_surjective x
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · intro hx
    obtain ⟨y, hy⟩ := Quotient.mk_surjective x
    

Proof state:
case h.mp.intro
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
hx : x ∈ ker (Quotient.lift I f H)
y : R
hy : (Quotient.mk I) y = x
⊢ x ∈ map (Quotient.mk I) (ker f)

Next tactic:
rw [mem_ker, ← hy, Ideal.Quotient.lift_mk, ← mem_ker] at hx
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · intro hx
    obtain ⟨y, hy⟩ := Quotient.mk_surjective x
    rw [mem_ker, ← hy, Ideal.Quotient.lift_mk, ← mem_ker] at hx
    

Proof state:
case h.mp.intro
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
y : R
hx : y ∈ ker f
hy : (Quotient.mk I) y = x
⊢ x ∈ map (Quotient.mk I) (ker f)

Next tactic:
rw [← hy, mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective]
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · intro hx
    obtain ⟨y, hy⟩ := Quotient.mk_surjective x
    rw [mem_ker, ← hy, Ideal.Quotient.lift_mk, ← mem_ker] at hx
    rw [← hy, mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective]
    

Proof state:
case h.mp.intro
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
y : R
hx : y ∈ ker f
hy : (Quotient.mk I) y = x
⊢ ∃ x ∈ ker f, (Quotient.mk I) x = (Quotient.mk I) y

Next tactic:
exact ⟨y, hx, rfl⟩
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · intro hx
    obtain ⟨y, hy⟩ := Quotient.mk_surjective x
    rw [mem_ker, ← hy, Ideal.Quotient.lift_mk, ← mem_ker] at hx
    rw [← hy, mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective]
    exact ⟨y, hx, rfl⟩
  · 

Proof state:
case h.mpr
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
⊢ x ∈ map (Quotient.mk I) (ker f) → x ∈ ker (Quotient.lift I f H)

Next tactic:
intro hx
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · intro hx
    obtain ⟨y, hy⟩ := Quotient.mk_surjective x
    rw [mem_ker, ← hy, Ideal.Quotient.lift_mk, ← mem_ker] at hx
    rw [← hy, mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective]
    exact ⟨y, hx, rfl⟩
  · intro hx
    

Proof state:
case h.mpr
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
hx : x ∈ map (Quotient.mk I) (ker f)
⊢ x ∈ ker (Quotient.lift I f H)

Next tactic:
rw [mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective] at hx
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · intro hx
    obtain ⟨y, hy⟩ := Quotient.mk_surjective x
    rw [mem_ker, ← hy, Ideal.Quotient.lift_mk, ← mem_ker] at hx
    rw [← hy, mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective]
    exact ⟨y, hx, rfl⟩
  · intro hx
    rw [mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective] at hx
    

Proof state:
case h.mpr
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
hx : ∃ x_1 ∈ ker f, (Quotient.mk I) x_1 = x
⊢ x ∈ ker (Quotient.lift I f H)

Next tactic:
obtain ⟨y, hy⟩ := hx
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · intro hx
    obtain ⟨y, hy⟩ := Quotient.mk_surjective x
    rw [mem_ker, ← hy, Ideal.Quotient.lift_mk, ← mem_ker] at hx
    rw [← hy, mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective]
    exact ⟨y, hx, rfl⟩
  · intro hx
    rw [mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective] at hx
    obtain ⟨y, hy⟩ := hx
    

Proof state:
case h.mpr.intro
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
y : R
hy : y ∈ ker f ∧ (Quotient.mk I) y = x
⊢ x ∈ ker (Quotient.lift I f H)

Next tactic:
rw [mem_ker, ← hy.right, Ideal.Quotient.lift_mk]
theorem ker_quotient_lift {S : Type v} [CommRing S] {I : Ideal R} (f : R →+* S)
    (H : I ≤ ker f) :
    ker (Ideal.Quotient.lift I f H) = f.ker.map (Quotient.mk I) := by
  apply Ideal.ext
  intro x
  constructor
  · intro hx
    obtain ⟨y, hy⟩ := Quotient.mk_surjective x
    rw [mem_ker, ← hy, Ideal.Quotient.lift_mk, ← mem_ker] at hx
    rw [← hy, mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective]
    exact ⟨y, hx, rfl⟩
  · intro hx
    rw [mem_map_iff_of_surjective (Quotient.mk I) Quotient.mk_surjective] at hx
    obtain ⟨y, hy⟩ := hx
    rw [mem_ker, ← hy.right, Ideal.Quotient.lift_mk]
    

Proof state:
case h.mpr.intro
R : Type u
S✝ : Type v
F : Type w
inst✝² : CommRing R
inst✝¹ : CommRing S✝
S : Type v
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : I ≤ ker f
x : R ⧸ I
y : R
hy : y ∈ ker f ∧ (Quotient.mk I) y = x
⊢ f y = 0

Next tactic:
exact hy.left
lemma injective_lift_iff {I : Ideal R} {f : R →+* S} (H : ∀ (a : R), a ∈ I → f a = 0) :
    Injective (Quotient.lift I f H) ↔ ker f = I := by
  

Proof state:
R : Type u
S : Type v
F : Type w
inst✝¹ : CommRing R
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : ∀ a ∈ I, f a = 0
⊢ Injective ⇑(Quotient.lift I f H) ↔ ker f = I

Next tactic:
rw [injective_iff_ker_eq_bot, ker_quotient_lift, map_eq_bot_iff_le_ker, mk_ker]
lemma injective_lift_iff {I : Ideal R} {f : R →+* S} (H : ∀ (a : R), a ∈ I → f a = 0) :
    Injective (Quotient.lift I f H) ↔ ker f = I := by
  rw [injective_iff_ker_eq_bot, ker_quotient_lift, map_eq_bot_iff_le_ker, mk_ker]
  

Proof state:
R : Type u
S : Type v
F : Type w
inst✝¹ : CommRing R
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : ∀ a ∈ I, f a = 0
⊢ ker f ≤ I ↔ ker f = I

Next tactic:
constructor
lemma injective_lift_iff {I : Ideal R} {f : R →+* S} (H : ∀ (a : R), a ∈ I → f a = 0) :
    Injective (Quotient.lift I f H) ↔ ker f = I := by
  rw [injective_iff_ker_eq_bot, ker_quotient_lift, map_eq_bot_iff_le_ker, mk_ker]
  constructor
  · 

Proof state:
case mp
R : Type u
S : Type v
F : Type w
inst✝¹ : CommRing R
inst✝ : CommRing S
I : Ideal R
f : R →+* S
H : ∀ a ∈ I, f a = 0
⊢ ker f ≤ I → ker f = I

Next tactic:
exact fun h ↦ le_antisymm h H