l3lab/ntp-mathlib huggingface dataset:
/-- Let `P` be a property on ideals. If `P` holds for square-zero ideals, and if
  `P I → P (J ⧸ I) → P J`, then `P` holds for all nilpotent ideals. -/
theorem Ideal.IsNilpotent.induction_on (hI : IsNilpotent I)
    {P : ∀ ⦃S : Type _⦄ [CommRing S], ∀ _I : Ideal S, Prop}
    (h₁ : ∀ ⦃S : Type _⦄ [CommRing S], ∀ I : Ideal S, I ^ 2 = ⊥ → P I)
    (h₂ : ∀ ⦃S : Type _⦄ [CommRing S], ∀ I J : Ideal S, I ≤ J → P I →
      P (J.map (Ideal.Quotient.mk I)) → P J) :
    P I := by
  obtain ⟨n, hI : I ^ n = ⊥⟩ := hI
  induction' n using Nat.strong_induction_on with n H generalizing S
  by_cases hI' : I = ⊥
  · subst hI'
    apply h₁
    rw [← Ideal.zero_eq_bot, zero_pow]
    exact zero_lt_two
  cases' n with n
  · rw [pow_zero, Ideal.one_eq_top] at hI
    haveI := subsingleton_of_bot_eq_top hI.symm
    exact (hI' (Subsingleton.elim _ _)).elim
  cases' n with n
  · rw [pow_one] at hI
    exact (hI' hI).elim
  apply h₂ (I ^ 2) _ (Ideal.pow_le_self two_ne_zero)
  · apply H n.succ _ (I ^ 2)
    · rw [← pow_mul, eq_bot_iff, ← hI, Nat.succ_eq_add_one, Nat.succ_eq_add_one]
      apply Ideal.pow_le_pow_right (by linarith)
    · exact n.succ.lt_succ_self
  · 

Proof state:
case neg.succ.succ.a
R : Type u_1
inst✝² : CommSemiring R
P : ⦃S : Type u_2⦄ → [inst : CommRing S] → Ideal S → Prop
h₁ : ∀ ⦃S : Type u_2⦄ [inst : CommRing S] (I : Ideal S), I ^ 2 = ⊥ → P I
h₂ : ∀ ⦃S : Type u_2⦄ [inst : CommRing S] (I J : Ideal S), I ≤ J → P I → P (map (Quotient.mk I) J) → P J
S : Type u_2
inst✝¹ : CommRing S
inst✝ : Algebra R S
I : Ideal S
hI' : ¬I = ⊥
n : ℕ
H :
  ∀ m < Nat.succ (Nat.succ n),
    ∀ {S : Type u_2} [inst : CommRing S] [inst_1 : Algebra R S] (I : Ideal S), I ^ m = ⊥ → P I
hI : I ^ Nat.succ (Nat.succ n) = ⊥
⊢ P (map (Quotient.mk (I ^ 2)) I)

Next tactic:
apply h₁
/-- Let `P` be a property on ideals. If `P` holds for square-zero ideals, and if
  `P I → P (J ⧸ I) → P J`, then `P` holds for all nilpotent ideals. -/
theorem Ideal.IsNilpotent.induction_on (hI : IsNilpotent I)
    {P : ∀ ⦃S : Type _⦄ [CommRing S], ∀ _I : Ideal S, Prop}
    (h₁ : ∀ ⦃S : Type _⦄ [CommRing S], ∀ I : Ideal S, I ^ 2 = ⊥ → P I)
    (h₂ : ∀ ⦃S : Type _⦄ [CommRing S], ∀ I J : Ideal S, I ≤ J → P I →
      P (J.map (Ideal.Quotient.mk I)) → P J) :
    P I := by
  obtain ⟨n, hI : I ^ n = ⊥⟩ := hI
  induction' n using Nat.strong_induction_on with n H generalizing S
  by_cases hI' : I = ⊥
  · subst hI'
    apply h₁
    rw [← Ideal.zero_eq_bot, zero_pow]
    exact zero_lt_two
  cases' n with n
  · rw [pow_zero, Ideal.one_eq_top] at hI
    haveI := subsingleton_of_bot_eq_top hI.symm
    exact (hI' (Subsingleton.elim _ _)).elim
  cases' n with n
  · rw [pow_one] at hI
    exact (hI' hI).elim
  apply h₂ (I ^ 2) _ (Ideal.pow_le_self two_ne_zero)
  · apply H n.succ _ (I ^ 2)
    · rw [← pow_mul, eq_bot_iff, ← hI, Nat.succ_eq_add_one, Nat.succ_eq_add_one]
      apply Ideal.pow_le_pow_right (by linarith)
    · exact n.succ.lt_succ_self
  · apply h₁
    

Proof state:
case neg.succ.succ.a.a
R : Type u_1
inst✝² : CommSemiring R
P : ⦃S : Type u_2⦄ → [inst : CommRing S] → Ideal S → Prop
h₁ : ∀ ⦃S : Type u_2⦄ [inst : CommRing S] (I : Ideal S), I ^ 2 = ⊥ → P I
h₂ : ∀ ⦃S : Type u_2⦄ [inst : CommRing S] (I J : Ideal S), I ≤ J → P I → P (map (Quotient.mk I) J) → P J
S : Type u_2
inst✝¹ : CommRing S
inst✝ : Algebra R S
I : Ideal S
hI' : ¬I = ⊥
n : ℕ
H :
  ∀ m < Nat.succ (Nat.succ n),
    ∀ {S : Type u_2} [inst : CommRing S] [inst_1 : Algebra R S] (I : Ideal S), I ^ m = ⊥ → P I
hI : I ^ Nat.succ (Nat.succ n) = ⊥
⊢ map (Quotient.mk (I ^ 2)) I ^ 2 = ⊥

Next tactic:
rw [← Ideal.map_pow, Ideal.map_quotient_self]
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  

Proof state:
R✝ : Type u_1
S : Type u_2
inst✝³ : CommSemiring R✝
inst✝² : CommRing S
inst✝¹ : Algebra R✝ S
I✝ : Ideal S
R : Type u_3
inst✝ : CommRing R
I : Ideal R
hI : IsNilpotent I
x : R
⊢ IsUnit ((Ideal.Quotient.mk I) x) ↔ IsUnit x

Next tactic:
refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  

Proof state:
R✝ : Type u_1
S : Type u_2
inst✝³ : CommSemiring R✝
inst✝² : CommRing S
inst✝¹ : Algebra R✝ S
I✝ : Ideal S
R : Type u_3
inst✝ : CommRing R
I : Ideal R
hI : IsNilpotent I
x : R
⊢ IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x

Next tactic:
revert x
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  

Proof state:
R✝ : Type u_1
S : Type u_2
inst✝³ : CommSemiring R✝
inst✝² : CommRing S
inst✝¹ : Algebra R✝ S
I✝ : Ideal S
R : Type u_3
inst✝ : CommRing R
I : Ideal R
hI : IsNilpotent I
⊢ ∀ {x : R}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x

Next tactic:
apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> 

Proof state:
case h₁
R✝ : Type u_1
S : Type u_2
inst✝³ : CommSemiring R✝
inst✝² : CommRing S
inst✝¹ : Algebra R✝ S
I✝ : Ideal S
R : Type u_3
inst✝ : CommRing R
I : Ideal R
hI : IsNilpotent I
⊢ ∀ ⦃S : Type u_3⦄ [inst : CommRing S] (I : Ideal S), I ^ 2 = ⊥ → ∀ {x : S}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x

Next tactic:
clear hI I
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> 

Proof state:
case h₂
R✝ : Type u_1
S : Type u_2
inst✝³ : CommSemiring R✝
inst✝² : CommRing S
inst✝¹ : Algebra R✝ S
I✝ : Ideal S
R : Type u_3
inst✝ : CommRing R
I : Ideal R
hI : IsNilpotent I
⊢ ∀ ⦃S : Type u_3⦄ [inst : CommRing S] (I J : Ideal S),
    I ≤ J →
      (∀ {x : S}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x) →
        (∀ {x : S ⧸ I}, IsUnit ((Ideal.Quotient.mk (Ideal.map (Ideal.Quotient.mk I) J)) x) → IsUnit x) →
          ∀ {x : S}, IsUnit ((Ideal.Quotient.mk J) x) → IsUnit x

Next tactic:
clear hI I
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  

Proof state:
case h₁
R✝ : Type u_1
S : Type u_2
inst✝³ : CommSemiring R✝
inst✝² : CommRing S
inst✝¹ : Algebra R✝ S
I : Ideal S
R : Type u_3
inst✝ : CommRing R
⊢ ∀ ⦃S : Type u_3⦄ [inst : CommRing S] (I : Ideal S), I ^ 2 = ⊥ → ∀ {x : S}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x
case h₂
R✝ : Type u_1
S : Type u_2
inst✝³ : CommSemiring R✝
inst✝² : CommRing S
inst✝¹ : Algebra R✝ S
I : Ideal S
R : Type u_3
inst✝ : CommRing R
⊢ ∀ ⦃S : Type u_3⦄ [inst : CommRing S] (I J : Ideal S),
    I ≤ J →
      (∀ {x : S}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x) →
        (∀ {x : S ⧸ I}, IsUnit ((Ideal.Quotient.mk (Ideal.map (Ideal.Quotient.mk I) J)) x) → IsUnit x) →
          ∀ {x : S}, IsUnit ((Ideal.Quotient.mk J) x) → IsUnit x

Next tactic:
swap
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · 

Proof state:
case h₂
R✝ : Type u_1
S : Type u_2
inst✝³ : CommSemiring R✝
inst✝² : CommRing S
inst✝¹ : Algebra R✝ S
I : Ideal S
R : Type u_3
inst✝ : CommRing R
⊢ ∀ ⦃S : Type u_3⦄ [inst : CommRing S] (I J : Ideal S),
    I ≤ J →
      (∀ {x : S}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x) →
        (∀ {x : S ⧸ I}, IsUnit ((Ideal.Quotient.mk (Ideal.map (Ideal.Quotient.mk I) J)) x) → IsUnit x) →
          ∀ {x : S}, IsUnit ((Ideal.Quotient.mk J) x) → IsUnit x

Next tactic:
introv e h₁ h₂ h₃
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    

Proof state:
case h₂
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I J : Ideal S
e : I ≤ J
h₁ : ∀ {x : S}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x
h₂ : ∀ {x : S ⧸ I}, IsUnit ((Ideal.Quotient.mk (Ideal.map (Ideal.Quotient.mk I) J)) x) → IsUnit x
x : S
h₃ : IsUnit ((Ideal.Quotient.mk J) x)
⊢ IsUnit x

Next tactic:
apply h₁
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    

Proof state:
case h₂.a
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I J : Ideal S
e : I ≤ J
h₁ : ∀ {x : S}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x
h₂ : ∀ {x : S ⧸ I}, IsUnit ((Ideal.Quotient.mk (Ideal.map (Ideal.Quotient.mk I) J)) x) → IsUnit x
x : S
h₃ : IsUnit ((Ideal.Quotient.mk J) x)
⊢ IsUnit ((Ideal.Quotient.mk I) x)

Next tactic:
apply h₂
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    

Proof state:
case h₂.a.a
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I J : Ideal S
e : I ≤ J
h₁ : ∀ {x : S}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x
h₂ : ∀ {x : S ⧸ I}, IsUnit ((Ideal.Quotient.mk (Ideal.map (Ideal.Quotient.mk I) J)) x) → IsUnit x
x : S
h₃ : IsUnit ((Ideal.Quotient.mk J) x)
⊢ IsUnit ((Ideal.Quotient.mk (Ideal.map (Ideal.Quotient.mk I) J)) ((Ideal.Quotient.mk I) x))

Next tactic:
exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · 

Proof state:
case h₁
R✝ : Type u_1
S : Type u_2
inst✝³ : CommSemiring R✝
inst✝² : CommRing S
inst✝¹ : Algebra R✝ S
I : Ideal S
R : Type u_3
inst✝ : CommRing R
⊢ ∀ ⦃S : Type u_3⦄ [inst : CommRing S] (I : Ideal S), I ^ 2 = ⊥ → ∀ {x : S}, IsUnit ((Ideal.Quotient.mk I) x) → IsUnit x

Next tactic:
introv e H
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    

Proof state:
case h₁
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
⊢ IsUnit x

Next tactic:
skip
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    skip
    

Proof state:
case h₁
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
⊢ IsUnit x

Next tactic:
obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (↑H.unit⁻¹ : S ⧸ I)
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    skip
    obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (↑H.unit⁻¹ : S ⧸ I)
    

Proof state:
case h₁.intro
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
y : S
hy : (Ideal.Quotient.mk I) y = ↑(IsUnit.unit H)⁻¹
⊢ IsUnit x

Next tactic:
have : Ideal.Quotient.mk I (x * y) = Ideal.Quotient.mk I 1 := by
      rw [map_one, _root_.map_mul, hy, IsUnit.mul_val_inv]
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    skip
    obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (↑H.unit⁻¹ : S ⧸ I)
    have : Ideal.Quotient.mk I (x * y) = Ideal.Quotient.mk I 1 := by
      

Proof state:
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
y : S
hy : (Ideal.Quotient.mk I) y = ↑(IsUnit.unit H)⁻¹
⊢ (Ideal.Quotient.mk I) (x * y) = (Ideal.Quotient.mk I) 1

Next tactic:
rw [map_one, _root_.map_mul, hy, IsUnit.mul_val_inv]
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    skip
    obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (↑H.unit⁻¹ : S ⧸ I)
    have : Ideal.Quotient.mk I (x * y) = Ideal.Quotient.mk I 1 := by
      rw [map_one, _root_.map_mul, hy, IsUnit.mul_val_inv]
    

Proof state:
case h₁.intro
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
y : S
hy : (Ideal.Quotient.mk I) y = ↑(IsUnit.unit H)⁻¹
this : (Ideal.Quotient.mk I) (x * y) = (Ideal.Quotient.mk I) 1
⊢ IsUnit x

Next tactic:
rw [Ideal.Quotient.eq] at this
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    skip
    obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (↑H.unit⁻¹ : S ⧸ I)
    have : Ideal.Quotient.mk I (x * y) = Ideal.Quotient.mk I 1 := by
      rw [map_one, _root_.map_mul, hy, IsUnit.mul_val_inv]
    rw [Ideal.Quotient.eq] at this
    

Proof state:
case h₁.intro
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
y : S
hy : (Ideal.Quotient.mk I) y = ↑(IsUnit.unit H)⁻¹
this : x * y - 1 ∈ I
⊢ IsUnit x

Next tactic:
have : (x * y - 1) ^ 2 = 0 := by
      rw [← Ideal.mem_bot, ← e]
      exact Ideal.pow_mem_pow this _
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    skip
    obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (↑H.unit⁻¹ : S ⧸ I)
    have : Ideal.Quotient.mk I (x * y) = Ideal.Quotient.mk I 1 := by
      rw [map_one, _root_.map_mul, hy, IsUnit.mul_val_inv]
    rw [Ideal.Quotient.eq] at this
    have : (x * y - 1) ^ 2 = 0 := by
      

Proof state:
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
y : S
hy : (Ideal.Quotient.mk I) y = ↑(IsUnit.unit H)⁻¹
this : x * y - 1 ∈ I
⊢ (x * y - 1) ^ 2 = 0

Next tactic:
rw [← Ideal.mem_bot, ← e]
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    skip
    obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (↑H.unit⁻¹ : S ⧸ I)
    have : Ideal.Quotient.mk I (x * y) = Ideal.Quotient.mk I 1 := by
      rw [map_one, _root_.map_mul, hy, IsUnit.mul_val_inv]
    rw [Ideal.Quotient.eq] at this
    have : (x * y - 1) ^ 2 = 0 := by
      rw [← Ideal.mem_bot, ← e]
      

Proof state:
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
y : S
hy : (Ideal.Quotient.mk I) y = ↑(IsUnit.unit H)⁻¹
this : x * y - 1 ∈ I
⊢ (x * y - 1) ^ 2 ∈ I ^ 2

Next tactic:
exact Ideal.pow_mem_pow this _
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    skip
    obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (↑H.unit⁻¹ : S ⧸ I)
    have : Ideal.Quotient.mk I (x * y) = Ideal.Quotient.mk I 1 := by
      rw [map_one, _root_.map_mul, hy, IsUnit.mul_val_inv]
    rw [Ideal.Quotient.eq] at this
    have : (x * y - 1) ^ 2 = 0 := by
      rw [← Ideal.mem_bot, ← e]
      exact Ideal.pow_mem_pow this _
    

Proof state:
case h₁.intro
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
y : S
hy : (Ideal.Quotient.mk I) y = ↑(IsUnit.unit H)⁻¹
this✝ : x * y - 1 ∈ I
this : (x * y - 1) ^ 2 = 0
⊢ IsUnit x

Next tactic:
have : x * (y * (2 - x * y)) = 1 := by
      rw [eq_comm, ← sub_eq_zero, ← this]
      ring
theorem IsNilpotent.isUnit_quotient_mk_iff {R : Type*} [CommRing R] {I : Ideal R}
    (hI : IsNilpotent I) {x : R} : IsUnit (Ideal.Quotient.mk I x) ↔ IsUnit x := by
  refine' ⟨_, fun h => h.map <| Ideal.Quotient.mk I⟩
  revert x
  apply Ideal.IsNilpotent.induction_on (R := R) (S := R) I hI <;> clear hI I
  swap
  · introv e h₁ h₂ h₃
    apply h₁
    apply h₂
    exact
      h₃.map
        ((DoubleQuot.quotQuotEquivQuotSup I J).trans
              (Ideal.quotEquivOfEq (sup_eq_right.mpr e))).symm.toRingHom
  · introv e H
    skip
    obtain ⟨y, hy⟩ := Ideal.Quotient.mk_surjective (↑H.unit⁻¹ : S ⧸ I)
    have : Ideal.Quotient.mk I (x * y) = Ideal.Quotient.mk I 1 := by
      rw [map_one, _root_.map_mul, hy, IsUnit.mul_val_inv]
    rw [Ideal.Quotient.eq] at this
    have : (x * y - 1) ^ 2 = 0 := by
      rw [← Ideal.mem_bot, ← e]
      exact Ideal.pow_mem_pow this _
    have : x * (y * (2 - x * y)) = 1 := by
      

Proof state:
R✝ : Type u_1
S✝ : Type u_2
inst✝⁴ : CommSemiring R✝
inst✝³ : CommRing S✝
inst✝² : Algebra R✝ S✝
I✝ : Ideal S✝
R : Type u_3
inst✝¹ : CommRing R
S : Type u_3
inst✝ : CommRing S
I : Ideal S
e : I ^ 2 = ⊥
x : S
H : IsUnit ((Ideal.Quotient.mk I) x)
y : S
hy : (Ideal.Quotient.mk I) y = ↑(IsUnit.unit H)⁻¹
this✝ : x * y - 1 ∈ I
this : (x * y - 1) ^ 2 = 0
⊢ x * (y * (2 - x * y)) = 1

Next tactic:
rw [eq_comm, ← sub_eq_zero, ← this]