l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem FormallySmooth.liftOfSurjective_apply [FormallySmooth R A] (f : A →ₐ[R] C) (g : B →ₐ[R] C)
    (hg : Function.Surjective g) (hg' : IsNilpotent <| RingHom.ker (g : B →+* C)) (x : A) :
    g (FormallySmooth.liftOfSurjective f g hg hg' x) = f x := by
  apply (Ideal.quotientKerAlgEquivOfSurjective hg).symm.injective
  change _ = ((Ideal.quotientKerAlgEquivOfSurjective hg).symm.toAlgHom.comp f) x
  -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
  erw [← FormallySmooth.mk_lift _ hg'
    ((Ideal.quotientKerAlgEquivOfSurjective hg).symm.toAlgHom.comp f)]
  apply (Ideal.quotientKerAlgEquivOfSurjective hg).injective
  

Proof state:
case a.a
R : Type u
inst✝⁷ : CommSemiring R
A : Type u
inst✝⁶ : Semiring A
inst✝⁵ : Algebra R A
B : Type u
inst✝⁴ : CommRing B
inst✝³ : Algebra R B
I : Ideal B
C : Type u
inst✝² : CommRing C
inst✝¹ : Algebra R C
inst✝ : FormallySmooth R A
f : A →ₐ[R] C
g : B →ₐ[R] C
hg : Function.Surjective ⇑g
hg' : IsNilpotent (RingHom.ker ↑g)
x : A
⊢ (Ideal.quotientKerAlgEquivOfSurjective hg)
      ((AlgEquiv.symm (Ideal.quotientKerAlgEquivOfSurjective hg)) (g ((liftOfSurjective f g hg hg') x))) =
    (Ideal.quotientKerAlgEquivOfSurjective hg)
      ((Ideal.Quotient.mk (RingHom.ker ↑g))
        ((lift (RingHom.ker ↑g) hg' (AlgHom.comp (↑(AlgEquiv.symm (Ideal.quotientKerAlgEquivOfSurjective hg))) f)) x))

Next tactic:
rw [AlgEquiv.apply_symm_apply, Ideal.quotientKerAlgEquivOfSurjective,
    Ideal.quotientKerAlgEquivOfRightInverse.apply]
@[simp]
theorem FormallySmooth.liftOfSurjective_apply [FormallySmooth R A] (f : A →ₐ[R] C) (g : B →ₐ[R] C)
    (hg : Function.Surjective g) (hg' : IsNilpotent <| RingHom.ker (g : B →+* C)) (x : A) :
    g (FormallySmooth.liftOfSurjective f g hg hg' x) = f x := by
  apply (Ideal.quotientKerAlgEquivOfSurjective hg).symm.injective
  change _ = ((Ideal.quotientKerAlgEquivOfSurjective hg).symm.toAlgHom.comp f) x
  -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
  erw [← FormallySmooth.mk_lift _ hg'
    ((Ideal.quotientKerAlgEquivOfSurjective hg).symm.toAlgHom.comp f)]
  apply (Ideal.quotientKerAlgEquivOfSurjective hg).injective
  rw [AlgEquiv.apply_symm_apply, Ideal.quotientKerAlgEquivOfSurjective,
    Ideal.quotientKerAlgEquivOfRightInverse.apply]
  

Proof state:
case a.a
R : Type u
inst✝⁷ : CommSemiring R
A : Type u
inst✝⁶ : Semiring A
inst✝⁵ : Algebra R A
B : Type u
inst✝⁴ : CommRing B
inst✝³ : Algebra R B
I : Ideal B
C : Type u
inst✝² : CommRing C
inst✝¹ : Algebra R C
inst✝ : FormallySmooth R A
f : A →ₐ[R] C
g : B →ₐ[R] C
hg : Function.Surjective ⇑g
hg' : IsNilpotent (RingHom.ker ↑g)
x : A
⊢ g ((liftOfSurjective f g hg hg') x) =
    (Ideal.kerLiftAlg g)
      ((Ideal.Quotient.mk (RingHom.ker ↑g))
        ((lift (RingHom.ker ↑g) hg'
            (AlgHom.comp
              (↑(AlgEquiv.symm
                  (Ideal.quotientKerAlgEquivOfRightInverse
                    (_ : Function.RightInverse (Classical.choose (_ : Function.HasRightInverse ⇑g)) ⇑g))))
              f))
          x))

Next tactic:
exact (Ideal.kerLiftAlg_mk _ _).symm
theorem FormallySmooth.of_equiv [FormallySmooth R A] (e : A ≃ₐ[R] B) : FormallySmooth R B := by
  

Proof state:
R : Type u
inst✝⁵ : CommSemiring R
A B : Type u
inst✝⁴ : Semiring A
inst✝³ : Algebra R A
inst✝² : Semiring B
inst✝¹ : Algebra R B
inst✝ : FormallySmooth R A
e : A ≃ₐ[R] B
⊢ FormallySmooth R B

Next tactic:
constructor
theorem FormallySmooth.of_equiv [FormallySmooth R A] (e : A ≃ₐ[R] B) : FormallySmooth R B := by
  constructor
  

Proof state:
case comp_surjective
R : Type u
inst✝⁵ : CommSemiring R
A B : Type u
inst✝⁴ : Semiring A
inst✝³ : Algebra R A
inst✝² : Semiring B
inst✝¹ : Algebra R B
inst✝ : FormallySmooth R A
e : A ≃ₐ[R] B
⊢ ∀ ⦃B_1 : Type u⦄ [inst : CommRing B_1] [inst_1 : Algebra R B_1] (I : Ideal B_1),
    I ^ 2 = ⊥ → Function.Surjective (AlgHom.comp (Ideal.Quotient.mkₐ R I))

Next tactic:
intro C _ _ I hI f
theorem FormallySmooth.of_equiv [FormallySmooth R A] (e : A ≃ₐ[R] B) : FormallySmooth R B := by
  constructor
  intro C _ _ I hI f
  

Proof state:
case comp_surjective
R : Type u
inst✝⁷ : CommSemiring R
A B : Type u
inst✝⁶ : Semiring A
inst✝⁵ : Algebra R A
inst✝⁴ : Semiring B
inst✝³ : Algebra R B
inst✝² : FormallySmooth R A
e : A ≃ₐ[R] B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f : B →ₐ[R] C ⧸ I
⊢ ∃ a, AlgHom.comp (Ideal.Quotient.mkₐ R I) a = f

Next tactic:
use (FormallySmooth.lift I ⟨2, hI⟩ (f.comp e : A →ₐ[R] C ⧸ I)).comp e.symm
theorem FormallySmooth.of_equiv [FormallySmooth R A] (e : A ≃ₐ[R] B) : FormallySmooth R B := by
  constructor
  intro C _ _ I hI f
  use (FormallySmooth.lift I ⟨2, hI⟩ (f.comp e : A →ₐ[R] C ⧸ I)).comp e.symm
  

Proof state:
case h
R : Type u
inst✝⁷ : CommSemiring R
A B : Type u
inst✝⁶ : Semiring A
inst✝⁵ : Algebra R A
inst✝⁴ : Semiring B
inst✝³ : Algebra R B
inst✝² : FormallySmooth R A
e : A ≃ₐ[R] B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f : B →ₐ[R] C ⧸ I
⊢ AlgHom.comp (Ideal.Quotient.mkₐ R I)
      (AlgHom.comp (lift I (_ : ∃ n, I ^ n = 0) (AlgHom.comp f ↑e)) ↑(AlgEquiv.symm e)) =
    f

Next tactic:
rw [← AlgHom.comp_assoc, FormallySmooth.comp_lift, AlgHom.comp_assoc, AlgEquiv.comp_symm,
    AlgHom.comp_id]
theorem FormallyUnramified.of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) :
    FormallyUnramified R B := by
  

Proof state:
R : Type u
inst✝⁵ : CommSemiring R
A B : Type u
inst✝⁴ : Semiring A
inst✝³ : Algebra R A
inst✝² : Semiring B
inst✝¹ : Algebra R B
inst✝ : FormallyUnramified R A
e : A ≃ₐ[R] B
⊢ FormallyUnramified R B

Next tactic:
constructor
theorem FormallyUnramified.of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) :
    FormallyUnramified R B := by
  constructor
  

Proof state:
case comp_injective
R : Type u
inst✝⁵ : CommSemiring R
A B : Type u
inst✝⁴ : Semiring A
inst✝³ : Algebra R A
inst✝² : Semiring B
inst✝¹ : Algebra R B
inst✝ : FormallyUnramified R A
e : A ≃ₐ[R] B
⊢ ∀ ⦃B_1 : Type u⦄ [inst : CommRing B_1] [inst_1 : Algebra R B_1] (I : Ideal B_1),
    I ^ 2 = ⊥ → Function.Injective (AlgHom.comp (Ideal.Quotient.mkₐ R I))

Next tactic:
intro C _ _ I hI f₁ f₂ e'
theorem FormallyUnramified.of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) :
    FormallyUnramified R B := by
  constructor
  intro C _ _ I hI f₁ f₂ e'
  

Proof state:
case comp_injective
R : Type u
inst✝⁷ : CommSemiring R
A B : Type u
inst✝⁶ : Semiring A
inst✝⁵ : Algebra R A
inst✝⁴ : Semiring B
inst✝³ : Algebra R B
inst✝² : FormallyUnramified R A
e : A ≃ₐ[R] B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f₁ f₂ : B →ₐ[R] C
e' : AlgHom.comp (Ideal.Quotient.mkₐ R I) f₁ = AlgHom.comp (Ideal.Quotient.mkₐ R I) f₂
⊢ f₁ = f₂

Next tactic:
rw [← f₁.comp_id, ← f₂.comp_id, ← e.comp_symm, ← AlgHom.comp_assoc, ← AlgHom.comp_assoc]
theorem FormallyUnramified.of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) :
    FormallyUnramified R B := by
  constructor
  intro C _ _ I hI f₁ f₂ e'
  rw [← f₁.comp_id, ← f₂.comp_id, ← e.comp_symm, ← AlgHom.comp_assoc, ← AlgHom.comp_assoc]
  

Proof state:
case comp_injective
R : Type u
inst✝⁷ : CommSemiring R
A B : Type u
inst✝⁶ : Semiring A
inst✝⁵ : Algebra R A
inst✝⁴ : Semiring B
inst✝³ : Algebra R B
inst✝² : FormallyUnramified R A
e : A ≃ₐ[R] B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f₁ f₂ : B →ₐ[R] C
e' : AlgHom.comp (Ideal.Quotient.mkₐ R I) f₁ = AlgHom.comp (Ideal.Quotient.mkₐ R I) f₂
⊢ AlgHom.comp (AlgHom.comp f₁ ↑e) ↑(AlgEquiv.symm e) = AlgHom.comp (AlgHom.comp f₂ ↑e) ↑(AlgEquiv.symm e)

Next tactic:
congr 1
theorem FormallyUnramified.of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) :
    FormallyUnramified R B := by
  constructor
  intro C _ _ I hI f₁ f₂ e'
  rw [← f₁.comp_id, ← f₂.comp_id, ← e.comp_symm, ← AlgHom.comp_assoc, ← AlgHom.comp_assoc]
  congr 1
  

Proof state:
case comp_injective.e_φ₁
R : Type u
inst✝⁷ : CommSemiring R
A B : Type u
inst✝⁶ : Semiring A
inst✝⁵ : Algebra R A
inst✝⁴ : Semiring B
inst✝³ : Algebra R B
inst✝² : FormallyUnramified R A
e : A ≃ₐ[R] B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f₁ f₂ : B →ₐ[R] C
e' : AlgHom.comp (Ideal.Quotient.mkₐ R I) f₁ = AlgHom.comp (Ideal.Quotient.mkₐ R I) f₂
⊢ AlgHom.comp f₁ ↑e = AlgHom.comp f₂ ↑e

Next tactic:
refine' FormallyUnramified.comp_injective I hI _
theorem FormallyUnramified.of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) :
    FormallyUnramified R B := by
  constructor
  intro C _ _ I hI f₁ f₂ e'
  rw [← f₁.comp_id, ← f₂.comp_id, ← e.comp_symm, ← AlgHom.comp_assoc, ← AlgHom.comp_assoc]
  congr 1
  refine' FormallyUnramified.comp_injective I hI _
  

Proof state:
case comp_injective.e_φ₁
R : Type u
inst✝⁷ : CommSemiring R
A B : Type u
inst✝⁶ : Semiring A
inst✝⁵ : Algebra R A
inst✝⁴ : Semiring B
inst✝³ : Algebra R B
inst✝² : FormallyUnramified R A
e : A ≃ₐ[R] B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f₁ f₂ : B →ₐ[R] C
e' : AlgHom.comp (Ideal.Quotient.mkₐ R I) f₁ = AlgHom.comp (Ideal.Quotient.mkₐ R I) f₂
⊢ AlgHom.comp (Ideal.Quotient.mkₐ R I) (AlgHom.comp f₁ ↑e) = AlgHom.comp (Ideal.Quotient.mkₐ R I) (AlgHom.comp f₂ ↑e)

Next tactic:
rw [← AlgHom.comp_assoc, e', AlgHom.comp_assoc]
instance FormallySmooth.mvPolynomial (σ : Type u) : FormallySmooth R (MvPolynomial σ R) := by
  

Proof state:
R : Type u
inst✝ : CommSemiring R
σ : Type u
⊢ FormallySmooth R (MvPolynomial σ R)

Next tactic:
constructor
instance FormallySmooth.mvPolynomial (σ : Type u) : FormallySmooth R (MvPolynomial σ R) := by
  constructor
  

Proof state:
case comp_surjective
R : Type u
inst✝ : CommSemiring R
σ : Type u
⊢ ∀ ⦃B : Type u⦄ [inst : CommRing B] [inst_1 : Algebra R B] (I : Ideal B),
    I ^ 2 = ⊥ → Function.Surjective (AlgHom.comp (Ideal.Quotient.mkₐ R I))

Next tactic:
intro C _ _ I _ f
instance FormallySmooth.mvPolynomial (σ : Type u) : FormallySmooth R (MvPolynomial σ R) := by
  constructor
  intro C _ _ I _ f
  

Proof state:
case comp_surjective
R : Type u
inst✝² : CommSemiring R
σ C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
x✝ : I ^ 2 = ⊥
f : MvPolynomial σ R →ₐ[R] C ⧸ I
⊢ ∃ a, AlgHom.comp (Ideal.Quotient.mkₐ R I) a = f

Next tactic:
have : ∀ s : σ, ∃ c : C, Ideal.Quotient.mk I c = f (MvPolynomial.X s) := fun s =>
    Ideal.Quotient.mk_surjective _
instance FormallySmooth.mvPolynomial (σ : Type u) : FormallySmooth R (MvPolynomial σ R) := by
  constructor
  intro C _ _ I _ f
  have : ∀ s : σ, ∃ c : C, Ideal.Quotient.mk I c = f (MvPolynomial.X s) := fun s =>
    Ideal.Quotient.mk_surjective _
  

Proof state:
case comp_surjective
R : Type u
inst✝² : CommSemiring R
σ C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
x✝ : I ^ 2 = ⊥
f : MvPolynomial σ R →ₐ[R] C ⧸ I
this : ∀ (s : σ), ∃ c, (Ideal.Quotient.mk I) c = f (MvPolynomial.X s)
⊢ ∃ a, AlgHom.comp (Ideal.Quotient.mkₐ R I) a = f

Next tactic:
choose g hg using this
instance FormallySmooth.mvPolynomial (σ : Type u) : FormallySmooth R (MvPolynomial σ R) := by
  constructor
  intro C _ _ I _ f
  have : ∀ s : σ, ∃ c : C, Ideal.Quotient.mk I c = f (MvPolynomial.X s) := fun s =>
    Ideal.Quotient.mk_surjective _
  choose g hg using this
  

Proof state:
case comp_surjective
R : Type u
inst✝² : CommSemiring R
σ C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
x✝ : I ^ 2 = ⊥
f : MvPolynomial σ R →ₐ[R] C ⧸ I
g : σ → C
hg : ∀ (s : σ), (Ideal.Quotient.mk I) (g s) = f (MvPolynomial.X s)
⊢ ∃ a, AlgHom.comp (Ideal.Quotient.mkₐ R I) a = f

Next tactic:
refine' ⟨MvPolynomial.aeval g, _⟩
instance FormallySmooth.mvPolynomial (σ : Type u) : FormallySmooth R (MvPolynomial σ R) := by
  constructor
  intro C _ _ I _ f
  have : ∀ s : σ, ∃ c : C, Ideal.Quotient.mk I c = f (MvPolynomial.X s) := fun s =>
    Ideal.Quotient.mk_surjective _
  choose g hg using this
  refine' ⟨MvPolynomial.aeval g, _⟩
  

Proof state:
case comp_surjective
R : Type u
inst✝² : CommSemiring R
σ C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
x✝ : I ^ 2 = ⊥
f : MvPolynomial σ R →ₐ[R] C ⧸ I
g : σ → C
hg : ∀ (s : σ), (Ideal.Quotient.mk I) (g s) = f (MvPolynomial.X s)
⊢ AlgHom.comp (Ideal.Quotient.mkₐ R I) (MvPolynomial.aeval g) = f

Next tactic:
ext s
instance FormallySmooth.mvPolynomial (σ : Type u) : FormallySmooth R (MvPolynomial σ R) := by
  constructor
  intro C _ _ I _ f
  have : ∀ s : σ, ∃ c : C, Ideal.Quotient.mk I c = f (MvPolynomial.X s) := fun s =>
    Ideal.Quotient.mk_surjective _
  choose g hg using this
  refine' ⟨MvPolynomial.aeval g, _⟩
  ext s
  

Proof state:
case comp_surjective.hf
R : Type u
inst✝² : CommSemiring R
σ C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
x✝ : I ^ 2 = ⊥
f : MvPolynomial σ R →ₐ[R] C ⧸ I
g : σ → C
hg : ∀ (s : σ), (Ideal.Quotient.mk I) (g s) = f (MvPolynomial.X s)
s : σ
⊢ (AlgHom.comp (Ideal.Quotient.mkₐ R I) (MvPolynomial.aeval g)) (MvPolynomial.X s) = f (MvPolynomial.X s)

Next tactic:
rw [← hg, AlgHom.comp_apply, MvPolynomial.aeval_X]
instance FormallySmooth.mvPolynomial (σ : Type u) : FormallySmooth R (MvPolynomial σ R) := by
  constructor
  intro C _ _ I _ f
  have : ∀ s : σ, ∃ c : C, Ideal.Quotient.mk I c = f (MvPolynomial.X s) := fun s =>
    Ideal.Quotient.mk_surjective _
  choose g hg using this
  refine' ⟨MvPolynomial.aeval g, _⟩
  ext s
  rw [← hg, AlgHom.comp_apply, MvPolynomial.aeval_X]
  

Proof state:
case comp_surjective.hf
R : Type u
inst✝² : CommSemiring R
σ C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
x✝ : I ^ 2 = ⊥
f : MvPolynomial σ R →ₐ[R] C ⧸ I
g : σ → C
hg : ∀ (s : σ), (Ideal.Quotient.mk I) (g s) = f (MvPolynomial.X s)
s : σ
⊢ (Ideal.Quotient.mkₐ R I) (g s) = (Ideal.Quotient.mk I) (g s)

Next tactic:
rfl
theorem FormallySmooth.comp [FormallySmooth R A] [FormallySmooth A B] : FormallySmooth R B := by
  

Proof state:
R : Type u
inst✝⁸ : CommSemiring R
A : Type u
inst✝⁷ : CommSemiring A
inst✝⁶ : Algebra R A
B : Type u
inst✝⁵ : Semiring B
inst✝⁴ : Algebra R B
inst✝³ : Algebra A B
inst✝² : IsScalarTower R A B
inst✝¹ : FormallySmooth R A
inst✝ : FormallySmooth A B
⊢ FormallySmooth R B

Next tactic:
constructor
theorem FormallySmooth.comp [FormallySmooth R A] [FormallySmooth A B] : FormallySmooth R B := by
  constructor
  

Proof state:
case comp_surjective
R : Type u
inst✝⁸ : CommSemiring R
A : Type u
inst✝⁷ : CommSemiring A
inst✝⁶ : Algebra R A
B : Type u
inst✝⁵ : Semiring B
inst✝⁴ : Algebra R B
inst✝³ : Algebra A B
inst✝² : IsScalarTower R A B
inst✝¹ : FormallySmooth R A
inst✝ : FormallySmooth A B
⊢ ∀ ⦃B_1 : Type u⦄ [inst : CommRing B_1] [inst_1 : Algebra R B_1] (I : Ideal B_1),
    I ^ 2 = ⊥ → Function.Surjective (AlgHom.comp (Ideal.Quotient.mkₐ R I))

Next tactic:
intro C _ _ I hI f
theorem FormallySmooth.comp [FormallySmooth R A] [FormallySmooth A B] : FormallySmooth R B := by
  constructor
  intro C _ _ I hI f
  

Proof state:
case comp_surjective
R : Type u
inst✝¹⁰ : CommSemiring R
A : Type u
inst✝⁹ : CommSemiring A
inst✝⁸ : Algebra R A
B : Type u
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R B
inst✝⁵ : Algebra A B
inst✝⁴ : IsScalarTower R A B
inst✝³ : FormallySmooth R A
inst✝² : FormallySmooth A B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f : B →ₐ[R] C ⧸ I
⊢ ∃ a, AlgHom.comp (Ideal.Quotient.mkₐ R I) a = f

Next tactic:
obtain ⟨f', e⟩ := FormallySmooth.comp_surjective I hI (f.comp (IsScalarTower.toAlgHom R A B))
theorem FormallySmooth.comp [FormallySmooth R A] [FormallySmooth A B] : FormallySmooth R B := by
  constructor
  intro C _ _ I hI f
  obtain ⟨f', e⟩ := FormallySmooth.comp_surjective I hI (f.comp (IsScalarTower.toAlgHom R A B))
  

Proof state:
case comp_surjective.intro
R : Type u
inst✝¹⁰ : CommSemiring R
A : Type u
inst✝⁹ : CommSemiring A
inst✝⁸ : Algebra R A
B : Type u
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R B
inst✝⁵ : Algebra A B
inst✝⁴ : IsScalarTower R A B
inst✝³ : FormallySmooth R A
inst✝² : FormallySmooth A B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f : B →ₐ[R] C ⧸ I
f' : A →ₐ[R] C
e : AlgHom.comp (Ideal.Quotient.mkₐ R I) f' = AlgHom.comp f (IsScalarTower.toAlgHom R A B)
⊢ ∃ a, AlgHom.comp (Ideal.Quotient.mkₐ R I) a = f

Next tactic:
letI := f'.toRingHom.toAlgebra
theorem FormallySmooth.comp [FormallySmooth R A] [FormallySmooth A B] : FormallySmooth R B := by
  constructor
  intro C _ _ I hI f
  obtain ⟨f', e⟩ := FormallySmooth.comp_surjective I hI (f.comp (IsScalarTower.toAlgHom R A B))
  letI := f'.toRingHom.toAlgebra
  

Proof state:
case comp_surjective.intro
R : Type u
inst✝¹⁰ : CommSemiring R
A : Type u
inst✝⁹ : CommSemiring A
inst✝⁸ : Algebra R A
B : Type u
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R B
inst✝⁵ : Algebra A B
inst✝⁴ : IsScalarTower R A B
inst✝³ : FormallySmooth R A
inst✝² : FormallySmooth A B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f : B →ₐ[R] C ⧸ I
f' : A →ₐ[R] C
e : AlgHom.comp (Ideal.Quotient.mkₐ R I) f' = AlgHom.comp f (IsScalarTower.toAlgHom R A B)
this : Algebra A C := RingHom.toAlgebra ↑f'
⊢ ∃ a, AlgHom.comp (Ideal.Quotient.mkₐ R I) a = f

Next tactic:
obtain ⟨f'', e'⟩ :=
    FormallySmooth.comp_surjective I hI { f.toRingHom with commutes' := AlgHom.congr_fun e.symm }
theorem FormallySmooth.comp [FormallySmooth R A] [FormallySmooth A B] : FormallySmooth R B := by
  constructor
  intro C _ _ I hI f
  obtain ⟨f', e⟩ := FormallySmooth.comp_surjective I hI (f.comp (IsScalarTower.toAlgHom R A B))
  letI := f'.toRingHom.toAlgebra
  obtain ⟨f'', e'⟩ :=
    FormallySmooth.comp_surjective I hI { f.toRingHom with commutes' := AlgHom.congr_fun e.symm }
  

Proof state:
case comp_surjective.intro.intro
R : Type u
inst✝¹⁰ : CommSemiring R
A : Type u
inst✝⁹ : CommSemiring A
inst✝⁸ : Algebra R A
B : Type u
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R B
inst✝⁵ : Algebra A B
inst✝⁴ : IsScalarTower R A B
inst✝³ : FormallySmooth R A
inst✝² : FormallySmooth A B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f : B →ₐ[R] C ⧸ I
f' : A →ₐ[R] C
e : AlgHom.comp (Ideal.Quotient.mkₐ R I) f' = AlgHom.comp f (IsScalarTower.toAlgHom R A B)
this : Algebra A C := RingHom.toAlgebra ↑f'
f'' : B →ₐ[A] C
e' :
  AlgHom.comp (Ideal.Quotient.mkₐ A I) f'' =
    let src := ↑f;
    {
      toRingHom :=
        { toMonoidHom := ↑src, map_zero' := (_ : OneHom.toFun (↑↑src) 0 = 0),
          map_add' :=
            (_ : ∀ (x y : B), OneHom.toFun (↑↑src) (x + y) = OneHom.toFun (↑↑src) x + OneHom.toFun (↑↑src) y) },
      commutes' :=
        (_ :
          ∀ (x : A), (AlgHom.comp f (IsScalarTower.toAlgHom R A B)) x = (AlgHom.comp (Ideal.Quotient.mkₐ R I) f') x) }
⊢ ∃ a, AlgHom.comp (Ideal.Quotient.mkₐ R I) a = f

Next tactic:
apply_fun AlgHom.restrictScalars R at e'
theorem FormallySmooth.comp [FormallySmooth R A] [FormallySmooth A B] : FormallySmooth R B := by
  constructor
  intro C _ _ I hI f
  obtain ⟨f', e⟩ := FormallySmooth.comp_surjective I hI (f.comp (IsScalarTower.toAlgHom R A B))
  letI := f'.toRingHom.toAlgebra
  obtain ⟨f'', e'⟩ :=
    FormallySmooth.comp_surjective I hI { f.toRingHom with commutes' := AlgHom.congr_fun e.symm }
  apply_fun AlgHom.restrictScalars R at e'
  

Proof state:
case comp_surjective.intro.intro
R : Type u
inst✝¹⁰ : CommSemiring R
A : Type u
inst✝⁹ : CommSemiring A
inst✝⁸ : Algebra R A
B : Type u
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R B
inst✝⁵ : Algebra A B
inst✝⁴ : IsScalarTower R A B
inst✝³ : FormallySmooth R A
inst✝² : FormallySmooth A B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f : B →ₐ[R] C ⧸ I
f' : A →ₐ[R] C
e : AlgHom.comp (Ideal.Quotient.mkₐ R I) f' = AlgHom.comp f (IsScalarTower.toAlgHom R A B)
this : Algebra A C := RingHom.toAlgebra ↑f'
f'' : B →ₐ[A] C
e' :
  AlgHom.restrictScalars R (AlgHom.comp (Ideal.Quotient.mkₐ A I) f'') =
    AlgHom.restrictScalars R
      (let src := ↑f;
      {
        toRingHom :=
          { toMonoidHom := ↑src, map_zero' := (_ : OneHom.toFun (↑↑src) 0 = 0),
            map_add' :=
              (_ : ∀ (x y : B), OneHom.toFun (↑↑src) (x + y) = OneHom.toFun (↑↑src) x + OneHom.toFun (↑↑src) y) },
        commutes' :=
          (_ :
            ∀ (x : A),
              (AlgHom.comp f (IsScalarTower.toAlgHom R A B)) x = (AlgHom.comp (Ideal.Quotient.mkₐ R I) f') x) })
⊢ ∃ a, AlgHom.comp (Ideal.Quotient.mkₐ R I) a = f

Next tactic:
exact ⟨f''.restrictScalars _, e'.trans (AlgHom.ext fun _ => rfl)⟩
theorem FormallyUnramified.comp [FormallyUnramified R A] [FormallyUnramified A B] :
    FormallyUnramified R B := by
  

Proof state:
R : Type u
inst✝⁸ : CommSemiring R
A : Type u
inst✝⁷ : CommSemiring A
inst✝⁶ : Algebra R A
B : Type u
inst✝⁵ : Semiring B
inst✝⁴ : Algebra R B
inst✝³ : Algebra A B
inst✝² : IsScalarTower R A B
inst✝¹ : FormallyUnramified R A
inst✝ : FormallyUnramified A B
⊢ FormallyUnramified R B

Next tactic:
constructor
theorem FormallyUnramified.comp [FormallyUnramified R A] [FormallyUnramified A B] :
    FormallyUnramified R B := by
  constructor
  

Proof state:
case comp_injective
R : Type u
inst✝⁸ : CommSemiring R
A : Type u
inst✝⁷ : CommSemiring A
inst✝⁶ : Algebra R A
B : Type u
inst✝⁵ : Semiring B
inst✝⁴ : Algebra R B
inst✝³ : Algebra A B
inst✝² : IsScalarTower R A B
inst✝¹ : FormallyUnramified R A
inst✝ : FormallyUnramified A B
⊢ ∀ ⦃B_1 : Type u⦄ [inst : CommRing B_1] [inst_1 : Algebra R B_1] (I : Ideal B_1),
    I ^ 2 = ⊥ → Function.Injective (AlgHom.comp (Ideal.Quotient.mkₐ R I))

Next tactic:
intro C _ _ I hI f₁ f₂ e
theorem FormallyUnramified.comp [FormallyUnramified R A] [FormallyUnramified A B] :
    FormallyUnramified R B := by
  constructor
  intro C _ _ I hI f₁ f₂ e
  

Proof state:
case comp_injective
R : Type u
inst✝¹⁰ : CommSemiring R
A : Type u
inst✝⁹ : CommSemiring A
inst✝⁸ : Algebra R A
B : Type u
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R B
inst✝⁵ : Algebra A B
inst✝⁴ : IsScalarTower R A B
inst✝³ : FormallyUnramified R A
inst✝² : FormallyUnramified A B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f₁ f₂ : B →ₐ[R] C
e : AlgHom.comp (Ideal.Quotient.mkₐ R I) f₁ = AlgHom.comp (Ideal.Quotient.mkₐ R I) f₂
⊢ f₁ = f₂

Next tactic:
have e' :=
    FormallyUnramified.lift_unique I ⟨2, hI⟩ (f₁.comp <| IsScalarTower.toAlgHom R A B)
      (f₂.comp <| IsScalarTower.toAlgHom R A B) (by rw [← AlgHom.comp_assoc, e, AlgHom.comp_assoc])
theorem FormallyUnramified.comp [FormallyUnramified R A] [FormallyUnramified A B] :
    FormallyUnramified R B := by
  constructor
  intro C _ _ I hI f₁ f₂ e
  have e' :=
    FormallyUnramified.lift_unique I ⟨2, hI⟩ (f₁.comp <| IsScalarTower.toAlgHom R A B)
      (f₂.comp <| IsScalarTower.toAlgHom R A B) (by 

Proof state:
R : Type u
inst✝¹⁰ : CommSemiring R
A : Type u
inst✝⁹ : CommSemiring A
inst✝⁸ : Algebra R A
B : Type u
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R B
inst✝⁵ : Algebra A B
inst✝⁴ : IsScalarTower R A B
inst✝³ : FormallyUnramified R A
inst✝² : FormallyUnramified A B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f₁ f₂ : B →ₐ[R] C
e : AlgHom.comp (Ideal.Quotient.mkₐ R I) f₁ = AlgHom.comp (Ideal.Quotient.mkₐ R I) f₂
⊢ AlgHom.comp (Ideal.Quotient.mkₐ R I) (AlgHom.comp f₁ (IsScalarTower.toAlgHom R A B)) =
    AlgHom.comp (Ideal.Quotient.mkₐ R I) (AlgHom.comp f₂ (IsScalarTower.toAlgHom R A B))

Next tactic:
rw [← AlgHom.comp_assoc, e, AlgHom.comp_assoc]
theorem FormallyUnramified.comp [FormallyUnramified R A] [FormallyUnramified A B] :
    FormallyUnramified R B := by
  constructor
  intro C _ _ I hI f₁ f₂ e
  have e' :=
    FormallyUnramified.lift_unique I ⟨2, hI⟩ (f₁.comp <| IsScalarTower.toAlgHom R A B)
      (f₂.comp <| IsScalarTower.toAlgHom R A B) (by rw [← AlgHom.comp_assoc, e, AlgHom.comp_assoc])
  

Proof state:
case comp_injective
R : Type u
inst✝¹⁰ : CommSemiring R
A : Type u
inst✝⁹ : CommSemiring A
inst✝⁸ : Algebra R A
B : Type u
inst✝⁷ : Semiring B
inst✝⁶ : Algebra R B
inst✝⁵ : Algebra A B
inst✝⁴ : IsScalarTower R A B
inst✝³ : FormallyUnramified R A
inst✝² : FormallyUnramified A B
C : Type u
inst✝¹ : CommRing C
inst✝ : Algebra R C
I : Ideal C
hI : I ^ 2 = ⊥
f₁ f₂ : B →ₐ[R] C
e : AlgHom.comp (Ideal.Quotient.mkₐ R I) f₁ = AlgHom.comp (Ideal.Quotient.mkₐ R I) f₂
e' : AlgHom.comp f₁ (IsScalarTower.toAlgHom R A B) = AlgHom.comp f₂ (IsScalarTower.toAlgHom R A B)
⊢ f₁ = f₂

Next tactic:
letI := (f₁.comp (IsScalarTower.toAlgHom R A B)).toRingHom.toAlgebra