Skip to content

Commit 2b7a1dd

Browse files
committed
feat(Combinatorics/SimpleGraph/Copy): add indLabelledCopyCount and indCopyCount
Fills in the two TODO sections in `Mathlib/Combinatorics/SimpleGraph/Copy.lean`: - `indLabelledCopyCount`: number of induced labelled copies of `H` in `G` (i.e. `|H ↪g G|`), the induced analogue of `labelledCopyCount` - `indCopyCount`: number of induced unlabelled copies of `H` in `G` (i.e. number of induced subgraphs of `G` isomorphic to `H`), the induced analogue of `copyCount` Supporting additions: - `Copy.range_embeddingToSubgraph`: range of `f ↦ f.toCopy.toSubgraph` over embeddings equals `{B' | B'.IsInduced ∧ Nonempty (H ≃g B'.coe)}`, the induced analogue of `Copy.range_toSubgraph` - `Subgraph.coe_isIndContained`: induced analogue of `Subgraph.coe_isContained` - `Subgraph.IsInduced.toEmbedding`: canonical embedding `G'.coe ↪g G` for an induced subgraph, the embedding analogue of `Subgraph.hom` - `Subgraph.IsInduced.map`: mapping an induced subgraph through an embedding stays induced - `Embedding.comp_toHom`: `(f'.comp f).toHom = f'.toHom.comp f.toHom` (@[simp])
1 parent 1fd32e2 commit 2b7a1dd

3 files changed

Lines changed: 125 additions & 8 deletions

File tree

Mathlib/Combinatorics/SimpleGraph/Copy.lean

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ Containment:
4545
Induced containment:
4646
* Induced copies of `G` inside `H` are already defined as `G ↪g H`.
4747
* `SimpleGraph.IsIndContained G H` : `G` is contained as an induced subgraph in `H`.
48+
* `SimpleGraph.indLabelledCopyCount G H`: Number of induced labelled copies of `H` in `G`, i.e.
49+
number of graph embeddings `H ↪g G`.
50+
* `SimpleGraph.indCopyCount G H`: Number of induced unlabelled copies of `H` in `G`, i.e. number
51+
of induced subgraphs of `G` isomorphic to `H`.
4852
4953
## Notation
5054
@@ -55,7 +59,6 @@ The following notation is declared in scope `SimpleGraph`:
5559
## TODO
5660
5761
* Relate `⊥ ⊴ H` to there being an independent set in `H`.
58-
* Count induced copies of a graph inside another.
5962
* Make `copyCount`/`labelledCopyCount` computable (not necessarily efficiently).
6063
-/
6164

@@ -187,6 +190,19 @@ noncomputable def isoToSubgraph (f : Copy A B) : A ≃g f.toSubgraph.coe :=
187190
refine ⟨⟨H'.hom.comp e.toHom, Subgraph.hom_injective.comp e.injective⟩, ?_⟩
188191
simp [toSubgraph, Subgraph.map_comp]
189192

193+
/-- The range of `f ↦ f.toCopy.toSubgraph` over embeddings is exactly the induced subgraphs
194+
isomorphic to `A`. Induced analogue of `Copy.range_toSubgraph`. -/
195+
lemma range_embeddingToSubgraph :
196+
Set.range (fun f : A ↪g B => f.toCopy.toSubgraph) =
197+
{B' : B.Subgraph | B'.IsInduced ∧ Nonempty (A ≃g B'.coe)} := by
198+
ext G'
199+
simp only [Set.mem_range, Set.mem_setOf_eq]
200+
constructor
201+
· rintro ⟨f, rfl⟩
202+
exact ⟨Subgraph.IsInduced.top.map f, ⟨f.toCopy.isoToSubgraph⟩⟩
203+
· rintro ⟨hInd, ⟨e⟩⟩
204+
exact ⟨hInd.toEmbedding.comp e.toEmbedding, by simp [toSubgraph, Subgraph.map_comp]⟩
205+
190206
lemma toSubgraph_surjOn :
191207
Set.SurjOn (toSubgraph (A := A)) .univ {B' : B.Subgraph | Nonempty (A ≃g B'.coe)} :=
192208
fun H' hH' ↦ by simpa
@@ -409,11 +425,8 @@ protected lemma Iso.isIndContained (e : G ≃g H) : G ⊴ H := e.toEmbedding.isI
409425
/-- If `G` is isomorphic to `H`, then `H` is inducingly contained in `G`. -/
410426
protected lemma Iso.isIndContained' (e : G ≃g H) : H ⊴ G := e.symm.isIndContained
411427

412-
protected lemma Subgraph.IsInduced.isIndContained {G' : G.Subgraph} (hG' : G'.IsInduced) :
413-
G'.coe ⊴ G :=
414-
⟨{ toFun := (↑)
415-
inj' := Subtype.coe_injective
416-
map_rel_iff' := hG'.adj.symm }⟩
428+
lemma Subgraph.coe_isIndContained {G' : G.Subgraph} (hG' : G'.IsInduced) : G'.coe ⊴ G :=
429+
⟨hG'.toEmbedding⟩
417430

418431
@[refl] lemma IsIndContained.refl (G : SimpleGraph V) : G ⊴ G := ⟨Embedding.refl⟩
419432
lemma IsIndContained.rfl : G ⊴ G := .refl _
@@ -440,7 +453,7 @@ lemma isIndContained_iff_exists_iso_subgraph :
440453
refine ⟨Subgraph.map f.toHom ⊤, f.toCopy.isoToSubgraph, ?_⟩
441454
simp [Subgraph.IsInduced, Relation.map_apply_apply, f.injective]
442455
· rintro ⟨H', e, hH'⟩
443-
exact e.isIndContained.trans hH'.isIndContained
456+
exact e.isIndContained.trans (Subgraph.coe_isIndContained hH')
444457

445458
alias ⟨IsIndContained.exists_iso_subgraph, IsIndContained.of_exists_iso_subgraph⟩ :=
446459
isIndContained_iff_exists_iso_subgraph
@@ -543,9 +556,92 @@ end CopyCount
543556

544557
/-!
545558
#### Induced copies
559+
-/
546560

547-
TODO
561+
section IndLabelledCopyCount
562+
variable [Fintype V] [Fintype W]
563+
564+
/-- `G.indLabelledCopyCount H` is the number of induced labelled copies of `H` in `G`,
565+
i.e., the number of graph embeddings from `H` to `G`.
566+
567+
This is the induced analogue of `SimpleGraph.labelledCopyCount`. -/
568+
noncomputable def indLabelledCopyCount (G : SimpleGraph V) (H : SimpleGraph W) : ℕ := by
569+
classical exact Fintype.card (H ↪g G)
570+
571+
@[simp] lemma indLabelledCopyCount_of_isEmpty [IsEmpty W] (G : SimpleGraph V) (H : SimpleGraph W) :
572+
G.indLabelledCopyCount H = 1 := by
573+
convert Fintype.card_unique
574+
exact { default := RelEmbedding.ofIsEmpty H.Adj G.Adj
575+
uniq := fun f => RelEmbedding.ext fun a => isEmptyElim a }
576+
577+
@[simp] lemma indLabelledCopyCount_eq_zero : G.indLabelledCopyCount H = 0 ↔ ¬(H ⊴ G) := by
578+
simp [indLabelledCopyCount, Fintype.card_eq_zero_iff, IsIndContained]
579+
580+
@[simp] lemma indLabelledCopyCount_pos : 0 < G.indLabelledCopyCount H ↔ H ⊴ G := by
581+
simp [Nat.pos_iff_ne_zero, indLabelledCopyCount_eq_zero]
582+
583+
/-- Every induced labelled copy is a (non-induced) labelled copy. -/
584+
lemma indLabelledCopyCount_le_labelledCopyCount :
585+
G.indLabelledCopyCount H ≤ G.labelledCopyCount H := by
586+
classical
587+
simp only [indLabelledCopyCount, labelledCopyCount]
588+
exact Fintype.card_le_of_injective Embedding.toCopy fun f g h =>
589+
RelEmbedding.ext fun w => DFunLike.congr_fun h w
590+
591+
end IndLabelledCopyCount
592+
593+
section IndCopyCount
594+
variable [Fintype V]
548595

596+
/-- `G.indCopyCount H` is the number of induced unlabelled copies of `H` in `G`,
597+
i.e., the number of induced subgraphs of `G` isomorphic to `H`.
598+
599+
This is the induced analogue of `SimpleGraph.copyCount`. -/
600+
noncomputable def indCopyCount (G : SimpleGraph V) (H : SimpleGraph W) : ℕ := by
601+
classical exact #{G' : G.Subgraph | G'.IsInduced ∧ Nonempty (H ≃g G'.coe)}
602+
603+
lemma indCopyCount_eq_card_image_embeddingToSubgraph
604+
[Fintype W] [DecidableEq G.Subgraph] :
605+
G.indCopyCount H = #((Finset.univ : Finset (H ↪g G)).image (·.toCopy.toSubgraph)) := by
606+
rw [indCopyCount]
607+
congr
608+
refine Finset.coe_injective ?_
609+
simpa using Copy.range_embeddingToSubgraph.symm
610+
611+
@[simp] lemma indCopyCount_pos : 0 < G.indCopyCount H ↔ H ⊴ G := by
612+
rw [isIndContained_iff_exists_iso_subgraph]
613+
classical
614+
simp only [indCopyCount, card_pos, filter_nonempty_iff, mem_univ, true_and]
615+
exact ⟨fun ⟨G', hInd, hn⟩ => ⟨G', hn.some, hInd⟩,
616+
fun ⟨G', e, hInd⟩ => ⟨G', hInd, ⟨e⟩⟩⟩
617+
618+
@[simp] lemma indCopyCount_eq_zero : G.indCopyCount H = 0 ↔ ¬(H ⊴ G) := by
619+
rw [← indCopyCount_pos]; omega
620+
621+
/-- Every induced unlabelled copy corresponds to at least one induced labelled copy. -/
622+
lemma indCopyCount_le_indLabelledCopyCount [Fintype W] :
623+
G.indCopyCount H ≤ G.indLabelledCopyCount H := by
624+
classical
625+
rw [indCopyCount_eq_card_image_embeddingToSubgraph, indLabelledCopyCount]
626+
exact card_image_le
627+
628+
@[simp] lemma indCopyCount_of_isEmpty [IsEmpty W] (G : SimpleGraph V) (H : SimpleGraph W) :
629+
G.indCopyCount H = 1 := by
630+
cases nonempty_fintype W
631+
exact (indCopyCount_le_indLabelledCopyCount.trans_eq <|
632+
indLabelledCopyCount_of_isEmpty ..).antisymm <|
633+
indCopyCount_pos.2 <| .of_isEmpty
634+
635+
/-- Every induced unlabelled copy is a (non-induced) unlabelled copy. -/
636+
lemma indCopyCount_le_copyCount : G.indCopyCount H ≤ G.copyCount H := by
637+
classical
638+
simp only [indCopyCount, copyCount]
639+
exact Finset.card_le_card fun G' hG' => by
640+
simp only [mem_filter, mem_univ, true_and] at hG' ⊢; exact hG'.2
641+
642+
end IndCopyCount
643+
644+
/-!
549645
### Killing a subgraph
550646
551647
An important aspect of graph containment is that we can remove not too many edges from a graph `H`

Mathlib/Combinatorics/SimpleGraph/Maps.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,9 @@ abbrev comp (f' : G' ↪g G'') (f : G ↪g G') : G ↪g G'' :=
529529
theorem coe_comp (f' : G' ↪g G'') (f : G ↪g G') : ⇑(f'.comp f) = f' ∘ f :=
530530
rfl
531531

532+
@[simp] lemma comp_toHom (f' : G' ↪g G'') (f : G ↪g G') :
533+
(f'.comp f).toHom = f'.toHom.comp f.toHom := rfl
534+
532535
/-- Graph embeddings from `G` to `H` are the same thing as graph embeddings from `Gᶜ` to `Hᶜ`. -/
533536
def complEquiv : G ↪g H ≃ Gᶜ ↪g Hᶜ where
534537
toFun f := ⟨f.toEmbedding, by simp⟩

Mathlib/Combinatorics/SimpleGraph/Subgraph.lean

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,15 @@ theorem map_sup (f : G →g G') (H₁ H₂ : G.Subgraph) : (H₁ ⊔ H₂).map f
669669
@[simp] lemma edgeSet_map (f : G →g G') (H : G.Subgraph) :
670670
(H.map f).edgeSet = Sym2.map f '' H.edgeSet := Sym2.fromRel_relationMap ..
671671

672+
lemma IsInduced.map {H : G.Subgraph} (hH : H.IsInduced) (e : G ↪g G') :
673+
(H.map e.toHom).IsInduced := by
674+
intro v hv w hw hAdj
675+
rw [map_verts] at hv hw
676+
obtain ⟨a, ha, rfl⟩ := hv
677+
obtain ⟨b, hb, rfl⟩ := hw
678+
simp only [map_adj, Relation.map_apply]
679+
exact ⟨a, b, hH ha hb (e.map_adj_iff.mp hAdj), rfl, rfl⟩
680+
672681
end map
673682

674683
/-- Graph homomorphisms induce a contravariant function on subgraphs. -/
@@ -747,6 +756,15 @@ theorem hom_injective {x : Subgraph G} : Function.Injective x.hom :=
747756
@[simp] lemma map_hom_top (G' : G.Subgraph) : Subgraph.map G'.hom ⊤ = G' := by
748757
aesop (add unfold safe Relation.Map, unsafe G'.edge_vert, unsafe Adj.symm)
749758

759+
/-- The canonical embedding of an induced subgraph into the ambient graph.
760+
Unlike `Subgraph.hom`, this is an embedding rather than a homomorphism, since induced subgraphs
761+
reflect adjacency. -/
762+
def IsInduced.toEmbedding {G' : G.Subgraph} (hG' : G'.IsInduced) : G'.coe ↪g G :=
763+
{ toFun := (↑), inj' := Subtype.coe_injective, map_rel_iff' := hG'.adj.symm }
764+
765+
@[simp] lemma IsInduced.toHom_toEmbedding {G' : G.Subgraph} (hG' : G'.IsInduced) :
766+
hG'.toEmbedding.toHom = G'.hom := rfl
767+
750768
/-- There is an induced injective homomorphism of a subgraph of `G` as
751769
a spanning subgraph into `G`. -/
752770
@[simps]

0 commit comments

Comments
 (0)