l3lab/ntp-mathlib huggingface dataset:
/-- The equivalence of the two definitions of `I / I ^ 2`, either as the quotient of `I` or the
ideal of `R / I ^ 2`. -/
noncomputable def cotangentEquivIdeal : I.Cotangent ≃ₗ[R] I.cotangentIdeal := by
  refine
  { LinearMap.codRestrict (I.cotangentIdeal.restrictScalars R) I.cotangentToQuotientSquare
      fun x => by { rw [← to_quotient_square_range]; exact LinearMap.mem_range_self _ _ },
    Equiv.ofBijective _ ⟨?_, ?_⟩ with }
  · rintro x y e
    replace e := congr_arg Subtype.val e
    

Proof state:
case refine_1
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
src✝ : Cotangent I →ₗ[R] ↥(Submodule.restrictScalars R (cotangentIdeal I)) :=
  LinearMap.codRestrict (Submodule.restrictScalars R (cotangentIdeal I)) (cotangentToQuotientSquare I)
    (_ : ∀ (x : Cotangent I), (cotangentToQuotientSquare I) x ∈ Submodule.restrictScalars R (cotangentIdeal I))
x y : Cotangent I
e :
  ↑((fun c =>
          { val := (cotangentToQuotientSquare I) c,
            property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) })
        x) =
    ↑((fun c =>
          { val := (cotangentToQuotientSquare I) c,
            property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) })
        y)
⊢ x = y

Next tactic:
obtain ⟨x, rfl⟩ := I.toCotangent_surjective x
/-- The equivalence of the two definitions of `I / I ^ 2`, either as the quotient of `I` or the
ideal of `R / I ^ 2`. -/
noncomputable def cotangentEquivIdeal : I.Cotangent ≃ₗ[R] I.cotangentIdeal := by
  refine
  { LinearMap.codRestrict (I.cotangentIdeal.restrictScalars R) I.cotangentToQuotientSquare
      fun x => by { rw [← to_quotient_square_range]; exact LinearMap.mem_range_self _ _ },
    Equiv.ofBijective _ ⟨?_, ?_⟩ with }
  · rintro x y e
    replace e := congr_arg Subtype.val e
    obtain ⟨x, rfl⟩ := I.toCotangent_surjective x
    

Proof state:
case refine_1.intro
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
src✝ : Cotangent I →ₗ[R] ↥(Submodule.restrictScalars R (cotangentIdeal I)) :=
  LinearMap.codRestrict (Submodule.restrictScalars R (cotangentIdeal I)) (cotangentToQuotientSquare I)
    (_ : ∀ (x : Cotangent I), (cotangentToQuotientSquare I) x ∈ Submodule.restrictScalars R (cotangentIdeal I))
y : Cotangent I
x : ↥I
e :
  ↑((fun c =>
          { val := (cotangentToQuotientSquare I) c,
            property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) })
        ((toCotangent I) x)) =
    ↑((fun c =>
          { val := (cotangentToQuotientSquare I) c,
            property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) })
        y)
⊢ (toCotangent I) x = y

Next tactic:
obtain ⟨y, rfl⟩ := I.toCotangent_surjective y
/-- The equivalence of the two definitions of `I / I ^ 2`, either as the quotient of `I` or the
ideal of `R / I ^ 2`. -/
noncomputable def cotangentEquivIdeal : I.Cotangent ≃ₗ[R] I.cotangentIdeal := by
  refine
  { LinearMap.codRestrict (I.cotangentIdeal.restrictScalars R) I.cotangentToQuotientSquare
      fun x => by { rw [← to_quotient_square_range]; exact LinearMap.mem_range_self _ _ },
    Equiv.ofBijective _ ⟨?_, ?_⟩ with }
  · rintro x y e
    replace e := congr_arg Subtype.val e
    obtain ⟨x, rfl⟩ := I.toCotangent_surjective x
    obtain ⟨y, rfl⟩ := I.toCotangent_surjective y
    

Proof state:
case refine_1.intro.intro
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
src✝ : Cotangent I →ₗ[R] ↥(Submodule.restrictScalars R (cotangentIdeal I)) :=
  LinearMap.codRestrict (Submodule.restrictScalars R (cotangentIdeal I)) (cotangentToQuotientSquare I)
    (_ : ∀ (x : Cotangent I), (cotangentToQuotientSquare I) x ∈ Submodule.restrictScalars R (cotangentIdeal I))
x y : ↥I
e :
  ↑((fun c =>
          { val := (cotangentToQuotientSquare I) c,
            property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) })
        ((toCotangent I) x)) =
    ↑((fun c =>
          { val := (cotangentToQuotientSquare I) c,
            property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) })
        ((toCotangent I) y))
⊢ (toCotangent I) x = (toCotangent I) y

Next tactic:
rw [I.toCotangent_eq]
/-- The equivalence of the two definitions of `I / I ^ 2`, either as the quotient of `I` or the
ideal of `R / I ^ 2`. -/
noncomputable def cotangentEquivIdeal : I.Cotangent ≃ₗ[R] I.cotangentIdeal := by
  refine
  { LinearMap.codRestrict (I.cotangentIdeal.restrictScalars R) I.cotangentToQuotientSquare
      fun x => by { rw [← to_quotient_square_range]; exact LinearMap.mem_range_self _ _ },
    Equiv.ofBijective _ ⟨?_, ?_⟩ with }
  · rintro x y e
    replace e := congr_arg Subtype.val e
    obtain ⟨x, rfl⟩ := I.toCotangent_surjective x
    obtain ⟨y, rfl⟩ := I.toCotangent_surjective y
    rw [I.toCotangent_eq]
    

Proof state:
case refine_1.intro.intro
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
src✝ : Cotangent I →ₗ[R] ↥(Submodule.restrictScalars R (cotangentIdeal I)) :=
  LinearMap.codRestrict (Submodule.restrictScalars R (cotangentIdeal I)) (cotangentToQuotientSquare I)
    (_ : ∀ (x : Cotangent I), (cotangentToQuotientSquare I) x ∈ Submodule.restrictScalars R (cotangentIdeal I))
x y : ↥I
e :
  ↑((fun c =>
          { val := (cotangentToQuotientSquare I) c,
            property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) })
        ((toCotangent I) x)) =
    ↑((fun c =>
          { val := (cotangentToQuotientSquare I) c,
            property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) })
        ((toCotangent I) y))
⊢ ↑x - ↑y ∈ I ^ 2

Next tactic:
dsimp only [toCotangent_to_quotient_square, Submodule.mkQ_apply] at e
/-- The equivalence of the two definitions of `I / I ^ 2`, either as the quotient of `I` or the
ideal of `R / I ^ 2`. -/
noncomputable def cotangentEquivIdeal : I.Cotangent ≃ₗ[R] I.cotangentIdeal := by
  refine
  { LinearMap.codRestrict (I.cotangentIdeal.restrictScalars R) I.cotangentToQuotientSquare
      fun x => by { rw [← to_quotient_square_range]; exact LinearMap.mem_range_self _ _ },
    Equiv.ofBijective _ ⟨?_, ?_⟩ with }
  · rintro x y e
    replace e := congr_arg Subtype.val e
    obtain ⟨x, rfl⟩ := I.toCotangent_surjective x
    obtain ⟨y, rfl⟩ := I.toCotangent_surjective y
    rw [I.toCotangent_eq]
    dsimp only [toCotangent_to_quotient_square, Submodule.mkQ_apply] at e
    

Proof state:
case refine_1.intro.intro
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
src✝ : Cotangent I →ₗ[R] ↥(Submodule.restrictScalars R (cotangentIdeal I)) :=
  LinearMap.codRestrict (Submodule.restrictScalars R (cotangentIdeal I)) (cotangentToQuotientSquare I)
    (_ : ∀ (x : Cotangent I), (cotangentToQuotientSquare I) x ∈ Submodule.restrictScalars R (cotangentIdeal I))
x y : ↥I
e : Submodule.Quotient.mk ↑x = Submodule.Quotient.mk ↑y
⊢ ↑x - ↑y ∈ I ^ 2

Next tactic:
rwa [Submodule.Quotient.eq] at e
/-- The equivalence of the two definitions of `I / I ^ 2`, either as the quotient of `I` or the
ideal of `R / I ^ 2`. -/
noncomputable def cotangentEquivIdeal : I.Cotangent ≃ₗ[R] I.cotangentIdeal := by
  refine
  { LinearMap.codRestrict (I.cotangentIdeal.restrictScalars R) I.cotangentToQuotientSquare
      fun x => by { rw [← to_quotient_square_range]; exact LinearMap.mem_range_self _ _ },
    Equiv.ofBijective _ ⟨?_, ?_⟩ with }
  · rintro x y e
    replace e := congr_arg Subtype.val e
    obtain ⟨x, rfl⟩ := I.toCotangent_surjective x
    obtain ⟨y, rfl⟩ := I.toCotangent_surjective y
    rw [I.toCotangent_eq]
    dsimp only [toCotangent_to_quotient_square, Submodule.mkQ_apply] at e
    rwa [Submodule.Quotient.eq] at e
  · 

Proof state:
case refine_2
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
src✝ : Cotangent I →ₗ[R] ↥(Submodule.restrictScalars R (cotangentIdeal I)) :=
  LinearMap.codRestrict (Submodule.restrictScalars R (cotangentIdeal I)) (cotangentToQuotientSquare I)
    (_ : ∀ (x : Cotangent I), (cotangentToQuotientSquare I) x ∈ Submodule.restrictScalars R (cotangentIdeal I))
⊢ Function.Surjective fun c =>
    { val := (cotangentToQuotientSquare I) c,
      property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) }

Next tactic:
rintro ⟨_, x, hx, rfl⟩
/-- The equivalence of the two definitions of `I / I ^ 2`, either as the quotient of `I` or the
ideal of `R / I ^ 2`. -/
noncomputable def cotangentEquivIdeal : I.Cotangent ≃ₗ[R] I.cotangentIdeal := by
  refine
  { LinearMap.codRestrict (I.cotangentIdeal.restrictScalars R) I.cotangentToQuotientSquare
      fun x => by { rw [← to_quotient_square_range]; exact LinearMap.mem_range_self _ _ },
    Equiv.ofBijective _ ⟨?_, ?_⟩ with }
  · rintro x y e
    replace e := congr_arg Subtype.val e
    obtain ⟨x, rfl⟩ := I.toCotangent_surjective x
    obtain ⟨y, rfl⟩ := I.toCotangent_surjective y
    rw [I.toCotangent_eq]
    dsimp only [toCotangent_to_quotient_square, Submodule.mkQ_apply] at e
    rwa [Submodule.Quotient.eq] at e
  · rintro ⟨_, x, hx, rfl⟩
    

Proof state:
case refine_2.mk.intro.intro
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
src✝ : Cotangent I →ₗ[R] ↥(Submodule.restrictScalars R (cotangentIdeal I)) :=
  LinearMap.codRestrict (Submodule.restrictScalars R (cotangentIdeal I)) (cotangentToQuotientSquare I)
    (_ : ∀ (x : Cotangent I), (cotangentToQuotientSquare I) x ∈ Submodule.restrictScalars R (cotangentIdeal I))
x : R
hx : x ∈ ↑I
⊢ ∃ a,
    (fun c =>
          { val := (cotangentToQuotientSquare I) c,
            property := (_ : (cotangentToQuotientSquare I) c ∈ Submodule.restrictScalars R (cotangentIdeal I)) })
        a =
      { val := (RingHom.toSemilinearMap (Quotient.mk (I ^ 2))) x,
        property :=
          (_ :
            ∃ a ∈ ↑I,
              (RingHom.toSemilinearMap (Quotient.mk (I ^ 2))) a = (RingHom.toSemilinearMap (Quotient.mk (I ^ 2))) x) }

Next tactic:
exact ⟨I.toCotangent ⟨x, hx⟩, Subtype.ext rfl⟩
theorem cotangentEquivIdeal_symm_apply (x : R) (hx : x ∈ I) :
    I.cotangentEquivIdeal.symm ⟨(I ^ 2).mkQ x, Submodule.mem_map_of_mem hx⟩ =
      I.toCotangent ⟨x, hx⟩ := by
  

Proof state:
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
x : R
hx : x ∈ I
⊢ (LinearEquiv.symm (cotangentEquivIdeal I))
      { val := (Submodule.mkQ (I ^ 2)) x,
        property := (_ : (Submodule.mkQ (I ^ 2)) x ∈ Submodule.map (Submodule.mkQ (I ^ 2)) I) } =
    (toCotangent I) { val := x, property := hx }

Next tactic:
apply I.cotangentEquivIdeal.injective
theorem cotangentEquivIdeal_symm_apply (x : R) (hx : x ∈ I) :
    I.cotangentEquivIdeal.symm ⟨(I ^ 2).mkQ x, Submodule.mem_map_of_mem hx⟩ =
      I.toCotangent ⟨x, hx⟩ := by
  apply I.cotangentEquivIdeal.injective
  

Proof state:
case a
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
x : R
hx : x ∈ I
⊢ (cotangentEquivIdeal I)
      ((LinearEquiv.symm (cotangentEquivIdeal I))
        { val := (Submodule.mkQ (I ^ 2)) x,
          property := (_ : (Submodule.mkQ (I ^ 2)) x ∈ Submodule.map (Submodule.mkQ (I ^ 2)) I) }) =
    (cotangentEquivIdeal I) ((toCotangent I) { val := x, property := hx })

Next tactic:
rw [I.cotangentEquivIdeal.apply_symm_apply]
theorem cotangentEquivIdeal_symm_apply (x : R) (hx : x ∈ I) :
    I.cotangentEquivIdeal.symm ⟨(I ^ 2).mkQ x, Submodule.mem_map_of_mem hx⟩ =
      I.toCotangent ⟨x, hx⟩ := by
  apply I.cotangentEquivIdeal.injective
  rw [I.cotangentEquivIdeal.apply_symm_apply]
  

Proof state:
case a
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
x : R
hx : x ∈ I
⊢ { val := (Submodule.mkQ (I ^ 2)) x,
      property := (_ : (Submodule.mkQ (I ^ 2)) x ∈ Submodule.map (Submodule.mkQ (I ^ 2)) I) } =
    (cotangentEquivIdeal I) ((toCotangent I) { val := x, property := hx })

Next tactic:
ext
theorem cotangentEquivIdeal_symm_apply (x : R) (hx : x ∈ I) :
    I.cotangentEquivIdeal.symm ⟨(I ^ 2).mkQ x, Submodule.mem_map_of_mem hx⟩ =
      I.toCotangent ⟨x, hx⟩ := by
  apply I.cotangentEquivIdeal.injective
  rw [I.cotangentEquivIdeal.apply_symm_apply]
  ext
  

Proof state:
case a.a
R : Type u
S : Type v
S' : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S R
inst✝³ : CommSemiring S'
inst✝² : Algebra S' R
inst✝¹ : Algebra S S'
inst✝ : IsScalarTower S S' R
I : Ideal R
x : R
hx : x ∈ I
⊢ ↑{ val := (Submodule.mkQ (I ^ 2)) x,
        property := (_ : (Submodule.mkQ (I ^ 2)) x ∈ Submodule.map (Submodule.mkQ (I ^ 2)) I) } =
    ↑((cotangentEquivIdeal I) ((toCotangent I) { val := x, property := hx }))

Next tactic:
rfl
/-- The lift of `f : A →ₐ[R] B` to `A ⧸ J ^ 2 →ₐ[R] B` with `J` being the kernel of `f`. -/
def _root_.AlgHom.kerSquareLift (f : A →ₐ[R] B) : A ⧸ RingHom.ker f.toRingHom ^ 2 →ₐ[R] B := by
  

Proof state:
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
⊢ A ⧸ RingHom.ker ↑f ^ 2 →ₐ[R] B

Next tactic:
refine { Ideal.Quotient.lift (RingHom.ker f.toRingHom ^ 2) f.toRingHom ?_ with commutes' := ?_ }
/-- The lift of `f : A →ₐ[R] B` to `A ⧸ J ^ 2 →ₐ[R] B` with `J` being the kernel of `f`. -/
def _root_.AlgHom.kerSquareLift (f : A →ₐ[R] B) : A ⧸ RingHom.ker f.toRingHom ^ 2 →ₐ[R] B := by
  refine { Ideal.Quotient.lift (RingHom.ker f.toRingHom ^ 2) f.toRingHom ?_ with commutes' := ?_ }
  · 

Proof state:
case refine_1
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
⊢ ∀ a ∈ RingHom.ker ↑f ^ 2, ↑f a = 0

Next tactic:
intro a ha
/-- The lift of `f : A →ₐ[R] B` to `A ⧸ J ^ 2 →ₐ[R] B` with `J` being the kernel of `f`. -/
def _root_.AlgHom.kerSquareLift (f : A →ₐ[R] B) : A ⧸ RingHom.ker f.toRingHom ^ 2 →ₐ[R] B := by
  refine { Ideal.Quotient.lift (RingHom.ker f.toRingHom ^ 2) f.toRingHom ?_ with commutes' := ?_ }
  · intro a ha; 

Proof state:
case refine_1
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
a : A
ha : a ∈ RingHom.ker ↑f ^ 2
⊢ ↑f a = 0

Next tactic:
exact Ideal.pow_le_self two_ne_zero ha
/-- The lift of `f : A →ₐ[R] B` to `A ⧸ J ^ 2 →ₐ[R] B` with `J` being the kernel of `f`. -/
def _root_.AlgHom.kerSquareLift (f : A →ₐ[R] B) : A ⧸ RingHom.ker f.toRingHom ^ 2 →ₐ[R] B := by
  refine { Ideal.Quotient.lift (RingHom.ker f.toRingHom ^ 2) f.toRingHom ?_ with commutes' := ?_ }
  · intro a ha; exact Ideal.pow_le_self two_ne_zero ha
  · 

Proof state:
case refine_2
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
src✝ : A ⧸ RingHom.ker ↑f ^ 2 →+* B :=
  Quotient.lift (RingHom.ker ↑f ^ 2) ↑f (_ : ∀ a ∈ RingHom.ker ↑f ^ 2, a ∈ RingHom.ker ↑f)
⊢ ∀ (r : R),
    OneHom.toFun
        (↑↑{ toMonoidHom := ↑src✝, map_zero' := (_ : OneHom.toFun (↑↑src✝) 0 = 0),
              map_add' :=
                (_ :
                  ∀ (x y : A ⧸ RingHom.ker ↑f ^ 2),
                    OneHom.toFun (↑↑src✝) (x + y) = OneHom.toFun (↑↑src✝) x + OneHom.toFun (↑↑src✝) y) })
        ((algebraMap R (A ⧸ RingHom.ker ↑f ^ 2)) r) =
      (algebraMap R B) r

Next tactic:
intro r
/-- The lift of `f : A →ₐ[R] B` to `A ⧸ J ^ 2 →ₐ[R] B` with `J` being the kernel of `f`. -/
def _root_.AlgHom.kerSquareLift (f : A →ₐ[R] B) : A ⧸ RingHom.ker f.toRingHom ^ 2 →ₐ[R] B := by
  refine { Ideal.Quotient.lift (RingHom.ker f.toRingHom ^ 2) f.toRingHom ?_ with commutes' := ?_ }
  · intro a ha; exact Ideal.pow_le_self two_ne_zero ha
  · intro r
    

Proof state:
case refine_2
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
src✝ : A ⧸ RingHom.ker ↑f ^ 2 →+* B :=
  Quotient.lift (RingHom.ker ↑f ^ 2) ↑f (_ : ∀ a ∈ RingHom.ker ↑f ^ 2, a ∈ RingHom.ker ↑f)
r : R
⊢ OneHom.toFun
      (↑↑{ toMonoidHom := ↑src✝, map_zero' := (_ : OneHom.toFun (↑↑src✝) 0 = 0),
            map_add' :=
              (_ :
                ∀ (x y : A ⧸ RingHom.ker ↑f ^ 2),
                  OneHom.toFun (↑↑src✝) (x + y) = OneHom.toFun (↑↑src✝) x + OneHom.toFun (↑↑src✝) y) })
      ((algebraMap R (A ⧸ RingHom.ker ↑f ^ 2)) r) =
    (algebraMap R B) r

Next tactic:
rw [IsScalarTower.algebraMap_apply R A, RingHom.toFun_eq_coe, Ideal.Quotient.algebraMap_eq,
      Ideal.Quotient.lift_mk]
/-- The lift of `f : A →ₐ[R] B` to `A ⧸ J ^ 2 →ₐ[R] B` with `J` being the kernel of `f`. -/
def _root_.AlgHom.kerSquareLift (f : A →ₐ[R] B) : A ⧸ RingHom.ker f.toRingHom ^ 2 →ₐ[R] B := by
  refine { Ideal.Quotient.lift (RingHom.ker f.toRingHom ^ 2) f.toRingHom ?_ with commutes' := ?_ }
  · intro a ha; exact Ideal.pow_le_self two_ne_zero ha
  · intro r
    rw [IsScalarTower.algebraMap_apply R A, RingHom.toFun_eq_coe, Ideal.Quotient.algebraMap_eq,
      Ideal.Quotient.lift_mk]
    

Proof state:
case refine_2
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
src✝ : A ⧸ RingHom.ker ↑f ^ 2 →+* B :=
  Quotient.lift (RingHom.ker ↑f ^ 2) ↑f (_ : ∀ a ∈ RingHom.ker ↑f ^ 2, a ∈ RingHom.ker ↑f)
r : R
⊢ ↑f ((algebraMap R A) r) = (algebraMap R B) r

Next tactic:
exact f.map_algebraMap r
theorem _root_.AlgHom.ker_kerSquareLift (f : A →ₐ[R] B) :
    RingHom.ker f.kerSquareLift.toRingHom = f.toRingHom.ker.cotangentIdeal := by
  

Proof state:
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
⊢ RingHom.ker ↑(AlgHom.kerSquareLift f) = cotangentIdeal (RingHom.ker ↑f)

Next tactic:
apply le_antisymm
theorem _root_.AlgHom.ker_kerSquareLift (f : A →ₐ[R] B) :
    RingHom.ker f.kerSquareLift.toRingHom = f.toRingHom.ker.cotangentIdeal := by
  apply le_antisymm
  · 

Proof state:
case a
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
⊢ RingHom.ker ↑(AlgHom.kerSquareLift f) ≤ cotangentIdeal (RingHom.ker ↑f)

Next tactic:
intro x hx
theorem _root_.AlgHom.ker_kerSquareLift (f : A →ₐ[R] B) :
    RingHom.ker f.kerSquareLift.toRingHom = f.toRingHom.ker.cotangentIdeal := by
  apply le_antisymm
  · intro x hx; 

Proof state:
case a
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
x : A ⧸ RingHom.ker ↑f ^ 2
hx : x ∈ RingHom.ker ↑(AlgHom.kerSquareLift f)
⊢ x ∈ cotangentIdeal (RingHom.ker ↑f)

Next tactic:
obtain ⟨x, rfl⟩ := Ideal.Quotient.mk_surjective x
theorem _root_.AlgHom.ker_kerSquareLift (f : A →ₐ[R] B) :
    RingHom.ker f.kerSquareLift.toRingHom = f.toRingHom.ker.cotangentIdeal := by
  apply le_antisymm
  · intro x hx; obtain ⟨x, rfl⟩ := Ideal.Quotient.mk_surjective x; 

Proof state:
case a.intro
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
x : A
hx : (Quotient.mk (RingHom.ker ↑f ^ 2)) x ∈ RingHom.ker ↑(AlgHom.kerSquareLift f)
⊢ (Quotient.mk (RingHom.ker ↑f ^ 2)) x ∈ cotangentIdeal (RingHom.ker ↑f)

Next tactic:
exact ⟨x, hx, rfl⟩
theorem _root_.AlgHom.ker_kerSquareLift (f : A →ₐ[R] B) :
    RingHom.ker f.kerSquareLift.toRingHom = f.toRingHom.ker.cotangentIdeal := by
  apply le_antisymm
  · intro x hx; obtain ⟨x, rfl⟩ := Ideal.Quotient.mk_surjective x; exact ⟨x, hx, rfl⟩
  · 

Proof state:
case a
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
⊢ cotangentIdeal (RingHom.ker ↑f) ≤ RingHom.ker ↑(AlgHom.kerSquareLift f)

Next tactic:
rintro _ ⟨x, hx, rfl⟩
theorem _root_.AlgHom.ker_kerSquareLift (f : A →ₐ[R] B) :
    RingHom.ker f.kerSquareLift.toRingHom = f.toRingHom.ker.cotangentIdeal := by
  apply le_antisymm
  · intro x hx; obtain ⟨x, rfl⟩ := Ideal.Quotient.mk_surjective x; exact ⟨x, hx, rfl⟩
  · rintro _ ⟨x, hx, rfl⟩; 

Proof state:
case a.intro.intro
R : Type u
S : Type v
S' : Type w
inst✝¹⁰ : CommRing R
inst✝⁹ : CommSemiring S
inst✝⁸ : Algebra S R
inst✝⁷ : CommSemiring S'
inst✝⁶ : Algebra S' R
inst✝⁵ : Algebra S S'
inst✝⁴ : IsScalarTower S S' R
I : Ideal R
A : Type u_1
B : Type u_2
inst✝³ : CommRing A
inst✝² : CommRing B
inst✝¹ : Algebra R A
inst✝ : Algebra R B
f : A →ₐ[R] B
x : A
hx : x ∈ ↑(RingHom.ker ↑f)
⊢ (RingHom.toSemilinearMap (Quotient.mk (RingHom.ker ↑f ^ 2))) x ∈ RingHom.ker ↑(AlgHom.kerSquareLift f)

Next tactic:
exact hx