-- Mathlib/RingTheory/WittVector/MulCoeff.lean
theorem nth_mul_coeff' (n : ℕ) :
    ∃ f : TruncatedWittVector p (n + 1) k → TruncatedWittVector p (n + 1) k → k,
    ∀ x y : 𝕎 k, f (truncateFun (n + 1) x) (truncateFun (n + 1) y) =
      (x * y).coeff (n + 1) - y.coeff (n + 1) * x.coeff 0 ^ p ^ (n + 1) -
        x.coeff (n + 1) * y.coeff 0 ^ p ^ (n + 1)

Proof state:
case mk
p : ℕ
hp : Fact (Nat.Prime p)
k : Type u_1
inst✝¹ : CommRing k
inst✝ : CharP k p
n : ℕ
f₀ : (↑(Membership.mem (univ ×ˢ range (n + 1)).val) → k) → k
hf₀ : ∀ (x : Fin 2 × ℕ → k), f₀ (x ∘ Subtype.val) = (aeval x) (polyOfInterest p n)
this : ∀ (a : Multiset (Fin 2)) (b : Multiset ℕ), a ×ˢ b = a.product b
x y : TruncatedWittVector p (n + 1) k
a : Fin 2 × ℕ
ha : a ∈ Membership.mem (univ ×ˢ range (n + 1)).val
⊢ k

Tactic:
apply Function.uncurry ![x, y]

Result:
case mk
p : ℕ
hp : Fact (Nat.Prime p)
k : Type u_1
inst✝¹ : CommRing k
inst✝ : CharP k p
n : ℕ
f₀ : (↑(Membership.mem (univ ×ˢ range (n + 1)).val) → k) → k
hf₀ : ∀ (x : Fin 2 × ℕ → k), f₀ (x ∘ Subtype.val) = (aeval x) (polyOfInterest p n)
this : ∀ (a : Multiset (Fin 2)) (b : Multiset ℕ), a ×ˢ b = a.product b
x y : TruncatedWittVector p (n + 1) k
a : Fin 2 × ℕ
ha : a ∈ Membership.mem (univ ×ˢ range (n + 1)).val
⊢ Fin (Nat.succ 0).succ × Fin (n + 1)

Proof state:
case h.e_a.h
p : ℕ
hp : Fact (Nat.Prime p)
k : Type u_1
inst✝¹ : CommRing k
inst✝ : CharP k p
n : ℕ
f₀ : (↑(Membership.mem (univ ×ˢ range (n + 1)).val) → k) → k
hf₀ : ∀ (x : Fin 2 × ℕ → k), f₀ (x ∘ Subtype.val) = (aeval x) (polyOfInterest p n)
this : ∀ (a : Multiset (Fin 2)) (b : Multiset ℕ), a ×ˢ b = a.product b
f : TruncatedWittVector p (n + 1) k → TruncatedWittVector p (n + 1) k → k :=
  fun x y =>
    f₀ fun a =>
      Subtype.casesOn a fun a ha =>
        Function.uncurry ![x, y]
          (let S := fun a => a.2 = n ∨ a.2 < n;
          let_fun ha' := ⋯;
          (a.1, ⟨a.2, ⋯⟩))
x y : 𝕎 k
a : ↑(Membership.mem (univ.val ×ˢ Multiset.range (n + 1)))
⊢ ![truncateFun (n + 1) x, truncateFun (n + 1) y] (↑a).1 ⟨(↑a).2, ⋯⟩ =
    (Function.uncurry ![fun i => x.coeff i, fun i => y.coeff i] ∘ Subtype.val) a

Tactic:
obtain ⟨a, ha⟩ := a

Result:
case h.e_a.h.mk
p : ℕ
hp : Fact (Nat.Prime p)
k : Type u_1
inst✝¹ : CommRing k
inst✝ : CharP k p
n : ℕ
f₀ : (↑(Membership.mem (univ ×ˢ range (n + 1)).val) → k) → k
hf₀ : ∀ (x : Fin 2 × ℕ → k), f₀ (x ∘ Subtype.val) = (aeval x) (polyOfInterest p n)
this : ∀ (a : Multiset (Fin 2)) (b : Multiset ℕ), a ×ˢ b = a.product b
f : TruncatedWittVector p (n + 1) k → TruncatedWittVector p (n + 1) k → k :=
  fun x y =>
    f₀ fun a =>
      Subtype.casesOn a fun a ha =>
        Function.uncurry ![x, y]
          (let S := fun a => a.2 = n ∨ a.2 < n;
          let_fun ha' := ⋯;
          (a.1, ⟨a.2, ⋯⟩))
x y : 𝕎 k
a : Fin 2 × ℕ
ha : a ∈ Membership.mem (univ.val ×ˢ Multiset.range (n + 1))
⊢ ![truncateFun (n + 1) x, truncateFun (n + 1) y] (↑⟨a, ha⟩).1 ⟨(↑⟨a, ha⟩).2, ⋯⟩ =
    (Function.uncurry ![fun i => x.coeff i, fun i => y.coeff i] ∘ Subtype.val) ⟨a, ha⟩

Proof state:
case intro
p : ℕ
hp : Fact (Nat.Prime p)
k : Type u_1
inst✝¹ : CommRing k
inst✝ : CharP k p
n : ℕ
f₀ : (↑(Membership.mem (univ ×ˢ range (n + 1)).val) → k) → k
hf₀ : ∀ (x : Fin 2 × ℕ → k), f₀ (x ∘ Subtype.val) = (aeval x) (polyOfInterest p n)
this : ∀ (a : Multiset (Fin 2)) (b : Multiset ℕ), a ×ˢ b = a.product b
⊢ ∃ f,
    ∀ (x y : 𝕎 k),
      f (truncateFun (n + 1) x) (truncateFun (n + 1) y) =
        peval (polyOfInterest p n) ![fun i => x.coeff i, fun i => y.coeff i]

Tactic:
let f : TruncatedWittVector p (n + 1) k → TruncatedWittVector p (n + 1) k → k := by
  intro x y
  apply f₀
  rintro ⟨a, ha⟩
  apply Function.uncurry ![x, y]
  simp_rw [product_val, this, range_val, Multiset.range_succ] at ha
  let S : Set (Fin 2 × ℕ) := (fun a => a.2 = n ∨ a.2 < n)
  have ha' : a ∈ S := by
    convert ha
    dsimp [S]
    congr!
    simp
  refine ⟨a.fst, ⟨a.snd, ?_⟩⟩
  obtain ⟨ha, ha⟩ := ha' <;> omega

Result:
case intro
p : ℕ
hp : Fact (Nat.Prime p)
k : Type u_1
inst✝¹ : CommRing k
inst✝ : CharP k p
n : ℕ
f₀ : (↑(Membership.mem (univ ×ˢ range (n + 1)).val) → k) → k
hf₀ : ∀ (x : Fin 2 × ℕ → k), f₀ (x ∘ Subtype.val) = (aeval x) (polyOfInterest p n)
this : ∀ (a : Multiset (Fin 2)) (b : Multiset ℕ), a ×ˢ b = a.product b
f : TruncatedWittVector p (n + 1) k → TruncatedWittVector p (n + 1) k → k :=
  fun x y =>
    f₀ fun a =>
      Subtype.casesOn a fun a ha =>
        Function.uncurry ![x, y]
          (let S := fun a => a.2 = n ∨ a.2 < n;
          let_fun ha' := ⋯;
          (a.1, ⟨a.2, ⋯⟩))
⊢ ∃ f,
    ∀ (x y : 𝕎 k),
      f (truncateFun (n + 1) x) (truncateFun (n + 1) y) =
        peval (polyOfInterest p n) ![fun i => x.coeff i, fun i => y.coeff i]

Proof state:
case intro
p : ℕ
hp : Fact (Nat.Prime p)
k : Type u_1
inst✝¹ : CommRing k
inst✝ : CharP k p
n : ℕ
f₀ : (↑(Membership.mem (univ ×ˢ range (n + 1)).val) → k) → k
hf₀ : ∀ (x : Fin 2 × ℕ → k), f₀ (x ∘ Subtype.val) = (aeval x) (polyOfInterest p n)
this : ∀ (a : Multiset (Fin 2)) (b : Multiset ℕ), a ×ˢ b = a.product b
f : TruncatedWittVector p (n + 1) k → TruncatedWittVector p (n + 1) k → k :=
  fun x y =>
    f₀ fun a =>
      Subtype.casesOn a fun a ha =>
        Function.uncurry ![x, y]
          (let S := fun a => a.2 = n ∨ a.2 < n;
          let_fun ha' := ⋯;
          (a.1, ⟨a.2, ⋯⟩))
⊢ ∃ f,
    ∀ (x y : 𝕎 k),
      f (truncateFun (n + 1) x) (truncateFun (n + 1) y) =
        peval (polyOfInterest p n) ![fun i => x.coeff i, fun i => y.coeff i]

Tactic:
use f

Result:
case h
p : ℕ
hp : Fact (Nat.Prime p)
k : Type u_1
inst✝¹ : CommRing k
inst✝ : CharP k p
n : ℕ
f₀ : (↑(Membership.mem (univ ×ˢ range (n + 1)).val) → k) → k
hf₀ : ∀ (x : Fin 2 × ℕ → k), f₀ (x ∘ Subtype.val) = (aeval x) (polyOfInterest p n)
this : ∀ (a : Multiset (Fin 2)) (b : Multiset ℕ), a ×ˢ b = a.product b
f : TruncatedWittVector p (n + 1) k → TruncatedWittVector p (n + 1) k → k :=
  fun x y =>
    f₀ fun a =>
      Subtype.casesOn a fun a ha =>
        Function.uncurry ![x, y]
          (let S := fun a => a.2 = n ∨ a.2 < n;
          let_fun ha' := ⋯;
          (a.1, ⟨a.2, ⋯⟩))
⊢ ∀ (x y : 𝕎 k),
    f (truncateFun (n + 1) x) (truncateFun (n + 1) y) =
      peval (polyOfInterest p n) ![fun i => x.coeff i, fun i => y.coeff i]

Proof state:
case h.e'_4.h.a
p : ℕ
hp : Fact (Nat.Prime p)
k : Type u_1
inst✝¹ : CommRing k
inst✝ : CharP k p
n : ℕ
f₀ : (↑(Membership.mem (univ ×ˢ range (n + 1)).val) → k) → k
hf₀ : ∀ (x : Fin 2 × ℕ → k), f₀ (x ∘ Subtype.val) = (aeval x) (polyOfInterest p n)
this : ∀ (a : Multiset (Fin 2)) (b : Multiset ℕ), a ×ˢ b = a.product b
x y : TruncatedWittVector p (n + 1) k
a : Fin 2 × ℕ
ha : a ∈ Membership.mem (univ.val.product (n ::ₘ Multiset.range n))
S : Set (Fin 2 × ℕ) := fun a => a.2 = n ∨ a.2 < n
x✝ : Fin 2 × ℕ
⊢ x✝.2 = n ∨ x✝.2 < n ↔ x✝ ∈ univ.val.product (n ::ₘ Multiset.range n)

Tactic:
simp

Result:
no goals