l3lab/ntp-mathlib huggingface dataset:
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    

Proof state:
case refine'_10
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
⊢ a✝ * b✝ = b✝ * a✝

Next tactic:
first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        first
          | rw [mul_add]
          | rw [add_mul]
          | rw [zero_apply, zero_mul]
          | rw [zero_apply, mul_zero]
          | rw [← mul_assoc]
          | rw [one_apply, one_mul]
          | rw [one_apply, mul_one]
          | rw [mul_comm]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | 

Proof state:
case refine'_10
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
⊢ a✝ * b✝ = b✝ * a✝

Next tactic:
rfl
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | 

Proof state:
case refine'_10
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
⊢ a✝ * b✝ = b✝ * a✝

Next tactic:
ext
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; 

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ (a✝ * b✝) x✝ = (b✝ * a✝) x✝

Next tactic:
simp only [add_apply, mul_apply]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ a✝ x✝ * b✝ x✝ = b✝ x✝ * a✝ x✝

Next tactic:
first
          | rw [mul_add]
          | rw [add_mul]
          | rw [zero_apply, zero_mul]
          | rw [zero_apply, mul_zero]
          | rw [← mul_assoc]
          | rw [one_apply, one_mul]
          | rw [one_apply, mul_one]
          | rw [mul_comm]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        first
          | 

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ a✝ x✝ * b✝ x✝ = b✝ x✝ * a✝ x✝

Next tactic:
rw [mul_add]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        first
          | rw [mul_add]
          | 

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ a✝ x✝ * b✝ x✝ = b✝ x✝ * a✝ x✝

Next tactic:
rw [add_mul]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        first
          | rw [mul_add]
          | rw [add_mul]
          | 

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ a✝ x✝ * b✝ x✝ = b✝ x✝ * a✝ x✝

Next tactic:
rw [zero_apply, zero_mul]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        first
          | rw [mul_add]
          | rw [add_mul]
          | rw [zero_apply, zero_mul]
          | 

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ a✝ x✝ * b✝ x✝ = b✝ x✝ * a✝ x✝

Next tactic:
rw [zero_apply, mul_zero]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        first
          | rw [mul_add]
          | rw [add_mul]
          | rw [zero_apply, zero_mul]
          | rw [zero_apply, mul_zero]
          | 

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ a✝ x✝ * b✝ x✝ = b✝ x✝ * a✝ x✝

Next tactic:
rw [← mul_assoc]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        first
          | rw [mul_add]
          | rw [add_mul]
          | rw [zero_apply, zero_mul]
          | rw [zero_apply, mul_zero]
          | rw [← mul_assoc]
          | 

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ a✝ x✝ * b✝ x✝ = b✝ x✝ * a✝ x✝

Next tactic:
rw [one_apply, one_mul]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        first
          | rw [mul_add]
          | rw [add_mul]
          | rw [zero_apply, zero_mul]
          | rw [zero_apply, mul_zero]
          | rw [← mul_assoc]
          | rw [one_apply, one_mul]
          | 

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ a✝ x✝ * b✝ x✝ = b✝ x✝ * a✝ x✝

Next tactic:
rw [one_apply, mul_one]
instance : CommRing (Poly α) := by
  refine' { (inferInstance : AddCommGroup (Poly α)),
            (inferInstance : AddGroupWithOne (Poly α)) with
              mul := (· * ·)
              npow := @npowRec _ ⟨(1 : Poly α)⟩ ⟨(· * ·)⟩
              .. }
  all_goals
    intros
    first
      | rfl
      | ext; simp only [add_apply, mul_apply]
        first
          | rw [mul_add]
          | rw [add_mul]
          | rw [zero_apply, zero_mul]
          | rw [zero_apply, mul_zero]
          | rw [← mul_assoc]
          | rw [one_apply, one_mul]
          | rw [one_apply, mul_one]
          | 

Proof state:
case refine'_10.a
α : Type u_1
β : Type u_2
γ : Type u_3
src✝¹ : AddCommGroup (Poly α) := inferInstance
src✝ : AddGroupWithOne (Poly α) := inferInstance
a✝ b✝ : Poly α
x✝ : α → ℕ
⊢ a✝ x✝ * b✝ x✝ = b✝ x✝ * a✝ x✝

Next tactic:
rw [mul_comm]
theorem induction {C : Poly α → Prop} (H1 : ∀ i, C (proj i)) (H2 : ∀ n, C (const n))
    (H3 : ∀ f g, C f → C g → C (f - g)) (H4 : ∀ f g, C f → C g → C (f * g)) (f : Poly α) : C f := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f : Poly α
⊢ C f

Next tactic:
cases' f with f pf
theorem induction {C : Poly α → Prop} (H1 : ∀ i, C (proj i)) (H2 : ∀ n, C (const n))
    (H3 : ∀ f g, C f → C g → C (f - g)) (H4 : ∀ f g, C f → C g → C (f * g)) (f : Poly α) : C f := by
  cases' f with f pf
  

Proof state:
case mk
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f : (α → ℕ) → ℤ
pf : IsPoly f
⊢ C { val := f, property := pf }

Next tactic:
induction' pf with i n f g pf pg ihf ihg f g pf pg ihf ihg
theorem induction {C : Poly α → Prop} (H1 : ∀ i, C (proj i)) (H2 : ∀ n, C (const n))
    (H3 : ∀ f g, C f → C g → C (f - g)) (H4 : ∀ f g, C f → C g → C (f * g)) (f : Poly α) : C f := by
  cases' f with f pf
  induction' pf with i n f g pf pg ihf ihg f g pf pg ihf ihg
  

Proof state:
case mk.proj
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f : (α → ℕ) → ℤ
i : α
⊢ C { val := fun x => ↑(x i), property := (_ : IsPoly fun x => ↑(x i)) }
case mk.const
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f : (α → ℕ) → ℤ
n : ℤ
⊢ C { val := fun x => n, property := (_ : IsPoly fun x => n) }
case mk.sub
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f✝ f g : (α → ℕ) → ℤ
pf : IsPoly f
pg : IsPoly g
ihf : C { val := f, property := pf }
ihg : C { val := g, property := pg }
⊢ C { val := fun x => f x - g x, property := (_ : IsPoly fun x => f x - g x) }
case mk.mul
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f✝ f g : (α → ℕ) → ℤ
pf : IsPoly f
pg : IsPoly g
ihf : C { val := f, property := pf }
ihg : C { val := g, property := pg }
⊢ C { val := fun x => f x * g x, property := (_ : IsPoly fun x => f x * g x) }

Next tactic:
apply H1
theorem induction {C : Poly α → Prop} (H1 : ∀ i, C (proj i)) (H2 : ∀ n, C (const n))
    (H3 : ∀ f g, C f → C g → C (f - g)) (H4 : ∀ f g, C f → C g → C (f * g)) (f : Poly α) : C f := by
  cases' f with f pf
  induction' pf with i n f g pf pg ihf ihg f g pf pg ihf ihg
  apply H1; 

Proof state:
case mk.const
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f : (α → ℕ) → ℤ
n : ℤ
⊢ C { val := fun x => n, property := (_ : IsPoly fun x => n) }
case mk.sub
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f✝ f g : (α → ℕ) → ℤ
pf : IsPoly f
pg : IsPoly g
ihf : C { val := f, property := pf }
ihg : C { val := g, property := pg }
⊢ C { val := fun x => f x - g x, property := (_ : IsPoly fun x => f x - g x) }
case mk.mul
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f✝ f g : (α → ℕ) → ℤ
pf : IsPoly f
pg : IsPoly g
ihf : C { val := f, property := pf }
ihg : C { val := g, property := pg }
⊢ C { val := fun x => f x * g x, property := (_ : IsPoly fun x => f x * g x) }

Next tactic:
apply H2
theorem induction {C : Poly α → Prop} (H1 : ∀ i, C (proj i)) (H2 : ∀ n, C (const n))
    (H3 : ∀ f g, C f → C g → C (f - g)) (H4 : ∀ f g, C f → C g → C (f * g)) (f : Poly α) : C f := by
  cases' f with f pf
  induction' pf with i n f g pf pg ihf ihg f g pf pg ihf ihg
  apply H1; apply H2; 

Proof state:
case mk.sub
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f✝ f g : (α → ℕ) → ℤ
pf : IsPoly f
pg : IsPoly g
ihf : C { val := f, property := pf }
ihg : C { val := g, property := pg }
⊢ C { val := fun x => f x - g x, property := (_ : IsPoly fun x => f x - g x) }
case mk.mul
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f✝ f g : (α → ℕ) → ℤ
pf : IsPoly f
pg : IsPoly g
ihf : C { val := f, property := pf }
ihg : C { val := g, property := pg }
⊢ C { val := fun x => f x * g x, property := (_ : IsPoly fun x => f x * g x) }

Next tactic:
apply H3 _ _ ihf ihg
theorem induction {C : Poly α → Prop} (H1 : ∀ i, C (proj i)) (H2 : ∀ n, C (const n))
    (H3 : ∀ f g, C f → C g → C (f - g)) (H4 : ∀ f g, C f → C g → C (f * g)) (f : Poly α) : C f := by
  cases' f with f pf
  induction' pf with i n f g pf pg ihf ihg f g pf pg ihf ihg
  apply H1; apply H2; apply H3 _ _ ihf ihg; 

Proof state:
case mk.mul
α : Type u_1
β : Type u_2
γ : Type u_3
C : Poly α → Prop
H1 : ∀ (i : α), C (proj i)
H2 : ∀ (n : ℤ), C (const n)
H3 : ∀ (f g : Poly α), C f → C g → C (f - g)
H4 : ∀ (f g : Poly α), C f → C g → C (f * g)
f✝ f g : (α → ℕ) → ℤ
pf : IsPoly f
pg : IsPoly g
ihf : C { val := f, property := pf }
ihg : C { val := g, property := pg }
⊢ C { val := fun x => f x * g x, property := (_ : IsPoly fun x => f x * g x) }

Next tactic:
apply H4 _ _ ihf ihg
theorem sumsq_nonneg (x : α → ℕ) : ∀ l, 0 ≤ sumsq l x
  | [] => le_refl 0
  | p::ps => by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
⊢ 0 ≤ (sumsq (p :: ps)) x

Next tactic:
rw [sumsq]
theorem sumsq_nonneg (x : α → ℕ) : ∀ l, 0 ≤ sumsq l x
  | [] => le_refl 0
  | p::ps => by
    rw [sumsq]
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
⊢ 0 ≤ (p * p + sumsq ps) x

Next tactic:
exact add_nonneg (mul_self_nonneg _) (sumsq_nonneg _ ps)
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
⊢ (sumsq (p :: ps)) x = 0 ↔ List.Forall (fun a => a x = 0) (p :: ps)

Next tactic:
rw [List.forall_cons, ← sumsq_eq_zero _ ps]
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    rw [List.forall_cons, ← sumsq_eq_zero _ ps]; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
⊢ (sumsq (p :: ps)) x = 0 ↔ p x = 0 ∧ (sumsq ps) x = 0

Next tactic:
rw [sumsq]
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    rw [List.forall_cons, ← sumsq_eq_zero _ ps]; rw [sumsq]
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
⊢ (p * p + sumsq ps) x = 0 ↔ p x = 0 ∧ (sumsq ps) x = 0

Next tactic:
exact
      ⟨fun h : p x * p x + sumsq ps x = 0 =>
        have : p x = 0 :=
          eq_zero_of_mul_self_eq_zero <|
            le_antisymm
              (by
                rw [← h]
                have t := add_le_add_left (sumsq_nonneg x ps) (p x * p x)
                rwa [add_zero] at t)
              (mul_self_nonneg _)
        ⟨this, by simp [this] at h; exact h⟩,
      fun ⟨h1, h2⟩ => by rw [add_apply, mul_apply, h1, h2]; rfl⟩
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    rw [List.forall_cons, ← sumsq_eq_zero _ ps]; rw [sumsq]
    exact
      ⟨fun h : p x * p x + sumsq ps x = 0 =>
        have : p x = 0 :=
          eq_zero_of_mul_self_eq_zero <|
            le_antisymm
              (by
                

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
h : p x * p x + (sumsq ps) x = 0
⊢ p x * p x ≤ 0

Next tactic:
rw [← h]
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    rw [List.forall_cons, ← sumsq_eq_zero _ ps]; rw [sumsq]
    exact
      ⟨fun h : p x * p x + sumsq ps x = 0 =>
        have : p x = 0 :=
          eq_zero_of_mul_self_eq_zero <|
            le_antisymm
              (by
                rw [← h]
                

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
h : p x * p x + (sumsq ps) x = 0
⊢ p x * p x ≤ p x * p x + (sumsq ps) x

Next tactic:
have t := add_le_add_left (sumsq_nonneg x ps) (p x * p x)
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    rw [List.forall_cons, ← sumsq_eq_zero _ ps]; rw [sumsq]
    exact
      ⟨fun h : p x * p x + sumsq ps x = 0 =>
        have : p x = 0 :=
          eq_zero_of_mul_self_eq_zero <|
            le_antisymm
              (by
                rw [← h]
                have t := add_le_add_left (sumsq_nonneg x ps) (p x * p x)
                

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
h : p x * p x + (sumsq ps) x = 0
t : p x * p x + 0 ≤ p x * p x + (sumsq ps) x
⊢ p x * p x ≤ p x * p x + (sumsq ps) x

Next tactic:
rwa [add_zero] at t
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    rw [List.forall_cons, ← sumsq_eq_zero _ ps]; rw [sumsq]
    exact
      ⟨fun h : p x * p x + sumsq ps x = 0 =>
        have : p x = 0 :=
          eq_zero_of_mul_self_eq_zero <|
            le_antisymm
              (by
                rw [← h]
                have t := add_le_add_left (sumsq_nonneg x ps) (p x * p x)
                rwa [add_zero] at t)
              (mul_self_nonneg _)
        ⟨this, by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
h : p x * p x + (sumsq ps) x = 0
this : p x = 0
⊢ (sumsq ps) x = 0

Next tactic:
simp [this] at h
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    rw [List.forall_cons, ← sumsq_eq_zero _ ps]; rw [sumsq]
    exact
      ⟨fun h : p x * p x + sumsq ps x = 0 =>
        have : p x = 0 :=
          eq_zero_of_mul_self_eq_zero <|
            le_antisymm
              (by
                rw [← h]
                have t := add_le_add_left (sumsq_nonneg x ps) (p x * p x)
                rwa [add_zero] at t)
              (mul_self_nonneg _)
        ⟨this, by simp [this] at h; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
this : p x = 0
h : (sumsq ps) x = 0
⊢ (sumsq ps) x = 0

Next tactic:
exact h
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    rw [List.forall_cons, ← sumsq_eq_zero _ ps]; rw [sumsq]
    exact
      ⟨fun h : p x * p x + sumsq ps x = 0 =>
        have : p x = 0 :=
          eq_zero_of_mul_self_eq_zero <|
            le_antisymm
              (by
                rw [← h]
                have t := add_le_add_left (sumsq_nonneg x ps) (p x * p x)
                rwa [add_zero] at t)
              (mul_self_nonneg _)
        ⟨this, by simp [this] at h; exact h⟩,
      fun ⟨h1, h2⟩ => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
x✝ : p x = 0 ∧ (sumsq ps) x = 0
h1 : p x = 0
h2 : (sumsq ps) x = 0
⊢ (p * p + sumsq ps) x = 0

Next tactic:
rw [add_apply, mul_apply, h1, h2]
theorem sumsq_eq_zero (x) : ∀ l, sumsq l x = 0 ↔ l.Forall fun a : Poly α => a x = 0
  | [] => eq_self_iff_true _
  | p::ps => by
    rw [List.forall_cons, ← sumsq_eq_zero _ ps]; rw [sumsq]
    exact
      ⟨fun h : p x * p x + sumsq ps x = 0 =>
        have : p x = 0 :=
          eq_zero_of_mul_self_eq_zero <|
            le_antisymm
              (by
                rw [← h]
                have t := add_le_add_left (sumsq_nonneg x ps) (p x * p x)
                rwa [add_zero] at t)
              (mul_self_nonneg _)
        ⟨this, by simp [this] at h; exact h⟩,
      fun ⟨h1, h2⟩ => by rw [add_apply, mul_apply, h1, h2]; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x : α → ℕ
p : Poly α
ps : List (Poly α)
x✝ : p x = 0 ∧ (sumsq ps) x = 0
h1 : p x = 0
h2 : (sumsq ps) x = 0
⊢ 0 * 0 + 0 = 0

Next tactic:
rfl
/-- Map the index set of variables, replacing `x_i` with `x_(f i)`. -/
def map {α β} (f : α → β) (g : Poly α) : Poly β :=
  ⟨fun v => g <| v ∘ f, Poly.induction (C := fun g => IsPoly (fun v => g (v ∘ f)))
    (fun i => by 

Proof state:
α✝ : Type u_1
β✝ : Type u_2
γ : Type u_3
α : Type ?u.107838
β : Type ?u.107841
f : α → β
g : Poly α
i : α
⊢ (fun g => IsPoly fun v => g (v ∘ f)) (proj i)

Next tactic:
simp
/-- Map the index set of variables, replacing `x_i` with `x_(f i)`. -/
def map {α β} (f : α → β) (g : Poly α) : Poly β :=
  ⟨fun v => g <| v ∘ f, Poly.induction (C := fun g => IsPoly (fun v => g (v ∘ f)))
    (fun i => by simp; 

Proof state:
α✝ : Type u_1
β✝ : Type u_2
γ : Type u_3
α : Type ?u.107838
β : Type ?u.107841
f : α → β
g : Poly α
i : α
⊢ IsPoly fun v => ↑(v (f i))

Next tactic:
apply IsPoly.proj
/-- Map the index set of variables, replacing `x_i` with `x_(f i)`. -/
def map {α β} (f : α → β) (g : Poly α) : Poly β :=
  ⟨fun v => g <| v ∘ f, Poly.induction (C := fun g => IsPoly (fun v => g (v ∘ f)))
    (fun i => by simp; apply IsPoly.proj) (fun n => by 

Proof state:
α✝ : Type u_1
β✝ : Type u_2
γ : Type u_3
α : Type ?u.107838
β : Type ?u.107841
f : α → β
g : Poly α
n : ℤ
⊢ (fun g => IsPoly fun v => g (v ∘ f)) (const n)

Next tactic:
simp
/-- Map the index set of variables, replacing `x_i` with `x_(f i)`. -/
def map {α β} (f : α → β) (g : Poly α) : Poly β :=
  ⟨fun v => g <| v ∘ f, Poly.induction (C := fun g => IsPoly (fun v => g (v ∘ f)))
    (fun i => by simp; apply IsPoly.proj) (fun n => by simp; 

Proof state:
α✝ : Type u_1
β✝ : Type u_2
γ : Type u_3
α : Type ?u.107838
β : Type ?u.107841
f : α → β
g : Poly α
n : ℤ
⊢ IsPoly fun v => n

Next tactic:
apply IsPoly.const