Theorem: numDerangements_tendsto_inv_e
File: Mathlib/Combinatorics/Derangements/Exponential.lean

Proof steps:
state_before: ⊢ Tendsto (fun n => ↑(numDerangements n) / ↑n.factorial) atTop (𝓝 (Real.exp (-1)))
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
⊢ Tendsto (fun n => ↑(numDerangements n) / ↑n.factorial) atTop (𝓝 (Real.exp (-1)))
tactic: let s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1 : ℝ) ^ k / k.factorial
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
⊢ Tendsto (fun n => ↑(numDerangements n) / ↑n.factorial) atTop (𝓝 (Real.exp (-1)))
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
⊢ ∀ (n : ℕ), ↑(numDerangements n) / ↑n.factorial = s (n + 1)
tactic: suffices ∀ n : ℕ, (numDerangements n : ℝ) / n.factorial = s (n + 1) by
    simp_rw [this]
    -- shift the function by 1, and then use the fact that the partial sums
    -- converge to the infinite sum
    rw [tendsto_add_atTop_iff_nat
      (f := fun n => ∑ k ∈ Finset.range n, (-1 : ℝ) ^ k / k.factorial) 1]
    apply HasSum.tendsto_sum_nat
    -- there's no specific lemma for ℝ that ∑ x^k/k! sums to exp(x), but it's
    -- true in more general fields, so use that lemma
    rw [Real.exp_eq_exp_ℝ]
    exact expSeries_div_hasSum_exp ℝ (-1 : ℝ)
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
⊢ ∀ (n : ℕ), ↑(numDerangements n) / ↑n.factorial = s (n + 1)
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ ↑(numDerangements n) / ↑n.factorial = s (n + 1)
tactic: intro n
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ ↑(numDerangements n) / ↑n.factorial = s (n + 1)
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ ↑(∑ k ∈ Finset.range (n + 1), (-1) ^ k * ↑((k + 1).ascFactorial (n - k))) / ↑n.factorial = s (n + 1)
tactic: rw [← Int.cast_natCast, numDerangements_sum]
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ ↑(∑ k ∈ Finset.range (n + 1), (-1) ^ k * ↑((k + 1).ascFactorial (n - k))) / ↑n.factorial = s (n + 1)
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ (∑ x ∈ Finset.range (n + 1), (-1) ^ x * ↑((x + 1).ascFactorial (n - x))) / ↑n.factorial = s (n + 1)
tactic: push_cast
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ (∑ x ∈ Finset.range (n + 1), (-1) ^ x * ↑((x + 1).ascFactorial (n - x))) / ↑n.factorial = s (n + 1)
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ ∑ i ∈ Finset.range (n + 1), (-1) ^ i * ↑((i + 1).ascFactorial (n - i)) / ↑n.factorial = s (n + 1)
tactic: rw [Finset.sum_div]
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ ∑ i ∈ Finset.range (n + 1), (-1) ^ i * ↑((i + 1).ascFactorial (n - i)) / ↑n.factorial = s (n + 1)
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ ∀ x ∈ Finset.range (n + 1), (-1) ^ x * ↑((x + 1).ascFactorial (n - x)) / ↑n.factorial = (-1) ^ x / ↑x.factorial
tactic: refine Finset.sum_congr (refl _) ?_
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n : ℕ
⊢ ∀ x ∈ Finset.range (n + 1), (-1) ^ x * ↑((x + 1).ascFactorial (n - x)) / ↑n.factorial = (-1) ^ x / ↑x.factorial
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
⊢ (-1) ^ k * ↑((k + 1).ascFactorial (n - k)) / ↑n.factorial = (-1) ^ k / ↑k.factorial
tactic: intro k hk
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
⊢ (-1) ^ k * ↑((k + 1).ascFactorial (n - k)) / ↑n.factorial = (-1) ^ k / ↑k.factorial
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
h_le : k ≤ n
⊢ (-1) ^ k * ↑((k + 1).ascFactorial (n - k)) / ↑n.factorial = (-1) ^ k / ↑k.factorial
tactic: have h_le : k ≤ n := Finset.mem_range_succ_iff.mp hk
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
h_le : k ≤ n
⊢ (-1) ^ k * ↑((k + 1).ascFactorial (n - k)) / ↑n.factorial = (-1) ^ k / ↑k.factorial
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
h_le : k ≤ n
⊢ (-1) ^ k * ↑(n.factorial / k.factorial) / ↑n.factorial = (-1) ^ k / ↑k.factorial
tactic: rw [Nat.ascFactorial_eq_div, add_tsub_cancel_of_le h_le]
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
h_le : k ≤ n
⊢ (-1) ^ k * ↑(n.factorial / k.factorial) / ↑n.factorial = (-1) ^ k / ↑k.factorial
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
h_le : k ≤ n
⊢ (-1) ^ k * (↑n.factorial / ↑k.factorial) / ↑n.factorial = (-1) ^ k / ↑k.factorial
tactic: push_cast [Nat.factorial_dvd_factorial h_le]
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
h_le : k ≤ n
⊢ (-1) ^ k * (↑n.factorial / ↑k.factorial) / ↑n.factorial = (-1) ^ k / ↑k.factorial
state_after: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
h_le : k ≤ n
⊢ (-1) ^ k * ↑n.factorial * ↑k.factorial = (-1) ^ k * (↑k.factorial * ↑n.factorial)
tactic: field_simp [Nat.factorial_ne_zero]
state_before: s : ℕ → ℝ := fun n => ∑ k ∈ Finset.range n, (-1) ^ k / ↑k.factorial
n k : ℕ
hk : k ∈ Finset.range (n + 1)
h_le : k ≤ n
⊢ (-1) ^ k * ↑n.factorial * ↑k.factorial = (-1) ^ k * (↑k.factorial * ↑n.factorial)
state_after: no goals
tactic: ring