Skip to content

Commit 578c033

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 578c033

3 files changed

Lines changed: 123 additions & 5 deletions

File tree

Mathlib/Combinatorics/SimpleGraph/Copy.lean

Lines changed: 102 additions & 5 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
@@ -411,9 +427,7 @@ protected lemma Iso.isIndContained' (e : G ≃g H) : H ⊴ G := e.symm.isIndCont
411427

412428
protected lemma Subgraph.IsInduced.isIndContained {G' : G.Subgraph} (hG' : G'.IsInduced) :
413429
G'.coe ⊴ G :=
414-
⟨{ toFun := (↑)
415-
inj' := Subtype.coe_injective
416-
map_rel_iff' := hG'.adj.symm }⟩
430+
⟨hG'.toEmbedding⟩
417431

418432
@[refl] lemma IsIndContained.refl (G : SimpleGraph V) : G ⊴ G := ⟨Embedding.refl⟩
419433
lemma IsIndContained.rfl : G ⊴ G := .refl _
@@ -543,9 +557,92 @@ end CopyCount
543557

544558
/-!
545559
#### Induced copies
560+
-/
546561

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

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