Skip to content

Commit b16b285

Browse files
committed
feat(Combinatorics/Enumerative/Bonferroni): add Bonferroni inequalities
1 parent 1757879 commit b16b285

1 file changed

Lines changed: 329 additions & 0 deletions

File tree

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
/-
2+
Copyright (c) 2026 Louis (Yiyang) Liu. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Louis (Yiyang) Liu
5+
-/
6+
import Mathlib.Data.Nat.Choose.Sum
7+
8+
/-!
9+
# Bonferroni inequalities
10+
11+
This file proves the Bonferroni inequalities, i.e. the alternating upper and lower bounds obtained
12+
by truncating the inclusion–exclusion formula for a finite union of sets.
13+
14+
## Main results
15+
16+
* `Finset.indicator_biUnion_le_bonferroniIndicator_of_odd`: for odd `k`, the indicator of the
17+
union is at most the truncated indicator.
18+
* `Finset.bonferroniIndicator_le_indicator_biUnion_of_even`: for even `k`, the truncated
19+
indicator is at most the indicator of the union.
20+
* `Finset.card_biUnion_le_bonferroniCard_of_odd`: for odd `k`, the cardinality of the union is
21+
at most the truncated sum.
22+
* `Finset.bonferroniCard_le_card_biUnion_of_even`: for even `k`, the truncated sum is at most
23+
the cardinality of the union.
24+
-/
25+
26+
open Nat Int Set
27+
28+
/-! ### Binomial identities -/
29+
30+
section Binomial
31+
32+
open Finset
33+
34+
/-- The truncated alternating binomial sum equals `1 - (-1) ^ k * (m - 1).choose k`
35+
when `k < m`. -/
36+
private lemma trunc_choose_sum_eq_one_sub (m k : ℕ) (hk : k < m) :
37+
(∑ j ∈ Finset.Icc 1 k, ((-1 : ℤ) ^ (j + 1)) * (choose m j)) =
38+
1 - ((-1 : ℤ) ^ k) * (choose (m - 1) k) := by
39+
simp only [show ∀ j : ℕ, ((-1 : ℤ) ^ (j + 1)) = -((-1 : ℤ) ^ j) from fun j ↦ by ring,
40+
neg_mul, sum_neg_distrib]
41+
simp [neg_eq_iff_eq_neg]
42+
have insert_eq : range (k + 1) = insert 0 (Finset.Icc 1 k) := by grind
43+
calc
44+
_ = (∑ j ∈ range (k + 1), ((-1 : ℤ) ^ j) * (choose m j)) - 1 := by simp [insert_eq]
45+
_ = (∑ j ∈ range (k + 1), ((-1 : ℤ) ^ j) * (choose ((m - 1) + 1) j)) - 1 := by grind
46+
_ = _ := by rw [alternating_sum_range_choose_eq_choose]
47+
48+
/-- The full alternating binomial sum equals `1` when `1 ≤ m`. -/
49+
private lemma full_choose_sum_eq_one (m : ℕ) (hm : 1 ≤ m) :
50+
(∑ j ∈ Finset.Icc 1 m, ((-1 : ℤ) ^ (j + 1)) * (choose m j)) = 1 := by
51+
simp only [show ∀ j : ℕ, ((-1 : ℤ) ^ (j + 1)) = -((-1 : ℤ) ^ j) from fun j ↦ by ring,
52+
neg_mul, sum_neg_distrib]
53+
suffices ∑ j ∈ Icc 1 m, ((-1 : ℤ) ^ j) * (choose m j) = -1 by linarith
54+
have insert_eq : range (m + 1) = insert 0 (Finset.Icc 1 m) := by
55+
rw [congr_fun range_eq_Ico (m + 1), ← Finset.Ico_succ_right_eq_Icc 1 m,
56+
← Finset.insert_Ico_succ_left_eq_Ico (zero_lt_succ m)]
57+
simp
58+
calc
59+
_ = (∑ j ∈ range (m + 1), ((-1 : ℤ) ^ j) * (choose m j)) - 1 := by simp [insert_eq]
60+
_ = _ := by grind [alternating_sum_range_choose_of_ne]
61+
62+
/-- The truncated alternating binomial sum is `≥ 1` when `k` is odd and `≤ 1` when `k` is even,
63+
provided `1 ≤ m`. -/
64+
private lemma trunc_choose_sum_bounds (m k : ℕ) (hm : 1 ≤ m) :
65+
(Odd k → 1 ≤ ∑ j ∈ Finset.Icc 1 (min k m), ((-1 : ℤ) ^ (j + 1)) * (choose m j)) ∧
66+
(Even k → (∑ j ∈ Finset.Icc 1 (min k m), ((-1 : ℤ) ^ (j + 1)) * (choose m j)) ≤ 1) := by
67+
by_cases! hkm : k < m
68+
· constructor
69+
all_goals
70+
intro hk
71+
rw [min_eq_left hkm.le, trunc_choose_sum_eq_one_sub m k hkm]
72+
simp [hk.neg_one_pow]
73+
· constructor
74+
all_goals
75+
intro hk
76+
rw [min_eq_right hkm, full_choose_sum_eq_one m hm]
77+
78+
end Binomial
79+
80+
namespace Finset
81+
82+
variable {ι α : Type*}
83+
84+
/-! ### Truncated powerset -/
85+
86+
section TruncPowerset
87+
88+
variable {s t : Finset ι} {k : ℕ}
89+
90+
/-- `s.truncPowerset k` is the finset of nonempty subsets of `s` whose cardinality is at
91+
most `k`. -/
92+
def truncPowerset (s : Finset ι) (k : ℕ) : Finset (Finset ι) :=
93+
s.powerset.filter (fun t ↦ t.Nonempty ∧ #t ≤ k)
94+
95+
@[simp]
96+
theorem mem_truncPowerset : t ∈ s.truncPowerset k ↔ t ⊆ s ∧ t.Nonempty ∧ #t ≤ k := by
97+
simp [truncPowerset]
98+
99+
theorem truncPowerset_nonempty (ht : t ∈ s.truncPowerset k) : t.Nonempty := by
100+
rw [mem_truncPowerset] at ht
101+
exact ht.2.1
102+
103+
private lemma truncPowerset_eq_filter_nonempty (hk : #s ≤ k) :
104+
s.truncPowerset k = s.powerset.filter Finset.Nonempty := by
105+
ext t
106+
simp only [truncPowerset, mem_filter, mem_powerset]
107+
constructor
108+
· grind
109+
· intro ⟨h1, h2⟩
110+
exact ⟨h1, h2, (card_le_card h1).trans hk⟩
111+
112+
private lemma truncPowerset_stabilize {k₁ k₂ : ℕ} (h₁ : #s ≤ k₁) (h₂ : #s ≤ k₂) :
113+
s.truncPowerset k₁ = s.truncPowerset k₂ := by
114+
rw [truncPowerset_eq_filter_nonempty h₁, truncPowerset_eq_filter_nonempty h₂]
115+
116+
end TruncPowerset
117+
118+
/-! ### Pointwise indicator inequalities -/
119+
120+
section IndicatorBonferroni
121+
122+
variable (s : Finset ι) (S : ι → Set α)
123+
124+
/-- The truncated inclusion–exclusion indicator at a point `a`, defined as
125+
`∑ t ∈ s.truncPowerset k, (-1) ^ (#t + 1) * (⋂ i ∈ t, S i).indicator 1 a`. -/
126+
noncomputable def bonferroniIndicator (k : ℕ) (a : α) : ℤ :=
127+
∑ t ∈ s.truncPowerset k, ((-1 : ℤ) ^ (#t + 1)) * ((⋂ i ∈ t, S i).indicator 1 a)
128+
129+
private lemma bonferroniIndicator_eq_zero (k : ℕ) (a : α) (ha : a ∉ ⋃ i ∈ s, S i) :
130+
bonferroniIndicator s S k a = 0 := by
131+
unfold bonferroniIndicator
132+
apply Finset.sum_eq_zero
133+
intro t ht
134+
rw [mem_truncPowerset] at ht
135+
have : a ∉ ⋂ i ∈ t, S i := by
136+
intro hmem
137+
apply ha
138+
obtain ⟨i, hi⟩ := ht.2.1
139+
exact mem_iUnion₂.mpr ⟨i, ht.1 hi, mem_iInter₂.mp hmem i hi⟩
140+
rw [indicator_of_notMem this, mul_zero]
141+
142+
private lemma bonferroniIndicator_eq_trunc_choose_sum (k : ℕ) (a : α) (ha : a ∈ ⋃ i ∈ s, S i) :
143+
∃ (m : ℕ), 1 ≤ m ∧ bonferroniIndicator s S k a =
144+
∑ j ∈ Icc 1 (min k m), (-1 : ℤ) ^ (j + 1) * (Nat.choose m j) := by
145+
classical
146+
unfold bonferroniIndicator
147+
set T := s.filter (fun i ↦ a ∈ S i)
148+
have hT_sub : T ⊆ s := filter_subset _ s
149+
have hT_nonempty : T.Nonempty := by
150+
obtain ⟨i, his, hia⟩ := mem_iUnion₂.mp ha
151+
exact ⟨i, mem_filter.mpr ⟨his, hia⟩⟩
152+
refine ⟨#T, hT_nonempty.card_pos, ?_⟩
153+
have mem_inter_iff : ∀ t, t ⊆ s → (a ∈ ⋂ i ∈ t, S i ↔ t ⊆ T) := by
154+
intro t hts
155+
simp only [mem_iInter]
156+
grind
157+
have term_eq : ∀ t ∈ s.truncPowerset k,
158+
(-1 : ℤ) ^ (#t + 1) * (⋂ i ∈ t, S i).indicator 1 a =
159+
if t ⊆ T then (-1 : ℤ) ^ (#t + 1) else 0 := by
160+
intro t ht
161+
rw [mem_truncPowerset] at ht
162+
by_cases htT : t ⊆ T
163+
· rw [indicator_of_mem ((mem_inter_iff t ht.1).mpr htT), Pi.one_apply, mul_one, if_pos htT]
164+
· rw [indicator_of_notMem (mt (mem_inter_iff t ht.1).mp htT), mul_zero, if_neg htT]
165+
have filter_eq : (s.truncPowerset k).filter (· ⊆ T) = T.truncPowerset k := by
166+
ext t
167+
simp [mem_filter, mem_truncPowerset]
168+
grind
169+
have trunc_eq : T.truncPowerset k =
170+
(Icc 1 (min k #T)).biUnion (fun j ↦ T.powersetCard j) := by
171+
ext t
172+
simp only [mem_biUnion, mem_Icc, mem_powersetCard, mem_truncPowerset]
173+
constructor
174+
· intro ⟨htT, hne, hcard⟩
175+
exact ⟨#t, ⟨hne.card_pos, le_min hcard (card_le_card htT)⟩, htT, rfl⟩
176+
· intro ⟨j, ⟨hj1, hjk⟩, htT, hjt⟩
177+
rw [← hjt] at hj1 hjk
178+
exact ⟨htT, card_pos.mp hj1, (le_min_iff.mp hjk).1
179+
have disj : (Icc 1 (min k #T) : Set ℕ).PairwiseDisjoint
180+
(fun j ↦ T.powersetCard j) := by
181+
intro i _ j _ hij
182+
rw [Function.onFun, disjoint_left]
183+
intro t hi hj
184+
rw [mem_powersetCard] at hi hj
185+
omega
186+
calc
187+
_ = ∑ t ∈ T.truncPowerset k, (-1 : ℤ) ^ (#t + 1) := by
188+
rw [← filter_eq, sum_filter]
189+
exact sum_congr rfl term_eq
190+
_ = ∑ j ∈ Icc 1 (min k #T),
191+
∑ t ∈ T.powersetCard j, (-1 : ℤ) ^ (#t + 1) := by
192+
rw [trunc_eq, sum_biUnion disj]
193+
_ = _ := by
194+
apply sum_congr rfl
195+
intro j _
196+
have card_eq : ∀ t ∈ T.powersetCard j, #t = j := fun t ht ↦ (mem_powersetCard.mp ht).2
197+
rw [sum_congr rfl (fun t ht ↦ by rw [card_eq t ht]),
198+
sum_const, card_powersetCard, nsmul_eq_mul, mul_comm]
199+
200+
private lemma bonferroniIndicator_bounds (k : ℕ) (a : α) :
201+
(Odd k → ((⋃ i ∈ s, S i).indicator 1 a : ℤ) ≤ bonferroniIndicator s S k a) ∧
202+
(Even k → bonferroniIndicator s S k a ≤ ((⋃ i ∈ s, S i).indicator 1 a : ℤ)) := by
203+
by_cases ha : a ∈ ⋃ i ∈ s, S i
204+
· simp only [indicator_of_mem ha, Pi.one_apply]
205+
obtain ⟨m, hm, heq⟩ := bonferroniIndicator_eq_trunc_choose_sum s S k a ha
206+
simp only [heq]
207+
exact trunc_choose_sum_bounds m k hm
208+
· simp [indicator_of_notMem ha, bonferroniIndicator_eq_zero s S k a ha]
209+
210+
/-- **Bonferroni inequality**, upper bound. For odd `k`, the truncated inclusion–exclusion
211+
indicator is at least the indicator of `⋃ i ∈ s, S i`. -/
212+
theorem indicator_biUnion_le_bonferroniIndicator_of_odd (k : ℕ) (hk : Odd k) (a : α) :
213+
((⋃ i ∈ s, S i).indicator 1 a : ℤ) ≤ bonferroniIndicator s S k a :=
214+
(bonferroniIndicator_bounds s S k a).1 hk
215+
216+
/-- **Bonferroni inequality**, lower bound. For even `k`, the truncated inclusion–exclusion
217+
indicator is at most the indicator of `⋃ i ∈ s, S i`. -/
218+
theorem bonferroniIndicator_le_indicator_biUnion_of_even (k : ℕ) (hk : Even k) (a : α) :
219+
bonferroniIndicator s S k a ≤ ((⋃ i ∈ s, S i).indicator 1 a : ℤ) :=
220+
(bonferroniIndicator_bounds s S k a).2 hk
221+
222+
private lemma bonferroniIndicator_congr (k₁ k₂ : ℕ) (h₁ : #s ≤ k₁) (h₂ : #s ≤ k₂) (a : α) :
223+
bonferroniIndicator s S k₁ a = bonferroniIndicator s S k₂ a := by
224+
simp_rw [bonferroniIndicator, truncPowerset_stabilize h₁ h₂]
225+
226+
/-- When `#s ≤ k`, the truncated inclusion–exclusion indicator equals the indicator of the
227+
union. -/
228+
theorem bonferroniIndicator_eq_indicator_biUnion_of_card_le (k : ℕ) (hk : #s ≤ k) (a : α) :
229+
bonferroniIndicator s S k a = (⋃ i ∈ s, S i).indicator 1 a := by
230+
apply le_antisymm
231+
· rw [bonferroniIndicator_congr s S k (2 * #s) hk (by omega) a]
232+
exact bonferroniIndicator_le_indicator_biUnion_of_even s S _ ⟨#s, by ring⟩ a
233+
· rw [bonferroniIndicator_congr s S k (2 * #s + 1) hk (by omega) a]
234+
exact indicator_biUnion_le_bonferroniIndicator_of_odd s S _ ⟨#s, rfl⟩ a
235+
236+
end IndicatorBonferroni
237+
238+
/-! ### Cardinality bounds -/
239+
240+
section CardinalityBonferroni
241+
242+
variable [DecidableEq α] {s : Finset ι} {S : ι → Finset α}
243+
244+
/-- The truncated inclusion–exclusion sum of intersection cardinalities, over nonempty subsets of
245+
`s` with at most `k` elements. This is the cardinality analogue of `bonferroniIndicator`. -/
246+
def bonferroniCard (s : Finset ι) (S : ι → Finset α) (k : ℕ) : ℤ :=
247+
∑ t : s.truncPowerset k,
248+
(-1 : ℤ) ^ (#(t : Finset ι) + 1) * #((t : Finset ι).inf' (truncPowerset_nonempty t.2) S)
249+
250+
private lemma mem_iUnion_of_mem_biUnion {a : α} (ha : a ∈ s.biUnion S) :
251+
a ∈ ⋃ i ∈ s, (↑(S i) : Set α) := by
252+
obtain ⟨i, hi, hia⟩ := mem_biUnion.mp ha
253+
exact mem_iUnion₂.mpr ⟨i, hi, hia⟩
254+
255+
private lemma card_inf'_eq_sum_indicator {t : Finset ι} (ht : t.Nonempty) (hts : t ⊆ s) :
256+
(#(t.inf' ht S) : ℤ) =
257+
∑ a ∈ s.biUnion S, (⋂ i ∈ t, (↑(S i) : Set α)).indicator (1 : α → ℤ) a := by
258+
have hmem : ∀ a, a ∈ ⋂ i ∈ t, (↑(S i) : Set α) ↔ a ∈ t.inf' ht S := by
259+
intro a; simp [mem_inf', mem_iInter]
260+
have hsub : t.inf' ht S ⊆ s.biUnion S := by
261+
intro a ha; obtain ⟨i, hi⟩ := ht
262+
rw [mem_inf'] at ha
263+
exact mem_biUnion.mpr ⟨i, hts hi, ha i hi⟩
264+
calc (#(t.inf' ht S) : ℤ)
265+
= ∑ a ∈ t.inf' ht S, (1 : ℤ) := by exact_mod_cast card_eq_sum_ones _
266+
_ = ∑ a ∈ t.inf' ht S, (⋂ i ∈ t, (↑(S i) : Set α)).indicator 1 a := by
267+
apply sum_congr rfl; intro a ha
268+
rw [indicator_of_mem ((hmem a).mpr ha), Pi.one_apply]
269+
_ = ∑ a ∈ s.biUnion S, (⋂ i ∈ t, (↑(S i) : Set α)).indicator 1 a := by
270+
apply sum_subset hsub; intro a _ ha
271+
exact indicator_of_notMem (mt (hmem a).mp ha) _
272+
273+
private lemma bonferroniCard_eq_sum_bonferroniIndicator (s : Finset ι) (S : ι → Finset α)
274+
(k : ℕ) : bonferroniCard s S k =
275+
∑ a ∈ s.biUnion S, bonferroniIndicator s (fun i ↦ ↑(S i)) k a := by
276+
unfold bonferroniCard
277+
conv_lhs =>
278+
arg 2; ext t
279+
rw [card_inf'_eq_sum_indicator (truncPowerset_nonempty t.2) (mem_truncPowerset.mp t.2).1]
280+
simp_rw [Finset.mul_sum]
281+
rw [Finset.sum_comm]
282+
congr 1; ext a
283+
rw [bonferroniIndicator]
284+
exact Finset.sum_coe_sort (s.truncPowerset k)
285+
(fun t => (-1 : ℤ) ^ (#t + 1) * (⋂ i ∈ t, (↑(S i) : Set α)).indicator 1 a)
286+
287+
/-- **Bonferroni inequality**, upper bound for cardinalities. For odd `k`, the cardinality of
288+
`s.biUnion S` is at most `bonferroniCard s S k`. -/
289+
theorem card_biUnion_le_bonferroniCard_of_odd (s : Finset ι) (S : ι → Finset α) (k : ℕ)
290+
(hk : Odd k) : (#(s.biUnion S) : ℤ) ≤ bonferroniCard s S k := by
291+
rw [bonferroniCard_eq_sum_bonferroniIndicator]
292+
calc
293+
_ = ∑ a ∈ s.biUnion S, (1 : ℤ) := by exact_mod_cast card_eq_sum_ones _
294+
_ ≤ ∑ a ∈ s.biUnion S, bonferroniIndicator s (fun i ↦ ↑(S i)) k a := by
295+
apply sum_le_sum
296+
intro a ha
297+
have := indicator_biUnion_le_bonferroniIndicator_of_odd s (fun i ↦ ↑(S i)) k hk a
298+
rwa [indicator_of_mem (mem_iUnion_of_mem_biUnion ha), Pi.one_apply] at this
299+
300+
/-- **Bonferroni inequality**, lower bound for cardinalities. For even `k`,
301+
`bonferroniCard s S k` is at most the cardinality of `s.biUnion S`. -/
302+
theorem bonferroniCard_le_card_biUnion_of_even (s : Finset ι) (S : ι → Finset α) (k : ℕ)
303+
(hk : Even k) : bonferroniCard s S k ≤ (#(s.biUnion S) : ℤ) := by
304+
rw [bonferroniCard_eq_sum_bonferroniIndicator]
305+
calc
306+
_ ≤ ∑ a ∈ s.biUnion S, (1 : ℤ) := by
307+
apply sum_le_sum
308+
intro a ha
309+
have := bonferroniIndicator_le_indicator_biUnion_of_even s (fun i ↦ ↑(S i)) k hk a
310+
rwa [indicator_of_mem (mem_iUnion_of_mem_biUnion ha), Pi.one_apply] at this
311+
_ = _ := by exact_mod_cast (card_eq_sum_ones _).symm
312+
313+
/-- When `#s ≤ k`, the truncated inclusion–exclusion cardinality sum equals the cardinality of
314+
`s.biUnion S`. -/
315+
theorem card_biUnion_eq_bonferroniCard_of_card_le (s : Finset ι) (S : ι → Finset α) (k : ℕ)
316+
(hk : #s ≤ k) : (#(s.biUnion S) : ℤ) = bonferroniCard s S k := by
317+
rw [bonferroniCard_eq_sum_bonferroniIndicator]
318+
calc
319+
_ = ∑ a ∈ s.biUnion S, (1 : ℤ) := by exact_mod_cast card_eq_sum_ones _
320+
_ = ∑ a ∈ s.biUnion S, bonferroniIndicator s (fun i ↦ ↑(S i)) k a := by
321+
apply sum_congr rfl
322+
intro a ha
323+
have := bonferroniIndicator_eq_indicator_biUnion_of_card_le s (fun i ↦ ↑(S i)) k hk a
324+
rw [indicator_of_mem (mem_iUnion_of_mem_biUnion ha), Pi.one_apply] at this
325+
exact this.symm
326+
327+
end CardinalityBonferroni
328+
329+
end Finset

0 commit comments

Comments
 (0)