Skip to content

Commit e7cb121

Browse files
committed
chore(Combinatorics/SimpleGraph/Copy): migrate copyCount/unlabeledCopyCount to Nat.card
* `copyCount` and `unlabeledCopyCount` redefined via `Nat.card` instead of `Fintype.card`. * `Fintype` hypotheses weakened to `Finite` throughout (`copyCount_eq_zero`, `copyCount_pos`, `unlabeledCopyCount_eq_zero`, `unlabeledCopyCount_pos`, `unlabeledCopyCount_le_copyCount`, `uniqueUnlabeledCopyBot`, `unlabeledCopyCount_bot`, `unlabeledCopyCount_of_isEmpty`, `bot_isContained_iff_card_le`, `le_card_edgeFinset_killCopies`, `le_card_edgeFinset_killCopies_add_unlabeledCopyCount`). * `bot_isContained_iff_card_le`: `Fintype.card → Nat.card`. * New `Finite (G.Copy H)` instance (sibling to the existing `Fintype` instance). * New `Nonempty (Copy G H)` instance for `[IsEmpty V]`, used to give a one-line `copyCount_of_isEmpty` proof via `Nat.card_unique`. * New `copyCount_eq_nat_card` and `unlabeledCopyCount_eq_nat_card` bridge lemmas exposing the underlying `Nat.card`, intended as the public characterisation since the count bodies are deliberately not `@[expose]`d. * New private `Nonempty` / `Subsingleton` instances on `G.UnlabeledCopy H` for `[IsEmpty V]`, used to give a one-line `unlabeledCopyCount_of_isEmpty` proof via `Nat.card_unique`. * `le_card_edgeFinset_killCopies` proof simplified accordingly.
1 parent 568138c commit e7cb121

1 file changed

Lines changed: 76 additions & 62 deletions

File tree

Mathlib/Combinatorics/SimpleGraph/Copy.lean

Lines changed: 76 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module
77

88
public import Mathlib.Algebra.Order.Group.Nat
99
public import Mathlib.Combinatorics.SimpleGraph.Subgraph
10+
public import Mathlib.SetTheory.Cardinal.NatCard
1011

1112
/-!
1213
# Copies, containment, and counting of subgraphs
@@ -69,7 +70,6 @@ The following notation is declared in scope `SimpleGraph`:
6970
public section
7071

7172
open Finset Function
72-
open Fintype (card)
7373

7474
namespace SimpleGraph
7575
variable {V V' W W' X : Type*}
@@ -207,6 +207,9 @@ instance [Fintype {f : G →g H // Injective f}] : Fintype (G.Copy H) :=
207207
invFun f := ⟨f.1, f.2
208208
}
209209

210+
instance [Finite V] [Finite W] : Finite (G.Copy H) :=
211+
Finite.of_injective _ DFunLike.coe_injective
212+
210213
/-- A copy of `⊤` gives rise to an embedding of `⊤`. -/
211214
@[expose] def topEmbedding (f : Copy (⊤ : SimpleGraph V) H) : (⊤ : SimpleGraph V) ↪g H :=
212215
{ f.toEmbedding with
@@ -298,10 +301,11 @@ lemma IsContained.of_isEmpty [IsEmpty V] : G ⊑ H :=
298301
⟨⟨isEmptyElim, fun {a} ↦ isEmptyElim a⟩, isEmptyElim⟩
299302

300303
/-- `⊥` 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⟩⟩
305309

306310
protected alias IsContained.bot := bot_isContained_iff_card_le
307311

@@ -501,101 +505,112 @@ For finite `G` and `H`, we count labeled and unlabeled copies of `G` in `H`.
501505
-/
502506

503507
section CopyCount
504-
variable [Fintype V] [Fintype W]
505508

506509
/-- `H.copyCount G` is the number of labeled copies of `G` in `H`, i.e. the number of injective
507510
graph homomorphisms from `G` to `H`. See `SimpleGraph.unlabeledCopyCount` for the number of
508511
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]
511517

512518
@[deprecated (since := "2026-04-30")] alias labelledCopyCount := copyCount
513519

520+
private instance [IsEmpty V] : Nonempty (Copy G H) := IsContained.of_isEmpty
521+
514522
@[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
518524

519525
@[deprecated (since := "2026-04-30")]
520526
alias labelledCopyCount_of_isEmpty := copyCount_of_isEmpty
521527

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]
524531

525532
@[deprecated (since := "2026-04-30")] alias labelledCopyCount_eq_zero := copyCount_eq_zero
526533

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]
529536

530537
@[deprecated (since := "2026-04-30")] alias labelledCopyCount_pos := copyCount_pos
531538

532539
end CopyCount
533540

534541
section UnlabeledCopyCount
535-
variable [Fintype W]
536542

537543
/-- `G.UnlabeledCopy H` is the type of `SimpleGraph.Subgraph`s of `H` isomorphic to `G`. The
538544
corresponding count is `SimpleGraph.unlabeledCopyCount`. -/
539545
abbrev UnlabeledCopy (G : SimpleGraph V) (H : SimpleGraph W) : Type _ :=
540546
{H' : H.Subgraph // Nonempty (G ≃g H'.coe)}
541547

548+
instance [Finite W] : Finite (G.UnlabeledCopy H) := Subtype.finite
549+
542550
/-- `H.unlabeledCopyCount G` is the number of `SimpleGraph.Subgraph`s of `H` isomorphic to `G`. See
543551
`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]
546557

547558
@[deprecated "the bridge through the image of `Copy.toSubgraph` is no longer needed now that the \
548559
count is defined directly on the subtype of isomorphic subgraphs" (since := "2026-07-12")]
549560
lemma copyCount_eq_card_image_copyToSubgraph [Fintype {f : G →g H // Injective f}]
550561
[DecidableEq H.Subgraph] :
551562
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]
557567
rw [← Set.mem_range, Copy.range_toSubgraph, Set.mem_setOf_eq]
558568

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]
562573

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]
565576

566577
/-- 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
569580
rw [unlabeledCopyCount, copyCount]
570-
apply Fintype.card_le_of_surjective
581+
apply Nat.card_le_card_of_surjective
571582
(fun c : Copy G H ↦ (⟨c.toSubgraph, ⟨c.isoToSubgraph⟩⟩ : G.UnlabeledCopy H))
572583
rintro ⟨H', hG'⟩
573584
obtain ⟨c, hc⟩ : ∃ c, Copy.toSubgraph c = H' := by
574585
rwa [← Set.mem_range, Copy.range_toSubgraph]
575586
exact ⟨c, Subtype.ext hc⟩
576587

577-
instance uniqueUnlabeledCopyBot (H : SimpleGraph W) :
588+
instance uniqueUnlabeledCopyBot [Finite W] (H : SimpleGraph W) :
578589
Unique ((⊥ : SimpleGraph W).UnlabeledCopy H) where
579590
default := ⟨{ verts := .univ, Adj := ⊥, adj_sub := False.elim, edge_vert := False.elim },
580591
⟨(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⟩
593611

594612
@[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
599614

600615
end UnlabeledCopyCount
601616

@@ -684,28 +699,27 @@ noncomputable instance killCopies.edgeSet.instFintype : Fintype (H.killCopies G)
684699

685700
/-- Removing an edge from `H` for each subgraph isomorphic to `G` means that the number of edges
686701
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] :
688703
#H.edgeFinset - H.unlabeledCopyCount G ≤ #(H.killCopies G).edgeFinset := by
689704
classical
690705
obtain rfl | hG := eq_or_ne G ⊥
691706
· simp [← card_edgeSet]
707+
cases nonempty_fintype (G.UnlabeledCopy H)
692708
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]
705719

706720
/-- Removing an edge from `H` for each subgraph isomorphic to `G` means that the number of edges
707721
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] :
709723
#H.edgeFinset ≤ #(H.killCopies G).edgeFinset + H.unlabeledCopyCount G :=
710724
tsub_le_iff_right.1 le_card_edgeFinset_killCopies
711725

0 commit comments

Comments
 (0)