|
7 | 7 |
|
8 | 8 | public import Mathlib.Algebra.Order.Group.Nat |
9 | 9 | public import Mathlib.Combinatorics.SimpleGraph.Subgraph |
| 10 | +public import Mathlib.Data.Finite.Card |
| 11 | +public import Mathlib.Data.Set.Finite.Range |
10 | 12 |
|
11 | 13 | /-! |
12 | 14 | # Containment of graphs |
@@ -62,7 +64,6 @@ The following notation is declared in scope `SimpleGraph`: |
62 | 64 | public section |
63 | 65 |
|
64 | 66 | open Finset Function |
65 | | -open Fintype (card) |
66 | 67 |
|
67 | 68 | namespace SimpleGraph |
68 | 69 | variable {V W X α β γ : Type*} {G G₁ G₂ G₃ : SimpleGraph V} {H : SimpleGraph W} {I : SimpleGraph X} |
@@ -202,6 +203,9 @@ instance [Fintype {f : G →g H // Injective f}] : Fintype (G.Copy H) := |
202 | 203 | invFun f := ⟨f.1, f.2⟩ |
203 | 204 | } |
204 | 205 |
|
| 206 | +instance [Finite V] [Finite W] : Finite (G.Copy H) := |
| 207 | + Finite.of_injective _ DFunLike.coe_injective |
| 208 | + |
205 | 209 | /-- A copy of `⊤` gives rise to an embedding of `⊤`. -/ |
206 | 210 | @[expose] def topEmbedding (f : Copy (⊤ : SimpleGraph α) G) : (⊤ : SimpleGraph α) ↪g G := |
207 | 211 | { f.toEmbedding with |
@@ -297,10 +301,11 @@ lemma IsContained.of_isEmpty [IsEmpty α] : A ⊑ B := |
297 | 301 | ⟨⟨isEmptyElim, fun {a} ↦ isEmptyElim a⟩, isEmptyElim⟩ |
298 | 302 |
|
299 | 303 | /-- `⊥` is contained in any simple graph having sufficiently many vertices. -/ |
300 | | -lemma bot_isContained_iff_card_le [Fintype α] [Fintype β] : |
301 | | - (⊥ : SimpleGraph α) ⊑ B ↔ Fintype.card α ≤ Fintype.card β := |
302 | | - ⟨fun ⟨f⟩ ↦ Fintype.card_le_of_embedding f.toEmbedding, |
303 | | - fun h ↦ ⟨Copy.bot (Function.Embedding.nonempty_of_card_le h).some⟩⟩ |
| 304 | +lemma bot_isContained_iff_card_le [Finite α] [Finite β] : |
| 305 | + (⊥ : SimpleGraph α) ⊑ B ↔ Nat.card α ≤ Nat.card β := |
| 306 | + ⟨fun ⟨f⟩ ↦ Finite.card_le_of_embedding f.toEmbedding, |
| 307 | + fun h ↦ ⟨Copy.bot (Cardinal.lift_mk_le'.mp (by |
| 308 | + simp only [← Nat.cast_card, Cardinal.lift_natCast]; exact_mod_cast h)).some⟩⟩ |
304 | 309 |
|
305 | 310 | protected alias IsContained.bot := bot_isContained_iff_card_le |
306 | 311 |
|
@@ -478,86 +483,113 @@ in `H`. |
478 | 483 | -/ |
479 | 484 |
|
480 | 485 | section LabeledCopyCount |
481 | | -variable [Fintype V] [Fintype W] |
482 | 486 |
|
483 | 487 | /-- `G.labeledCopyCount H` is the number of labeled copies of `H` in `G`, i.e. the number of graph |
484 | 488 | embeddings from `H` to `G`. See `SimpleGraph.copyCount` for the number of unlabeled copies. -/ |
485 | | -noncomputable def labeledCopyCount (G : SimpleGraph V) (H : SimpleGraph W) : ℕ := by |
486 | | - classical exact Fintype.card (Copy H G) |
| 489 | +noncomputable def labeledCopyCount (G : SimpleGraph V) (H : SimpleGraph W) : ℕ := |
| 490 | + Nat.card (Copy H G) |
487 | 491 |
|
488 | 492 | @[deprecated (since := "2026-04-30")] alias labelledCopyCount := labeledCopyCount |
489 | 493 |
|
| 494 | +private instance [IsEmpty W] : Nonempty (H.Copy G) := IsContained.of_isEmpty |
| 495 | + |
490 | 496 | @[simp] lemma labeledCopyCount_of_isEmpty [IsEmpty W] (G : SimpleGraph V) (H : SimpleGraph W) : |
491 | | - G.labeledCopyCount H = 1 := by |
492 | | - convert Fintype.card_unique |
493 | | - exact { default := ⟨default, isEmptyElim⟩, uniq := fun _ ↦ Subsingleton.elim _ _ } |
| 497 | + G.labeledCopyCount H = 1 := Nat.card_unique |
494 | 498 |
|
495 | 499 | @[deprecated (since := "2026-04-30")] |
496 | 500 | alias labelledCopyCount_of_isEmpty := labeledCopyCount_of_isEmpty |
497 | 501 |
|
498 | | -@[simp] lemma labeledCopyCount_eq_zero : G.labeledCopyCount H = 0 ↔ H.Free G := by |
499 | | - simp [labeledCopyCount, Fintype.card_eq_zero_iff] |
| 502 | +@[simp] lemma labeledCopyCount_eq_zero [Finite V] [Finite W] : |
| 503 | + G.labeledCopyCount H = 0 ↔ H.Free G := by |
| 504 | + rw [labeledCopyCount, Nat.card_eq_zero, or_iff_left (Finite.not_infinite inferInstance)] |
| 505 | + simp [Free, IsContained] |
500 | 506 |
|
501 | 507 | @[deprecated (since := "2026-04-30")] alias labelledCopyCount_eq_zero := labeledCopyCount_eq_zero |
502 | 508 |
|
503 | | -@[simp] lemma labeledCopyCount_pos : 0 < G.labeledCopyCount H ↔ H ⊑ G := by |
504 | | - simp [labeledCopyCount, IsContained, Fintype.card_pos_iff] |
| 509 | +@[simp] lemma labeledCopyCount_pos [Finite V] [Finite W] : 0 < G.labeledCopyCount H ↔ H ⊑ G := by |
| 510 | + simp [Nat.pos_iff_ne_zero, labeledCopyCount_eq_zero] |
505 | 511 |
|
506 | 512 | @[deprecated (since := "2026-04-30")] alias labelledCopyCount_pos := labeledCopyCount_pos |
507 | 513 |
|
508 | 514 | end LabeledCopyCount |
509 | 515 |
|
510 | 516 | section CopyCount |
511 | | -variable [Fintype V] |
512 | 517 |
|
513 | 518 | /-- `G.copyCount H` is the number of unlabeled copies of `H` in `G`, i.e. the number of subgraphs |
514 | 519 | of `G` isomorphic to `H`. See `SimpleGraph.labeledCopyCount` for the number of labeled copies. -/ |
515 | | -noncomputable def copyCount (G : SimpleGraph V) (H : SimpleGraph W) : ℕ := by |
516 | | - classical exact #{G' : G.Subgraph | Nonempty (H ≃g G'.coe)} |
| 520 | +noncomputable def copyCount (G : SimpleGraph V) (H : SimpleGraph W) : ℕ := |
| 521 | + Nat.card {G' : G.Subgraph // Nonempty (H ≃g G'.coe)} |
| 522 | + |
| 523 | +lemma copyCount_eq_nat_card_range_toSubgraph : |
| 524 | + copyCount G H = Nat.card (Set.range (Copy.toSubgraph : H.Copy G → G.Subgraph)) := by |
| 525 | + rw [copyCount, Copy.range_toSubgraph]; rfl |
517 | 526 |
|
518 | | -lemma copyCount_eq_card_image_copyToSubgraph [Fintype {f : H →g G // Injective f}] |
519 | | - [DecidableEq G.Subgraph] : |
520 | | - copyCount G H = #((Finset.univ : Finset (H.Copy G)).image Copy.toSubgraph) := by |
| 527 | +@[deprecated copyCount_eq_nat_card_range_toSubgraph (since := "2026-05-04")] |
| 528 | +lemma copyCount_eq_card_image_copyToSubgraph [Fintype (H.Copy G)] [DecidableEq G.Subgraph] : |
| 529 | + copyCount G H = (Finset.univ.image (Copy.toSubgraph (A := H) (B := G))).card := by |
521 | 530 | rw [copyCount] |
522 | | - congr |
523 | | - refine Finset.coe_injective ?_ |
524 | | - simpa [-Copy.range_toSubgraph] using Copy.range_toSubgraph.symm |
| 531 | + exact Nat.subtype_card _ fun G' => by |
| 532 | + simp only [Finset.mem_image, Finset.mem_univ, true_and] |
| 533 | + constructor |
| 534 | + · rintro ⟨f, rfl⟩; exact ⟨f.isoToSubgraph⟩ |
| 535 | + · rintro ⟨e⟩ |
| 536 | + exact ⟨⟨G'.hom.comp e.toHom, Subgraph.hom_injective.comp e.injective⟩, |
| 537 | + by simp [Copy.toSubgraph, Subgraph.map_comp]⟩ |
525 | 538 |
|
526 | | -@[simp] lemma copyCount_eq_zero : G.copyCount H = 0 ↔ H.Free G := by |
527 | | - simp [copyCount, Free, -nonempty_subtype, isContained_iff_exists_iso_subgraph, |
528 | | - filter_eq_empty_iff] |
| 539 | +@[simp] lemma copyCount_eq_zero [Finite V] : G.copyCount H = 0 ↔ H.Free G := by |
| 540 | + rw [copyCount, Nat.card_eq_zero, or_iff_left (Finite.not_infinite inferInstance), isEmpty_subtype] |
| 541 | + simp [Free, isContained_iff_exists_iso_subgraph] |
529 | 542 |
|
530 | | -@[simp] lemma copyCount_pos : 0 < G.copyCount H ↔ H ⊑ G := by |
531 | | - simp [copyCount, -nonempty_subtype, isContained_iff_exists_iso_subgraph, card_pos, |
532 | | - filter_nonempty_iff] |
| 543 | +@[simp] lemma copyCount_pos [Finite V] : 0 < G.copyCount H ↔ H ⊑ G := by |
| 544 | + simp [Nat.pos_iff_ne_zero, copyCount_eq_zero] |
533 | 545 |
|
534 | 546 | /-- There's at least as many labeled copies of `H` in `G` than unlabeled ones. -/ |
535 | | -lemma copyCount_le_labeledCopyCount [Fintype W] : G.copyCount H ≤ G.labeledCopyCount H := by |
536 | | - classical rw [copyCount_eq_card_image_copyToSubgraph]; exact card_image_le |
| 547 | +lemma copyCount_le_labeledCopyCount [Finite V] [Finite W] : |
| 548 | + G.copyCount H ≤ G.labeledCopyCount H := |
| 549 | + copyCount_eq_nat_card_range_toSubgraph ▸ Finite.card_range_le _ |
537 | 550 |
|
538 | 551 | @[deprecated (since := "2026-04-30")] |
539 | 552 | alias copyCount_le_labelledCopyCount := copyCount_le_labeledCopyCount |
540 | 553 |
|
541 | | -@[simp] lemma copyCount_bot (G : SimpleGraph V) : copyCount G (⊥ : SimpleGraph V) = 1 := by |
| 554 | +private lemma subgraph_iso_bot [Finite V] (Gx : G.Subgraph) (e : (⊥ : SimpleGraph V) ≃g Gx.coe) : |
| 555 | + Gx.verts = Set.univ ∧ Gx.Adj = ⊥ := by |
| 556 | + constructor |
| 557 | + · apply Set.eq_univ_of_forall |
| 558 | + intro v |
| 559 | + obtain ⟨w, hw⟩ := (Finite.injective_iff_surjective.mp |
| 560 | + (Subtype.val_injective.comp e.toEquiv.injective)) v |
| 561 | + exact hw ▸ (e.toEquiv w).prop |
| 562 | + · exact funext₂ fun a b => eq_false fun hadj => |
| 563 | + absurd (e.symm.map_rel_iff.mpr hadj.coe) (by simp) |
| 564 | + |
| 565 | +private instance [Finite V] : |
| 566 | + Nonempty {G' : G.Subgraph // Nonempty ((⊥ : SimpleGraph V) ≃g G'.coe)} := |
| 567 | + ⟨{ verts := .univ, Adj := ⊥, adj_sub := False.elim, edge_vert := False.elim }, |
| 568 | + ⟨⟨(Equiv.Set.univ V).symm, by simp⟩⟩⟩ |
| 569 | + |
| 570 | +private instance [Finite V] : |
| 571 | + Subsingleton {G' : G.Subgraph // Nonempty ((⊥ : SimpleGraph V) ≃g G'.coe)} := by |
542 | 572 | classical |
543 | | - rw [copyCount] |
544 | | - convert card_singleton (α := G.Subgraph) |
545 | | - { verts := .univ |
546 | | - Adj := ⊥ |
547 | | - adj_sub := False.elim |
548 | | - edge_vert := False.elim } |
549 | | - simp only [eq_singleton_iff_unique_mem, mem_filter_univ, Nonempty.forall] |
550 | | - refine ⟨⟨⟨(Equiv.Set.univ _).symm, by simp⟩⟩, fun H' e ↦ |
551 | | - Subgraph.ext ((set_fintype_card_eq_univ_iff _).1 <| Fintype.card_congr e.toEquiv.symm) ?_⟩ |
552 | | - ext a b |
553 | | - simp only [Prop.bot_eq_false, Pi.bot_apply, iff_false] |
554 | | - exact fun hab ↦ e.symm.map_rel_iff.2 hab.coe |
| 573 | + constructor |
| 574 | + rintro ⟨G', ⟨e⟩⟩ ⟨G'', ⟨e'⟩⟩ |
| 575 | + congr 1 |
| 576 | + exact Subgraph.ext ((subgraph_iso_bot G' e).1.trans (subgraph_iso_bot G'' e').1.symm) |
| 577 | + ((subgraph_iso_bot G' e).2.trans (subgraph_iso_bot G'' e').2.symm) |
| 578 | + |
| 579 | +@[simp] lemma copyCount_bot [Finite V] (G : SimpleGraph V) : |
| 580 | + copyCount G (⊥ : SimpleGraph V) = 1 := by |
| 581 | + rw [copyCount]; exact Nat.card_unique |
| 582 | + |
| 583 | +private instance [IsEmpty W] : Nonempty {G' : G.Subgraph // Nonempty (H ≃g G'.coe)} := |
| 584 | + nonempty_subtype.mpr (isContained_iff_exists_iso_subgraph.mp IsContained.of_isEmpty) |
| 585 | + |
| 586 | +private instance [IsEmpty W] : Subsingleton {G' : G.Subgraph // Nonempty (H ≃g G'.coe)} := |
| 587 | + ⟨fun ⟨G', ⟨e⟩⟩ ⟨G'', ⟨e'⟩⟩ => Subtype.ext <| |
| 588 | + (G'.eq_bot_iff_verts_eq_empty.mpr (Set.isEmpty_coe_sort.mp e.toEquiv.symm.isEmpty)).trans |
| 589 | + (G''.eq_bot_iff_verts_eq_empty.mpr (Set.isEmpty_coe_sort.mp e'.toEquiv.symm.isEmpty)).symm⟩ |
555 | 590 |
|
556 | 591 | @[simp] lemma copyCount_of_isEmpty [IsEmpty W] (G : SimpleGraph V) (H : SimpleGraph W) : |
557 | | - G.copyCount H = 1 := by |
558 | | - cases nonempty_fintype W |
559 | | - exact (copyCount_le_labeledCopyCount.trans_eq <| labeledCopyCount_of_isEmpty ..).antisymm <| |
560 | | - copyCount_pos.2 <| .of_isEmpty |
| 592 | + G.copyCount H = 1 := by rw [copyCount]; exact Nat.card_unique |
561 | 593 |
|
562 | 594 | end CopyCount |
563 | 595 |
|
@@ -655,28 +687,28 @@ noncomputable instance killCopies.edgeSet.instFintype : Fintype (G.killCopies H) |
655 | 687 |
|
656 | 688 | /-- Removing an edge from `H` for each subgraph isomorphic to `G` means that the number of edges |
657 | 689 | we've removed is at most the number of copies of `G` in `H`. -/ |
658 | | -lemma le_card_edgeFinset_killCopies [Fintype V] : |
| 690 | +lemma le_card_edgeFinset_killCopies [Finite V] : |
659 | 691 | #G.edgeFinset - G.copyCount H ≤ #(G.killCopies H).edgeFinset := by |
660 | 692 | classical |
661 | 693 | obtain rfl | hH := eq_or_ne H ⊥ |
662 | 694 | · simp [← card_edgeSet] |
663 | 695 | let f (G' : {G' : G.Subgraph // Nonempty (H ≃g G'.coe)}) := (aux hH G'.2).some |
664 | | - calc |
665 | | - _ = #G.edgeFinset - card {G' : G.Subgraph // Nonempty (H ≃g G'.coe)} := ?_ |
666 | | - _ ≤ #G.edgeFinset - #(univ.image f) := Nat.sub_le_sub_left card_image_le _ |
667 | | - _ = #G.edgeFinset - #(Set.range f).toFinset := by rw [Set.toFinset_range] |
668 | | - _ ≤ #(G.edgeFinset \ (Set.range f).toFinset) := le_card_sdiff .. |
669 | | - _ = #(G.killCopies H).edgeFinset := ?_ |
670 | | - · simp only [edgeFinset, Set.toFinset_card] |
671 | | - rw [← Set.toFinset_card, ← edgeFinset, copyCount, ← card_subtype, subtype_univ, card_univ] |
672 | | - congr 1 |
673 | | - ext e |
674 | | - induction e using Sym2.inductionOn with | hf v w |
675 | | - simp [mem_edgeSet, killCopies_of_ne_bot hH, f, eq_comm] |
| 696 | + have hrf : (Set.range f).Finite := Set.finite_range f |
| 697 | + have hle : hrf.toFinset.card ≤ G.copyCount H := by |
| 698 | + rw [← Nat.card_eq_card_finite_toFinset hrf, copyCount] |
| 699 | + exact Finite.card_range_le f |
| 700 | + calc #G.edgeFinset - G.copyCount H |
| 701 | + ≤ #G.edgeFinset - hrf.toFinset.card := Nat.sub_le_sub_left hle _ |
| 702 | + _ ≤ #(G.edgeFinset \ hrf.toFinset) := le_card_sdiff .. |
| 703 | + _ = #(G.killCopies H).edgeFinset := by |
| 704 | + congr 1 |
| 705 | + ext e |
| 706 | + induction e using Sym2.inductionOn with | hf v w |
| 707 | + simp [mem_edgeSet, killCopies_of_ne_bot hH, f, eq_comm] |
676 | 708 |
|
677 | 709 | /-- Removing an edge from `H` for each subgraph isomorphic to `G` means that the number of edges |
678 | 710 | we've removed is at most the number of copies of `G` in `H`. -/ |
679 | | -lemma le_card_edgeFinset_killCopies_add_copyCount [Fintype V] : |
| 711 | +lemma le_card_edgeFinset_killCopies_add_copyCount [Finite V] : |
680 | 712 | #G.edgeFinset ≤ #(G.killCopies H).edgeFinset + G.copyCount H := |
681 | 713 | tsub_le_iff_right.1 le_card_edgeFinset_killCopies |
682 | 714 |
|
|
0 commit comments