Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3609,6 +3609,7 @@ public import Mathlib.Combinatorics.SimpleGraph.Clique
public import Mathlib.Combinatorics.SimpleGraph.Coloring
public import Mathlib.Combinatorics.SimpleGraph.Coloring.Constructions
public import Mathlib.Combinatorics.SimpleGraph.Coloring.EdgeLabeling
public import Mathlib.Combinatorics.SimpleGraph.Coloring.Greedy
public import Mathlib.Combinatorics.SimpleGraph.Coloring.Vertex
public import Mathlib.Combinatorics.SimpleGraph.Coloring.VertexColoring
public import Mathlib.Combinatorics.SimpleGraph.CompleteMultipartite
Expand Down
274 changes: 274 additions & 0 deletions Mathlib/Combinatorics/SimpleGraph/Coloring/Greedy.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
/-
Copyright (c) 2026 Snir Broshi. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Snir Broshi
-/
module

public import Mathlib.Combinatorics.SimpleGraph.Coloring.Vertex
public import Mathlib.SetTheory.Ordinal.Arithmetic

/-!
# Greedy Coloring
-/

@[expose] public section Dependencies

set_option warn.sorry false
set_option linter.style.longLine false

-- #36626
theorem IsLowerSet.eqOn_id_of_injOn_of_forall_not_lt {α : Type*} {r : α → α → Prop} [IsWellOrder α r] {s : Set α} (hs : @IsLowerSet α ⟨r⟩ s) {f : α → α} (hf : s.InjOn f) (h : ∀ x ∈ s, ¬r x (f x)) : s.EqOn f id := sorry

end Dependencies

public section

namespace SimpleGraph

open Cardinal Ordinal

variable {V : Type*} (G : SimpleGraph V) (r : V → V → Prop) [IsWellOrder V r]

/-- A greedy coloring of the graph where the vertices are greedily colored in the order specified
by the given well-order. The colors are the vertices of the graph, ordered by the same
well-order. -/
noncomputable def greedyColoring : G.Coloring V :=
let f v ih :=
-- The set of possible colors is the complement of the set of colors that are already taken by
-- neighbors of `v` that were already colored
let s := {(ih u hu).val | (u : V) (hu : r u v) (_ : G.Adj u v)}ᶜ
-- This set is not empty since `v` itself is always a possible color
have : v ∈ s := fun ⟨u, hu, _, heq⟩ ↦ heq ▸ (ih u hu).prop <| hu
-- Color `v` with the minimum possible color, ordered by the well-order
⟨IsWellFounded.wf.min s ⟨v, this⟩, IsWellFounded.wf.not_lt_min s this⟩
let toFun v :=
-- Recurse to color each vertex, ordered by the well-order
IsWellFounded.fix (motive := ({ c // ¬r · c })) r f v |>.val
{ toFun := toFun
map_rel' {u v} hadj heq := by
-- As `r` is trichotomous and `u ≠ v` because they are adjacent in the graph, wlog `r u v`
wlog hr : r u v
· exact hadj.ne <| Std.Trichotomous.trichotomous u v hr <| this G r hadj.symm heq.symm
-- Therefore the color of `u` was considered when choosing a color for `v`
let sv := {toFun u | (u : V) (hu : r u v) (_ : G.Adj u v)}
have : toFun u ∈ sv := ⟨u, hr, hadj, rfl⟩
-- Since the color of `v` was chosen to be the minimum of the complement of `sv`,
-- it can't be in `sv`, so surely the colors of `u` and `v` cannot be the same
refine absurd this <| heq ▸ ?_
unfold toFun
rw [IsWellFounded.fix_eq]
refine IsWellFounded.wf.min_mem svᶜ ⟨v, fun ⟨w, hw, _, heq'⟩ ↦ absurd hw ?_⟩
rw [← heq']
exact IsWellFounded.fix r f w |>.prop }

variable {G} in
/-- Given a coloring of a graph, consider the mapped graph `G.map f` which can be thought of as
taking the original graph `G` and considering every color class (independent set) as a single
vertex. This greedily colors this graph by the given order on colors, which produces a new coloring
of the original graph. -/
noncomputable def Coloring.recolorGreedily {α : Type*} (r : α → α → Prop) [IsWellOrder α r]
(f : G.Coloring α) : G.Coloring α :=
G.map f |>.greedyColoring r |>.comp f.homMap

/-- The color assigned to a vertex `v` by greedy coloring is not greater than `v` -/
theorem not_lt_greedyColoring (v : V) : ¬r v (G.greedyColoring r v) := by
grind [greedyColoring, RelHom.coeFn_mk]

/-- The set of colors that `v` could not use when `G` was greedily colored in the order specified
by the given well-order -/
def greedyColorsBefore (v : V) : Set V :=
{G.greedyColoring r u | (u) (_ : r u v) (_ : G.Adj u v)}

variable {G r} in
theorem greedyColoring_mem_greedyColorsBefore {u v : V} (hr : r u v) (hadj : G.Adj u v) :
G.greedyColoring r u ∈ G.greedyColorsBefore r v :=
⟨u, hr, hadj, rfl⟩

theorem lt_of_mem_greedyColorsBefore {u v : V} (h : u ∈ G.greedyColorsBefore r v) : r u v := by
obtain ⟨w, hr, _, rfl⟩ := h
exact trans_trichotomous_left (G.not_lt_greedyColoring r w) hr

/-- Greedy coloring cannot get stuck since it is always possible for a vertex to be its own color -/
theorem notMem_greedyColorsBefore_self (v : V) : v ∉ G.greedyColorsBefore r v :=
fun ⟨u, hu, _, heq⟩ ↦ heq ▸ G.not_lt_greedyColoring r u <| hu

theorem greedyColorsBefore_subset_image_neighborSet (v : V) :
G.greedyColorsBefore r v ⊆ G.greedyColoring r '' G.neighborSet v :=
fun _u ⟨w, _, hwv, hu⟩ ↦ ⟨w, hwv.symm, hu⟩

/-- Greedy coloring assigns the smallest available color -/
theorem greedyColoring_eq_min (v : V) :
G.greedyColoring r v = IsWellFounded.wf.min (r := r) (G.greedyColorsBefore r v)ᶜ
⟨v, G.notMem_greedyColorsBefore_self r v⟩ := by
rw [greedyColoring, RelHom.coeFn_mk, IsWellFounded.fix_eq]
rfl

theorem greedyColoring_notMem_greedyColorsBefore (v : V) :
G.greedyColoring r v ∉ G.greedyColorsBefore r v := by
rw [greedyColoring_eq_min, ← Set.mem_compl_iff]
apply WellFounded.min_mem

variable {G r} in
theorem mem_greedyColorsBefore_of_lt_greedyColoring {u v : V} (h : r u (G.greedyColoring r v)) :
u ∈ G.greedyColorsBefore r v := by
rw [greedyColoring_eq_min] at h
exact WellFounded.mem_of_lt_min_compl h

variable {G r} in
theorem greedyColoring_eq_iff_subset_and_notMem {v c : V} :
G.greedyColoring r v = c ↔
{u | r u c} ⊆ G.greedyColorsBefore r v ∧ c ∉ G.greedyColorsBefore r v := by
refine ⟨(· ▸ ⟨?_, ?_⟩), fun ⟨hsub, hmem⟩ ↦ ?_⟩
· exact fun _ ↦ mem_greedyColorsBefore_of_lt_greedyColoring
· exact G.greedyColoring_notMem_greedyColorsBefore r v
· rw [greedyColoring_eq_min]
exact WellFounded.min_eq_of_forall_not_lt _ hmem <| Set.compl_subset_compl.mpr hsub

variable {G r} in
theorem greedyColoring_eq_of_greedyColorsBefore_eq {v c : V}
(h : G.greedyColorsBefore r v = {u | r u c}) : G.greedyColoring r v = c := by
rw [greedyColoring_eq_iff_subset_and_notMem, h]
exact ⟨Set.Subset.rfl, irrefl c⟩

variable {G r} in
theorem greedyColoring_eq_self_tfae {v : V} :
[G.greedyColoring r v = v, G.greedyColorsBefore r v = {u | r u v},
{u | r u v} ⊆ G.greedyColorsBefore r v].TFAE := by
tfae_have 1 → 3 := fun h u ↦ by
nth_rw 1 [← h]
exact mem_greedyColorsBefore_of_lt_greedyColoring
tfae_have 2 → 1 := greedyColoring_eq_of_greedyColorsBefore_eq
tfae_have 3 → 2 := antisymm fun _ ↦ G.lt_of_mem_greedyColorsBefore r
tfae_finish

theorem isLowerSet_range_greedyColoring : @IsLowerSet V ⟨r⟩ <| Set.range <| G.greedyColoring r := by
rintro _ u hle ⟨v, rfl⟩
rcases mem_greedyColorsBefore_of_lt_greedyColoring hle with ⟨u, _, _, rfl⟩
exact Set.mem_range_self u

theorem mk_greedyColorsBefore_le_coe_degree (v : V) [Fintype <| G.neighborSet v] :
#(G.greedyColorsBefore r v) ≤ G.degree v := by
rw [← G.card_neighborFinset_eq_degree, G.neighborFinset_def, ← Set.ncard_eq_toFinset_card',
Set.cast_ncard <| Set.toFinite _]
grw [← mk_image_le (f := G.greedyColoring r) (s := G.neighborSet v)]
exact mk_le_mk_of_subset <| G.greedyColorsBefore_subset_image_neighborSet r v

theorem encard_greedyColorsBefore_le_coe_degree (v : V) [Fintype <| G.neighborSet v] :
(G.greedyColorsBefore r v).encard ≤ G.degree v := by
grw [G.greedyColorsBefore_subset_image_neighborSet r v, Set.encard_image_le]
rw [← card_neighborFinset_eq_degree, neighborFinset_def, Set.encard_eq_coe_toFinset_card]

theorem ncard_greedyColorsBefore_le_degree (v : V) [Fintype <| G.neighborSet v] :
(G.greedyColorsBefore r v).ncard ≤ G.degree v := by
grw [← Nat.cast_le (α := ℕ∞), ← G.encard_greedyColorsBefore_le_coe_degree r v]
apply Set.ncard_le_encard

variable {G r} in
theorem greedyColoring_isClique_tfae {s : Set V} (hs : @IsLowerSet V ⟨r⟩ s) :
[s.InjOn (G.greedyColoring r), s.EqOn (G.greedyColoring r) id, G.IsClique s].TFAE := by
tfae_have 2 → 3 := fun h u hu v hv hne ↦ by
wlog huv : r u v
· refine this hs h v hv u hu hne.symm ?_ |>.symm
exact hne.imp_symm <| Std.Trichotomous.trichotomous u v huv
obtain ⟨u, hr, hadj, rfl⟩ := mem_greedyColorsBefore_of_lt_greedyColoring (h hv ▸ id_def v ▸ huv)
rwa [h <| hs hr hv]
tfae_have 3 → 2 := fun h v hv ↦ by
induction v using IsWellFounded.induction r with | ind v ih
rw [id_eq, greedyColoring_eq_self_tfae.out 0 2 rfl]
refine fun u huv ↦ ⟨u, huv, h (hs huv hv) hv (irrefl v <| · ▸ huv), ?_⟩
rw [ih u huv <| hs huv hv, id_eq]
tfae_have 1 → 2 :=
fun h ↦ hs.eqOn_id_of_injOn_of_forall_not_lt h fun v _ ↦ G.not_lt_greedyColoring r v
tfae_have 2 → 1 := fun h ↦ s.injOn_id.congr h.symm
tfae_finish

variable {G r} in
theorem greedyColoring_eq_id_tfae :
[Function.Injective (G.greedyColoring r), ↑(G.greedyColoring r) = id, G = ⊤].TFAE := by
rw [← Set.eqOn_univ, ← Set.injOn_univ, ← isClique_univ]
exact greedyColoring_isClique_tfae <| @isLowerSet_univ V ⟨r⟩

@[simp]
theorem greedyColoring_top_eq_id : greedyColoring ⊤ r = .id :=
RelHom.ext <| congrFun <| greedyColoring_eq_id_tfae.out 2 1 |>.mp rfl

theorem card_typein_greedyColoring_le_mk_greedyColorsBefore (v : V) :
(typein r <| G.greedyColoring r v).card ≤ #(G.greedyColorsBefore r v) := by
rw [greedyColoring_eq_min]
apply card_typein_min_le_mk

theorem typein_greedyColoring_le_coe_degree (v : V) [Fintype <| G.neighborSet v] :
typein r (G.greedyColoring r v) ≤ G.degree v := by
grw [← card_le_nat, card_typein_greedyColoring_le_mk_greedyColorsBefore,
mk_greedyColorsBefore_le_coe_degree]

theorem not_lt_enum_ord_greedyColorsBefore (v : V) (h : G.greedyColorsBefore r v |>.Finite) :
¬r (enum r ⟨#(G.greedyColorsBefore r v) |>.ord,
ord_mk_lt_type r h ⟨v, G.notMem_greedyColorsBefore_self r v⟩⟩) (G.greedyColoring r v) := by
rw [greedyColoring_eq_min]
exact not_lt_enum_ord_mk_min_compl r h _

theorem not_lt_enum_degree_greedyColoring (v : V) [Fintype <| G.neighborSet v] :
¬r (enum r ⟨G.degree v, by
rw [Set.mem_Iio, ← card_neighborFinset_eq_degree, ← ord_natCast, ← Cardinal.mk_coe_finset]
exact ord_mk_lt_type r (Finset.finite_toSet _) ⟨v, G.notMem_neighborFinset_self v⟩
⟩) (G.greedyColoring r v) := by
grw [← typein_le_typein, typein_enum, typein_greedyColoring_le_coe_degree]

variable {G} in
/-- A graph is `α`-colorable iff there exists a well-ordering of its vertices such that
greedy coloring uses at most `|α|` colors -/
theorem nonempty_coloring_iff_exists_isWellOrder {α : Type*} :
Nonempty (G.Coloring α) ↔ ∃ (r : V → V → Prop) (_ : IsWellOrder V r),
Nonempty (Set.range (G.greedyColoring r) ↪ α) := by
refine ⟨fun ⟨C⟩ ↦ ?_,
fun ⟨r, _, ⟨f⟩⟩ ↦ ⟨Embedding.completeGraph f |>.toHom.comp <| G.greedyColoring r |>.attach⟩⟩
-- Take arbitrary well-orders on `α` and `V`, then order the vertices first by their color,
-- and then by themselves to break ties (i.e. use the lexicographic order).
let r := Prod.Lex WellOrderingRel WellOrderingRel |>.onFun fun v ↦ (C v, v)
have : IsWellOrder V r := Function.Injective.isWellOrder _ fun _ _ h ↦ congr(($h).snd)
-- For every color `v` assigned in the greedy coloring, let `f v` be the first vertex that was
-- greedy-colored by the color `v`, with respect to the order `r`.
let f : Set.range (G.greedyColoring r) → V := (IsWellFounded.wf.min (r := r) _ <| ·.prop)
-- We claim that `C ∘ f` is injective.
refine ⟨r, this, C ∘ f, fun u v heq ↦ Subtype.ext ?_⟩
-- WLOG `r u v` since `r` is trichotomous.
wlog hr : r u v
· grind [Std.Trichotomous.trichotomous (r := r)]
-- Since `f v` got the greedy-color `v`,
have : G.greedyColoring r (f v) = v := WellFounded.min_mem _ _ v.prop
-- and `u` precedes `v`, there must exist a `w` before `f v` with color `u` and `G.Adj w (f v)`.
have ⟨w, hrw, hadj, hw⟩ := mem_greedyColorsBefore_of_lt_greedyColoring <| this ▸ hr
-- Since `f u` is the first vertex with color `u`, we get `f u ≤ w < f v` (using `r`).
have hnrw : ¬r w (f u) := WellFounded.not_lt_min _ _ <| by exact hw
-- Due to the lexicographic order and `C (f u) = C (f v)`, we get `C w = C (f v)`.
-- But since `G.Adj w (f v)` and `C` is a valid coloring, this is a contradiction.
exact absurd (by grind) <| C.map_adj hadj

theorem coe_recolorGreedily_coloringOfEmbedding_le_degree {n : ℕ} (f : V ↪ Fin n) (v : V)
[Fintype <| G.neighborSet v] :
(G.coloringOfEmbedding f).recolorGreedily LT.lt v ≤ G.degree v := by
classical
grw [← G.degree_map_apply f, ← Nat.cast_le (α := Ordinal),
← typein_greedyColoring_le_coe_degree _ LT.lt, typein_lt_fin]
rfl

/-- A coloring of a graph `G` using at most `G.maxDegree + 1` colors,
constructed by greedy coloring in an arbitrary order -/
noncomputable def coloringMaxDegreeAddOne [Fintype V] [DecidableRel G.Adj] :
G.Coloring <| Fin <| G.maxDegree + 1 :=
.castLT (G.coloringOfEmbedding (Fintype.equivFin V).toEmbedding |>.recolorGreedily LT.lt)
fun v ↦ by
grw [coe_recolorGreedily_coloringOfEmbedding_le_degree, degree_le_maxDegree]
apply Nat.lt_add_one

theorem colorable_maxDegree_add_one [Fintype V] [DecidableRel G.Adj] :
G.Colorable <| G.maxDegree + 1 :=
⟨G.coloringMaxDegreeAddOne⟩

theorem chromaticNumber_le_maxDegree_add_one [Fintype V] [DecidableRel G.Adj] :
G.chromaticNumber ≤ G.maxDegree + 1 :=
G.colorable_maxDegree_add_one.chromaticNumber_le

end SimpleGraph
22 changes: 22 additions & 0 deletions Mathlib/Combinatorics/SimpleGraph/Coloring/Vertex.lean
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,28 @@ theorem Colorable.of_hom {V' : Type*} {G' : SimpleGraph V'} (f : G →g G') {n :
(h : G'.Colorable n) : G.Colorable n :=
⟨(h.toColoring (by simp)).comp f⟩

/-- Given an `ℕ`-coloring where only colors below `n` are used, convert it to an `n`-coloring -/
@[simps!]
def Coloring.natToFin {n : ℕ} (C : G.Coloring ℕ) (h : ∀ v, C v < n) : G.Coloring <| Fin n :=
.mk (fun v ↦ ⟨C v, h v⟩) <| by grind [C.valid]

/-- Given a `k`-coloring where only colors below `n` are used, convert it to an `n`-coloring -/
@[simps!]
def Coloring.castLT {k n : ℕ} (C : G.Coloring <| Fin k) (h : ∀ v, C v < n) : G.Coloring <| Fin n :=
.mk (fun v ↦ C v |>.castLT <| h v) <| by grind [Fin.castLT, C.valid]

/-- Given an `α`-coloring `C`, convert it to a coloring where the only available colors are from the
range of `C`, possibly producing a coloring with fewer colors -/
@[simps!]
def Coloring.attach (C : G.Coloring α) : G.Coloring <| Set.range C :=
.mk (Set.rangeFactorization C) <| by grind [Set.rangeFactorization, C.valid]

variable (G) in
/-- Color a graph using an embedding of its vertices to colors -/
@[simps!]
def coloringOfEmbedding {α : Type*} (f : V ↪ α) : G.Coloring α :=
G.recolorOfEmbedding f G.selfColoring

theorem colorable_iff_exists_bdd_nat_coloring (n : ℕ) :
G.Colorable n ↔ ∃ C : G.Coloring ℕ, ∀ v, C v < n := by
constructor
Expand Down
2 changes: 1 addition & 1 deletion Mathlib/Combinatorics/SimpleGraph/Copy.lean
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ alias ⟨IsContained.exists_iso_subgraph, IsContained.of_exists_iso_subgraph⟩

theorem Copy.degree_le (f : Copy G H) (v : V) [Fintype <| G.neighborSet v]
[Fintype <| H.neighborSet (f v)] : G.degree v ≤ H.degree (f v) := by
simpa [card_neighborSet_eq_degree] using
simpa [card_neighborSet_eq_degree, -Set.fintypeCard_eq_ncard] using
Fintype.card_le_of_injective _ (f.mapNeighborSet v).injective

theorem Copy.maxDegree_mono [Fintype V] [Fintype W] [DecidableRel G.Adj] [DecidableRel H.Adj]
Expand Down
16 changes: 12 additions & 4 deletions Mathlib/Combinatorics/SimpleGraph/Finite.lean
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module

public import Mathlib.Combinatorics.SimpleGraph.Maps
public import Mathlib.Data.Finset.Max
public import Mathlib.Data.Set.Card
public import Mathlib.Data.Sym.Card

/-!
Expand Down Expand Up @@ -125,7 +126,7 @@ theorem card_edgeSet : Fintype.card G.edgeSet = #G.edgeFinset :=
.symm <| Set.toFinset_card _

theorem edgeSet_univ_card : #(univ : Finset G.edgeSet) = #G.edgeFinset := by
simp [card_edgeSet]
simp [card_edgeSet, -Set.fintypeCard_eq_ncard]

variable [Fintype V]

Expand Down Expand Up @@ -251,7 +252,7 @@ theorem degree_compl [Fintype (Gᶜ.neighborSet v)] [Fintype V] :
classical
rw [← card_neighborSet_union_compl_neighborSet G v, Set.toFinset_union]
simp [card_union_of_disjoint (Set.disjoint_toFinset.mpr (compl_neighborSet_disjoint G v)),
card_neighborSet_eq_degree]
card_neighborSet_eq_degree, -Set.fintypeCard_eq_ncard]

instance incidenceSetFintype [DecidableEq V] : Fintype (G.incidenceSet v) :=
Fintype.ofEquiv (G.neighborSet v) (G.incidenceSetEquivNeighborSet v).symm
Expand Down Expand Up @@ -472,7 +473,7 @@ lemma minDegree_le_maxDegree [DecidableRel G.Adj] : G.minDegree ≤ G.maxDegree

theorem IsRegularOfDegree.minDegree_eq [Nonempty V] [DecidableRel G.Adj] {d : ℕ}
(h : G.IsRegularOfDegree d) : G.minDegree = d := by
simp [minDegree, h.degree_eq, Finset.image_const]
simp [minDegree, h.degree_eq, Finset.image_const, -ENat.some_eq_coe]

@[simp]
lemma minDegree_bot_eq_zero : (⊥ : SimpleGraph V).minDegree = 0 :=
Expand Down Expand Up @@ -520,7 +521,8 @@ theorem Adj.card_commonNeighbors_lt_degree {G : SimpleGraph V} [DecidableRel G.A

theorem card_commonNeighbors_top [DecidableEq V] {v w : V} (h : v ≠ w) :
Fintype.card (commonNeighbors ⊤ v w) = Fintype.card V - 2 := by
simp [commonNeighbors_top_eq, ← Set.toFinset_card, Finset.card_sdiff, h]
simp [commonNeighbors_top_eq, ← Set.toFinset_card, Finset.card_sdiff, h,
-Set.fintypeCard_eq_ncard]

end Finite

Expand Down Expand Up @@ -631,6 +633,12 @@ theorem card_edgeFinset_map (f : V ↪ W) (G : SimpleGraph V) [DecidableRel G.Ad
rw [edgeFinset_map]
exact G.edgeFinset.card_map f.sym2Map

theorem degree_map_apply {V W : Type*} (G : SimpleGraph V) (f : V ↪ W) (v : V)
[Fintype <| G.neighborSet v] [Fintype <| G.map f |>.neighborSet <| f v] :
(G.map f).degree (f v) = G.degree v := by
simp_rw [← card_neighborSet_eq_degree, ← Set.toFinset_card, ← Set.ncard_eq_toFinset_card',
← Set.ncard_image_of_injective _ f.injective, neighborSet_map]

end Map

end SimpleGraph
3 changes: 2 additions & 1 deletion Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ variable [NonAssocSemiring R] [DecidableEq α] [DecidableRel G.Adj] {a : α} {e

theorem sum_incMatrix_apply [Fintype (Sym2 α)] [Fintype (neighborSet G a)] :
∑ e, G.incMatrix R a e = G.degree a := by
simp [incMatrix_apply', sum_boole, Set.filter_mem_univ_eq_toFinset, card_incidenceSet_eq_degree]
simp [incMatrix_apply', sum_boole, Set.filter_mem_univ_eq_toFinset, card_incidenceSet_eq_degree,
-Set.fintypeCard_eq_ncard]

theorem incMatrix_mul_transpose_diag [Fintype (Sym2 α)] [Fintype (neighborSet G a)] :
(G.incMatrix R * (G.incMatrix R)ᵀ) a a = G.degree a := by
Expand Down
2 changes: 1 addition & 1 deletion Mathlib/Combinatorics/SimpleGraph/Subgraph.lean
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ theorem card_neighborSet_toSubgraph (G H : SimpleGraph V) (h : H ≤ G)
lemma degree_toSubgraph (G H : SimpleGraph V) (h : H ≤ G) {v : V}
[Fintype ↑((toSubgraph H h).neighborSet v)] [Fintype ↑(H.neighborSet v)] :
(toSubgraph H h).degree v = H.degree v := by
simp [Subgraph.degree, card_neighborSet_toSubgraph]
simp [Subgraph.degree, card_neighborSet_toSubgraph, -Set.fintypeCard_eq_ncard]

section MkProperties

Expand Down
Loading