Skip to content

Commit 8d2c70b

Browse files
Jun2Mapnelson1
andcommitted
feat(Order/Partition): IsRepFun predicate for Partition (#36993)
This PR adds **representative functions** for partitions: it defines `Partition.IsRepFun`, a predicate characterizing when a function maps each element to a representative in its partial equivalence class and is the identity on elements outside the support. ### Motivation The main downstream uses are in graph theory (minors, simplification) and matroid theory. A partition describes a family of equivalent objects (for example, parallel classes of edges in a loopless graph, or connected components). A representative function chooses one distinguished element per part: for instance, which edge remains when simplifying parallel edges, or how to label a supervertex after contraction. Taking constructions to depend on `IsRepFun` rather than fixing an arbitrary choice avoids consistency issues when relating different objects: For example, you could arbitrarily choose the representation for each graph. One thing you might want to say is if `G ≤ H` then `G.simplification ≤ H.simplification`. However, depending on what that arbitrary choice for `G` and `H` are, this may not be true. Choosing some linear ordering on the type and take the minimal/maximal element as the representative fixes the issue between graphs with same type. However, 1. There are graphs comes with some ordering and it can clash with the arbitrarily chosen ordering. 2. Similar to previous problem, if I have an injective homomorphism `f` between `G : Graph α β` and `H : Graph α' β'`, then I would want to say `f` (or its suitable restriction) is also an injective homomorphism between `G.simplification` and `H.simplification`. However, as they have different type and therefore different choice of representation, this is not true in general. The best answer to this problem I have is to take repfun as an argument for simplification & minor and have a lemma that arbitrarily choose/extends a repfun of a partition (#36691). Co-authored-by: Peter Nelson <apn.uni@gmail.com>
1 parent 830917a commit 8d2c70b

File tree

1 file changed

+109
-3
lines changed

1 file changed

+109
-3
lines changed

Mathlib/Order/Partition/Basic.lean

Lines changed: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,26 @@ of `Q`.
2828
collection of nontrivial elements whose supremum is `s`.
2929
* `Partition.removeBot`: A constructor for `Partition s` that removes `⊥` from a set of parts.
3030
* `Partition.Rel`: The partial equivalence relation induced by a partition of a set.
31+
* `Partition.IsRepFun`: A predicate characterizing a representative function for a partition.
32+
33+
## Representative functions (`IsRepFun`)
34+
35+
`IsRepFun P f` means that `f` sends each element of the support to a representative in its
36+
`Partition.Rel`-class, agrees on related elements, and is the identity outside the support.
37+
38+
This is useful whenever a construction must pick one distinguished element per part of a partition.
39+
For example, in graph theory one may partition edges into parallel classes or vertices into
40+
connected components; a representative function can specify which edge remains when simplifying
41+
parallel edges, or how supervertices are labeled after contraction. Similar uses arise in matroid
42+
theory and in the definition of minors.
43+
44+
Tempting alternatives are to use `Classical.choice` or fix a global well-order and take minimal
45+
representatives. However, these lead to issues with inconsistencies: independent choices need not
46+
respect relations between different instances (e.g. monotonicity of simplifications with respect
47+
to subgraph order), a global order can clash with structure already carried by the type, and maps
48+
between different types need not intertwine two separate canonical choices. Stating hypotheses with
49+
`IsRepFun` keeps the chosen representatives explicit; existence under suitable conditions can be
50+
proved separately.
3151
3252
## TODO
3353
@@ -286,9 +306,7 @@ lemma Rel.forall (h : P.Rel x y) (ht : t ∈ P) : x ∈ t ↔ y ∈ t := by
286306

287307
@[simp]
288308
lemma rel_rfl_iff : P.Rel x x ↔ x ∈ u := by
289-
refine ⟨fun hx ↦ ?_, fun hx ↦ ?_⟩
290-
· obtain ⟨t, ht, hxP, -⟩ := hx
291-
exact subset_of_mem ht hxP
309+
refine ⟨fun ⟨t, ht, hxP, _⟩ ↦ subset_of_mem ht hxP, fun hx ↦ ?_⟩
292310
obtain ⟨t, ⟨ht, hxt⟩, -⟩ := P.mem_iff_unique.mp hx
293311
exact ⟨t, ht, hxt, hxt⟩
294312

@@ -313,4 +331,92 @@ lemma Rel.right_mem (h : P.Rel x y) : y ∈ u := h.symm.left_mem
313331

314332
end Rel
315333

334+
/-! ### Representative functions
335+
336+
See the module docstring for motivation (graph simplification, minors, and why we use an explicit
337+
`IsRepFun` hypothesis rather than a global choice of representatives).
338+
-/
339+
340+
section IsRepFun
341+
342+
/-- A predicate characterizing when a function `f : α → α` is a representative function for a
343+
partition `P`. A representative function maps each element to a canonical representative in its
344+
equivalence class, is the identity outside the support, and maps related elements to the same
345+
representative. -/
346+
structure IsRepFun {u : Set α} (P : Partition u) (f : α → α) : Prop where
347+
apply_of_notMem : ∀ ⦃a⦄, a ∉ u → f a = a
348+
rel_apply : ∀ ⦃a⦄, a ∈ u → P.Rel a (f a)
349+
apply_eq_apply : ∀ ⦃a b⦄, P.Rel a b → f a = f b
350+
351+
namespace IsRepFun
352+
353+
variable {u : Set α} {P : Partition u} {f g : α → α} {a b c : α}
354+
355+
lemma apply_mem (hf : IsRepFun P f) (ha : a ∈ u) : f a ∈ u := (hf.rel_apply ha).right_mem
356+
357+
lemma image_subset (hf : IsRepFun P f) (hs : u ⊆ s) : f '' s ⊆ s := by
358+
rintro _ ⟨a, haS, rfl⟩
359+
by_cases ha : a ∈ u
360+
· exact hs <| hf.apply_mem ha
361+
exact (hf.apply_of_notMem ha).symm ▸ haS
362+
363+
lemma mapsTo (hf : IsRepFun P f) (hs : u ⊆ s) : Set.MapsTo f s s :=
364+
fun x h ↦ hf.image_subset hs ⟨x, h, rfl⟩
365+
366+
lemma mapsTo_of_disjoint (hf : IsRepFun P f) (hs : Disjoint u s) : Set.MapsTo f s s :=
367+
fun _ h ↦ (hf.apply_of_notMem <| hs.notMem_of_mem_right h).symm ▸ h
368+
369+
lemma apply_mem_iff (hf : IsRepFun P f) (hs : u ⊆ s) : f a ∈ s ↔ a ∈ s :=
370+
hf.mapsTo hs |>.mem_iff <| mapsTo_of_disjoint hf hs.disjoint_compl_right
371+
372+
lemma apply_eq_apply_iff_rel (hf : IsRepFun P f) (ha : a ∈ u) : f a = f b ↔ P.Rel a b := by
373+
refine ⟨fun hab ↦ (hf.rel_apply ha).trans ?_, (hf.apply_eq_apply ·)⟩
374+
rw [hab, P.rel_comm]
375+
refine hf.rel_apply <| by_contra fun hb ↦ ?_
376+
rw [hf.apply_of_notMem hb] at hab
377+
exact hab ▸ hb <| hf.apply_mem ha
378+
379+
lemma apply_eq_apply_iff (hf : IsRepFun P f) : f a = f b ↔ a = b ∨ P.Rel a b := by
380+
simp only [or_iff_not_imp_left, ← ne_eq]
381+
refine ⟨fun hab hne ↦ ?_, fun h ↦ ?_⟩
382+
· obtain (ha | ha) := em (a ∈ u)
383+
· exact hf.apply_eq_apply_iff_rel ha |>.mp hab
384+
obtain (hb | hb) := em (b ∈ u)
385+
· exact (hf.apply_eq_apply_iff_rel hb |>.mp hab.symm).symm
386+
rw [hf.apply_of_notMem ha, hf.apply_of_notMem hb] at hab
387+
contradiction
388+
obtain rfl | hne := eq_or_ne a b
389+
· rfl
390+
exact hf.apply_eq_apply (h hne)
391+
392+
lemma forall_apply_eq_apply_iff (hf : IsRepFun P f) (a) :
393+
(∀ (x : α), f a = f x ↔ a = x) ∨ (∀ (x : α), f a = f x ↔ P.Rel a x) := by
394+
refine (em (a ∈ u)).elim (fun ha ↦ Or.inr fun b ↦ ?_) (fun ha ↦ Or.inl fun b ↦ ?_)
395+
· rw [hf.apply_eq_apply_iff_rel ha]
396+
rw [hf.apply_of_notMem ha]
397+
constructor <;> rintro rfl
398+
· exact hf.apply_of_notMem <| hf.apply_mem_iff le_rfl |>.not.mp ha
399+
exact hf.apply_of_notMem ha |>.symm
400+
401+
lemma apply_eq_apply_iff' (hf : IsRepFun P f) :
402+
f a = f b ↔ (a = b ∧ ∀ c, f a = f c ↔ a = c) ∨ P.Rel a b := by
403+
obtain h1 | h2 := hf.forall_apply_eq_apply_iff a
404+
· refine ⟨by grind, ?_⟩
405+
rintro (h | h)
406+
· exact congrArg _ h.1
407+
exact hf.apply_eq_apply h
408+
grind
409+
410+
lemma idem (hf : IsRepFun P f) : f (f a) = f a := by
411+
obtain (ha | ha) := em (a ∈ u)
412+
· rw [eq_comm, hf.apply_eq_apply_iff_rel ha]
413+
exact hf.rel_apply ha
414+
simp_rw [hf.apply_of_notMem ha]
415+
416+
theorem apply_apply (hf : IsRepFun P f) (hg : IsRepFun P g) (x : α) : f (g x) = f x := by
417+
obtain (hx | hx) := em (x ∈ u)
418+
· exact hf.apply_eq_apply (hg.rel_apply hx).symm
419+
rw [hg.apply_of_notMem hx, hf.apply_of_notMem hx]
420+
421+
end IsRepFun.IsRepFun
316422
end Partition

0 commit comments

Comments
 (0)