|
7 | 7 |
|
8 | 8 | public import Mathlib.Algebra.Order.Group.Nat |
9 | 9 | public import Mathlib.Combinatorics.SimpleGraph.Subgraph |
| 10 | +public import Mathlib.SetTheory.Cardinal.NatCard |
10 | 11 |
|
11 | 12 | /-! |
12 | 13 | # Copies, containment, and counting of subgraphs |
@@ -69,7 +70,6 @@ The following notation is declared in scope `SimpleGraph`: |
69 | 70 | public section |
70 | 71 |
|
71 | 72 | open Finset Function |
72 | | -open Fintype (card) |
73 | 73 |
|
74 | 74 | namespace SimpleGraph |
75 | 75 | variable {V V' W W' X : Type*} |
@@ -207,6 +207,9 @@ instance [Fintype {f : G →g H // Injective f}] : Fintype (G.Copy H) := |
207 | 207 | invFun f := ⟨f.1, f.2⟩ |
208 | 208 | } |
209 | 209 |
|
| 210 | +instance [Finite V] [Finite W] : Finite (G.Copy H) := |
| 211 | + Finite.of_injective _ DFunLike.coe_injective |
| 212 | + |
210 | 213 | /-- A copy of `⊤` gives rise to an embedding of `⊤`. -/ |
211 | 214 | @[expose] def topEmbedding (f : Copy (⊤ : SimpleGraph V) H) : (⊤ : SimpleGraph V) ↪g H := |
212 | 215 | { f.toEmbedding with |
@@ -298,10 +301,11 @@ lemma IsContained.of_isEmpty [IsEmpty V] : G ⊑ H := |
298 | 301 | ⟨⟨isEmptyElim, fun {a} ↦ isEmptyElim a⟩, isEmptyElim⟩ |
299 | 302 |
|
300 | 303 | /-- `⊥` is contained in any simple graph having sufficiently many vertices. -/ |
301 | | -lemma bot_isContained_iff_card_le [Fintype V] [Fintype W] : |
302 | | - (⊥ : SimpleGraph V) ⊑ H ↔ Fintype.card V ≤ Fintype.card W := |
303 | | - ⟨fun ⟨f⟩ ↦ Fintype.card_le_of_embedding f.toEmbedding, |
304 | | - fun h ↦ ⟨Copy.bot (Function.Embedding.nonempty_of_card_le h).some⟩⟩ |
| 304 | +lemma bot_isContained_iff_card_le [Finite V] [Finite W] : |
| 305 | + (⊥ : SimpleGraph V) ⊑ H ↔ Nat.card V ≤ Nat.card W := |
| 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⟩⟩ |
305 | 309 |
|
306 | 310 | protected alias IsContained.bot := bot_isContained_iff_card_le |
307 | 311 |
|
@@ -501,101 +505,112 @@ For finite `G` and `H`, we count labeled and unlabeled copies of `G` in `H`. |
501 | 505 | -/ |
502 | 506 |
|
503 | 507 | section CopyCount |
504 | | -variable [Fintype V] [Fintype W] |
505 | 508 |
|
506 | 509 | /-- `H.copyCount G` is the number of labeled copies of `G` in `H`, i.e. the number of injective |
507 | 510 | graph homomorphisms from `G` to `H`. See `SimpleGraph.unlabeledCopyCount` for the number of |
508 | 511 | unlabeled copies. -/ |
509 | | -noncomputable def copyCount (H : SimpleGraph W) (G : SimpleGraph V) : ℕ := by |
510 | | - classical exact Fintype.card (Copy G H) |
| 512 | +noncomputable def copyCount (H : SimpleGraph W) (G : SimpleGraph V) : ℕ := |
| 513 | + Nat.card (Copy G H) |
| 514 | + |
| 515 | +lemma copyCount_eq_nat_card (H : SimpleGraph W) (G : SimpleGraph V) : |
| 516 | + H.copyCount G = Nat.card (Copy G H) := by rw [copyCount] |
511 | 517 |
|
512 | 518 | @[deprecated (since := "2026-04-30")] alias labelledCopyCount := copyCount |
513 | 519 |
|
| 520 | +private instance [IsEmpty V] : Nonempty (Copy G H) := IsContained.of_isEmpty |
| 521 | + |
514 | 522 | @[simp] lemma copyCount_of_isEmpty [IsEmpty V] (H : SimpleGraph W) (G : SimpleGraph V) : |
515 | | - H.copyCount G = 1 := by |
516 | | - convert! Fintype.card_unique |
517 | | - exact { default := ⟨default, isEmptyElim⟩, uniq := fun _ ↦ Subsingleton.elim _ _ } |
| 523 | + H.copyCount G = 1 := Nat.card_unique |
518 | 524 |
|
519 | 525 | @[deprecated (since := "2026-04-30")] |
520 | 526 | alias labelledCopyCount_of_isEmpty := copyCount_of_isEmpty |
521 | 527 |
|
522 | | -@[simp] lemma copyCount_eq_zero : H.copyCount G = 0 ↔ G.Free H := by |
523 | | - simp [copyCount, Fintype.card_eq_zero_iff] |
| 528 | +@[simp] lemma copyCount_eq_zero [Finite V] [Finite W] : H.copyCount G = 0 ↔ G.Free H := by |
| 529 | + rw [copyCount, Nat.card_eq_zero, or_iff_left (Finite.not_infinite inferInstance)] |
| 530 | + simp [Free, IsContained] |
524 | 531 |
|
525 | 532 | @[deprecated (since := "2026-04-30")] alias labelledCopyCount_eq_zero := copyCount_eq_zero |
526 | 533 |
|
527 | | -@[simp] lemma copyCount_pos : 0 < H.copyCount G ↔ G ⊑ H := by |
528 | | - simp [copyCount, IsContained, Fintype.card_pos_iff] |
| 534 | +@[simp] lemma copyCount_pos [Finite V] [Finite W] : 0 < H.copyCount G ↔ G ⊑ H := by |
| 535 | + simp [Nat.pos_iff_ne_zero, copyCount_eq_zero] |
529 | 536 |
|
530 | 537 | @[deprecated (since := "2026-04-30")] alias labelledCopyCount_pos := copyCount_pos |
531 | 538 |
|
532 | 539 | end CopyCount |
533 | 540 |
|
534 | 541 | section UnlabeledCopyCount |
535 | | -variable [Fintype W] |
536 | 542 |
|
537 | 543 | /-- `G.UnlabeledCopy H` is the type of `SimpleGraph.Subgraph`s of `H` isomorphic to `G`. The |
538 | 544 | corresponding count is `SimpleGraph.unlabeledCopyCount`. -/ |
539 | 545 | abbrev UnlabeledCopy (G : SimpleGraph V) (H : SimpleGraph W) : Type _ := |
540 | 546 | {H' : H.Subgraph // Nonempty (G ≃g H'.coe)} |
541 | 547 |
|
| 548 | +instance [Finite W] : Finite (G.UnlabeledCopy H) := Subtype.finite |
| 549 | + |
542 | 550 | /-- `H.unlabeledCopyCount G` is the number of `SimpleGraph.Subgraph`s of `H` isomorphic to `G`. See |
543 | 551 | `SimpleGraph.copyCount` for the number of labeled copies. -/ |
544 | | -noncomputable def unlabeledCopyCount (H : SimpleGraph W) (G : SimpleGraph V) : ℕ := by |
545 | | - classical exact Fintype.card (G.UnlabeledCopy H) |
| 552 | +noncomputable def unlabeledCopyCount (H : SimpleGraph W) (G : SimpleGraph V) : ℕ := |
| 553 | + Nat.card (G.UnlabeledCopy H) |
| 554 | + |
| 555 | +lemma unlabeledCopyCount_eq_nat_card (H : SimpleGraph W) (G : SimpleGraph V) : |
| 556 | + H.unlabeledCopyCount G = Nat.card (G.UnlabeledCopy H) := by rw [unlabeledCopyCount] |
546 | 557 |
|
547 | 558 | @[deprecated "the bridge through the image of `Copy.toSubgraph` is no longer needed now that the \ |
548 | 559 | count is defined directly on the subtype of isomorphic subgraphs" (since := "2026-07-12")] |
549 | 560 | lemma copyCount_eq_card_image_copyToSubgraph [Fintype {f : G →g H // Injective f}] |
550 | 561 | [DecidableEq H.Subgraph] : |
551 | 562 | H.unlabeledCopyCount G = #((Finset.univ : Finset (G.Copy H)).image Copy.toSubgraph) := by |
552 | | - classical |
553 | | - rw [unlabeledCopyCount, Fintype.card_subtype] |
554 | | - congr 1 |
555 | | - ext H' |
556 | | - simp only [Finset.mem_filter, Finset.mem_univ, true_and, Finset.mem_image] |
| 563 | + rw [unlabeledCopyCount, ← Fintype.card_coe (Finset.univ.image Copy.toSubgraph), |
| 564 | + ← Nat.card_eq_fintype_card] |
| 565 | + refine Nat.card_congr (Equiv.subtypeEquivRight fun H' => ?_) |
| 566 | + simp only [Finset.mem_image, Finset.mem_univ, true_and] |
557 | 567 | rw [← Set.mem_range, Copy.range_toSubgraph, Set.mem_setOf_eq] |
558 | 568 |
|
559 | | -@[simp] lemma unlabeledCopyCount_eq_zero : H.unlabeledCopyCount G = 0 ↔ G.Free H := by |
560 | | - simp [unlabeledCopyCount, Free, -nonempty_subtype, isContained_iff_exists_iso_subgraph, |
561 | | - Fintype.card_eq_zero_iff, isEmpty_subtype, not_nonempty_iff] |
| 569 | +@[simp] lemma unlabeledCopyCount_eq_zero [Finite W] : H.unlabeledCopyCount G = 0 ↔ G.Free H := by |
| 570 | + rw [unlabeledCopyCount, Nat.card_eq_zero, |
| 571 | + or_iff_left (Finite.not_infinite inferInstance), isEmpty_subtype] |
| 572 | + simp [Free, isContained_iff_exists_iso_subgraph] |
562 | 573 |
|
563 | | -@[simp] lemma unlabeledCopyCount_pos : 0 < H.unlabeledCopyCount G ↔ G ⊑ H := by |
564 | | - rw [Nat.pos_iff_ne_zero, ne_eq, unlabeledCopyCount_eq_zero, Free, not_not] |
| 574 | +@[simp] lemma unlabeledCopyCount_pos [Finite W] : 0 < H.unlabeledCopyCount G ↔ G ⊑ H := by |
| 575 | + simp [Nat.pos_iff_ne_zero, unlabeledCopyCount_eq_zero] |
565 | 576 |
|
566 | 577 | /-- There are at least as many labeled copies of `G` in `H` as there are unlabeled ones. -/ |
567 | | -lemma unlabeledCopyCount_le_copyCount [Fintype V] : H.unlabeledCopyCount G ≤ H.copyCount G := by |
568 | | - classical |
| 578 | +lemma unlabeledCopyCount_le_copyCount [Finite V] [Finite W] : |
| 579 | + H.unlabeledCopyCount G ≤ H.copyCount G := by |
569 | 580 | rw [unlabeledCopyCount, copyCount] |
570 | | - apply Fintype.card_le_of_surjective |
| 581 | + apply Nat.card_le_card_of_surjective |
571 | 582 | (fun c : Copy G H ↦ (⟨c.toSubgraph, ⟨c.isoToSubgraph⟩⟩ : G.UnlabeledCopy H)) |
572 | 583 | rintro ⟨H', hG'⟩ |
573 | 584 | obtain ⟨c, hc⟩ : ∃ c, Copy.toSubgraph c = H' := by |
574 | 585 | rwa [← Set.mem_range, Copy.range_toSubgraph] |
575 | 586 | exact ⟨c, Subtype.ext hc⟩ |
576 | 587 |
|
577 | | -instance uniqueUnlabeledCopyBot (H : SimpleGraph W) : |
| 588 | +instance uniqueUnlabeledCopyBot [Finite W] (H : SimpleGraph W) : |
578 | 589 | Unique ((⊥ : SimpleGraph W).UnlabeledCopy H) where |
579 | 590 | default := ⟨{ verts := .univ, Adj := ⊥, adj_sub := False.elim, edge_vert := False.elim }, |
580 | 591 | ⟨(Equiv.Set.univ _).symm, by simp⟩⟩ |
581 | | - uniq := fun ⟨G', ⟨e⟩⟩ ↦ Subtype.ext <| Subgraph.ext |
582 | | - (by classical exact (set_fintype_card_eq_univ_iff _).1 <| Fintype.card_congr e.toEquiv.symm) |
583 | | - (by ext a b |
584 | | - simp only [Prop.bot_eq_false, Pi.bot_apply, iff_false] |
585 | | - exact fun hab ↦ e.symm.map_rel_iff.2 hab.coe) |
586 | | - |
587 | | -@[simp] lemma unlabeledCopyCount_bot (H : SimpleGraph W) : |
588 | | - H.unlabeledCopyCount (⊥ : SimpleGraph W) = 1 := by |
589 | | - classical |
590 | | - rw [unlabeledCopyCount] |
591 | | - convert Fintype.card_unique |
592 | | - exact uniqueUnlabeledCopyBot H |
| 592 | + uniq := fun ⟨H', ⟨e⟩⟩ ↦ Subtype.ext <| Subgraph.ext |
| 593 | + (Set.eq_univ_of_forall fun v ↦ by |
| 594 | + obtain ⟨w, hw⟩ := (Finite.injective_iff_surjective.mp |
| 595 | + (Subtype.val_injective.comp e.toEquiv.injective)) v |
| 596 | + exact hw ▸ (e.toEquiv w).prop) |
| 597 | + (funext₂ fun a b ↦ eq_false fun hadj ↦ absurd (e.symm.map_rel_iff.mpr hadj.coe) (by simp)) |
| 598 | + |
| 599 | +@[simp] lemma unlabeledCopyCount_bot [Finite W] (H : SimpleGraph W) : |
| 600 | + H.unlabeledCopyCount (⊥ : SimpleGraph W) = 1 := |
| 601 | + Nat.card_unique |
| 602 | + |
| 603 | +private instance [IsEmpty V] : Nonempty (G.UnlabeledCopy H) := |
| 604 | + let ⟨H', ⟨e⟩⟩ := (IsContained.of_isEmpty (G := G) (H := H)).exists_iso_subgraph |
| 605 | + ⟨⟨H', ⟨e⟩⟩⟩ |
| 606 | + |
| 607 | +private instance [IsEmpty V] : Subsingleton (G.UnlabeledCopy H) := |
| 608 | + ⟨fun ⟨H', ⟨e⟩⟩ ⟨H'', ⟨e'⟩⟩ ↦ Subtype.ext <| |
| 609 | + (H'.eq_bot_iff_verts_eq_empty.mpr (Set.isEmpty_coe_sort.mp e.toEquiv.symm.isEmpty)).trans |
| 610 | + (H''.eq_bot_iff_verts_eq_empty.mpr (Set.isEmpty_coe_sort.mp e'.toEquiv.symm.isEmpty)).symm⟩ |
593 | 611 |
|
594 | 612 | @[simp] lemma unlabeledCopyCount_of_isEmpty [IsEmpty V] (H : SimpleGraph W) (G : SimpleGraph V) : |
595 | | - H.unlabeledCopyCount G = 1 := by |
596 | | - cases nonempty_fintype V |
597 | | - exact (unlabeledCopyCount_le_copyCount.trans_eq <| copyCount_of_isEmpty ..).antisymm <| |
598 | | - unlabeledCopyCount_pos.2 <| .of_isEmpty |
| 613 | + H.unlabeledCopyCount G = 1 := Nat.card_unique |
599 | 614 |
|
600 | 615 | end UnlabeledCopyCount |
601 | 616 |
|
@@ -684,28 +699,27 @@ noncomputable instance killCopies.edgeSet.instFintype : Fintype (H.killCopies G) |
684 | 699 |
|
685 | 700 | /-- Removing an edge from `H` for each subgraph isomorphic to `G` means that the number of edges |
686 | 701 | we've removed is at most the number of copies of `G` in `H`. -/ |
687 | | -lemma le_card_edgeFinset_killCopies [Fintype W] : |
| 702 | +lemma le_card_edgeFinset_killCopies [Finite W] : |
688 | 703 | #H.edgeFinset - H.unlabeledCopyCount G ≤ #(H.killCopies G).edgeFinset := by |
689 | 704 | classical |
690 | 705 | obtain rfl | hG := eq_or_ne G ⊥ |
691 | 706 | · simp [← card_edgeSet] |
| 707 | + cases nonempty_fintype (G.UnlabeledCopy H) |
692 | 708 | let f (H' : G.UnlabeledCopy H) := (aux hG H'.2).some |
693 | | - calc |
694 | | - _ = #H.edgeFinset - Fintype.card (G.UnlabeledCopy H) := ?_ |
695 | | - _ ≤ #H.edgeFinset - #(univ.image f) := Nat.sub_le_sub_left card_image_le _ |
696 | | - _ = #H.edgeFinset - #(Set.range f).toFinset := by rw [Set.toFinset_range] |
697 | | - _ ≤ #(H.edgeFinset \ (Set.range f).toFinset) := le_card_sdiff .. |
698 | | - _ = #(H.killCopies G).edgeFinset := ?_ |
699 | | - · simp only [edgeFinset, Set.toFinset_card] |
700 | | - rw [← Set.toFinset_card, ← edgeFinset, unlabeledCopyCount] |
701 | | - congr 1 |
702 | | - ext e |
703 | | - induction e using Sym2.inductionOn with | hf v w |
704 | | - simp [mem_edgeSet, killCopies_of_ne_bot hG, f, eq_comm] |
| 709 | + calc #H.edgeFinset - H.unlabeledCopyCount G |
| 710 | + = #H.edgeFinset - Fintype.card (G.UnlabeledCopy H) := by |
| 711 | + rw [unlabeledCopyCount, Nat.card_eq_fintype_card] |
| 712 | + _ ≤ #H.edgeFinset - #(Finset.univ.image f) := Nat.sub_le_sub_left Finset.card_image_le _ |
| 713 | + _ ≤ #(H.edgeFinset \ Finset.univ.image f) := le_card_sdiff .. |
| 714 | + _ = #(H.killCopies G).edgeFinset := by |
| 715 | + congr 1 |
| 716 | + ext e |
| 717 | + induction e using Sym2.inductionOn with | hf v w |
| 718 | + simp [mem_edgeSet, killCopies_of_ne_bot hG, f, eq_comm] |
705 | 719 |
|
706 | 720 | /-- Removing an edge from `H` for each subgraph isomorphic to `G` means that the number of edges |
707 | 721 | we've removed is at most the number of copies of `G` in `H`. -/ |
708 | | -lemma le_card_edgeFinset_killCopies_add_unlabeledCopyCount [Fintype W] : |
| 722 | +lemma le_card_edgeFinset_killCopies_add_unlabeledCopyCount [Finite W] : |
709 | 723 | #H.edgeFinset ≤ #(H.killCopies G).edgeFinset + H.unlabeledCopyCount G := |
710 | 724 | tsub_le_iff_right.1 le_card_edgeFinset_killCopies |
711 | 725 |
|
|
0 commit comments