l3lab/ntp-mathlib huggingface dataset:
/-- An auxiliary induction lemma, which is generalized by `solvableByRad.isSolvable`. -/
theorem induction2 {α β γ : solvableByRad F E} (hγ : γ ∈ F⟮α, β⟯) (hα : P α) (hβ : P β) : P γ := by
  let p := minpoly F α
  let q := minpoly F β
  have hpq := Polynomial.splits_of_splits_mul _
    (mul_ne_zero (minpoly.ne_zero (isIntegral α)) (minpoly.ne_zero (isIntegral β)))
    (SplittingField.splits (p * q))
  let f : ↥F⟮α, β⟯ →ₐ[F] (p * q).SplittingField :=
    Classical.choice <| nonempty_algHom_adjoin_of_splits <| by
      intro x hx
      cases' hx with hx hx
      rw [hx]
      exact ⟨isIntegral α, hpq.1⟩
      cases hx
      exact ⟨isIntegral β, hpq.2⟩
  have key : minpoly F γ = minpoly F (f ⟨γ, hγ⟩) := by
    refine' minpoly.eq_of_irreducible_of_monic
      (minpoly.irreducible (isIntegral γ)) _ (minpoly.monic (isIntegral γ))
    suffices aeval (⟨γ, hγ⟩ : F⟮α, β⟯) (minpoly F γ) = 0 by
      rw [aeval_algHom_apply, this, AlgHom.map_zero]
    -- Porting note: this instance is needed for the following `apply`
    haveI := @IntermediateField.toAlgebra F (solvableByRad F E) _ _ _ F⟮α, β⟯
      (solvableByRad F E) _ (Algebra.id (solvableByRad F E))
    apply (algebraMap (↥F⟮α, β⟯) (solvableByRad F E)).injective
    simp only [map_zero, _root_.map_eq_zero]
    -- Porting note: end of the proof was `exact minpoly.aeval F γ`.
    apply Subtype.val_injective
    -- This used to be `simp`, but we need `erw` and `simp` after leanprover/lean4#2644
    erw [Polynomial.aeval_subalgebra_coe (minpoly F γ)]
    simp
  rw [P, key]
  refine' gal_isSolvable_of_splits ⟨Normal.splits _ (f ⟨γ, hγ⟩)⟩ (gal_mul_isSolvable hα hβ)
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ : E
α β γ : ↥(solvableByRad F E)
hγ : γ ∈ F⟮α, β⟯
hα : P α
hβ : P β
p : F[X] := minpoly F α
q : F[X] := minpoly F β
hpq :
  Splits (algebraMap F (SplittingField (p * q))) (minpoly F α) ∧
    Splits (algebraMap F (SplittingField (p * q))) (minpoly F β)
f : ↥F⟮α, β⟯ →ₐ[F] SplittingField (p * q) := Classical.choice (_ : Nonempty (↥F⟮α, β⟯ →ₐ[F] SplittingField (p * q)))
key : minpoly F γ = minpoly F (f { val := γ, property := hγ })
⊢ Normal F (SplittingField (p * q))

Next tactic:
apply SplittingField.instNormal
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ : E
α : ↥(solvableByRad F E)
⊢ IsSolvable (Gal (minpoly F α))

Next tactic:
revert α
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  revert α
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α : E
⊢ ∀ (α : ↥(solvableByRad F E)), IsSolvable (Gal (minpoly F α))

Next tactic:
apply solvableByRad.induction
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  revert α
  apply solvableByRad.induction
  · 

Proof state:
case base
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α : E
⊢ ∀ (α : F), IsSolvable (Gal (minpoly F ((algebraMap F ↥(solvableByRad F E)) α)))

Next tactic:
exact fun α => by rw [minpoly.eq_X_sub_C (solvableByRad F E)]; exact gal_X_sub_C_isSolvable α
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  revert α
  apply solvableByRad.induction
  · exact fun α => by 

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ : E
α : F
⊢ IsSolvable (Gal (minpoly F ((algebraMap F ↥(solvableByRad F E)) α)))

Next tactic:
rw [minpoly.eq_X_sub_C (solvableByRad F E)]
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  revert α
  apply solvableByRad.induction
  · exact fun α => by rw [minpoly.eq_X_sub_C (solvableByRad F E)]; 

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ : E
α : F
⊢ IsSolvable (Gal (X - C α))

Next tactic:
exact gal_X_sub_C_isSolvable α
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  revert α
  apply solvableByRad.induction
  · exact fun α => by rw [minpoly.eq_X_sub_C (solvableByRad F E)]; exact gal_X_sub_C_isSolvable α
  · 

Proof state:
case add
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α : E
⊢ ∀ (α β : ↥(solvableByRad F E)),
    IsSolvable (Gal (minpoly F α)) → IsSolvable (Gal (minpoly F β)) → IsSolvable (Gal (minpoly F (α + β)))

Next tactic:
exact fun α β => induction2 (add_mem (subset_adjoin F _ (Set.mem_insert α _))
      (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β))))
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  revert α
  apply solvableByRad.induction
  · exact fun α => by rw [minpoly.eq_X_sub_C (solvableByRad F E)]; exact gal_X_sub_C_isSolvable α
  · exact fun α β => induction2 (add_mem (subset_adjoin F _ (Set.mem_insert α _))
      (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β))))
  · 

Proof state:
case neg
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α : E
⊢ ∀ (α : ↥(solvableByRad F E)), IsSolvable (Gal (minpoly F α)) → IsSolvable (Gal (minpoly F (-α)))

Next tactic:
exact fun α => induction1 (neg_mem (mem_adjoin_simple_self F α))
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  revert α
  apply solvableByRad.induction
  · exact fun α => by rw [minpoly.eq_X_sub_C (solvableByRad F E)]; exact gal_X_sub_C_isSolvable α
  · exact fun α β => induction2 (add_mem (subset_adjoin F _ (Set.mem_insert α _))
      (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β))))
  · exact fun α => induction1 (neg_mem (mem_adjoin_simple_self F α))
  · 

Proof state:
case mul
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α : E
⊢ ∀ (α β : ↥(solvableByRad F E)),
    IsSolvable (Gal (minpoly F α)) → IsSolvable (Gal (minpoly F β)) → IsSolvable (Gal (minpoly F (α * β)))

Next tactic:
exact fun α β => induction2 (mul_mem (subset_adjoin F _ (Set.mem_insert α _))
      (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β))))
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  revert α
  apply solvableByRad.induction
  · exact fun α => by rw [minpoly.eq_X_sub_C (solvableByRad F E)]; exact gal_X_sub_C_isSolvable α
  · exact fun α β => induction2 (add_mem (subset_adjoin F _ (Set.mem_insert α _))
      (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β))))
  · exact fun α => induction1 (neg_mem (mem_adjoin_simple_self F α))
  · exact fun α β => induction2 (mul_mem (subset_adjoin F _ (Set.mem_insert α _))
      (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β))))
  · 

Proof state:
case inv
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α : E
⊢ ∀ (α : ↥(solvableByRad F E)), IsSolvable (Gal (minpoly F α)) → IsSolvable (Gal (minpoly F α⁻¹))

Next tactic:
exact fun α => induction1 (inv_mem (mem_adjoin_simple_self F α))
theorem isSolvable (α : solvableByRad F E) : IsSolvable (minpoly F α).Gal := by
  revert α
  apply solvableByRad.induction
  · exact fun α => by rw [minpoly.eq_X_sub_C (solvableByRad F E)]; exact gal_X_sub_C_isSolvable α
  · exact fun α β => induction2 (add_mem (subset_adjoin F _ (Set.mem_insert α _))
      (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β))))
  · exact fun α => induction1 (neg_mem (mem_adjoin_simple_self F α))
  · exact fun α β => induction2 (mul_mem (subset_adjoin F _ (Set.mem_insert α _))
      (subset_adjoin F _ (Set.mem_insert_of_mem α (Set.mem_singleton β))))
  · exact fun α => induction1 (inv_mem (mem_adjoin_simple_self F α))
  · 

Proof state:
case rad
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α : E
⊢ ∀ (α : ↥(solvableByRad F E)) (n : ℕ), n ≠ 0 → IsSolvable (Gal (minpoly F (α ^ n))) → IsSolvable (Gal (minpoly F α))

Next tactic:
exact fun α n => induction3
/-- **Abel-Ruffini Theorem** (one direction): An irreducible polynomial with an
`IsSolvableByRad` root has solvable Galois group -/
theorem isSolvable' {α : E} {q : F[X]} (q_irred : Irreducible q) (q_aeval : aeval α q = 0)
    (hα : IsSolvableByRad F α) : IsSolvable q.Gal := by
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ α : E
q : F[X]
q_irred : Irreducible q
q_aeval : (aeval α) q = 0
hα : IsSolvableByRad F α
⊢ IsSolvable (Gal q)

Next tactic:
have : _root_.IsSolvable (q * C q.leadingCoeff⁻¹).Gal := by
    rw [minpoly.eq_of_irreducible q_irred q_aeval, ←
      show minpoly F (⟨α, hα⟩ : solvableByRad F E) = minpoly F α from
        (minpoly.algebraMap_eq (RingHom.injective _) _).symm]
    exact isSolvable ⟨α, hα⟩
/-- **Abel-Ruffini Theorem** (one direction): An irreducible polynomial with an
`IsSolvableByRad` root has solvable Galois group -/
theorem isSolvable' {α : E} {q : F[X]} (q_irred : Irreducible q) (q_aeval : aeval α q = 0)
    (hα : IsSolvableByRad F α) : IsSolvable q.Gal := by
  have : _root_.IsSolvable (q * C q.leadingCoeff⁻¹).Gal := by
    

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ α : E
q : F[X]
q_irred : Irreducible q
q_aeval : (aeval α) q = 0
hα : IsSolvableByRad F α
⊢ IsSolvable (Gal (q * C (leadingCoeff q)⁻¹))

Next tactic:
rw [minpoly.eq_of_irreducible q_irred q_aeval, ←
      show minpoly F (⟨α, hα⟩ : solvableByRad F E) = minpoly F α from
        (minpoly.algebraMap_eq (RingHom.injective _) _).symm]
/-- **Abel-Ruffini Theorem** (one direction): An irreducible polynomial with an
`IsSolvableByRad` root has solvable Galois group -/
theorem isSolvable' {α : E} {q : F[X]} (q_irred : Irreducible q) (q_aeval : aeval α q = 0)
    (hα : IsSolvableByRad F α) : IsSolvable q.Gal := by
  have : _root_.IsSolvable (q * C q.leadingCoeff⁻¹).Gal := by
    rw [minpoly.eq_of_irreducible q_irred q_aeval, ←
      show minpoly F (⟨α, hα⟩ : solvableByRad F E) = minpoly F α from
        (minpoly.algebraMap_eq (RingHom.injective _) _).symm]
    

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ α : E
q : F[X]
q_irred : Irreducible q
q_aeval : (aeval α) q = 0
hα : IsSolvableByRad F α
⊢ IsSolvable (Gal (minpoly F { val := α, property := hα }))

Next tactic:
exact isSolvable ⟨α, hα⟩
/-- **Abel-Ruffini Theorem** (one direction): An irreducible polynomial with an
`IsSolvableByRad` root has solvable Galois group -/
theorem isSolvable' {α : E} {q : F[X]} (q_irred : Irreducible q) (q_aeval : aeval α q = 0)
    (hα : IsSolvableByRad F α) : IsSolvable q.Gal := by
  have : _root_.IsSolvable (q * C q.leadingCoeff⁻¹).Gal := by
    rw [minpoly.eq_of_irreducible q_irred q_aeval, ←
      show minpoly F (⟨α, hα⟩ : solvableByRad F E) = minpoly F α from
        (minpoly.algebraMap_eq (RingHom.injective _) _).symm]
    exact isSolvable ⟨α, hα⟩
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ α : E
q : F[X]
q_irred : Irreducible q
q_aeval : (aeval α) q = 0
hα : IsSolvableByRad F α
this : IsSolvable (Gal (q * C (leadingCoeff q)⁻¹))
⊢ IsSolvable (Gal q)

Next tactic:
refine' solvable_of_surjective (Gal.restrictDvd_surjective ⟨C q.leadingCoeff⁻¹, rfl⟩ _)
/-- **Abel-Ruffini Theorem** (one direction): An irreducible polynomial with an
`IsSolvableByRad` root has solvable Galois group -/
theorem isSolvable' {α : E} {q : F[X]} (q_irred : Irreducible q) (q_aeval : aeval α q = 0)
    (hα : IsSolvableByRad F α) : IsSolvable q.Gal := by
  have : _root_.IsSolvable (q * C q.leadingCoeff⁻¹).Gal := by
    rw [minpoly.eq_of_irreducible q_irred q_aeval, ←
      show minpoly F (⟨α, hα⟩ : solvableByRad F E) = minpoly F α from
        (minpoly.algebraMap_eq (RingHom.injective _) _).symm]
    exact isSolvable ⟨α, hα⟩
  refine' solvable_of_surjective (Gal.restrictDvd_surjective ⟨C q.leadingCoeff⁻¹, rfl⟩ _)
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ α : E
q : F[X]
q_irred : Irreducible q
q_aeval : (aeval α) q = 0
hα : IsSolvableByRad F α
this : IsSolvable (Gal (q * C (leadingCoeff q)⁻¹))
⊢ q * C (leadingCoeff q)⁻¹ ≠ 0

Next tactic:
rw [mul_ne_zero_iff, Ne, Ne, C_eq_zero, inv_eq_zero]
/-- **Abel-Ruffini Theorem** (one direction): An irreducible polynomial with an
`IsSolvableByRad` root has solvable Galois group -/
theorem isSolvable' {α : E} {q : F[X]} (q_irred : Irreducible q) (q_aeval : aeval α q = 0)
    (hα : IsSolvableByRad F α) : IsSolvable q.Gal := by
  have : _root_.IsSolvable (q * C q.leadingCoeff⁻¹).Gal := by
    rw [minpoly.eq_of_irreducible q_irred q_aeval, ←
      show minpoly F (⟨α, hα⟩ : solvableByRad F E) = minpoly F α from
        (minpoly.algebraMap_eq (RingHom.injective _) _).symm]
    exact isSolvable ⟨α, hα⟩
  refine' solvable_of_surjective (Gal.restrictDvd_surjective ⟨C q.leadingCoeff⁻¹, rfl⟩ _)
  rw [mul_ne_zero_iff, Ne, Ne, C_eq_zero, inv_eq_zero]
  

Proof state:
F : Type u_1
inst✝² : Field F
E : Type u_2
inst✝¹ : Field E
inst✝ : Algebra F E
α✝ α : E
q : F[X]
q_irred : Irreducible q
q_aeval : (aeval α) q = 0
hα : IsSolvableByRad F α
this : IsSolvable (Gal (q * C (leadingCoeff q)⁻¹))
⊢ ¬q = 0 ∧ ¬leadingCoeff q = 0

Next tactic:
exact ⟨q_irred.ne_zero, leadingCoeff_ne_zero.mpr q_irred.ne_zero⟩
@[nolint unusedHavesSuffices]
theorem toPGame_def (o : Ordinal) :
    have : IsWellOrder o.out.α (· < ·) := isWellOrder_out_lt o
    o.toPGame = ⟨o.out.α, PEmpty, fun x => (typein (· < ·) x).toPGame, PEmpty.elim⟩ := by
  

Proof state:
o : Ordinal.{u_1}
⊢ let_fun this := (_ : IsWellOrder (Quotient.out o).α fun x x_1 => x < x_1);
  toPGame o = mk (Quotient.out o).α PEmpty.{u_1 + 1} (fun x => toPGame (typein (fun x x_1 => x < x_1) x)) PEmpty.elim

Next tactic:
rw [toPGame]
@[simp, nolint unusedHavesSuffices]
theorem toPGame_leftMoves (o : Ordinal) : o.toPGame.LeftMoves = o.out.α := by
  

Proof state:
o : Ordinal.{u_1}
⊢ LeftMoves (toPGame o) = (Quotient.out o).α

Next tactic:
rw [toPGame, LeftMoves]
@[simp, nolint unusedHavesSuffices]
theorem toPGame_rightMoves (o : Ordinal) : o.toPGame.RightMoves = PEmpty := by
  

Proof state:
o : Ordinal.{u_1}
⊢ RightMoves (toPGame o) = PEmpty.{u_1 + 1}

Next tactic:
rw [toPGame, RightMoves]
instance isEmpty_zero_toPGame_leftMoves : IsEmpty (toPGame 0).LeftMoves := by
  

Proof state:
⊢ IsEmpty (LeftMoves (toPGame 0))

Next tactic:
rw [toPGame_leftMoves]
instance isEmpty_zero_toPGame_leftMoves : IsEmpty (toPGame 0).LeftMoves := by
  rw [toPGame_leftMoves]; 

Proof state:
⊢ IsEmpty (Quotient.out 0).α

Next tactic:
infer_instance
instance isEmpty_toPGame_rightMoves (o : Ordinal) : IsEmpty o.toPGame.RightMoves := by
  

Proof state:
o : Ordinal.{?u.10522}
⊢ IsEmpty (RightMoves (toPGame o))

Next tactic:
rw [toPGame_rightMoves]
instance isEmpty_toPGame_rightMoves (o : Ordinal) : IsEmpty o.toPGame.RightMoves := by
  rw [toPGame_rightMoves]; 

Proof state:
o : Ordinal.{?u.10522}
⊢ IsEmpty PEmpty.{?u.10522 + 1}

Next tactic:
infer_instance
@[nolint unusedHavesSuffices]
theorem toPGame_moveLeft_hEq {o : Ordinal} :
    have : IsWellOrder o.out.α (· < ·) := isWellOrder_out_lt o
    HEq o.toPGame.moveLeft fun x : o.out.α => (typein (· < ·) x).toPGame := by
  

Proof state:
o : Ordinal.{u_1}
⊢ let_fun this := (_ : IsWellOrder (Quotient.out o).α fun x x_1 => x < x_1);
  HEq (moveLeft (toPGame o)) fun x => toPGame (typein (fun x x_1 => x < x_1) x)

Next tactic:
rw [toPGame]
@[nolint unusedHavesSuffices]
theorem toPGame_moveLeft_hEq {o : Ordinal} :
    have : IsWellOrder o.out.α (· < ·) := isWellOrder_out_lt o
    HEq o.toPGame.moveLeft fun x : o.out.α => (typein (· < ·) x).toPGame := by
  rw [toPGame]
  

Proof state:
o : Ordinal.{u_1}
⊢ let_fun this := (_ : IsWellOrder (Quotient.out o).α fun x x_1 => x < x_1);
  HEq
    (moveLeft
      ((fun this =>
          mk (Quotient.out o).α PEmpty.{u_1 + 1}
            (fun x =>
              let_fun this_1 := (_ : typein (fun x x_1 => x < x_1) x < o);
              toPGame (typein (fun x x_1 => x < x_1) x))
            PEmpty.elim)
        (_ : IsWellOrder (Quotient.out o).α fun x x_1 => x < x_1)))
    fun x => toPGame (typein (fun x x_1 => x < x_1) x)

Next tactic:
rfl
theorem toPGame_moveLeft {o : Ordinal} (i) :
    o.toPGame.moveLeft (toLeftMovesToPGame i) = i.val.toPGame := by 

Proof state:
o : Ordinal.{u_1}
i : ↑(Set.Iio o)
⊢ moveLeft (toPGame o) (toLeftMovesToPGame i) = toPGame ↑i

Next tactic:
simp
@[simp]
theorem to_leftMoves_one_toPGame_symm (i) :
    (@toLeftMovesToPGame 1).symm i = ⟨0, Set.mem_Iio.mpr zero_lt_one⟩ := by
  

Proof state:
i : LeftMoves (toPGame 1)
⊢ toLeftMovesToPGame.symm i = { val := 0, property := (_ : 0 ∈ Set.Iio 1) }

Next tactic:
simp [eq_iff_true_of_subsingleton]
theorem one_toPGame_moveLeft (x) : (toPGame 1).moveLeft x = toPGame 0 := by 

Proof state:
x : LeftMoves (toPGame 1)
⊢ moveLeft (toPGame 1) x = toPGame 0

Next tactic:
simp
/-- `1.toPGame` has the same moves as `1`. -/
noncomputable def oneToPGameRelabelling : toPGame 1 ≡r 1 :=
  ⟨Equiv.equivOfUnique _ _, Equiv.equivOfIsEmpty _ _, fun i => by
    

Proof state:
i : LeftMoves (toPGame 1)
⊢ moveLeft (toPGame 1) i ≡r moveLeft 1 ((Equiv.equivOfUnique (LeftMoves (toPGame 1)) (LeftMoves 1)) i)

Next tactic:
simpa using zeroToPGameRelabelling
theorem toPGame_lf {a b : Ordinal} (h : a < b) : a.toPGame ⧏ b.toPGame := by
  

Proof state:
a b : Ordinal.{u_1}
h : a < b
⊢ toPGame a ⧏ toPGame b

Next tactic:
convert moveLeft_lf (toLeftMovesToPGame ⟨a, h⟩)
theorem toPGame_lf {a b : Ordinal} (h : a < b) : a.toPGame ⧏ b.toPGame := by
  convert moveLeft_lf (toLeftMovesToPGame ⟨a, h⟩); 

Proof state:
case h.e'_1
a b : Ordinal.{u_1}
h : a < b
⊢ toPGame a = moveLeft (toPGame b) (toLeftMovesToPGame { val := a, property := h })

Next tactic:
rw [toPGame_moveLeft]
theorem toPGame_le {a b : Ordinal} (h : a ≤ b) : a.toPGame ≤ b.toPGame := by
  

Proof state:
a b : Ordinal.{u_1}
h : a ≤ b
⊢ toPGame a ≤ toPGame b

Next tactic:
refine' le_iff_forall_lf.2 ⟨fun i => _, isEmptyElim⟩
theorem toPGame_le {a b : Ordinal} (h : a ≤ b) : a.toPGame ≤ b.toPGame := by
  refine' le_iff_forall_lf.2 ⟨fun i => _, isEmptyElim⟩
  

Proof state:
a b : Ordinal.{u_1}
h : a ≤ b
i : LeftMoves (toPGame a)
⊢ moveLeft (toPGame a) i ⧏ toPGame b

Next tactic:
rw [toPGame_moveLeft']
theorem toPGame_le {a b : Ordinal} (h : a ≤ b) : a.toPGame ≤ b.toPGame := by
  refine' le_iff_forall_lf.2 ⟨fun i => _, isEmptyElim⟩
  rw [toPGame_moveLeft']
  

Proof state:
a b : Ordinal.{u_1}
h : a ≤ b
i : LeftMoves (toPGame a)
⊢ toPGame ↑(toLeftMovesToPGame.symm i) ⧏ toPGame b

Next tactic:
exact toPGame_lf ((toLeftMovesToPGame_symm_lt i).trans_le h)
@[simp]
theorem toPGame_lf_iff {a b : Ordinal} : a.toPGame ⧏ b.toPGame ↔ a < b :=
  ⟨by 

Proof state:
a b : Ordinal.{u_1}
⊢ toPGame a ⧏ toPGame b → a < b

Next tactic:
contrapose
@[simp]
theorem toPGame_lf_iff {a b : Ordinal} : a.toPGame ⧏ b.toPGame ↔ a < b :=
  ⟨by contrapose; 

Proof state:
a b : Ordinal.{u_1}
⊢ ¬a < b → ¬toPGame a ⧏ toPGame b

Next tactic:
rw [not_lt, not_lf]
@[simp]
theorem toPGame_lf_iff {a b : Ordinal} : a.toPGame ⧏ b.toPGame ↔ a < b :=
  ⟨by contrapose; rw [not_lt, not_lf]; 

Proof state:
a b : Ordinal.{u_1}
⊢ b ≤ a → toPGame b ≤ toPGame a

Next tactic:
exact toPGame_le
@[simp]
theorem toPGame_le_iff {a b : Ordinal} : a.toPGame ≤ b.toPGame ↔ a ≤ b :=
  ⟨by 

Proof state:
a b : Ordinal.{u_1}
⊢ toPGame a ≤ toPGame b → a ≤ b

Next tactic:
contrapose
@[simp]
theorem toPGame_le_iff {a b : Ordinal} : a.toPGame ≤ b.toPGame ↔ a ≤ b :=
  ⟨by contrapose; 

Proof state:
a b : Ordinal.{u_1}
⊢ ¬a ≤ b → ¬toPGame a ≤ toPGame b

Next tactic:
rw [not_le, PGame.not_le]
@[simp]
theorem toPGame_le_iff {a b : Ordinal} : a.toPGame ≤ b.toPGame ↔ a ≤ b :=
  ⟨by contrapose; rw [not_le, PGame.not_le]; 

Proof state:
a b : Ordinal.{u_1}
⊢ b < a → toPGame b ⧏ toPGame a

Next tactic:
exact toPGame_lf
@[simp]
theorem toPGame_lt_iff {a b : Ordinal} : a.toPGame < b.toPGame ↔ a < b :=
  ⟨by 

Proof state:
a b : Ordinal.{u_1}
⊢ toPGame a < toPGame b → a < b

Next tactic:
contrapose
@[simp]
theorem toPGame_lt_iff {a b : Ordinal} : a.toPGame < b.toPGame ↔ a < b :=
  ⟨by contrapose; 

Proof state:
a b : Ordinal.{u_1}
⊢ ¬a < b → ¬toPGame a < toPGame b

Next tactic:
rw [not_lt]
@[simp]
theorem toPGame_lt_iff {a b : Ordinal} : a.toPGame < b.toPGame ↔ a < b :=
  ⟨by contrapose; rw [not_lt]; 

Proof state:
a b : Ordinal.{u_1}
⊢ b ≤ a → ¬toPGame a < toPGame b

Next tactic:
exact fun h => not_lt_of_le (toPGame_le h)
@[simp]
theorem toPGame_equiv_iff {a b : Ordinal} : (a.toPGame ≈ b.toPGame) ↔ a = b := by
  -- Porting note: was `rw [PGame.Equiv]`
  

Proof state:
a b : Ordinal.{u_1}
⊢ toPGame a ≈ toPGame b ↔ a = b

Next tactic:
change _ ≤_ ∧ _ ≤ _ ↔ _
@[simp]
theorem toPGame_equiv_iff {a b : Ordinal} : (a.toPGame ≈ b.toPGame) ↔ a = b := by
  -- Porting note: was `rw [PGame.Equiv]`
  change _ ≤_ ∧ _ ≤ _ ↔ _
  

Proof state:
a b : Ordinal.{u_1}
⊢ toPGame a ≤ toPGame b ∧ toPGame b ≤ toPGame a ↔ a = b

Next tactic:
rw [le_antisymm_iff, toPGame_le_iff, toPGame_le_iff]
/-- The sum of ordinals as games corresponds to natural addition of ordinals. -/
theorem toPGame_add : ∀ a b : Ordinal.{u}, a.toPGame + b.toPGame ≈ (a ♯ b).toPGame
  | a, b => by
    

Proof state:
a b : Ordinal.{u}
⊢ toPGame a + toPGame b ≈ toPGame (a ♯ b)

Next tactic:
refine' ⟨le_of_forall_lf (fun i => _) isEmptyElim, le_of_forall_lf (fun i => _) isEmptyElim⟩
/-- The sum of ordinals as games corresponds to natural addition of ordinals. -/
theorem toPGame_add : ∀ a b : Ordinal.{u}, a.toPGame + b.toPGame ≈ (a ♯ b).toPGame
  | a, b => by
    refine' ⟨le_of_forall_lf (fun i => _) isEmptyElim, le_of_forall_lf (fun i => _) isEmptyElim⟩
    · 

Proof state:
case refine'_1
a b : Ordinal.{u}
i : LeftMoves (toPGame a + toPGame b)
⊢ moveLeft (toPGame a + toPGame b) i ⧏ toPGame (a ♯ b)

Next tactic:
apply leftMoves_add_cases i
/-- The sum of ordinals as games corresponds to natural addition of ordinals. -/
theorem toPGame_add : ∀ a b : Ordinal.{u}, a.toPGame + b.toPGame ≈ (a ♯ b).toPGame
  | a, b => by
    refine' ⟨le_of_forall_lf (fun i => _) isEmptyElim, le_of_forall_lf (fun i => _) isEmptyElim⟩
    · apply leftMoves_add_cases i <;>
      

Proof state:
case refine'_1.hl
a b : Ordinal.{u}
i : LeftMoves (toPGame a + toPGame b)
⊢ ∀ (i : LeftMoves (toPGame a)), moveLeft (toPGame a + toPGame b) (toLeftMovesAdd (Sum.inl i)) ⧏ toPGame (a ♯ b)

Next tactic:
intro i
/-- The sum of ordinals as games corresponds to natural addition of ordinals. -/
theorem toPGame_add : ∀ a b : Ordinal.{u}, a.toPGame + b.toPGame ≈ (a ♯ b).toPGame
  | a, b => by
    refine' ⟨le_of_forall_lf (fun i => _) isEmptyElim, le_of_forall_lf (fun i => _) isEmptyElim⟩
    · apply leftMoves_add_cases i <;>
      

Proof state:
case refine'_1.hr
a b : Ordinal.{u}
i : LeftMoves (toPGame a + toPGame b)
⊢ ∀ (i : LeftMoves (toPGame b)), moveLeft (toPGame a + toPGame b) (toLeftMovesAdd (Sum.inr i)) ⧏ toPGame (a ♯ b)

Next tactic:
intro i
/-- The sum of ordinals as games corresponds to natural addition of ordinals. -/
theorem toPGame_add : ∀ a b : Ordinal.{u}, a.toPGame + b.toPGame ≈ (a ♯ b).toPGame
  | a, b => by
    refine' ⟨le_of_forall_lf (fun i => _) isEmptyElim, le_of_forall_lf (fun i => _) isEmptyElim⟩
    · apply leftMoves_add_cases i <;>
      intro i <;>
      

Proof state:
case refine'_1.hl
a b : Ordinal.{u}
i✝ : LeftMoves (toPGame a + toPGame b)
i : LeftMoves (toPGame a)
⊢ moveLeft (toPGame a + toPGame b) (toLeftMovesAdd (Sum.inl i)) ⧏ toPGame (a ♯ b)

Next tactic:
let wf := toLeftMovesToPGame_symm_lt i
/-- The sum of ordinals as games corresponds to natural addition of ordinals. -/
theorem toPGame_add : ∀ a b : Ordinal.{u}, a.toPGame + b.toPGame ≈ (a ♯ b).toPGame
  | a, b => by
    refine' ⟨le_of_forall_lf (fun i => _) isEmptyElim, le_of_forall_lf (fun i => _) isEmptyElim⟩
    · apply leftMoves_add_cases i <;>
      intro i <;>
      

Proof state:
case refine'_1.hr
a b : Ordinal.{u}
i✝ : LeftMoves (toPGame a + toPGame b)
i : LeftMoves (toPGame b)
⊢ moveLeft (toPGame a + toPGame b) (toLeftMovesAdd (Sum.inr i)) ⧏ toPGame (a ♯ b)

Next tactic:
let wf := toLeftMovesToPGame_symm_lt i