@@ -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+
190206lemma 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`. -/
410426protected 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⟩
419432lemma 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
445458alias ⟨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
551647An important aspect of graph containment is that we can remove not too many edges from a graph `H`
0 commit comments