[Merged by Bors] - feat(combinatorics/simple_graph/connected): support of connected components #18442
[Merged by Bors] - feat(combinatorics/simple_graph/connected): support of connected components #184420art0 wants to merge 32 commits intoleanprover-community:masterfrom
Conversation
|
Did you mean to give this PR a proper name? |
|
|
||
| /-- The set of vertices in a connected component of a graph. -/ | ||
| def connected_component.supp (C : G.connected_component) := | ||
| { v | G.connected_component_mk v = C } |
There was a problem hiding this comment.
| { v | G.connected_component_mk v = C } | |
| G.connected_component_mk ⁻¹' {C} |
is another, possibly more convenient, way to put it.
There was a problem hiding this comment.
We were considering it before making the PR, but decided to stick with the more verbose notation.
There was a problem hiding this comment.
I prefer the original notation: I feel it's a bit more transparent; e.g. when C := G.connected_component_mk v, membership is clear rfl while with the other notation you have (well, at least I do) to think to convince yourself that it unfolds to a rfl.
There was a problem hiding this comment.
In one of my branches I had written connected_component_mk ⁻¹' {c} directly, but since we're developing this API for the support of a connected component, I'm happy with { v | G.connected_component_mk v = C }.
|
Sorry for not updating the name of the PR earlier. |
|
I think we'll need to close the PR and open a new one eventually since the branch is wrong, and can't be changed in an existing PR. |
| h.elim (λ p, ⟨p.map f⟩) | ||
|
|
||
| lemma iso.reachable_iff {G : simple_graph V} {G' : simple_graph V'} | ||
| {φ : G ≃g G'} {u v : V} : G.reachable u v ↔ G'.reachable (φ u) (φ v) := |
There was a problem hiding this comment.
I would turn this one around
| {φ : G ≃g G'} {u v : V} : G.reachable u v ↔ G'.reachable (φ u) (φ v) := | ||
| ⟨reachable.map φ.to_hom, λ r, (φ.left_inv u) ▸ (φ.left_inv v) ▸ (r.map φ.symm.to_hom)⟩ | ||
|
|
||
| lemma iso.reachable_iff' {G : simple_graph V} {G' : simple_graph V'} |
There was a problem hiding this comment.
You can look at order_iso.symm_apply_le for a better naming convention.
|
|
||
| section connected_component | ||
| variables {G} | ||
| variables {G} {V'} {G'} {G''} |
There was a problem hiding this comment.
The following is valid syntax
| variables {G} {V'} {G'} {G''} | |
| variables {V' G G' G''} |
| by { refine C.ind _, exact (λ _, rfl), } | ||
|
|
||
| @[simp] lemma connected_component.iso_image_comp_eq_map_iff_eq_comp | ||
| {φ : G ≃g G'} {v : V} {C : G.connected_component} : |
There was a problem hiding this comment.
You can pull a few more variables out
| {φ : G ≃g G'} {v : V} {C : G.connected_component} : | |
| {C : G.connected_component} : |
| exact ((h v).mp (reachable.refl _)), | ||
| end | ||
|
|
||
| lemma connected_component.supp_inj {C D : G.connected_component} : C.supp = D.supp ↔ C = D := |
There was a problem hiding this comment.
| lemma connected_component.supp_inj {C D : G.connected_component} : C.supp = D.supp ↔ C = D := | |
| @[simp] lemma connected_component.supp_inj {C D : G.connected_component} : C.supp = D.supp ↔ C = D := |
| left_inv := λ v, subtype.ext_val (φ.to_equiv.left_inv ↑v), | ||
| right_inv := λ v, subtype.ext_val (φ.to_equiv.right_inv ↑v), } | ||
|
|
||
| lemma connected_component.connected : |
There was a problem hiding this comment.
| lemma connected_component.connected : | |
| protected lemma connected_component.connected : |
|
I will close this PR and open another one directly on |
|
Somehow the CI has started working on this branch (after my tinkering around with |
kmill
left a comment
There was a problem hiding this comment.
Most of my comments are minor, and if they're addressed I'd be happy with merging these parts. There is one major comment, which is I think we should exclude connected_component.connected from this PR.
It shouldn't be that bad to develop the theory to properly support this lemma, but it'll be enough work that I do not want it to hold up getting the rest merged.
| begin | ||
| rw [←φ.left_inv u, ←φ.right_inv v], | ||
| simp only [equiv.inv_fun_as_coe, equiv.to_fun_as_coe, rel_iso.coe_fn_to_equiv, | ||
| rel_iso.symm_apply_apply], | ||
| rw [iso.reachable_iff], | ||
| end |
There was a problem hiding this comment.
| begin | |
| rw [←φ.left_inv u, ←φ.right_inv v], | |
| simp only [equiv.inv_fun_as_coe, equiv.to_fun_as_coe, rel_iso.coe_fn_to_equiv, | |
| rel_iso.symm_apply_apply], | |
| rw [iso.reachable_iff], | |
| end | |
| by rw [← iso.reachable_iff, rel_iso.apply_symm_apply] |
|
|
||
| lemma connected_component_mk_eq_of_adj (G : simple_graph V) {v w : V} | ||
| (a : G.adj v w) : G.connected_component_mk v = G.connected_component_mk w := | ||
| connected_component.eq.mpr a.reachable |
There was a problem hiding this comment.
Is there a reason for G to be explicit here? If not, could you please make it be implicit?
Also, I think the proof would be nicer as connected_component.sound a.reachable.
There was a problem hiding this comment.
Further, you could leverage dot notation on adj.
| (G'.connected_component_mk (φ v)) = C.map φ.to_hom ↔ (G.connected_component_mk v) = C := | ||
| begin | ||
| refine C.ind (λ u, _), | ||
| simp only [connected_component.map_mk, connected_component.eq], | ||
| exact iso.reachable_iff, | ||
| end |
There was a problem hiding this comment.
Make sure to use the coercion for φ rather than φ.to_hom. There are some extraneous parenthesis as well, and note that you can combine the last two lines of the proof (you can squeeze it if you want).
| (G'.connected_component_mk (φ v)) = C.map φ.to_hom ↔ (G.connected_component_mk v) = C := | |
| begin | |
| refine C.ind (λ u, _), | |
| simp only [connected_component.map_mk, connected_component.eq], | |
| exact iso.reachable_iff, | |
| end | |
| G'.connected_component_mk (φ v) = C.map φ ↔ G.connected_component_mk v = C := | |
| begin | |
| refine C.ind (λ u, _), | |
| simp [iso.reachable_iff], | |
| end |
|
|
||
| @[simp] lemma connected_component.iso_inv_image_comp_eq_iff_eq_map | ||
| {C : G.connected_component} : | ||
| G.connected_component_mk (φ.symm v') = C ↔ G'.connected_component_mk v' = C.map φ := |
There was a problem hiding this comment.
| G.connected_component_mk (φ.symm v') = C ↔ G'.connected_component_mk v' = C.map φ := | |
| G.connected_component_mk (φ.symm v') = C ↔ G'.connected_component_mk v' = C.map φ := |
The last two lines of the proof can be merged as simp [iso.symm_apply_reachable]
| { to_fun := connected_component.map φ.to_hom, | ||
| inv_fun := connected_component.map φ.symm.to_hom, |
There was a problem hiding this comment.
| { to_fun := connected_component.map φ.to_hom, | |
| inv_fun := connected_component.map φ.symm.to_hom, | |
| { to_fun := connected_component.map φ, | |
| inv_fun := connected_component.map φ.symm, |
|
|
||
| /-- The set of vertices in a connected component of a graph. -/ | ||
| def connected_component.supp (C : G.connected_component) := | ||
| { v | G.connected_component_mk v = C } |
There was a problem hiding this comment.
In one of my branches I had written connected_component_mk ⁻¹' {c} directly, but since we're developing this API for the support of a connected component, I'm happy with { v | G.connected_component_mk v = C }.
| begin | ||
| refine connected_component.ind₂ _, | ||
| intros v w h, | ||
| simp only [set.ext_iff, connected_component.eq, set.mem_set_of_eq, connected_component.supp] at | ||
| h ⊢, | ||
| exact ((h v).mp (reachable.refl _)), | ||
| end |
There was a problem hiding this comment.
Here's perhaps less of a technical proof? In any case, I think the last line would be nice.
| begin | |
| refine connected_component.ind₂ _, | |
| intros v w h, | |
| simp only [set.ext_iff, connected_component.eq, set.mem_set_of_eq, connected_component.supp] at | |
| h ⊢, | |
| exact ((h v).mp (reachable.refl _)), | |
| end | |
| begin | |
| refine connected_component.ind₂ _, | |
| intros v w, | |
| simp only [connected_component.supp, set.ext_iff, connected_component.eq, set.mem_set_of_eq], | |
| intro h, | |
| rw [reachable_comm, h], | |
| end |
| v ∈ C.supp ↔ G.connected_component_mk v = C := iff.rfl | ||
|
|
||
| lemma connected_component_mk_mem (G : simple_graph V) {v : V} : | ||
| v ∈ G.connected_component_mk v := by { exact rfl, } |
There was a problem hiding this comment.
Maybe G should be implicit?
Just to nitpick, you can do this:
| v ∈ G.connected_component_mk v := by { exact rfl, } | |
| v ∈ G.connected_component_mk v := by exact rfl |
| { to_fun := λ v, ⟨φ.to_fun v.val, connected_component.iso_image_comp_eq_map_iff_eq_comp.mpr v.prop⟩, | ||
| inv_fun := λ v', ⟨φ.inv_fun v', connected_component.iso_inv_image_comp_eq_iff_eq_map.mpr v'.prop⟩, |
There was a problem hiding this comment.
I haven't tested this, but these should work, and it would be preferred:
| { to_fun := λ v, ⟨φ.to_fun v.val, connected_component.iso_image_comp_eq_map_iff_eq_comp.mpr v.prop⟩, | |
| inv_fun := λ v', ⟨φ.inv_fun v', connected_component.iso_inv_image_comp_eq_iff_eq_map.mpr v'.prop⟩, | |
| { to_fun := λ v, ⟨φ v, connected_component.iso_image_comp_eq_map_iff_eq_comp.mpr v.prop⟩, | |
| inv_fun := λ v', ⟨φ.symm v', connected_component.iso_inv_image_comp_eq_iff_eq_map.mpr v'.prop⟩, |
| rintro ⟨u,hu⟩ ⟨w,hw⟩, | ||
| simp only [connected_component.eq, set.mem_set_of_eq] at hu hw, | ||
| exact this (reachable.trans hu $ reachable.symm hw).some hu hw, | ||
| end |
There was a problem hiding this comment.
I don't think this lemma is ready for the library. To do it right, we should have supporting theory for relating walks in G.induce s to walks whose support is contained in s.
I started writing
def induce_lift (s : set V) : Π {v w : V} (p : G.walk v w) (h : ∀ u, u ∈ p.support → u ∈ s),
(G.induce s).walk ⟨v, h v p.start_mem_support⟩ ⟨w, h w p.end_mem_support⟩
| _ _ walk.nil _ := walk.nil
| _ _ (walk.cons' u v w ha p) h :=
let p' := induce_lift p (λ x hx, h x (by simp [hx]))
in walk.cons (by exact ha) p'
but fleshing everything out would take some time. Would you be ok with removing the lemma for now?
There was a problem hiding this comment.
Thanks for the review! I agree having a more general theory for mapping walks back and forth would be better (this is how we handled it before), but at the same time the lemma works as-is and can be made to use this API when it gets there…
Since it's needed to make progress on Freudenthal-Hopf, I'd rather have it there, but I understand if you don't want to introduce "half-baked" results in simple_graph.*. Your call in any case :)
There was a problem hiding this comment.
I get that it works as-is, but at least for now it seems somewhat out of place from the rest of the PR.
I'm dusting off some things I have in a branch to make use of what you have here. I've said it before, but I suspect a number of things are cleaner through subgraphs rather than induced graphs (or at least, if you want to work with induced graphs, they can follow from facts about subgraphs).
In the meantime, would you be ok keeping this lemma in your Freudenthal-Hopf project?
There was a problem hiding this comment.
Yeah, works for me :) (I'm not doing any changes (yet?) since @0art0 might want to pitch in first and/or do the changes themselves).
|
Merge conflict. |
|
@bottine Regarding mathlib4 synchronization, for now my plan was to do them myself, collecting multiple mathlib3 PRs and updating mathlib4 in batches. But if you need something sooner go ahead. Once every file in |
|
There were a few issues left that I couldn't fix yesterday. I have now integrated the changes from #18410 into this PR. I noticed that there was some overlap between the PRs - |
|
@0art0 Thanks! Indeed, the |
That's very good to hear! I hate doing sync PRs, so if you can take care of it and we can just work on mathlib4 asap, that's doubly good news. |
|
@kmill This pleases the linter, but it's a bit ugly. Any alternative? |
|
Shall we ask bors to merge this now? |
|
@kmill could you take another look at this? |
|
bors r+ |
…onents (#18442) Co-authored-by: Rémi Bottinelli <remi.bottinelli@bluewin.ch> Co-authored-by: ART <anand.rao.art@gmail.com> Co-authored-by: Anand Rao <18333981+0art0@users.noreply.github.com>
|
Pull request successfully merged into master. Build succeeded: |
Co-authored-by: Rémi Bottinelli remi.bottinelli@bluewin.ch
Some basic API around the definition of the "support" of a connected component of a graph. The support consists of the set of vertices in a given component. This can be a convenient definition in certain situations.