l3lab/ntp-mathlib huggingface dataset:
theorem ext [Fact p.Prime] {f g} (hf : IsPoly p f) (hg : IsPoly p g)
    (h : ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R) (n : ℕ),
        ghostComponent n (f x) = ghostComponent n (g x)) :
    ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R), f x = g x := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  intros
  ext n
  rw [hf, hg, poly_eq_of_wittPolynomial_bind_eq p φ ψ]
  intro k
  apply MvPolynomial.funext
  intro x
  simp only [hom_bind₁]
  specialize h (ULift ℤ) (mk p fun i => ⟨x i⟩) k
  simp only [ghostComponent_apply, aeval_eq_eval₂Hom] at h
  apply (ULift.ringEquiv.symm : ℤ ≃+* _).injective
  simp only [← RingEquiv.coe_toRingHom, map_eval₂Hom]
  convert h using 1
  all_goals
    --  porting note: this proof started with `funext i`
    simp only [hf, hg, MvPolynomial.eval, map_eval₂Hom]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    

Proof state:
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
inst✝ : Fact (Nat.Prime p)
f g : ⦃R : Type u⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
R✝ : Type u
_Rcr✝ : CommRing R✝
x✝ : 𝕎 R✝
n k : ℕ
x : ℕ → ℤ
h :
  (aeval (f (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k) =
    (aeval (g (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k)
⊢ (fun i =>
      (eval₂Hom (RingHom.comp (↑(RingEquiv.symm ULift.ringEquiv)) (RingHom.id ℤ)) fun i =>
          ↑(RingEquiv.symm ULift.ringEquiv) (x i))
        (φ i)) =
    fun n => (aeval (mk p fun i => { down := x i }).coeff) (φ n)

Next tactic:
ext1
theorem ext [Fact p.Prime] {f g} (hf : IsPoly p f) (hg : IsPoly p g)
    (h : ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R) (n : ℕ),
        ghostComponent n (f x) = ghostComponent n (g x)) :
    ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R), f x = g x := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  intros
  ext n
  rw [hf, hg, poly_eq_of_wittPolynomial_bind_eq p φ ψ]
  intro k
  apply MvPolynomial.funext
  intro x
  simp only [hom_bind₁]
  specialize h (ULift ℤ) (mk p fun i => ⟨x i⟩) k
  simp only [ghostComponent_apply, aeval_eq_eval₂Hom] at h
  apply (ULift.ringEquiv.symm : ℤ ≃+* _).injective
  simp only [← RingEquiv.coe_toRingHom, map_eval₂Hom]
  convert h using 1
  all_goals
    --  porting note: this proof started with `funext i`
    simp only [hf, hg, MvPolynomial.eval, map_eval₂Hom]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    ext1
    

Proof state:
case h
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
inst✝ : Fact (Nat.Prime p)
f g : ⦃R : Type u⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
R✝ : Type u
_Rcr✝ : CommRing R✝
x✝¹ : 𝕎 R✝
n k : ℕ
x : ℕ → ℤ
h :
  (aeval (f (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k) =
    (aeval (g (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k)
x✝ : ℕ
⊢ (eval₂Hom (RingHom.comp (↑(RingEquiv.symm ULift.ringEquiv)) (RingHom.id ℤ)) fun i =>
        ↑(RingEquiv.symm ULift.ringEquiv) (x i))
      (φ x✝) =
    (aeval (mk p fun i => { down := x i }).coeff) (φ x✝)

Next tactic:
apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
theorem ext [Fact p.Prime] {f g} (hf : IsPoly p f) (hg : IsPoly p g)
    (h : ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R) (n : ℕ),
        ghostComponent n (f x) = ghostComponent n (g x)) :
    ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R), f x = g x := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  intros
  ext n
  rw [hf, hg, poly_eq_of_wittPolynomial_bind_eq p φ ψ]
  intro k
  apply MvPolynomial.funext
  intro x
  simp only [hom_bind₁]
  specialize h (ULift ℤ) (mk p fun i => ⟨x i⟩) k
  simp only [ghostComponent_apply, aeval_eq_eval₂Hom] at h
  apply (ULift.ringEquiv.symm : ℤ ≃+* _).injective
  simp only [← RingEquiv.coe_toRingHom, map_eval₂Hom]
  convert h using 1
  all_goals
    --  porting note: this proof started with `funext i`
    simp only [hf, hg, MvPolynomial.eval, map_eval₂Hom]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    ext1
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    

Proof state:
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
inst✝ : Fact (Nat.Prime p)
f g : ⦃R : Type u⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
R✝ : Type u
_Rcr✝ : CommRing R✝
x✝¹ : 𝕎 R✝
n k : ℕ
x : ℕ → ℤ
h :
  (aeval (f (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k) =
    (aeval (g (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k)
x✝ : ℕ
⊢ (fun i => ↑(RingEquiv.symm ULift.ringEquiv) (x i)) = (mk p fun i => { down := x i }).coeff

Next tactic:
simp only [coeff_mk]
theorem ext [Fact p.Prime] {f g} (hf : IsPoly p f) (hg : IsPoly p g)
    (h : ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R) (n : ℕ),
        ghostComponent n (f x) = ghostComponent n (g x)) :
    ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R), f x = g x := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  intros
  ext n
  rw [hf, hg, poly_eq_of_wittPolynomial_bind_eq p φ ψ]
  intro k
  apply MvPolynomial.funext
  intro x
  simp only [hom_bind₁]
  specialize h (ULift ℤ) (mk p fun i => ⟨x i⟩) k
  simp only [ghostComponent_apply, aeval_eq_eval₂Hom] at h
  apply (ULift.ringEquiv.symm : ℤ ≃+* _).injective
  simp only [← RingEquiv.coe_toRingHom, map_eval₂Hom]
  convert h using 1
  all_goals
    --  porting note: this proof started with `funext i`
    simp only [hf, hg, MvPolynomial.eval, map_eval₂Hom]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    ext1
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    simp only [coeff_mk]; 

Proof state:
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
inst✝ : Fact (Nat.Prime p)
f g : ⦃R : Type u⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
R✝ : Type u
_Rcr✝ : CommRing R✝
x✝¹ : 𝕎 R✝
n k : ℕ
x : ℕ → ℤ
h :
  (aeval (f (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k) =
    (aeval (g (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k)
x✝ : ℕ
⊢ (fun i => ↑(RingEquiv.symm ULift.ringEquiv) (x i)) = fun i => { down := x i }

Next tactic:
rfl
theorem ext [Fact p.Prime] {f g} (hf : IsPoly p f) (hg : IsPoly p g)
    (h : ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R) (n : ℕ),
        ghostComponent n (f x) = ghostComponent n (g x)) :
    ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R), f x = g x := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  intros
  ext n
  rw [hf, hg, poly_eq_of_wittPolynomial_bind_eq p φ ψ]
  intro k
  apply MvPolynomial.funext
  intro x
  simp only [hom_bind₁]
  specialize h (ULift ℤ) (mk p fun i => ⟨x i⟩) k
  simp only [ghostComponent_apply, aeval_eq_eval₂Hom] at h
  apply (ULift.ringEquiv.symm : ℤ ≃+* _).injective
  simp only [← RingEquiv.coe_toRingHom, map_eval₂Hom]
  convert h using 1
  all_goals
    --  porting note: this proof started with `funext i`
    

Proof state:
case h.e'_3
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
inst✝ : Fact (Nat.Prime p)
f g : ⦃R : Type u⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
R✝ : Type u
_Rcr✝ : CommRing R✝
x✝ : 𝕎 R✝
n k : ℕ
x : ℕ → ℤ
h :
  (aeval (f (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k) =
    (aeval (g (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k)
⊢ (eval₂Hom (RingHom.comp (↑(RingEquiv.symm ULift.ringEquiv)) (RingHom.comp (MvPolynomial.eval x) C)) fun i =>
        ↑(RingEquiv.symm ULift.ringEquiv) ((MvPolynomial.eval x) (ψ i)))
      (wittPolynomial p ℤ k) =
    (aeval (g (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k)

Next tactic:
simp only [hf, hg, MvPolynomial.eval, map_eval₂Hom]
theorem ext [Fact p.Prime] {f g} (hf : IsPoly p f) (hg : IsPoly p g)
    (h : ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R) (n : ℕ),
        ghostComponent n (f x) = ghostComponent n (g x)) :
    ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R), f x = g x := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  intros
  ext n
  rw [hf, hg, poly_eq_of_wittPolynomial_bind_eq p φ ψ]
  intro k
  apply MvPolynomial.funext
  intro x
  simp only [hom_bind₁]
  specialize h (ULift ℤ) (mk p fun i => ⟨x i⟩) k
  simp only [ghostComponent_apply, aeval_eq_eval₂Hom] at h
  apply (ULift.ringEquiv.symm : ℤ ≃+* _).injective
  simp only [← RingEquiv.coe_toRingHom, map_eval₂Hom]
  convert h using 1
  all_goals
    --  porting note: this proof started with `funext i`
    simp only [hf, hg, MvPolynomial.eval, map_eval₂Hom]
    

Proof state:
case h.e'_3
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
inst✝ : Fact (Nat.Prime p)
f g : ⦃R : Type u⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
R✝ : Type u
_Rcr✝ : CommRing R✝
x✝ : 𝕎 R✝
n k : ℕ
x : ℕ → ℤ
h :
  (aeval (f (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k) =
    (aeval (g (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k)
⊢ (eval₂Hom (RingHom.comp (↑(RingEquiv.symm ULift.ringEquiv)) (RingHom.comp (eval₂Hom (RingHom.id ℤ) x) C)) fun i =>
        (eval₂Hom (RingHom.comp (↑(RingEquiv.symm ULift.ringEquiv)) (RingHom.id ℤ)) fun i =>
            ↑(RingEquiv.symm ULift.ringEquiv) (x i))
          (ψ i))
      (wittPolynomial p ℤ k) =
    (aeval fun n => (aeval (mk p fun i => { down := x i }).coeff) (ψ n)) (wittPolynomial p ℤ k)

Next tactic:
apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
theorem ext [Fact p.Prime] {f g} (hf : IsPoly p f) (hg : IsPoly p g)
    (h : ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R) (n : ℕ),
        ghostComponent n (f x) = ghostComponent n (g x)) :
    ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R), f x = g x := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  intros
  ext n
  rw [hf, hg, poly_eq_of_wittPolynomial_bind_eq p φ ψ]
  intro k
  apply MvPolynomial.funext
  intro x
  simp only [hom_bind₁]
  specialize h (ULift ℤ) (mk p fun i => ⟨x i⟩) k
  simp only [ghostComponent_apply, aeval_eq_eval₂Hom] at h
  apply (ULift.ringEquiv.symm : ℤ ≃+* _).injective
  simp only [← RingEquiv.coe_toRingHom, map_eval₂Hom]
  convert h using 1
  all_goals
    --  porting note: this proof started with `funext i`
    simp only [hf, hg, MvPolynomial.eval, map_eval₂Hom]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    

Proof state:
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
inst✝ : Fact (Nat.Prime p)
f g : ⦃R : Type u⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
R✝ : Type u
_Rcr✝ : CommRing R✝
x✝ : 𝕎 R✝
n k : ℕ
x : ℕ → ℤ
h :
  (aeval (f (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k) =
    (aeval (g (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k)
⊢ (fun i =>
      (eval₂Hom (RingHom.comp (↑(RingEquiv.symm ULift.ringEquiv)) (RingHom.id ℤ)) fun i =>
          ↑(RingEquiv.symm ULift.ringEquiv) (x i))
        (ψ i)) =
    fun n => (aeval (mk p fun i => { down := x i }).coeff) (ψ n)

Next tactic:
ext1
theorem ext [Fact p.Prime] {f g} (hf : IsPoly p f) (hg : IsPoly p g)
    (h : ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R) (n : ℕ),
        ghostComponent n (f x) = ghostComponent n (g x)) :
    ∀ (R : Type u) [_Rcr : CommRing R] (x : 𝕎 R), f x = g x := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  intros
  ext n
  rw [hf, hg, poly_eq_of_wittPolynomial_bind_eq p φ ψ]
  intro k
  apply MvPolynomial.funext
  intro x
  simp only [hom_bind₁]
  specialize h (ULift ℤ) (mk p fun i => ⟨x i⟩) k
  simp only [ghostComponent_apply, aeval_eq_eval₂Hom] at h
  apply (ULift.ringEquiv.symm : ℤ ≃+* _).injective
  simp only [← RingEquiv.coe_toRingHom, map_eval₂Hom]
  convert h using 1
  all_goals
    --  porting note: this proof started with `funext i`
    simp only [hf, hg, MvPolynomial.eval, map_eval₂Hom]
    apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
    ext1
    

Proof state:
case h
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
inst✝ : Fact (Nat.Prime p)
f g : ⦃R : Type u⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type u⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
R✝ : Type u
_Rcr✝ : CommRing R✝
x✝¹ : 𝕎 R✝
n k : ℕ
x : ℕ → ℤ
h :
  (aeval (f (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k) =
    (aeval (g (mk p fun i => { down := x i })).coeff) (wittPolynomial p ℤ k)
x✝ : ℕ
⊢ (eval₂Hom (RingHom.comp (↑(RingEquiv.symm ULift.ringEquiv)) (RingHom.id ℤ)) fun i =>
        ↑(RingEquiv.symm ULift.ringEquiv) (x i))
      (ψ x✝) =
    (aeval (mk p fun i => { down := x i }).coeff) (ψ x✝)

Next tactic:
apply eval₂Hom_congr (RingHom.ext_int _ _) _ rfl
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance comp {g f} [hg : IsPoly p g] [hf : IsPoly p f] :
    IsPoly p fun R _Rcr => @g R _Rcr ∘ @f R _Rcr := by
  

Proof state:
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝¹ : CommRing R
inst✝ : CommRing S
g f : ⦃R : Type ?u.278535⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
hg : IsPoly p g
hf : IsPoly p f
⊢ IsPoly p fun R _Rcr => g ∘ f

Next tactic:
obtain ⟨φ, hf⟩ := hf
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance comp {g f} [hg : IsPoly p g] [hf : IsPoly p f] :
    IsPoly p fun R _Rcr => @g R _Rcr ∘ @f R _Rcr := by
  obtain ⟨φ, hf⟩ := hf
  

Proof state:
case mk'.intro
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝¹ : CommRing R
inst✝ : CommRing S
g f : ⦃R : Type ?u.278535⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
hg : IsPoly p g
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type ?u.278535⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
⊢ IsPoly p fun R _Rcr => g ∘ f

Next tactic:
obtain ⟨ψ, hg⟩ := hg
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance comp {g f} [hg : IsPoly p g] [hf : IsPoly p f] :
    IsPoly p fun R _Rcr => @g R _Rcr ∘ @f R _Rcr := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  

Proof state:
case mk'.intro.mk'.intro
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝¹ : CommRing R
inst✝ : CommRing S
g f : ⦃R : Type ?u.278535⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type ?u.278535⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type ?u.278535⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
⊢ IsPoly p fun R _Rcr => g ∘ f

Next tactic:
use fun n => bind₁ φ (ψ n)
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance comp {g f} [hg : IsPoly p g] [hf : IsPoly p f] :
    IsPoly p fun R _Rcr => @g R _Rcr ∘ @f R _Rcr := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  use fun n => bind₁ φ (ψ n)
  

Proof state:
case h
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝¹ : CommRing R
inst✝ : CommRing S
g f : ⦃R : Type ?u.278535⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type ?u.278535⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type ?u.278535⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
⊢ ∀ ⦃R : Type ?u.278535⦄ [inst : CommRing R] (x : 𝕎 R), ((g ∘ f) x).coeff = fun n => (aeval x.coeff) ((bind₁ φ) (ψ n))

Next tactic:
intros
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance comp {g f} [hg : IsPoly p g] [hf : IsPoly p f] :
    IsPoly p fun R _Rcr => @g R _Rcr ∘ @f R _Rcr := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  use fun n => bind₁ φ (ψ n)
  intros
  

Proof state:
case h
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
g f : ⦃R : Type ?u.278535⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type ?u.278535⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type ?u.278535⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
R✝ : Type ?u.278535
inst✝ : CommRing R✝
x✝ : 𝕎 R✝
⊢ ((g ∘ f) x✝).coeff = fun n => (aeval x✝.coeff) ((bind₁ φ) (ψ n))

Next tactic:
simp only [aeval_bind₁, Function.comp, hg, hf]
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance IsPoly₂.comp {h f g} [hh : IsPoly₂ p h] [hf : IsPoly p f] [hg : IsPoly p g] :
    IsPoly₂ p fun R _Rcr x y => h (f x) (g y) := by
  

Proof state:
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝¹ : CommRing R
inst✝ : CommRing S
h : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R → 𝕎 R
f g : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
hh : IsPoly₂ p h
hf : IsPoly p f
hg : IsPoly p g
⊢ IsPoly₂ p fun R _Rcr x y => h (f x) (g y)

Next tactic:
obtain ⟨φ, hf⟩ := hf
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance IsPoly₂.comp {h f g} [hh : IsPoly₂ p h] [hf : IsPoly p f] [hg : IsPoly p g] :
    IsPoly₂ p fun R _Rcr x y => h (f x) (g y) := by
  obtain ⟨φ, hf⟩ := hf
  

Proof state:
case mk'.intro
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝¹ : CommRing R
inst✝ : CommRing S
h : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R → 𝕎 R
f g : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
hh : IsPoly₂ p h
hg : IsPoly p g
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
⊢ IsPoly₂ p fun R _Rcr x y => h (f x) (g y)

Next tactic:
obtain ⟨ψ, hg⟩ := hg
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance IsPoly₂.comp {h f g} [hh : IsPoly₂ p h] [hf : IsPoly p f] [hg : IsPoly p g] :
    IsPoly₂ p fun R _Rcr x y => h (f x) (g y) := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  

Proof state:
case mk'.intro.mk'.intro
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝¹ : CommRing R
inst✝ : CommRing S
h : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R → 𝕎 R
f g : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
hh : IsPoly₂ p h
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
⊢ IsPoly₂ p fun R _Rcr x y => h (f x) (g y)

Next tactic:
obtain ⟨χ, hh⟩ := hh
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance IsPoly₂.comp {h f g} [hh : IsPoly₂ p h] [hf : IsPoly p f] [hg : IsPoly p g] :
    IsPoly₂ p fun R _Rcr x y => h (f x) (g y) := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  obtain ⟨χ, hh⟩ := hh
  

Proof state:
case mk'.intro.mk'.intro.mk'.intro
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝¹ : CommRing R
inst✝ : CommRing S
h : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R → 𝕎 R
f g : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
χ : ℕ → MvPolynomial (Fin 2 × ℕ) ℤ
hh : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x y : 𝕎 R), (h x y).coeff = fun n => peval (χ n) ![x.coeff, y.coeff]
⊢ IsPoly₂ p fun R _Rcr x y => h (f x) (g y)

Next tactic:
refine' ⟨⟨fun n ↦ bind₁ (uncurry <|
    ![fun k ↦ rename (Prod.mk (0 : Fin 2)) (φ k),
      fun k ↦ rename (Prod.mk (1 : Fin 2)) (ψ k)]) (χ n), _⟩⟩
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance IsPoly₂.comp {h f g} [hh : IsPoly₂ p h] [hf : IsPoly p f] [hg : IsPoly p g] :
    IsPoly₂ p fun R _Rcr x y => h (f x) (g y) := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  obtain ⟨χ, hh⟩ := hh
  refine' ⟨⟨fun n ↦ bind₁ (uncurry <|
    ![fun k ↦ rename (Prod.mk (0 : Fin 2)) (φ k),
      fun k ↦ rename (Prod.mk (1 : Fin 2)) (ψ k)]) (χ n), _⟩⟩
  

Proof state:
case mk'.intro.mk'.intro.mk'.intro
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝¹ : CommRing R
inst✝ : CommRing S
h : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R → 𝕎 R
f g : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
χ : ℕ → MvPolynomial (Fin 2 × ℕ) ℤ
hh : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x y : 𝕎 R), (h x y).coeff = fun n => peval (χ n) ![x.coeff, y.coeff]
⊢ ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x y : 𝕎 R),
    (h (f x) (g y)).coeff = fun n =>
      peval
        ((fun n => (bind₁ (uncurry ![fun k => (rename (Prod.mk 0)) (φ k), fun k => (rename (Prod.mk 1)) (ψ k)])) (χ n))
          n)
        ![x.coeff, y.coeff]

Next tactic:
intros
/-- The composition of polynomial functions is polynomial. -/
-- Porting note: made this an instance
instance IsPoly₂.comp {h f g} [hh : IsPoly₂ p h] [hf : IsPoly p f] [hg : IsPoly p g] :
    IsPoly₂ p fun R _Rcr x y => h (f x) (g y) := by
  obtain ⟨φ, hf⟩ := hf
  obtain ⟨ψ, hg⟩ := hg
  obtain ⟨χ, hh⟩ := hh
  refine' ⟨⟨fun n ↦ bind₁ (uncurry <|
    ![fun k ↦ rename (Prod.mk (0 : Fin 2)) (φ k),
      fun k ↦ rename (Prod.mk (1 : Fin 2)) (ψ k)]) (χ n), _⟩⟩
  intros
  

Proof state:
case mk'.intro.mk'.intro.mk'.intro
p : ℕ
R S : Type u
σ : Type u_1
idx : Type u_2
inst✝² : CommRing R
inst✝¹ : CommRing S
h : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R → 𝕎 R
f g : ⦃R : Type ?u.296313⦄ → [inst : CommRing R] → 𝕎 R → 𝕎 R
φ : ℕ → MvPolynomial ℕ ℤ
hf : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x : 𝕎 R), (f x).coeff = fun n => (aeval x.coeff) (φ n)
ψ : ℕ → MvPolynomial ℕ ℤ
hg : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x : 𝕎 R), (g x).coeff = fun n => (aeval x.coeff) (ψ n)
χ : ℕ → MvPolynomial (Fin 2 × ℕ) ℤ
hh : ∀ ⦃R : Type ?u.296313⦄ [inst : CommRing R] (x y : 𝕎 R), (h x y).coeff = fun n => peval (χ n) ![x.coeff, y.coeff]
R✝ : Type ?u.296313
inst✝ : CommRing R✝
x✝ y✝ : 𝕎 R✝
⊢ (h (f x✝) (g y✝)).coeff = fun n =>
    peval
      ((fun n => (bind₁ (uncurry ![fun k => (rename (Prod.mk 0)) (φ k), fun k => (rename (Prod.mk 1)) (ψ k)])) (χ n)) n)
      ![x✝.coeff, y✝.coeff]

Next tactic:
funext n