-- Mathlib/RingTheory/Polynomial/Hermite/Basic.lean
theorem coeff_hermite_explicit :
    ∀ n k : ℕ, coeff (hermite (2 * n + k)) k = (-1) ^ n * (2 * n - 1)‼ * Nat.choose (2 * n + k) k
  | 0, _ => by simp
  | n + 1, 0 => by
    convert coeff_hermite_succ_zero (2 * n + 1) using 1
    -- Porting note: ring_nf did not solve the goal on line 165
    rw [coeff_hermite_explicit n 1, (by rw [Nat.left_distrib, mul_one, Nat.add_one_sub_one] :
      2 * (n + 1) - 1 = 2 * n + 1), Nat.doubleFactorial_add_one, Nat.choose_zero_right,
      Nat.choose_one_right, pow_succ]
    push_cast
    ring
  | n + 1, k + 1 => by
    let hermite_explicit : ℕ → ℕ → ℤ := fun n k =>
      (-1) ^ n * (2 * n - 1)‼ * Nat.choose (2 * n + k) k
    have hermite_explicit_recur :
      ∀ n k : ℕ,
        hermite_explicit (n + 1) (k + 1) =
          hermite_explicit (n + 1) k - (k + 2) * hermite_explicit n (k + 2)

Proof state:
n k : ℕ
hermite_explicit : ℕ → ℕ → ℤ := fun n k => (-1) ^ n * ↑(2 * n - 1)‼ * ↑((2 * n + k).choose k)
⊢ (hermite (2 * (n + 1) + (k + 1))).coeff (k + 1) =
    (-1) ^ (n + 1) * ↑(2 * (n + 1) - 1)‼ * ↑((2 * (n + 1) + (k + 1)).choose (k + 1))

Tactic:
have hermite_explicit_recur :
  ∀ n k : ℕ,
    hermite_explicit (n + 1) (k + 1) =
      hermite_explicit (n + 1) k - (k + 2) * hermite_explicit n (k + 2) := by
  intro n k
  simp only [hermite_explicit]
  rw [mul_comm (↑k + _ : ℤ), sub_eq_add_neg]
  nth_rw 3 [neg_eq_neg_one_mul]
  simp only [mul_assoc, ← mul_add, pow_succ']
  congr 2
  norm_cast
  rw [(by rw [Nat.left_distrib, mul_one, Nat.add_one_sub_one] : 2 * (n + 1) - 1 = 2 * n + 1),
    Nat.doubleFactorial_add_one, mul_comm (2 * n + 1)]
  simp only [mul_assoc, ← mul_add]
  congr 1
  rw [(by ring : 2 * (n + 1) + (k + 1) = 2 * n + 1 + (k + 1) + 1),
    (by ring : 2 * (n + 1) + k = 2 * n + 1 + (k + 1)),
    (by ring : 2 * n + (k + 2) = 2 * n + 1 + (k + 1))]
  rw [Nat.choose, Nat.choose_succ_right_eq (2 * n + 1 + (k + 1)) (k + 1), Nat.add_sub_cancel]
  ring

Result:
n k : ℕ
hermite_explicit : ℕ → ℕ → ℤ := fun n k => (-1) ^ n * ↑(2 * n - 1)‼ * ↑((2 * n + k).choose k)
hermite_explicit_recur :
  ∀ (n k : ℕ), hermite_explicit (n + 1) (k + 1) = hermite_explicit (n + 1) k - (↑k + 2) * hermite_explicit n (k + 2)
⊢ (hermite (2 * (n + 1) + (k + 1))).coeff (k + 1) =
    (-1) ^ (n + 1) * ↑(2 * (n + 1) - 1)‼ * ↑((2 * (n + 1) + (k + 1)).choose (k + 1))

Proof state:
case h.e'_3
n : ℕ
⊢ (-1) ^ n * -1 * ((2 * ↑n + 1) * ↑(2 * n - 1)‼) * 1 = -((-1) ^ n * ↑(2 * n - 1)‼ * (2 * ↑n + 1))

Tactic:
ring

Result:
no goals

Proof state:
n k : ℕ
⊢ (hermite (2 * (n + 1) + (k + 1))).coeff (k + 1) =
    (-1) ^ (n + 1) * ↑(2 * (n + 1) - 1)‼ * ↑((2 * (n + 1) + (k + 1)).choose (k + 1))

Tactic:
let hermite_explicit : ℕ → ℕ → ℤ := fun n k =>
  (-1) ^ n * (2 * n - 1)‼ * Nat.choose (2 * n + k) k

Result:
n k : ℕ
hermite_explicit : ℕ → ℕ → ℤ := fun n k => (-1) ^ n * ↑(2 * n - 1)‼ * ↑((2 * n + k).choose k)
⊢ (hermite (2 * (n + 1) + (k + 1))).coeff (k + 1) =
    (-1) ^ (n + 1) * ↑(2 * (n + 1) - 1)‼ * ↑((2 * (n + 1) + (k + 1)).choose (k + 1))

Proof state:
n✝ k✝ : ℕ
hermite_explicit : ℕ → ℕ → ℤ := fun n k => (-1) ^ n * ↑(2 * n - 1)‼ * ↑((2 * n + k).choose k)
n k : ℕ
⊢ 2 * (n + 1) + (k + 1) = 2 * n + 1 + (k + 1) + 1

Tactic:
ring

Result:
no goals

Proof state:
n k : ℕ
hermite_explicit : ℕ → ℕ → ℤ := fun n k => (-1) ^ n * ↑(2 * n - 1)‼ * ↑((2 * n + k).choose k)
hermite_explicit_recur :
  ∀ (n k : ℕ), hermite_explicit (n + 1) (k + 1) = hermite_explicit (n + 1) k - (↑k + 2) * hermite_explicit n (k + 2)
⊢ 2 * (n + 1) + k = 2 * n + (k + 2)

Tactic:
ring

Result:
no goals

Proof state:
case e_a.e_a
n✝ k✝ : ℕ
hermite_explicit : ℕ → ℕ → ℤ := fun n k => (-1) ^ n * ↑(2 * n - 1)‼ * ↑((2 * n + k).choose k)
n k : ℕ
⊢ (2 * (n + 1) - 1)‼ * (2 * (n + 1) + (k + 1)).choose (k + 1) =
    (2 * (n + 1) - 1)‼ * (2 * (n + 1) + k).choose k + (2 * n - 1)‼ * ((2 * n + (k + 2)).choose (k + 2) * (k + 2))

Tactic:
rw [(by rw [Nat.left_distrib, mul_one, Nat.add_one_sub_one] : 2 * (n + 1) - 1 = 2 * n + 1),
  Nat.doubleFactorial_add_one, mul_comm (2 * n + 1)]

Result:
case e_a.e_a
n✝ k✝ : ℕ
hermite_explicit : ℕ → ℕ → ℤ := fun n k => (-1) ^ n * ↑(2 * n - 1)‼ * ↑((2 * n + k).choose k)
n k : ℕ
⊢ (2 * n - 1)‼ * (2 * n + 1) * (2 * (n + 1) + (k + 1)).choose (k + 1) =
    (2 * n - 1)‼ * (2 * n + 1) * (2 * (n + 1) + k).choose k +
      (2 * n - 1)‼ * ((2 * n + (k + 2)).choose (k + 2) * (k + 2))