@@ -22,8 +22,18 @@ equivalent to saying that there is a graph embedding `G ↪ H`.
2222
2323## Main declarations
2424
25- * `SimpleGraph.is_contained G H` : `G` is contained in `H`.
26- * `SimpleGraph.isIndContained G H` : `G` is contained as an induced subgraph in `H`.
25+ * `SimpleGraph.Copy A B` is the type of copies of `A` in `B`, implemented as the subtype of
26+ *injective* homomorphisms.
27+ * `SimpleGraph.IsContained A B`, `A ⊑ B` is the relation that `B` contains a copy of `A`, that
28+ is, the type of copies of `A` in `B` is nonempty. This is equivalent to the existence of an
29+ isomorphism from `A` to a subgraph of `B`.
30+
31+ This is similar to `SimpleGraph.IsSubgraph` except that the simple graphs here need not have the
32+ same underlying vertex type.
33+ * `SimpleGraph.Free` is the predicate that `B` is `A`-free, that is, `B` does not contain a copy of
34+ `A`. This is the negation of `SimpleGraph.IsContained` implemented for convenience.
35+
36+ * `SimpleGraph.IsIndContained G H` : `G` is contained as an induced subgraph in `H`.
2737* `SimpleGraph.copyCount G H`: Number of copies `G` in `H`.
2838* `SimpleGraph.kill G H`: Subgraph of `H` that does not contain `G`. Obtained by arbitrarily
2939 removing an edge from each copy of `G` in `H`.
@@ -40,60 +50,192 @@ open Fintype (card)
4050open scoped BigOperators Classical
4151
4252namespace SimpleGraph
43- variable {α β γ : Type *} {G G₁ G₂ G₃ : SimpleGraph α} {H : SimpleGraph β} {I : SimpleGraph γ}
4453
45- /-!
46- ### Containment
54+ variable {V α β γ : Type *} {G G₁ G₂ G₃ : SimpleGraph V}
55+ {A : SimpleGraph α} {B : SimpleGraph β} {C : SimpleGraph γ}
4756
48- A graph `H` *contains* a graph `G` if there is some injective graph homomorphism `G → H`. This
49- amounts to `H` having a (not necessarily induced) subgraph isomorphic to `G`.
57+ section Copy
5058
51- We denote "`G` is contained in `H`" by `G ⊑ H` (`\squ`).
52- -/
59+ /-- The type of copies as a subtype of *injective* homomorphisms. -/
60+ abbrev Copy (A : SimpleGraph α) (B : SimpleGraph β) :=
61+ { f : A →g B // Function.Injective f }
62+
63+ /-- An injective homomorphism gives rise to a copy. -/
64+ abbrev Hom.toCopy (f : A →g B) (h : Function.Injective f) : Copy A B := ⟨f, h⟩
65+
66+ /-- An embedding gives rise to a copy. -/
67+ abbrev Embedding.toCopy (f : A ↪g B) : Copy A B := f.toHom.toCopy f.injective
68+
69+ /-- An isomorphism gives rise to a copy. -/
70+ abbrev Iso.toCopy (f : A ≃g B) : Copy A B := f.toEmbedding.toCopy
71+
72+ namespace Copy
73+
74+ /-- A copy gives rise to a homomorphism. -/
75+ abbrev toHom : Copy A B → A →g B := Subtype.val
76+
77+ @[simp] lemma coe_toHom (f : Copy A B) : ⇑f.toHom = f := rfl
78+
79+ lemma injective : (f : Copy A B) → (Function.Injective f.toHom) := Subtype.prop
80+
81+ instance : FunLike (Copy A B) α β where
82+ coe f := DFunLike.coe f.toHom
83+ coe_injective' _ _ h := Subtype.val_injective (DFunLike.coe_injective h)
84+
85+ @[simp] lemma coe_toHom_apply (f : Copy A B) (a : α) : ⇑f.toHom a = f a := rfl
86+
87+ /-- A copy induces an embedding of edge sets. -/
88+ def mapEdgeSet (f : Copy A B) : A.edgeSet ↪ B.edgeSet where
89+ toFun := Hom.mapEdgeSet f.toHom
90+ inj' := Hom.mapEdgeSet.injective f.toHom f.injective
91+
92+ /-- A copy induces an embedding of neighbor sets. -/
93+ def mapNeighborSet (f : Copy A B) (a : α) :
94+ A.neighborSet a ↪ B.neighborSet (f a) where
95+ toFun v := ⟨f v, f.toHom.apply_mem_neighborSet v.prop⟩
96+ inj' _ _ h := by
97+ rw [Subtype.mk_eq_mk] at h ⊢
98+ exact f.injective h
99+
100+ /-- A copy gives rise to an embedding of vertex types. -/
101+ def toEmbedding (f : Copy A B) : α ↪ β := ⟨f, f.injective⟩
102+
103+ /-- The identity copy from a simple graph to itself. -/
104+ @[refl] def id (G : SimpleGraph V) : Copy G G := ⟨Hom.id, Function.injective_id⟩
105+
106+ @[simp, norm_cast] lemma coe_id : ⇑(id G) = _root_.id := rfl
107+
108+ /-- The composition of copies is a copy. -/
109+ def comp (g : Copy B C) (f : Copy A B) : Copy A C := by
110+ use g.toHom.comp f.toHom
111+ rw [Hom.coe_comp]
112+ exact Function.Injective.comp g.injective f.injective
113+
114+ @[simp]
115+ theorem comp_apply (g : Copy B C) (f : Copy A B) (a : α) : g.comp f a = g (f a) :=
116+ RelHom.comp_apply g.toHom f.toHom a
117+
118+ /-- The copy from a subgraph to the supergraph. -/
119+ def ofLE (G₁ G₂ : SimpleGraph V) (h : G₁ ≤ G₂) : Copy G₁ G₂ := ⟨Hom.ofLE h, Function.injective_id⟩
120+
121+ @[simp, norm_cast]
122+ theorem coe_comp (g : Copy B C) (f : Copy A B) : ⇑(g.comp f) = g ∘ f := by ext; simp
123+
124+ @[simp, norm_cast] lemma coe_ofLE (h : G₁ ≤ G₂) : ⇑(ofLE G₁ G₂ h) = _root_.id := rfl
125+
126+ @[simp] theorem ofLE_refl : ofLE G G (le_refl G) = id G := by ext; simp
127+
128+ @[simp]
129+ theorem ofLE_comp (h₁₂ : G₁ ≤ G₂) (h₂₃ : G₂ ≤ G₃) :
130+ (ofLE _ _ h₂₃).comp (ofLE _ _ h₁₂) = ofLE _ _ (h₁₂.trans h₂₃) := by ext; simp
53131
54- /-- A simple graph `G` is contained in a simple graph `H` if there exists a subgraph of `H`
55- isomorphic to `G`. This is denoted by `G ⊑ H`. -/
56- def IsContained (G : SimpleGraph α) (H : SimpleGraph β) : Prop :=
57- ∃ f : G →g H, Injective f
132+ /-- The copy from an induced subgraph to the initial simple graph. -/
133+ def induce (G : SimpleGraph V) (s : Set V) : Copy (G.induce s) G :=
134+ (Embedding.induce s).toCopy
58135
59- scoped infixl : 50 " ⊑ " => SimpleGraph.IsContained
136+ end Copy
60137
61- lemma isContained_of_le (h : G₁ ≤ G₂) : G₁ ⊑ G₂ := ⟨.ofLE h, injective_id⟩
138+ /-- A `Subgraph G` gives rise to a copy from the coercion to `G`. -/
139+ def Subgraph.coeCopy (G' : G.Subgraph) : Copy G'.coe G :=
140+ G'.hom.toCopy Subgraph.hom.injective
62141
63- protected lemma Iso.isContained (e : G ≃g H) : G ⊑ H := ⟨e, e.injective⟩
64- protected lemma Iso.isContained' (e : G ≃g H) : H ⊑ G := e.symm.isContained
142+ end Copy
65143
66- lemma Subgraph.coe_isContained (G' : G.Subgraph) : G'.coe ⊑ G :=
67- ⟨G'.hom, Subtype.val_injective⟩
144+ section IsContained
68145
69- @[refl] lemma isContained_refl (G : SimpleGraph α) : G ⊑ G := isContained_of_le le_rfl
70- lemma isContained_rfl : G ⊑ G := isContained_refl _
71- lemma IsContained.trans : G ⊑ H → H ⊑ I → G ⊑ I := fun ⟨f, hf⟩ ⟨g, hg⟩ ↦ ⟨g.comp f, hg.comp hf⟩
146+ /-- The relation `IsContained A B`, `A ⊑ B` says that `B` contains a copy of `A`.
72147
73- lemma IsContained.mono_left (h₁₂ : G₁ ≤ G₂) (h₂₃ : G₂ ⊑ G₃) : G₁ ⊑ G₃ :=
74- (isContained_of_le h₁₂).trans h₂₃
148+ This is equivalent to the existence of an isomorphism from `A` to a subgraph of `B`. -/
149+ abbrev IsContained (A : SimpleGraph α) (B : SimpleGraph β) := Nonempty (Copy A B)
75150
76- lemma IsContained.mono_right (h₁₂ : G₁ ⊑ G₂) (h₂₃ : G₂ ≤ G₃) : G₁ ⊑ G₃ :=
77- h₁₂.trans <| isContained_of_le h₂₃
151+ @[inherit_doc] scoped infixl :50 " ⊑ " => SimpleGraph.IsContained
152+
153+ /-- A simple graph contains itself. -/
154+ @[refl] protected theorem IsContained.refl (G : SimpleGraph V) : G ⊑ G := ⟨.id G⟩
155+
156+ protected theorem IsContained.rfl : G ⊑ G := IsContained.refl G
157+
158+ /-- A simple graph contains its subgraphs. -/
159+ theorem isContained_of_le (h : G₁ ≤ G₂) : G₁ ⊑ G₂ := ⟨Copy.ofLE G₁ G₂ h⟩
160+
161+ /-- If `A` contains `B` and `B` contains `C`, then `A` contains `C`. -/
162+ theorem IsContained.trans : A ⊑ B → B ⊑ C → A ⊑ C := fun ⟨f⟩ ⟨g⟩ ↦ ⟨g.comp f⟩
163+
164+ /-- If `B` contains `C` and `A` contains `B`, then `A` contains `C`. -/
165+ theorem IsContained.trans' : B ⊑ C → A ⊑ B → A ⊑ C := flip IsContained.trans
166+
167+ lemma IsContained.mono_right {B' : SimpleGraph β} (h_isub : A ⊑ B) (h_sub : B ≤ B') : A ⊑ B' :=
168+ h_isub.trans <| isContained_of_le h_sub
78169
79170alias IsContained.trans_le := IsContained.mono_right
80171
81- lemma isContained_of_isEmpty [IsEmpty α] : G ⊑ H :=
82- ⟨{ toFun := isEmptyElim
83- map_rel' := fun {a} ↦ isEmptyElim a }, isEmptyElim⟩
172+ lemma IsContained.mono_left {A' : SimpleGraph α} (h_sub : A ≤ A') (h_isub : A' ⊑ B) : A ⊑ B :=
173+ (isContained_of_le h_sub).trans h_isub
84174
85- lemma bot_isContained (f : α ↪ β) : (⊥ : SimpleGraph α) ⊑ H :=
86- ⟨{ toFun := f
87- map_rel' := False.elim }, f.injective⟩
175+ alias IsContained.trans_le' := IsContained.mono_left
88176
89- lemma isContained_iff_exists_subgraph : G ⊑ H ↔ ∃ H' : H.Subgraph, Nonempty <| G ≃g H'.coe := by
90- constructor
91- · rintro ⟨f, hf⟩
92- exact ⟨Subgraph.map f ⊤, ⟨(Subgraph.isoMap _ hf _).comp Subgraph.topIso.symm⟩⟩
93- · rintro ⟨H', ⟨e⟩⟩
94- exact e.isContained.trans H'.coe_isContained
177+ /-- If `A ≃g B`, then `A` is contained in `C` if and only if `B` is contained in `C`. -/
178+ theorem isContained_congr (e : A ≃g B) : A ⊑ C ↔ B ⊑ C :=
179+ ⟨.trans ⟨e.symm.toCopy⟩, .trans ⟨e.toCopy⟩⟩
180+
181+ /-- A simple graph having no vertices is contained in any simple graph. -/
182+ lemma IsContained.of_isEmpty [IsEmpty α] : A ⊑ B :=
183+ ⟨⟨isEmptyElim, fun {a} ↦ isEmptyElim a⟩, isEmptyElim⟩
184+
185+ /-- A simple graph having no edges is contained in any simple graph having sufficent vertices. -/
186+ theorem isContained_of_isEmpty_edgeSet [IsEmpty A.edgeSet] [Fintype α] [Fintype β]
187+ (h : card α ≤ card β) : A ⊑ B := by
188+ haveI := Function.Embedding.nonempty_of_card_le h
189+ let ι : α ↪ β := Classical.arbitrary (α ↪ β)
190+ exact ⟨⟨ι, isEmptyElim ∘ fun hadj ↦ (⟨s(_, _), hadj⟩ : A.edgeSet)⟩, ι.injective⟩
191+
192+ lemma bot_isContained (f : α ↪ β) : (⊥ : SimpleGraph α) ⊑ B := ⟨⟨f, False.elim⟩, f.injective⟩
193+
194+ protected alias IsContained.bot := bot_isContained
95195
96- alias ⟨IsContained.exists_subgraph, _⟩ := isContained_iff_exists_subgraph
196+ /-- A simple graph `G` contains all `Subgraph G` coercions. -/
197+ lemma Subgraph.coe_isContained (G' : G.Subgraph) : G'.coe ⊑ G := ⟨G'.coeCopy⟩
198+
199+ /-- The isomorphism from `Subgraph A` to its map under a copy `Copy A B`. -/
200+ noncomputable def Subgraph.isoMap (f : Copy A B) (A' : A.Subgraph) :
201+ A'.coe ≃g (A'.map f.toHom).coe := by
202+ use Equiv.Set.image f.toHom _ f.injective
203+ simp_rw [map_verts, Equiv.Set.image_apply, coe_adj, map_adj, Relation.map_apply,
204+ Function.Injective.eq_iff f.injective, exists_eq_right_right, exists_eq_right, forall_true_iff]
205+
206+ /-- `B` contains `A` if and only if `B` has a subgraph `B'` and `B'` is isomorphic to `A`. -/
207+ theorem isContained_iff_exists_iso_subgraph :
208+ A ⊑ B ↔ ∃ B' : B.Subgraph, Nonempty (A ≃g B'.coe) :=
209+ ⟨fun ⟨f⟩ ↦ ⟨Subgraph.map f.toHom ⊤, ⟨(Subgraph.isoMap f ⊤).comp Subgraph.topIso.symm⟩⟩,
210+ fun ⟨B', ⟨e⟩⟩ ↦ B'.coe_isContained.trans' ⟨e.toCopy⟩⟩
211+
212+ alias ⟨IsContained.exists_iso_subgraph, IsContained.of_exists_iso_subgraph⟩ :=
213+ isContained_iff_exists_iso_subgraph
214+
215+ end IsContained
216+
217+ section Free
218+
219+ /-- The proposition that a simple graph does not contain a copy of another simple graph. -/
220+ abbrev Free (A : SimpleGraph α) (B : SimpleGraph β) := ¬A ⊑ B
221+
222+ lemma not_free : ¬A.Free B ↔ A ⊑ B := not_not
223+
224+ /-- If `A ≃g B`, then `C` is `A`-free if and only if `C` is `B`-free. -/
225+ theorem free_congr (e : A ≃g B) : A.Free C ↔ B.Free C := by
226+ rw [not_iff_not]
227+ exact isContained_congr e
228+
229+ lemma free_bot (h : A ≠ ⊥) : A.Free (⊥ : SimpleGraph β) := by
230+ rw [← edgeSet_nonempty] at h
231+ intro ⟨f, hf⟩
232+ absurd f.map_mem_edgeSet h.choose_spec
233+ rw [edgeSet_bot]
234+ exact Set.not_mem_empty (h.choose.map f)
235+
236+ end Free
237+
238+ variable {α β γ : Type *} {G G₁ G₂ G₃ : SimpleGraph α} {H : SimpleGraph β} {I : SimpleGraph γ}
97239
98240/-!
99241### Induced containment
@@ -120,27 +262,28 @@ protected lemma Subgraph.IsInduced'.isIndContained {G' : G.Subgraph} (hG' : G'.I
120262 inj' := Subtype.coe_injective
121263 map_rel_iff' := hG'.adj.symm }⟩
122264
123- @[refl] lemma isIndContained_refl (G : SimpleGraph α) : G ⊴ G := ⟨Embedding.refl⟩
124- lemma isIndContained_rfl : G ⊴ G := isIndContained_refl _
265+ @[refl] lemma IsIndContained.refl (G : SimpleGraph α) : G ⊴ G := ⟨Embedding.refl⟩
266+ lemma IsIndContained.rfl : G ⊴ G := .refl _
125267lemma IsIndContained.trans : G ⊴ H → H ⊴ I → G ⊴ I := fun ⟨f⟩ ⟨g⟩ ↦ ⟨g.comp f⟩
126268
127269lemma isIndContained_of_isEmpty [IsEmpty α] : G ⊴ H :=
128270 ⟨{ toFun := isEmptyElim
129271 inj' := isEmptyElim
130272 map_rel_iff' := fun {a} ↦ isEmptyElim a }⟩
131273
132- lemma isIndContained_iff_exists_subgraph :
274+ lemma isIndContained_iff_exists_iso_subgraph :
133275 G ⊴ H ↔ ∃ (H' : H.Subgraph) (_e : G ≃g H'.coe), H'.IsInduced' := by
134276 constructor
135277 · rintro ⟨f⟩
136278 refine ⟨Subgraph.map f.toHom ⊤,
137- (Subgraph.isoMap f.toHom f.injective _).comp Subgraph.topIso.symm, ?_⟩
279+ (Subgraph.isoMap ⟨ f.toHom, f.injective⟩ _).comp Subgraph.topIso.symm, ?_⟩
138280 rintro _ _ ⟨a, -, rfl⟩ ⟨b, -, rfl⟩
139281 simp [Relation.map_apply_apply, f.injective]
140282 · rintro ⟨H', e, hH'⟩
141283 exact e.isIndContained.trans hH'.isIndContained
142284
143- alias ⟨IsIndContained.exists_subgraph, _⟩ := isIndContained_iff_exists_subgraph
285+ alias ⟨IsIndContained.exists_iso_subgraph, IsIndContained.of_exists_iso_subgraph⟩ :=
286+ isIndContained_iff_exists_iso_subgraph
144287
145288/-!
146289### Counting the copies
@@ -190,10 +333,12 @@ noncomputable def copyCount (G : SimpleGraph α) (H : SimpleGraph β) : ℕ :=
190333 exact fun hab ↦ e.symm.map_rel_iff.2 hab.coe
191334
192335@[simp] lemma copyCount_eq_zero : G.copyCount H = 0 ↔ ¬ G ⊑ H := by
193- simp [copyCount, isContained_iff_exists_subgraph, card_pos, filter_eq_empty_iff]
336+ simp [copyCount, -nonempty_subtype, isContained_iff_exists_iso_subgraph, card_pos,
337+ filter_eq_empty_iff]
194338
195339@[simp] lemma copyCount_pos : 0 < G.copyCount H ↔ G ⊑ H := by
196- simp [copyCount, isContained_iff_exists_subgraph, card_pos, filter_nonempty_iff]
340+ simp [copyCount, -nonempty_subtype, isContained_iff_exists_iso_subgraph, card_pos,
341+ filter_nonempty_iff]
197342
198343end CopyCount
199344
@@ -262,7 +407,7 @@ private lemma kill_of_ne_bot (hG : G ≠ ⊥) (H : SimpleGraph β) :
262407 rw [kill]; exact dif_neg hG
263408
264409lemma kill_eq_right (hG : G ≠ ⊥) : G.kill H = H ↔ ¬ G ⊑ H := by
265- simp only [kill_of_ne_bot hG, Set.disjoint_left, isContained_iff_exists_subgraph ,
410+ simp only [kill_of_ne_bot hG, Set.disjoint_left, isContained_iff_exists_iso_subgraph ,
266411 @forall_swap _ H.Subgraph, Set.iUnion_singleton_eq_range, deleteEdges_eq_self, Set.mem_iUnion,
267412 Set.mem_range, not_exists, not_nonempty_iff, Nonempty.forall]
268413 exact forall_congr' fun H' ↦ ⟨fun h ↦ ⟨fun f ↦ h _
@@ -276,7 +421,7 @@ lemma kill_of_not_isContained (hGH : ¬ G ⊑ H) : G.kill H = H := by
276421/-- Removing an edge from `H` for each subgraph isomorphic to `G` results in a graph that doesn't
277422contain `G`. -/
278423lemma not_isContained_kill (hG : G ≠ ⊥) : ¬ G ⊑ G.kill H := by
279- rw [kill_of_ne_bot hG, deleteEdges, isContained_iff_exists_subgraph ]
424+ rw [kill_of_ne_bot hG, deleteEdges, isContained_iff_exists_iso_subgraph ]
280425 rintro ⟨H', hGH'⟩
281426 have hH' : (H'.map <| Hom.ofLE (sdiff_le : H \ _ ≤ H)).edgeSet.Nonempty := by
282427 rw [Subgraph.edgeSet_map]
@@ -287,14 +432,13 @@ lemma not_isContained_kill (hG : G ≠ ⊥) : ¬ G ⊑ G.kill H := by
287432 rw [← Subgraph.image_coe_edgeSet_coe] at this
288433 subst he
289434 obtain ⟨e, he₀, he₁⟩ := this
290- let e' : Sym2 H'.verts := Sym2.map (Subgraph.isoMap (Hom .ofLE _) injective_id _).symm e
435+ let e' : Sym2 H'.verts := Sym2.map (Subgraph.isoMap (.ofLE _ _ _) _).symm e
291436 have he' : e' ∈ H'.coe.edgeSet := (Iso.map_mem_edgeSet_iff _).2 he₀
292437 rw [Subgraph.edgeSet_coe] at he'
293438 have := Subgraph.edgeSet_subset _ he'
294439 simp only [edgeSet_sdiff, edgeSet_fromEdgeSet, edgeSet_sdiff_sdiff_isDiag, Set.mem_diff,
295440 Set.mem_iUnion, not_exists] at this
296- refine this.2 (H'.map <| Hom.ofLE sdiff_le)
297- ⟨(Subgraph.isoMap (Hom.ofLE _) injective_id _).comp hGH'.some⟩ ?_
441+ refine this.2 (H'.map <| Hom.ofLE sdiff_le) ⟨(Subgraph.isoMap (.ofLE _ _ _) _).comp hGH'.some⟩ ?_
298442 rw [Sym2.map_map, Set.mem_singleton_iff, ← he₁]
299443 congr 1 with x
300444 exact congr_arg _ (Equiv.Set.image_symm_apply _ _ injective_id _ _)
0 commit comments