Skip to content

Commit 582ddf8

Browse files
committed
feat: part-preserving equivalence of an equipartition with Fin s.card (#12196)
Part of #9317.
1 parent 724afa6 commit 582ddf8

File tree

2 files changed

+127
-5
lines changed

2 files changed

+127
-5
lines changed

Mathlib/Order/Partition/Equipartition.lean

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Yaël Dillies, Bhavik Mehta
55
-/
66
import Mathlib.Data.Set.Equitable
7+
import Mathlib.Logic.Equiv.Fin
78
import Mathlib.Order.Partition.Finpartition
89

910
#align_import order.partition.equipartition from "leanprover-community/mathlib"@"b363547b3113d350d053abdf2884e9850a56b205"
@@ -17,6 +18,9 @@ difference of `1`.
1718
## Main declarations
1819
1920
* `Finpartition.IsEquipartition`: Predicate for a `Finpartition` to be an equipartition.
21+
* `Finpartition.IsEquipartition.exists_partPreservingEquiv`: part-preserving enumeration of a finset
22+
equipped with an equipartition. Indices of elements in the same part are congruent modulo
23+
the number of parts.
2024
-/
2125

2226

@@ -41,7 +45,7 @@ theorem isEquipartition_iff_card_parts_eq_average :
4145
variable {P}
4246

4347
lemma not_isEquipartition :
44-
¬P.IsEquipartition ↔ ∃ a ∈ P.parts, ∃ b ∈ P.parts, Finset.card b + 1 < Finset.card a :=
48+
¬P.IsEquipartition ↔ ∃ a ∈ P.parts, ∃ b ∈ P.parts, b.card + 1 < a.card :=
4549
Set.not_equitableOn
4650

4751
theorem _root_.Set.Subsingleton.isEquipartition (h : (P.parts : Set (Finset α)).Subsingleton) :
@@ -54,6 +58,13 @@ theorem IsEquipartition.card_parts_eq_average (hP : P.IsEquipartition) (ht : t
5458
P.isEquipartition_iff_card_parts_eq_average.1 hP _ ht
5559
#align finpartition.is_equipartition.card_parts_eq_average Finpartition.IsEquipartition.card_parts_eq_average
5660

61+
theorem IsEquipartition.card_part_eq_average_iff (hP : P.IsEquipartition) (ht : t ∈ P.parts) :
62+
t.card = s.card / P.parts.card ↔ t.card ≠ s.card / P.parts.card + 1 := by
63+
have a := hP.card_parts_eq_average ht
64+
have b : ¬(t.card = s.card / P.parts.card ∧ t.card = s.card / P.parts.card + 1) := by
65+
by_contra h; exact absurd (h.1 ▸ h.2) (lt_add_one _).ne
66+
tauto
67+
5768
theorem IsEquipartition.average_le_card_part (hP : P.IsEquipartition) (ht : t ∈ P.parts) :
5869
s.card / P.parts.card ≤ t.card := by
5970
rw [← P.sum_card_parts]
@@ -66,7 +77,94 @@ theorem IsEquipartition.card_part_le_average_add_one (hP : P.IsEquipartition) (h
6677
exact Finset.EquitableOn.le_add_one hP ht
6778
#align finpartition.is_equipartition.card_part_le_average_add_one Finpartition.IsEquipartition.card_part_le_average_add_one
6879

69-
/-! ### Discrete and indiscrete finpartition -/
80+
theorem IsEquipartition.filter_ne_average_add_one_eq_average (hP : P.IsEquipartition) :
81+
P.parts.filter (fun p ↦ ¬p.card = s.card / P.parts.card + 1) =
82+
P.parts.filter (fun p ↦ p.card = s.card / P.parts.card) := by
83+
ext p
84+
simp only [mem_filter, and_congr_right_iff]
85+
exact fun hp ↦ (hP.card_part_eq_average_iff hp).symm
86+
87+
/-- An equipartition of a finset with `n` elements into `k` parts has
88+
`n % k` parts of size `n / k + 1`. -/
89+
theorem IsEquipartition.card_large_parts_eq_mod (hP : P.IsEquipartition) :
90+
(P.parts.filter fun p ↦ p.card = s.card / P.parts.card + 1).card = s.card % P.parts.card := by
91+
have z := P.sum_card_parts
92+
rw [← sum_filter_add_sum_filter_not (s := P.parts)
93+
(p := fun x ↦ x.card = s.card / P.parts.card + 1),
94+
hP.filter_ne_average_add_one_eq_average,
95+
sum_const_nat (m := s.card / P.parts.card + 1) (by simp),
96+
sum_const_nat (m := s.card / P.parts.card) (by simp),
97+
← hP.filter_ne_average_add_one_eq_average,
98+
mul_add, add_comm, ← add_assoc, ← add_mul, mul_one, add_comm (Finset.card _),
99+
filter_card_add_filter_neg_card_eq_card, add_comm] at z
100+
rw [← add_left_inj, Nat.mod_add_div, z]
101+
102+
/-- An equipartition of a finset with `n` elements into `k` parts has
103+
`n - n % k` parts of size `n / k`. -/
104+
theorem IsEquipartition.card_small_parts_eq_mod (hP : P.IsEquipartition) :
105+
(P.parts.filter fun p ↦ p.card = s.card / P.parts.card).card =
106+
P.parts.card - s.card % P.parts.card := by
107+
conv_rhs =>
108+
arg 1
109+
rw [← filter_card_add_filter_neg_card_eq_card (p := fun p ↦ p.card = s.card / P.parts.card + 1)]
110+
rw [hP.card_large_parts_eq_mod, add_tsub_cancel_left, hP.filter_ne_average_add_one_eq_average]
111+
112+
/-- There exists an enumeration of an equipartition's parts where
113+
larger parts map to smaller numbers and vice versa. -/
114+
theorem IsEquipartition.exists_partsEquiv (hP : P.IsEquipartition) :
115+
∃ f : P.parts ≃ Fin P.parts.card,
116+
∀ t, t.1.card = s.card / P.parts.card + 1 ↔ f t < s.card % P.parts.card := by
117+
let el := (P.parts.filter fun p ↦ p.card = s.card / P.parts.card + 1).equivFin
118+
let es := (P.parts.filter fun p ↦ p.card = s.card / P.parts.card).equivFin
119+
simp_rw [mem_filter, hP.card_large_parts_eq_mod] at el
120+
simp_rw [mem_filter, hP.card_small_parts_eq_mod] at es
121+
let sneg : { x // x ∈ P.parts ∧ ¬x.card = s.card / P.parts.card + 1 } ≃
122+
{ x // x ∈ P.parts ∧ x.card = s.card / P.parts.card } := by
123+
apply Equiv.subtypeEquiv (by rfl)
124+
simp only [Equiv.refl_apply, and_congr_right_iff]
125+
exact fun _ ha ↦ by rw [hP.card_part_eq_average_iff ha, ne_eq]
126+
replace el : { x : P.parts // x.1.card = s.card / P.parts.card + 1 } ≃
127+
Fin (s.card % P.parts.card) := (Equiv.Set.sep ..).symm.trans el
128+
replace es : { x : P.parts // ¬x.1.card = s.card / P.parts.card + 1 } ≃
129+
Fin (P.parts.card - s.card % P.parts.card) := (Equiv.Set.sep ..).symm.trans (sneg.trans es)
130+
let f := (Equiv.sumCompl _).symm.trans ((el.sumCongr es).trans finSumFinEquiv)
131+
use f.trans (finCongr (Nat.add_sub_of_le P.card_mod_card_parts_le))
132+
intro ⟨p, _⟩
133+
simp_rw [f, Equiv.trans_apply, Equiv.sumCongr_apply, finCongr_apply, Fin.coe_cast]
134+
by_cases hc : p.card = s.card / P.parts.card + 1 <;> simp [hc]
135+
136+
/-- Given a finset equipartitioned into `k` parts, its elements can be enumerated such that
137+
elements in the same part have congruent indices modulo `k`. -/
138+
theorem IsEquipartition.exists_partPreservingEquiv (hP : P.IsEquipartition) : ∃ f : s ≃ Fin s.card,
139+
∀ a b : s, P.part a = P.part b ↔ f a % P.parts.card = f b % P.parts.card := by
140+
obtain ⟨f, hf⟩ := P.exists_enumeration
141+
obtain ⟨g, hg⟩ := hP.exists_partsEquiv
142+
let z := fun a ↦ P.parts.card * (f a).2 + g (f a).1
143+
have gl := fun a ↦ (g (f a).1).2
144+
have less : ∀ a, z a < s.card := fun a ↦ by
145+
rcases hP.card_parts_eq_average (f a).1.2 with (c | c)
146+
· calc
147+
_ < P.parts.card * ((f a).2 + 1) := add_lt_add_left (gl a) _
148+
_ ≤ P.parts.card * (s.card / P.parts.card) := mul_le_mul_left' (c ▸ (f a).2.2) _
149+
_ ≤ P.parts.card * (s.card / P.parts.card) + s.card % P.parts.card := Nat.le_add_right ..
150+
_ = _ := Nat.div_add_mod ..
151+
· rw [← Nat.div_add_mod s.card P.parts.card]
152+
exact add_lt_add_of_le_of_lt (mul_le_mul_left' (by omega) _) ((hg (f a).1).mp c)
153+
let z' : s → Fin s.card := fun a ↦ ⟨z a, less a⟩
154+
have bij : z'.Bijective := by
155+
refine (bijective_iff_injective_and_card z').mpr ⟨fun a b e ↦ ?_, by simp⟩
156+
simp_rw [z', z, Fin.mk.injEq, mul_comm P.parts.card] at e
157+
haveI : NeZero P.parts.card := ⟨((Nat.zero_le _).trans_lt (gl a)).ne'⟩
158+
change P.parts.card.divModEquiv.symm (_, _) = P.parts.card.divModEquiv.symm (_, _) at e
159+
simp only [Equiv.apply_eq_iff_eq, Prod.mk.injEq] at e
160+
apply_fun f
161+
exact Sigma.ext e.2 <| (Fin.heq_ext_iff (by rw [e.2])).mpr e.1
162+
use Equiv.ofBijective _ bij
163+
intro a b
164+
simp_rw [Equiv.ofBijective_apply, z, hf a b, Nat.mul_add_mod,
165+
Nat.mod_eq_of_lt (gl a), Nat.mod_eq_of_lt (gl b), Fin.val_eq_val, g.apply_eq_iff_eq]
166+
167+
/-! ### Discrete and indiscrete finpartitions -/
70168

71169

72170
variable (s) -- [Decidable (a = ⊥)]

Mathlib/Order/Partition/Finpartition.lean

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ Authors: Yaël Dillies, Bhavik Mehta
66
import Mathlib.Algebra.BigOperators.Group.Finset
77
import Mathlib.Order.SupIndep
88
import Mathlib.Order.Atoms
9-
import Mathlib.Data.Fintype.Powerset
109

1110
#align_import order.partition.finpartition from "leanprover-community/mathlib"@"d6fad0e5bf2d6f48da9175d25c3dc5706b3834ce"
1211

@@ -505,14 +504,32 @@ theorem mem_part (ha : a ∈ s) : a ∈ P.part a := by simp [part, ha, choose_pr
505504

506505
theorem part_surjOn : Set.SurjOn P.part s P.parts := fun p hp ↦ by
507506
obtain ⟨x, hx⟩ := P.nonempty_of_mem_parts hp
508-
have hx' := mem_of_subset ((le_sup hp).trans P.sup_parts.le) hx
507+
have hx' := mem_of_subset (P.le hp) hx
509508
use x, hx', (P.existsUnique_mem hx').unique ⟨P.part_mem hx', P.mem_part hx'⟩ ⟨hp, hx⟩
510509

511510
theorem exists_subset_part_bijOn : ∃ r ⊆ s, Set.BijOn P.part r P.parts := by
512511
obtain ⟨r, hrs, hr⟩ := P.part_surjOn.exists_bijOn_subset
513512
lift r to Finset α using s.finite_toSet.subset hrs
514513
exact ⟨r, mod_cast hrs, hr⟩
515514

515+
/-- Equivalence between a finpartition's parts as a dependent sum and the partitioned set. -/
516+
def equivSigmaParts : s ≃ Σ t : P.parts, t.1 where
517+
toFun x := ⟨⟨P.part x.1, P.part_mem x.2⟩, ⟨x, P.mem_part x.2⟩⟩
518+
invFun x := ⟨x.2, mem_of_subset (P.le x.1.2) x.2.2
519+
left_inv x := by simp
520+
right_inv x := by
521+
ext e
522+
· obtain ⟨⟨p, mp⟩, ⟨f, mf⟩⟩ := x
523+
dsimp only at mf ⊢
524+
have mfs := mem_of_subset (P.le mp) mf
525+
rw [P.eq_of_mem_parts mp (P.part_mem mfs) mf (P.mem_part mfs)]
526+
· simp
527+
528+
lemma exists_enumeration : ∃ f : s ≃ Σ t : P.parts, Fin t.1.card,
529+
∀ a b : s, P.part a = P.part b ↔ (f a).1 = (f b).1 := by
530+
use P.equivSigmaParts.trans ((Equiv.refl _).sigmaCongr (fun t ↦ t.1.equivFin))
531+
simp [equivSigmaParts, Equiv.sigmaCongr, Equiv.sigmaCongrLeft]
532+
516533
theorem sum_card_parts : ∑ i ∈ P.parts, i.card = s.card := by
517534
convert congr_arg Finset.card P.biUnion_parts
518535
rw [card_biUnion P.supIndep.pairwiseDisjoint]
@@ -552,11 +569,18 @@ instance (s : Finset α) : OrderBot (Finpartition s) :=
552569
obtain ⟨t, ht, hat⟩ := P.exists_mem ha
553570
exact ⟨t, ht, singleton_subset_iff.2 hat⟩ }
554571

555-
theorem card_parts_le_card (P : Finpartition s) : P.parts.card ≤ s.card := by
572+
theorem card_parts_le_card : P.parts.card ≤ s.card := by
556573
rw [← card_bot s]
557574
exact card_mono bot_le
558575
#align finpartition.card_parts_le_card Finpartition.card_parts_le_card
559576

577+
lemma card_mod_card_parts_le : s.card % P.parts.card ≤ P.parts.card := by
578+
rcases P.parts.card.eq_zero_or_pos with h | h
579+
· have h' := h
580+
rw [Finset.card_eq_zero, parts_eq_empty_iff, bot_eq_empty, ← Finset.card_eq_zero] at h'
581+
rw [h, h']
582+
· exact (Nat.mod_lt _ h).le
583+
560584
variable [Fintype α]
561585

562586
/-- A setoid over a finite type induces a finpartition of the type's elements,

0 commit comments

Comments
 (0)