Skip to content

Commit fbd5742

Browse files
feat: port Data/Nat/Choose/Sum (#2121)
Co-authored-by: Johan Commelin <johan@commelin.net>
1 parent eb73e97 commit fbd5742

File tree

2 files changed

+185
-0
lines changed

2 files changed

+185
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ import Mathlib.Data.Nat.Cast.WithTop
474474
import Mathlib.Data.Nat.Choose.Basic
475475
import Mathlib.Data.Nat.Choose.Bounds
476476
import Mathlib.Data.Nat.Choose.Dvd
477+
import Mathlib.Data.Nat.Choose.Sum
477478
import Mathlib.Data.Nat.Dist
478479
import Mathlib.Data.Nat.EvenOddRec
479480
import Mathlib.Data.Nat.Factorial.Basic

Mathlib/Data/Nat/Choose/Sum.lean

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/-
2+
Copyright (c) 2018 Chris Hughes. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Chris Hughes, Patrick Stevens
5+
6+
! This file was ported from Lean 3 source module data.nat.choose.sum
7+
! leanprover-community/mathlib commit 4c19a16e4b705bf135cf9a80ac18fcc99c438514
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.Data.Nat.Choose.Basic
12+
import Mathlib.Tactic.Linarith
13+
import Mathlib.Algebra.BigOperators.Ring
14+
import Mathlib.Algebra.BigOperators.Intervals
15+
import Mathlib.Algebra.BigOperators.Order
16+
import Mathlib.Algebra.BigOperators.NatAntidiagonal
17+
18+
/-!
19+
# Sums of binomial coefficients
20+
21+
This file includes variants of the binomial theorem and other results on sums of binomial
22+
coefficients. Theorems whose proofs depend on such sums may also go in this file for import
23+
reasons.
24+
25+
-/
26+
27+
28+
open Nat
29+
30+
open Finset
31+
32+
open BigOperators
33+
34+
variable {R : Type _}
35+
36+
namespace Commute
37+
38+
variable [Semiring R] {x y : R}
39+
40+
/-- A version of the **binomial theorem** for commuting elements in noncommutative semirings. -/
41+
theorem add_pow (h : Commute x y) (n : ℕ) :
42+
(x + y) ^ n = ∑ m in range (n + 1), x ^ m * y ^ (n - m) * choose n m := by
43+
let t : ℕ → ℕ → R := fun n m ↦ x ^ m * y ^ (n - m) * choose n m
44+
change (x + y) ^ n = ∑ m in range (n + 1), t n m
45+
have h_first : ∀ n, t n 0 = y ^ n := fun n ↦ by
46+
simp only [choose_zero_right, _root_.pow_zero, Nat.cast_one, mul_one, one_mul, tsub_zero]
47+
have h_last : ∀ n, t n n.succ = 0 := fun n ↦ by
48+
simp only [ge_iff_le, choose_succ_self, cast_zero, mul_zero]
49+
have h_middle :
50+
∀ n i : ℕ, i ∈ range n.succ → (t n.succ ∘ Nat.succ) i =
51+
x * t n i + y * t n i.succ := by
52+
intro n i h_mem
53+
have h_le : i ≤ n := Nat.le_of_lt_succ (mem_range.mp h_mem)
54+
dsimp only
55+
rw [Function.comp_apply, choose_succ_succ, Nat.cast_add, mul_add]
56+
congr 1
57+
· rw [pow_succ x, succ_sub_succ, mul_assoc, mul_assoc, mul_assoc]
58+
· rw [← mul_assoc y, ← mul_assoc y, (h.symm.pow_right i.succ).eq]
59+
by_cases h_eq : i = n
60+
· rw [h_eq, choose_succ_self, Nat.cast_zero, mul_zero, mul_zero]
61+
· rw [succ_sub (lt_of_le_of_ne h_le h_eq)]
62+
rw [pow_succ y, mul_assoc, mul_assoc, mul_assoc, mul_assoc]
63+
induction' n with n ih
64+
· rw [_root_.pow_zero, sum_range_succ, range_zero, sum_empty, zero_add]
65+
dsimp only
66+
rw [_root_.pow_zero, _root_.pow_zero, choose_self, Nat.cast_one, mul_one, mul_one]
67+
· rw [sum_range_succ', h_first]
68+
erw [sum_congr rfl (h_middle n), sum_add_distrib, add_assoc]
69+
rw [pow_succ (x + y), ih, add_mul, mul_sum, mul_sum]
70+
congr 1
71+
rw [sum_range_succ', sum_range_succ, h_first, h_last, mul_zero, add_zero, _root_.pow_succ]
72+
#align commute.add_pow Commute.add_pow
73+
74+
/-- A version of `Commute.add_pow` that avoids ℕ-subtraction by summing over the antidiagonal and
75+
also with the binomial coefficient applied via scalar action of ℕ. -/
76+
theorem add_pow' (h : Commute x y) (n : ℕ) :
77+
(x + y) ^ n = ∑ m in Nat.antidiagonal n, choose n m.fst • (x ^ m.fst * y ^ m.snd) := by
78+
simp_rw [Finset.Nat.sum_antidiagonal_eq_sum_range_succ fun m p ↦ choose n m • (x ^ m * y ^ p),
79+
_root_.nsmul_eq_mul, cast_comm, h.add_pow]
80+
#align commute.add_pow' Commute.add_pow'
81+
82+
end Commute
83+
84+
/-- The **binomial theorem** -/
85+
theorem add_pow [CommSemiring R] (x y : R) (n : ℕ) :
86+
(x + y) ^ n = ∑ m in range (n + 1), x ^ m * y ^ (n - m) * choose n m :=
87+
(Commute.all x y).add_pow n
88+
#align add_pow add_pow
89+
90+
namespace Nat
91+
92+
/-- The sum of entries in a row of Pascal's triangle -/
93+
theorem sum_range_choose (n : ℕ) : (∑ m in range (n + 1), choose n m) = 2 ^ n := by
94+
have := (add_pow 1 1 n).symm
95+
simpa [one_add_one_eq_two] using this
96+
#align nat.sum_range_choose Nat.sum_range_choose
97+
98+
theorem sum_range_choose_halfway (m : Nat) : (∑ i in range (m + 1), choose (2 * m + 1) i) = 4 ^ m :=
99+
have : (∑ i in range (m + 1), choose (2 * m + 1) (2 * m + 1 - i)) =
100+
∑ i in range (m + 1), choose (2 * m + 1) i :=
101+
sum_congr rfl fun i hi ↦ choose_symm <| by linarith [mem_range.1 hi]
102+
mul_right_injective₀ two_ne_zero <|
103+
calc
104+
(2 * ∑ i in range (m + 1), choose (2 * m + 1) i) =
105+
(∑ i in range (m + 1), choose (2 * m + 1) i) +
106+
∑ i in range (m + 1), choose (2 * m + 1) (2 * m + 1 - i) := by rw [two_mul, this]
107+
_ = (∑ i in range (m + 1), choose (2 * m + 1) i) +
108+
∑ i in Ico (m + 1) (2 * m + 2), choose (2 * m + 1) i := by
109+
{ rw [range_eq_Ico, sum_Ico_reflect]
110+
· congr
111+
have A : m + 12 * m + 1 := by linarith
112+
rw [add_comm, add_tsub_assoc_of_le A, ← add_comm]
113+
congr
114+
rw [tsub_eq_iff_eq_add_of_le A]
115+
ring
116+
· linarith }
117+
_ = ∑ i in range (2 * m + 2), choose (2 * m + 1) i := sum_range_add_sum_Ico _ (by linarith)
118+
_ = 2 ^ (2 * m + 1) := sum_range_choose (2 * m + 1)
119+
_ = 2 * 4 ^ m := by rw [pow_succ, pow_mul, mul_comm]; rfl
120+
#align nat.sum_range_choose_halfway Nat.sum_range_choose_halfway
121+
122+
theorem choose_middle_le_pow (n : ℕ) : choose (2 * n + 1) n ≤ 4 ^ n := by
123+
have t : choose (2 * n + 1) n ≤ ∑ i in range (n + 1), choose (2 * n + 1) i :=
124+
single_le_sum (fun x _ ↦ by linarith) (self_mem_range_succ n)
125+
simpa [sum_range_choose_halfway n] using t
126+
#align nat.choose_middle_le_pow Nat.choose_middle_le_pow
127+
128+
theorem four_pow_le_two_mul_add_one_mul_central_binom (n : ℕ) :
129+
4 ^ n ≤ (2 * n + 1) * choose (2 * n) n :=
130+
calc
131+
4 ^ n = (1 + 1) ^ (2 * n) := by simp only [pow_mul, one_add_one_eq_two]; rfl
132+
_ = ∑ m in range (2 * n + 1), choose (2 * n) m := by simp [add_pow]
133+
_ ≤ ∑ m in range (2 * n + 1), choose (2 * n) (2 * n / 2) :=
134+
sum_le_sum fun i _ ↦ choose_le_middle i (2 * n)
135+
_ = (2 * n + 1) * choose (2 * n) n := by simp
136+
#align nat.four_pow_le_two_mul_add_one_mul_central_binom Nat.four_pow_le_two_mul_add_one_mul_central_binom
137+
138+
end Nat
139+
140+
theorem Int.alternating_sum_range_choose {n : ℕ} :
141+
(∑ m in range (n + 1), ((-1) ^ m * ↑(choose n m) : ℤ)) = if n = 0 then 1 else 0 := by
142+
cases n; · simp
143+
case succ n =>
144+
have h := add_pow (-1 : ℤ) 1 n.succ
145+
simp only [one_pow, mul_one, add_left_neg] at h
146+
rw [← h, zero_pow (Nat.succ_pos n), if_neg (Nat.succ_ne_zero n)]
147+
#align int.alternating_sum_range_choose Int.alternating_sum_range_choose
148+
149+
theorem Int.alternating_sum_range_choose_of_ne {n : ℕ} (h0 : n ≠ 0) :
150+
(∑ m in range (n + 1), ((-1) ^ m * ↑(choose n m) : ℤ)) = 0 := by
151+
rw [Int.alternating_sum_range_choose, if_neg h0]
152+
#align int.alternating_sum_range_choose_of_ne Int.alternating_sum_range_choose_of_ne
153+
154+
namespace Finset
155+
156+
theorem sum_powerset_apply_card {α β : Type _} [AddCommMonoid α] (f : ℕ → α) {x : Finset β} :
157+
(∑ m in x.powerset, f m.card) = ∑ m in range (x.card + 1), x.card.choose m • f m := by
158+
trans ∑ m in range (x.card + 1), ∑ j in x.powerset.filter fun z ↦ z.card = m, f j.card
159+
· refine' (sum_fiberwise_of_maps_to _ _).symm
160+
intro y hy
161+
rw [mem_range, Nat.lt_succ_iff]
162+
rw [mem_powerset] at hy
163+
exact card_le_of_subset hy
164+
· refine' sum_congr rfl fun y _ ↦ _
165+
rw [← card_powersetLen, ← sum_const]
166+
refine' sum_congr powersetLen_eq_filter.symm fun z hz ↦ _
167+
rw [(mem_powersetLen.1 hz).2]
168+
#align finset.sum_powerset_apply_card Finset.sum_powerset_apply_card
169+
170+
theorem sum_powerset_neg_one_pow_card {α : Type _} [DecidableEq α] {x : Finset α} :
171+
(∑ m in x.powerset, (-1 : ℤ) ^ m.card) = if x = ∅ then 1 else 0 := by
172+
rw [sum_powerset_apply_card]
173+
simp only [nsmul_eq_mul', ← card_eq_zero, Int.alternating_sum_range_choose]
174+
#align finset.sum_powerset_neg_one_pow_card Finset.sum_powerset_neg_one_pow_card
175+
176+
theorem sum_powerset_neg_one_pow_card_of_nonempty {α : Type _} {x : Finset α} (h0 : x.Nonempty) :
177+
(∑ m in x.powerset, (-1 : ℤ) ^ m.card) = 0 := by
178+
classical
179+
rw [sum_powerset_neg_one_pow_card, if_neg]
180+
rw [← Ne.def, ← nonempty_iff_ne_empty]
181+
apply h0
182+
#align finset.sum_powerset_neg_one_pow_card_of_nonempty Finset.sum_powerset_neg_one_pow_card_of_nonempty
183+
184+
end Finset

0 commit comments

Comments
 (0)