l3lab/ntp-mathlib huggingface dataset:
theorem summable_of_locally_summable_norm {ι : Type*} {F : ι → C(X, E)}
    (hF : ∀ K : Compacts X, Summable fun i => ‖(F i).restrict K‖) : Summable F := by
  refine' (ContinuousMap.exists_tendsto_compactOpen_iff_forall _).2 fun K hK => _
  lift K to Compacts X using hK
  have A : ∀ s : Finset ι, restrict (↑K) (∑ i in s, F i) = ∑ i in s, restrict K (F i) := by
    intro s
    ext1 x
    simp
    -- This used to be the end of the proof before leanprover/lean4#2644
    erw [restrict_apply, restrict_apply, restrict_apply, restrict_apply]
    simp? says simp only [coe_sum, Finset.sum_apply]
    congr!
  

Proof state:
case intro
X : Type u_1
inst✝⁴ : TopologicalSpace X
inst✝³ : T2Space X
inst✝² : LocallyCompactSpace X
E : Type u_2
inst✝¹ : NormedAddCommGroup E
inst✝ : CompleteSpace E
ι : Type u_3
F : ι → C(X, E)
hF : ∀ (K : Compacts X), Summable fun i => ‖restrict (↑K) (F i)‖
K : Compacts X
A : ∀ (s : Finset ι), restrict (↑K) (∑ i in s, F i) = ∑ i in s, restrict (↑K) (F i)
⊢ ∃ f, Tendsto (fun i => restrict (↑K) (∑ b in i, F b)) atTop (𝓝 f)

Next tactic:
simpa only [HasSum, A] using (hF K).of_norm
instance [CompactSpace α] : NormedStarGroup C(α, β) where
  norm_star f := by
    

Proof state:
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedAddCommGroup β
inst✝² : StarAddMonoid β
inst✝¹ : NormedStarGroup β
inst✝ : CompactSpace α
f : C(α, β)
⊢ ‖star f‖ = ‖f‖

Next tactic:
rw [← BoundedContinuousFunction.norm_mkOfCompact, BoundedContinuousFunction.mkOfCompact_star,
      norm_star, BoundedContinuousFunction.norm_mkOfCompact]
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    

Proof state:
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
⊢ ‖star f * f‖ = ‖f‖ * ‖f‖

Next tactic:
refine' le_antisymm _ _
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · 

Proof state:
case refine'_1
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
⊢ ‖star f * f‖ ≤ ‖f‖ * ‖f‖

Next tactic:
rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
      

Proof state:
case refine'_1
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
⊢ ∀ (x : α), ‖(star f * f) x‖ ≤ ‖f‖ ^ 2

Next tactic:
intro x
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
      intro x
      

Proof state:
case refine'_1
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
x : α
⊢ ‖(star f * f) x‖ ≤ ‖f‖ ^ 2

Next tactic:
simp only [ContinuousMap.coe_mul, coe_star, Pi.mul_apply, Pi.star_apply,
        CstarRing.norm_star_mul_self, ← sq]
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
      intro x
      simp only [ContinuousMap.coe_mul, coe_star, Pi.mul_apply, Pi.star_apply,
        CstarRing.norm_star_mul_self, ← sq]
      

Proof state:
case refine'_1
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
x : α
⊢ ‖f x‖ ^ 2 ≤ ‖f‖ ^ 2

Next tactic:
refine' sq_le_sq' _ _
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
      intro x
      simp only [ContinuousMap.coe_mul, coe_star, Pi.mul_apply, Pi.star_apply,
        CstarRing.norm_star_mul_self, ← sq]
      refine' sq_le_sq' _ _
      · 

Proof state:
case refine'_1.refine'_1
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
x : α
⊢ -‖f‖ ≤ ‖f x‖

Next tactic:
linarith [norm_nonneg (f x), norm_nonneg f]
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
      intro x
      simp only [ContinuousMap.coe_mul, coe_star, Pi.mul_apply, Pi.star_apply,
        CstarRing.norm_star_mul_self, ← sq]
      refine' sq_le_sq' _ _
      · linarith [norm_nonneg (f x), norm_nonneg f]
      · 

Proof state:
case refine'_1.refine'_2
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
x : α
⊢ ‖f x‖ ≤ ‖f‖

Next tactic:
exact ContinuousMap.norm_coe_le_norm f x
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
      intro x
      simp only [ContinuousMap.coe_mul, coe_star, Pi.mul_apply, Pi.star_apply,
        CstarRing.norm_star_mul_self, ← sq]
      refine' sq_le_sq' _ _
      · linarith [norm_nonneg (f x), norm_nonneg f]
      · exact ContinuousMap.norm_coe_le_norm f x
    · 

Proof state:
case refine'_2
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
⊢ ‖f‖ * ‖f‖ ≤ ‖star f * f‖

Next tactic:
rw [← sq, ← Real.le_sqrt (norm_nonneg _) (norm_nonneg _),
        ContinuousMap.norm_le _ (Real.sqrt_nonneg _)]
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
      intro x
      simp only [ContinuousMap.coe_mul, coe_star, Pi.mul_apply, Pi.star_apply,
        CstarRing.norm_star_mul_self, ← sq]
      refine' sq_le_sq' _ _
      · linarith [norm_nonneg (f x), norm_nonneg f]
      · exact ContinuousMap.norm_coe_le_norm f x
    · rw [← sq, ← Real.le_sqrt (norm_nonneg _) (norm_nonneg _),
        ContinuousMap.norm_le _ (Real.sqrt_nonneg _)]
      

Proof state:
case refine'_2
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
⊢ ∀ (x : α), ‖f x‖ ≤ Real.sqrt ‖star f * f‖

Next tactic:
intro x
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
      intro x
      simp only [ContinuousMap.coe_mul, coe_star, Pi.mul_apply, Pi.star_apply,
        CstarRing.norm_star_mul_self, ← sq]
      refine' sq_le_sq' _ _
      · linarith [norm_nonneg (f x), norm_nonneg f]
      · exact ContinuousMap.norm_coe_le_norm f x
    · rw [← sq, ← Real.le_sqrt (norm_nonneg _) (norm_nonneg _),
        ContinuousMap.norm_le _ (Real.sqrt_nonneg _)]
      intro x
      

Proof state:
case refine'_2
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
x : α
⊢ ‖f x‖ ≤ Real.sqrt ‖star f * f‖

Next tactic:
rw [Real.le_sqrt (norm_nonneg _) (norm_nonneg _), sq, ← CstarRing.norm_star_mul_self]
instance [CompactSpace α] [CstarRing β] : CstarRing C(α, β) where
  norm_star_mul_self {f} := by
    refine' le_antisymm _ _
    · rw [← sq, ContinuousMap.norm_le _ (sq_nonneg _)]
      intro x
      simp only [ContinuousMap.coe_mul, coe_star, Pi.mul_apply, Pi.star_apply,
        CstarRing.norm_star_mul_self, ← sq]
      refine' sq_le_sq' _ _
      · linarith [norm_nonneg (f x), norm_nonneg f]
      · exact ContinuousMap.norm_coe_le_norm f x
    · rw [← sq, ← Real.le_sqrt (norm_nonneg _) (norm_nonneg _),
        ContinuousMap.norm_le _ (Real.sqrt_nonneg _)]
      intro x
      rw [Real.le_sqrt (norm_nonneg _) (norm_nonneg _), sq, ← CstarRing.norm_star_mul_self]
      

Proof state:
case refine'_2
α : Type u_1
β : Type u_2
inst✝⁴ : TopologicalSpace α
inst✝³ : NormedRing β
inst✝² : StarRing β
inst✝¹ : CompactSpace α
inst✝ : CstarRing β
f : C(α, β)
x : α
⊢ ‖star (f x) * f x‖ ≤ ‖star f * f‖

Next tactic:
exact ContinuousMap.norm_coe_le_norm (star f * f) x
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  

Proof state:
⊢ Tendsto (fun n => ↑(numDerangements n) / ↑(Nat.factorial n)) atTop (𝓝 (Real.exp (-1)))

Next tactic:
let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
⊢ Tendsto (fun n => ↑(numDerangements n) / ↑(Nat.factorial n)) atTop (𝓝 (Real.exp (-1)))

Next 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 in 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 : ℝ)
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  suffices ∀ n : ℕ, (numDerangements n : ℝ) / n.factorial = s (n + 1) by
    

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
this : ∀ (n : ℕ), ↑(numDerangements n) / ↑(Nat.factorial n) = s (n + 1)
⊢ Tendsto (fun n => ↑(numDerangements n) / ↑(Nat.factorial n)) atTop (𝓝 (Real.exp (-1)))

Next tactic:
simp_rw [this]
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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
    

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
this : ∀ (n : ℕ), ↑(numDerangements n) / ↑(Nat.factorial n) = s (n + 1)
⊢ Tendsto (fun n => ∑ k in Finset.range (n + 1), (-1) ^ k / ↑(Nat.factorial k)) atTop (𝓝 (Real.exp (-1)))

Next tactic:
rw [tendsto_add_atTop_iff_nat
      (f := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial) 1]
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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 in Finset.range n, (-1 : ℝ) ^ k / k.factorial) 1]
    

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
this : ∀ (n : ℕ), ↑(numDerangements n) / ↑(Nat.factorial n) = s (n + 1)
⊢ Tendsto (fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)) atTop (𝓝 (Real.exp (-1)))

Next tactic:
apply HasSum.tendsto_sum_nat
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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 in 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
    

Proof state:
case h
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
this : ∀ (n : ℕ), ↑(numDerangements n) / ↑(Nat.factorial n) = s (n + 1)
⊢ HasSum (fun i => (-1) ^ i / ↑(Nat.factorial i)) (Real.exp (-1))

Next tactic:
rw [Real.exp_eq_exp_ℝ]
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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 in 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_ℝ]
    

Proof state:
case h
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
this : ∀ (n : ℕ), ↑(numDerangements n) / ↑(Nat.factorial n) = s (n + 1)
⊢ HasSum (fun i => (-1) ^ i / ↑(Nat.factorial i)) (exp ℝ (-1))

Next tactic:
exact expSeries_div_hasSum_exp ℝ (-1 : ℝ)
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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 in 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 : ℝ)
  

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
⊢ ∀ (n : ℕ), ↑(numDerangements n) / ↑(Nat.factorial n) = s (n + 1)

Next tactic:
intro n
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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 in 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 : ℝ)
  intro n
  

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
n : ℕ
⊢ ↑(numDerangements n) / ↑(Nat.factorial n) = s (n + 1)

Next tactic:
rw [← Int.cast_ofNat, numDerangements_sum]
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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 in 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 : ℝ)
  intro n
  rw [← Int.cast_ofNat, numDerangements_sum]
  

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
n : ℕ
⊢ ↑(∑ k in Finset.range (n + 1), (-1) ^ k * ↑(Nat.ascFactorial k (n - k))) / ↑(Nat.factorial n) = s (n + 1)

Next tactic:
push_cast
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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 in 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 : ℝ)
  intro n
  rw [← Int.cast_ofNat, numDerangements_sum]
  push_cast
  

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
n : ℕ
⊢ (∑ x in Finset.range (n + 1), (-1) ^ x * ↑(Nat.ascFactorial x (n - x))) / ↑(Nat.factorial n) =
    ∑ k in Finset.range (n + 1), (-1) ^ k / ↑(Nat.factorial k)

Next tactic:
rw [Finset.sum_div]
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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 in 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 : ℝ)
  intro n
  rw [← Int.cast_ofNat, numDerangements_sum]
  push_cast
  rw [Finset.sum_div]
  -- get down to individual terms
  

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
n : ℕ
⊢ ∑ x in Finset.range (n + 1), (-1) ^ x * ↑(Nat.ascFactorial x (n - x)) / ↑(Nat.factorial n) =
    ∑ k in Finset.range (n + 1), (-1) ^ k / ↑(Nat.factorial k)

Next tactic:
refine' Finset.sum_congr (refl _) _
theorem numDerangements_tendsto_inv_e :
    Tendsto (fun n => (numDerangements n : ℝ) / n.factorial) atTop (𝓝 (Real.exp (-1))) := by
  -- we show that d(n)/n! is the partial sum of exp(-1), but offset by 1.
  -- this isn't entirely obvious, since we have to ensure that asc_factorial and
  -- factorial interact in the right way, e.g., that k ≤ n always
  let s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1 : ℝ) ^ k / k.factorial
  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 in 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 : ℝ)
  intro n
  rw [← Int.cast_ofNat, numDerangements_sum]
  push_cast
  rw [Finset.sum_div]
  -- get down to individual terms
  refine' Finset.sum_congr (refl _) _
  

Proof state:
s : ℕ → ℝ := fun n => ∑ k in Finset.range n, (-1) ^ k / ↑(Nat.factorial k)
n : ℕ
⊢ ∀ x ∈ Finset.range (n + 1),
    (-1) ^ x * ↑(Nat.ascFactorial x (n - x)) / ↑(Nat.factorial n) = (-1) ^ x / ↑(Nat.factorial x)

Next tactic:
intro k hk