From 56adbb50555e4cedc953ae6b6ed0256551fcb33f Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sat, 3 Jan 2026 02:36:50 +0200 Subject: [PATCH 01/60] feat(Combinatorics/SimpleGraph/Finite): degrees for infinite graphs --- .../Combinatorics/SimpleGraph/Acyclic.lean | 10 +- .../Combinatorics/SimpleGraph/AdjMatrix.lean | 2 +- .../Combinatorics/SimpleGraph/Bipartite.lean | 4 + .../Combinatorics/SimpleGraph/Circulant.lean | 2 +- .../SimpleGraph/Connectivity/Connected.lean | 6 +- .../Combinatorics/SimpleGraph/DegreeSum.lean | 11 +- .../SimpleGraph/Extremal/Turan.lean | 11 +- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 404 +++++++++--------- .../SimpleGraph/FiveWheelLike.lean | 9 +- .../Combinatorics/SimpleGraph/LapMatrix.lean | 11 +- Mathlib/Combinatorics/SimpleGraph/Maps.lean | 4 + Mathlib/Combinatorics/SimpleGraph/Prod.lean | 3 +- .../SimpleGraph/StronglyRegular.lean | 13 +- .../Combinatorics/SimpleGraph/Subgraph.lean | 1 + Mathlib/Combinatorics/SimpleGraph/Trails.lean | 15 +- Mathlib/Data/Set/Card.lean | 4 + Mathlib/Data/Set/Insert.lean | 5 + .../ConditionallyCompleteLattice/Finset.lean | 7 + 18 files changed, 287 insertions(+), 235 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean index 3401b0a4f81b61..5c2c6e62b64b45 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean @@ -488,8 +488,10 @@ lemma isTree_iff_connected_and_card [Finite V] : exact Finset.card_lt_card <| by simpa [deleteEdges] /-- The minimum degree of all vertices in a nontrivial tree is one. -/ -lemma IsTree.minDegree_eq_one_of_nontrivial (h : G.IsTree) [Fintype V] [Nontrivial V] - [DecidableRel G.Adj] : G.minDegree = 1 := by +lemma IsTree.minDegree_eq_one_of_nontrivial (h : G.IsTree) [Finite V] [Nontrivial V] : + G.minDegree = 1 := by + classical + have := Fintype.ofFinite V by_cases q : 2 ≤ G.minDegree · have := h.card_edgeFinset have := G.sum_degrees_eq_twice_card_edges @@ -502,8 +504,8 @@ lemma IsTree.minDegree_eq_one_of_nontrivial (h : G.IsTree) [Fintype V] [Nontrivi lia /-- A nontrivial tree has a vertex of degree one. -/ -lemma IsTree.exists_vert_degree_one_of_nontrivial [Fintype V] [Nontrivial V] [DecidableRel G.Adj] - (h : G.IsTree) : ∃ v, G.degree v = 1 := by +lemma IsTree.exists_vert_degree_one_of_nontrivial [Finite V] [Nontrivial V] (h : G.IsTree) : + ∃ v, G.degree v = 1 := by obtain ⟨v, hv⟩ := G.exists_minimal_degree_vertex use v rw [← hv] diff --git a/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean index 3c1968ba4cdeed..fbf1391fdd5239 100644 --- a/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean @@ -232,7 +232,7 @@ theorem adjMatrix_mulVec_const_apply [NonAssocSemiring α] {a : α} {v : V} : theorem adjMatrix_mulVec_const_apply_of_regular [NonAssocSemiring α] {d : ℕ} {a : α} (hd : G.IsRegularOfDegree d) {v : V} : (G.adjMatrix α *ᵥ Function.const _ a) v = d * a := by - simp [hd v] + simp [hd.degree_eq v] theorem adjMatrix_pow_apply_eq_card_walk [DecidableEq V] [Semiring α] (n : ℕ) (u v : V) : (G.adjMatrix α ^ n) u v = Fintype.card { p : G.Walk u v | p.length = n } := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean b/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean index 1bd5c30b0cb3ab..54d324c82d3b92 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean @@ -417,10 +417,12 @@ lemma neighborFinset_subset_between_union (hv : v ∈ s) : G.neighborFinset v ⊆ (G.between s sᶜ).neighborFinset v ∪ s := by simpa [neighborFinset_def] using neighborSet_subset_between_union hv +omit [DecidableEq V] [DecidableRel G.Adj] in /-- The degree of `v ∈ s` in `G` is at most the degree in `G.between s sᶜ` plus the excluded vertices from `s`. -/ theorem degree_le_between_add (hv : v ∈ s) : G.degree v ≤ (G.between s sᶜ).degree v + s.card := by + classical have h_bipartite : (G.between s sᶜ).IsBipartiteWith s ↑(sᶜ) := by simpa using between_isBipartiteWith disjoint_compl_right simp_rw [← card_neighborFinset_eq_degree, @@ -433,10 +435,12 @@ lemma neighborFinset_subset_between_union_compl (hw : w ∈ sᶜ) : G.neighborFinset w ⊆ (G.between s sᶜ).neighborFinset w ∪ sᶜ := by simpa [neighborFinset_def] using G.neighborSet_subset_between_union_compl (by simpa using hw) +omit [DecidableRel G.Adj] in /-- The degree of `w ∈ sᶜ` in `G` is at most the degree in `G.between s sᶜ` plus the excluded vertices from `sᶜ`. -/ theorem degree_le_between_add_compl (hw : w ∈ sᶜ) : G.degree w ≤ (G.between s sᶜ).degree w + sᶜ.card := by + classical have h_bipartite : (G.between s sᶜ).IsBipartiteWith s ↑(sᶜ) := by simpa using between_isBipartiteWith disjoint_compl_right simp_rw [← card_neighborFinset_eq_degree, diff --git a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean index 24d370c21c22bd..801ccee36276ca 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean @@ -111,7 +111,7 @@ theorem cycleGraph_neighborFinset {n : ℕ} {v : Fin (n + 2)} : theorem cycleGraph_degree_two_le {n : ℕ} {v : Fin (n + 2)} : (cycleGraph (n + 2)).degree v = Finset.card {v - 1, v + 1} := by - rw [SimpleGraph.degree, cycleGraph_neighborFinset] + rw [← card_neighborFinset_eq_degree, cycleGraph_neighborFinset] theorem cycleGraph_degree_three_le {n : ℕ} {v : Fin (n + 3)} : (cycleGraph (n + 3)).degree v = 2 := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean index 9fddb94623684a..3100e534f30b34 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean @@ -243,8 +243,10 @@ lemma Preconnected.degree_pos_of_nontrivial [Nontrivial V] {G : SimpleGraph V} ( (v : V) [Fintype (G.neighborSet v)] : 0 < G.degree v := by simp [degree_pos_iff_mem_support, h.support_eq_univ] -lemma Preconnected.minDegree_pos_of_nontrivial [Nontrivial V] [Fintype V] {G : SimpleGraph V} - [DecidableRel G.Adj] (h : G.Preconnected) : 0 < G.minDegree := by +lemma Preconnected.minDegree_pos_of_nontrivial [Nontrivial V] [Finite V] {G : SimpleGraph V} + (h : G.Preconnected) : 0 < G.minDegree := by + classical + have := Fintype.ofFinite V obtain ⟨v, hv⟩ := G.exists_minimal_degree_vertex rw [hv] exact h.degree_pos_of_nontrivial v diff --git a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean index 0f93447a62f366..2840254404fc23 100644 --- a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean +++ b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean @@ -123,8 +123,7 @@ theorem sum_degrees_support_eq_twice_card_edges : end DegreeSum /-- The handshaking lemma. See also `SimpleGraph.sum_degrees_eq_twice_card_edges`. -/ -theorem even_card_odd_degree_vertices [Fintype V] [DecidableRel G.Adj] : - Even #{v | Odd (G.degree v)} := by +theorem even_card_odd_degree_vertices [Fintype V] : Even #{v | Odd (G.degree v)} := by classical have h := congr_arg (fun n => ↑n : ℕ → ZMod 2) G.sum_degrees_eq_twice_card_edges simp only [ZMod.natCast_self, zero_mul, Nat.cast_mul] at h @@ -139,8 +138,8 @@ theorem even_card_odd_degree_vertices [Fintype V] [DecidableRel G.Adj] : ← Nat.not_even_iff_odd] tauto -theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] [DecidableRel G.Adj] (v : V) - (h : Odd (G.degree v)) : Odd #{w | w ≠ v ∧ Odd (G.degree w)} := by +theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] (v : V) (h : Odd (G.degree v)) : + Odd #{w | w ≠ v ∧ Odd (G.degree w)} := by rcases G.even_card_odd_degree_vertices with ⟨k, hg⟩ have hk : 0 < k := by have hh : Finset.Nonempty {v : V | Odd (G.degree v)} := by @@ -158,8 +157,8 @@ theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] [DecidableRe lia · rwa [mem_filter_univ] -theorem exists_ne_odd_degree_of_exists_odd_degree [Fintype V] [DecidableRel G.Adj] (v : V) - (h : Odd (G.degree v)) : ∃ w : V, w ≠ v ∧ Odd (G.degree w) := by +theorem exists_ne_odd_degree_of_exists_odd_degree [Fintype V] (v : V) (h : Odd (G.degree v)) : + ∃ w : V, w ≠ v ∧ Odd (G.degree w) := by haveI := Classical.decEq V rcases G.odd_card_odd_degree_vertices_ne v h with ⟨k, hg⟩ have hg' : 0 < #{w | w ≠ v ∧ Odd (G.degree w)} := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Extremal/Turan.lean b/Mathlib/Combinatorics/SimpleGraph/Extremal/Turan.lean index a8ea3d976b773d..aed77c3ad2d10e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Extremal/Turan.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Extremal/Turan.lean @@ -141,13 +141,15 @@ lemma not_adj_trans (h : G.IsTuranMaximal r) (hts : ¬G.Adj t s) (hsu : ¬G.Adj rw [card_edgeFinset_replaceVertex_of_not_adj _ this, card_edgeFinset_replaceVertex_of_not_adj _ hst, dst, Nat.add_sub_cancel] have l1 : (G.replaceVertex s t).degree s = G.degree s := by - unfold degree; congr 1; ext v + rw [← card_neighborFinset_eq_degree, ← card_neighborFinset_eq_degree] + congr 1; ext v simp_rw [mem_neighborFinset] by_cases eq : v = t · simpa only [eq, not_adj_replaceVertex_same, false_iff] · rw [G.adj_replaceVertex_iff_of_ne s nst eq] have l2 : (G.replaceVertex s t).degree u = G.degree u - 1 := by - rw [degree, degree, ← card_singleton t, ← card_sdiff_of_subset (by simp [h.symm])] + rw [← card_neighborFinset_eq_degree, ← card_neighborFinset_eq_degree, ← card_singleton t, + ← card_sdiff_of_subset (by simp [h.symm])] congr 1; ext v simp_rw [mem_neighborFinset, mem_sdiff, mem_singleton, replaceVertex] split_ifs <;> simp_all [adj_comm] @@ -348,8 +350,8 @@ lemma card_edgeFinset_turanGraph_add : #(turanGraph (n + r) r).edgeFinset = #(turanGraph n r).edgeFinset + n * (r - 1) + r.choose 2 := by rw [← mul_right_inj' two_ne_zero] - simp_rw [mul_add, ← sum_degrees_eq_twice_card_edges, - degree, neighborFinset_eq_filter, turanGraph, card_filter] + simp_rw [mul_add, ← sum_degrees_eq_twice_card_edges, ← card_neighborFinset_eq_degree, + neighborFinset_eq_filter, turanGraph, card_filter] conv_lhs => enter [2, v] rw [Fin.sum_univ_eq_sum_range fun w ↦ if v % r ≠ w % r then 1 else 0, sum_range_add] @@ -408,7 +410,6 @@ theorem mul_card_edgeFinset_turanGraph_le : grw [card_edgeFinset_turanGraph, mul_add, Nat.mul_div_le] rw [tsub_mul, ← Nat.sub_add_comm]; swap · grw [Nat.mod_le] - exact Nat.zero_le _ rw [Nat.sub_le_iff_le_add, mul_comm, Nat.add_le_add_iff_left, Nat.choose_two_right, ← Nat.mul_div_assoc _ (Nat.even_mul_pred_self _).two_dvd, mul_assoc, mul_div_cancel_left₀ _ two_ne_zero, ← mul_assoc, ← mul_rotate, sq, ← mul_rotate (r - 1)] diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 1a861e8ed675b6..67afa21ff2c11f 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -6,7 +6,8 @@ Authors: Aaron Anderson, Jalex Stark, Kyle Miller, Alena Gusakov module public import Mathlib.Combinatorics.SimpleGraph.Maps -public import Mathlib.Data.Finset.Max +public import Mathlib.Data.ENat.Lattice +public import Mathlib.Data.Set.Card public import Mathlib.Data.Sym.Card /-! @@ -170,92 +171,117 @@ theorem neighborFinset_disjoint_singleton : Disjoint (G.neighborFinset v) {v} := theorem singleton_disjoint_neighborFinset : Disjoint {v} (G.neighborFinset v) := Finset.disjoint_singleton_left.mpr <| notMem_neighborFinset_self _ _ -/-- `G.degree v` is the number of vertices adjacent to `v`. -/ -def degree : ℕ := #(G.neighborFinset v) +/-- `G.edegree v` is the number of vertices adjacent to `v`, or `⊤` if there are infinitely many -/ +noncomputable def edegree : ℕ∞ := + G.neighborSet v |>.encard + +/-- `G.degree v` is the number of vertices adjacent to `v`, or `0` if there are infinitely many -/ +noncomputable def degree : ℕ := + G.neighborSet v |>.ncard @[simp] -theorem card_neighborFinset_eq_degree : #(G.neighborFinset v) = G.degree v := rfl +theorem card_neighborFinset_eq_degree : #(G.neighborFinset v) = G.degree v := + Set.ncard_eq_toFinset_card' _ |>.symm @[simp] theorem card_neighborSet_eq_degree : Fintype.card (G.neighborSet v) = G.degree v := - (Set.toFinset_card _).symm + Set.ncard_eq_card _ |>.symm -theorem degree_pos_iff_exists_adj : 0 < G.degree v ↔ ∃ w, G.Adj v w := by - simp only [degree, card_pos, Finset.Nonempty, mem_neighborFinset] +omit [Fintype <| G.neighborSet v] in +theorem degree_pos_iff_exists_adj [Finite <| G.neighborSet v] : 0 < G.degree v ↔ ∃ w, G.Adj v w := + Set.ncard_pos -theorem degree_pos_iff_mem_support : 0 < G.degree v ↔ v ∈ G.support := by +omit [Fintype <| G.neighborSet v] in +theorem degree_pos_iff_mem_support [Finite <| G.neighborSet v] : + 0 < G.degree v ↔ v ∈ G.support := by rw [G.degree_pos_iff_exists_adj v, mem_support] -theorem degree_eq_zero_iff_notMem_support : G.degree v = 0 ↔ v ∉ G.support := by +omit [Fintype <| G.neighborSet v] in +theorem degree_eq_zero_iff_notMem_support [Finite <| G.neighborSet v] : + G.degree v = 0 ↔ v ∉ G.support := by rw [← G.degree_pos_iff_mem_support v, Nat.pos_iff_ne_zero, not_ne_iff] +variable {G} in @[simp] -theorem degree_eq_zero_of_subsingleton {G : SimpleGraph V} (v : V) [Fintype (G.neighborSet v)] - [Subsingleton V] : G.degree v = 0 := by +theorem degree_eq_zero_of_subsingleton (v : V) [Subsingleton V] : G.degree v = 0 := by have := G.degree_pos_iff_exists_adj v simp_all [subsingleton_iff_forall_eq v] -theorem degree_eq_one_iff_existsUnique_adj {G : SimpleGraph V} {v : V} [Fintype (G.neighborSet v)] : - G.degree v = 1 ↔ ∃! w : V, G.Adj v w := by - rw [degree, Finset.card_eq_one, Finset.singleton_iff_unique_mem] - simp only [mem_neighborFinset] +omit [Fintype <| G.neighborSet v] in +variable {G} in +theorem degree_eq_one_iff_existsUnique_adj {v : V} : G.degree v = 1 ↔ ∃! w : V, G.Adj v w := by + rw [degree, Set.ncard_eq_one, Set.singleton_iff_unique_mem] + rfl -theorem nontrivial_of_degree_ne_zero {G : SimpleGraph V} {v : V} [Fintype (G.neighborSet v)] - (h : G.degree v ≠ 0) : Nontrivial V := by +variable {G} in +theorem nontrivial_of_degree_ne_zero {v : V} (h : G.degree v ≠ 0) : Nontrivial V := by by_contra! simp_all [degree_eq_zero_of_subsingleton] -theorem degree_compl [Fintype (Gᶜ.neighborSet v)] [Fintype V] : - Gᶜ.degree v = Fintype.card V - 1 - G.degree v := by +omit [Fintype <| G.neighborSet v] in +theorem degree_compl [Fintype V] : Gᶜ.degree v = Fintype.card V - 1 - G.degree v := by 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))] + have := Fintype.ofFinite <| G.neighborSet v + have := Fintype.ofFinite <| Gᶜ.neighborSet v + 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))] instance incidenceSetFintype [DecidableEq V] : Fintype (G.incidenceSet v) := Fintype.ofEquiv (G.neighborSet v) (G.incidenceSetEquivNeighborSet v).symm +omit [Fintype <| G.neighborSet v] in /-- This is the `Finset` version of `incidenceSet`. -/ -def incidenceFinset [DecidableEq V] : Finset (Sym2 V) := +def incidenceFinset [Fintype <| G.incidenceSet v] : Finset (Sym2 V) := (G.incidenceSet v).toFinset +omit [Fintype <| G.neighborSet v] in @[simp] -theorem card_incidenceSet_eq_degree [DecidableEq V] : +theorem card_incidenceSet_eq_degree [Fintype <| G.incidenceSet v] : Fintype.card (G.incidenceSet v) = G.degree v := by + classical + have := Fintype.ofEquiv _ <| G.incidenceSetEquivNeighborSet v rw [Fintype.card_congr (G.incidenceSetEquivNeighborSet v)] simp +omit [Fintype <| G.neighborSet v] in @[simp] -theorem card_incidenceFinset_eq_degree [DecidableEq V] : #(G.incidenceFinset v) = G.degree v := by +theorem card_incidenceFinset_eq_degree [Fintype <| G.incidenceSet v] : + #(G.incidenceFinset v) = G.degree v := by rw [← G.card_incidenceSet_eq_degree] apply Set.toFinset_card +omit [Fintype <| G.neighborSet v] in @[simp] -theorem mem_incidenceFinset [DecidableEq V] (e : Sym2 V) : +theorem mem_incidenceFinset [Fintype <| G.incidenceSet v] (e : Sym2 V) : e ∈ G.incidenceFinset v ↔ e ∈ G.incidenceSet v := Set.mem_toFinset -theorem incidenceFinset_eq_filter [DecidableEq V] [Fintype G.edgeSet] : - G.incidenceFinset v = {e ∈ G.edgeFinset | v ∈ e} := by +omit [Fintype <| G.neighborSet v] in +theorem incidenceFinset_eq_filter [DecidableEq V] [Fintype <| G.incidenceSet v] + [Fintype G.edgeSet] : G.incidenceFinset v = {e ∈ G.edgeFinset | v ∈ e} := by ext e induction e simp [mk'_mem_incidenceSet_iff] -theorem incidenceFinset_subset [DecidableEq V] [Fintype G.edgeSet] : +omit [Fintype <| G.neighborSet v] in +theorem incidenceFinset_subset [Fintype <| G.incidenceSet v] [Fintype G.edgeSet] : G.incidenceFinset v ⊆ G.edgeFinset := Set.toFinset_subset_toFinset.mpr (G.incidenceSet_subset v) +omit [Fintype <| G.neighborSet v] in /-- The degree of a vertex is at most the number of edges. -/ -theorem degree_le_card_edgeFinset [Fintype G.edgeSet] : - G.degree v ≤ #G.edgeFinset := by - classical - rw [← card_incidenceFinset_eq_degree] - exact card_le_card (G.incidenceFinset_subset v) +theorem degree_le_card_edgeFinset [Fintype G.edgeSet] : G.degree v ≤ #G.edgeFinset := by + have := @Fintype.ofFinite _ <| Finite.Set.subset _ <| G.incidenceSet_subset v + exact G.card_incidenceFinset_eq_degree v ▸ card_le_card (G.incidenceFinset_subset v) variable {G v} +omit [Fintype <| G.neighborSet v] in /-- If `G ≤ H` then `G.degree v ≤ H.degree v` for any vertex `v`. -/ -lemma degree_le_of_le {H : SimpleGraph V} [Fintype (H.neighborSet v)] (hle : G ≤ H) : +lemma degree_le_of_le {H : SimpleGraph V} [Finite <| H.neighborSet v] (hle : G ≤ H) : G.degree v ≤ H.degree v := by + have := Fintype.ofFinite <| H.neighborSet v + have := (Set.toFinite _ |>.subset <| neighborSet_subset hle v).fintype simp_rw [← card_neighborSet_eq_degree] exact Set.card_le_card fun v hv => hle hv @@ -267,21 +293,20 @@ section LocallyFinite abbrev LocallyFinite := ∀ v : V, Fintype (G.neighborSet v) -variable [LocallyFinite G] - -/-- A locally finite simple graph is regular of degree `d` if every vertex has degree `d`. -/ +/-- A simple graph is regular of degree `d` if every vertex has degree `d`. -/ def IsRegularOfDegree (d : ℕ) : Prop := - ∀ v : V, G.degree v = d + ∀ v : V, G.edegree v = d variable {G} theorem IsRegularOfDegree.degree_eq {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : G.degree v = d := - h v + congrArg _ <| h v -theorem IsRegularOfDegree.compl [Fintype V] [DecidableEq V] {G : SimpleGraph V} [DecidableRel G.Adj] - {k : ℕ} (h : G.IsRegularOfDegree k) : Gᶜ.IsRegularOfDegree (Fintype.card V - 1 - k) := by +theorem IsRegularOfDegree.compl [Fintype V] {k : ℕ} (h : G.IsRegularOfDegree k) : + Gᶜ.IsRegularOfDegree (Fintype.card V - 1 - k) := by intro v - rw [degree_compl, h v] + have : Gᶜ.degree v = Gᶜ.edegree v := ENat.coe_toNat <| Set.encard_ne_top_iff.mpr <| Set.toFinite _ + rw [← this, degree_compl, h.degree_eq] end LocallyFinite @@ -299,74 +324,82 @@ instance neighborSetFintype [DecidableRel G.Adj] (v : V) : Fintype (G.neighborSe theorem neighborFinset_eq_filter {v : V} [DecidableRel G.Adj] : G.neighborFinset v = ({w | G.Adj v w} : Finset _) := by ext; simp -theorem neighborFinset_compl [DecidableEq V] [DecidableRel G.Adj] (v : V) : - Gᶜ.neighborFinset v = (G.neighborFinset v)ᶜ \ {v} := by +theorem neighborFinset_compl [DecidableEq V] (v : V) [Fintype <| G.neighborSet v] + [Fintype <| Gᶜ.neighborSet v] : Gᶜ.neighborFinset v = (G.neighborFinset v)ᶜ \ {v} := by + classical simp only [neighborFinset, neighborSet_compl, Set.toFinset_diff, Set.toFinset_compl, Set.toFinset_singleton] @[simp] -theorem complete_graph_degree [DecidableEq V] (v : V) : - (completeGraph V).degree v = Fintype.card V - 1 := by - simp_rw [degree, neighborFinset_eq_filter, top_adj, filter_ne] +theorem complete_graph_degree (v : V) : degree ⊤ v = Fintype.card V - 1 := by + classical + simp_rw [← card_neighborFinset_eq_degree, neighborFinset_eq_filter, top_adj, filter_ne] rw [card_erase_of_mem (mem_univ v), card_univ] +omit [Fintype V] in @[simp] -theorem bot_degree (v : V) : (⊥ : SimpleGraph V).degree v = 0 := by - simp_rw [degree, neighborFinset_eq_filter, bot_adj, filter_false] - exact Finset.card_empty +theorem bot_degree (v : V) : degree ⊥ v = 0 := by + simp [degree, neighborSet] -theorem IsRegularOfDegree.top [DecidableEq V] : - (⊤ : SimpleGraph V).IsRegularOfDegree (Fintype.card V - 1) := by +theorem IsRegularOfDegree.top : (⊤ : SimpleGraph V).IsRegularOfDegree (Fintype.card V - 1) := by intro v - simp + have : degree ⊤ v = edegree ⊤ v := ENat.coe_toNat <| Set.encard_ne_top_iff.mpr <| Set.toFinite _ + simp [← this] + +theorem IsRegularOfDegree.bot : (⊥ : SimpleGraph V).IsRegularOfDegree 0 := by + intro v + have : degree ⊥ v = edegree ⊥ v := ENat.coe_toNat <| Set.encard_ne_top_iff.mpr <| Set.toFinite _ + simp [← this] + +/-- The minimum extended degree of all vertices (and `⊤` if there are no vertices) -/ +noncomputable def eminDegree : ℕ∞ := + ⨅ v, G.edegree v /-- The minimum degree of all vertices (and `0` if there are no vertices). The key properties of this are given in `exists_minimal_degree_vertex`, `minDegree_le_degree` and `le_minDegree_of_forall_le_degree`. -/ -def minDegree [DecidableRel G.Adj] : ℕ := - WithTop.untopD 0 (univ.image fun v => G.degree v).min +noncomputable def minDegree : ℕ := + G.eminDegree.toNat +omit [Fintype V] in /-- There exists a vertex of minimal degree. Note the assumption of being nonempty is necessary, as the lemma implies there exists a vertex. -/ -theorem exists_minimal_degree_vertex [DecidableRel G.Adj] [Nonempty V] : - ∃ v, G.minDegree = G.degree v := by - obtain ⟨t, ht : _ = _⟩ := min_of_nonempty (univ_nonempty.image fun v => G.degree v) - obtain ⟨v, _, rfl⟩ := mem_image.mp (mem_of_min ht) - exact ⟨v, by simp [minDegree, ht]⟩ +theorem exists_minimal_degree_vertex [Nonempty V] : ∃ v, G.minDegree = G.degree v := by + have ⟨v, hv⟩ := ciInf_mem G.edegree + exact ⟨v, congrArg _ hv.symm⟩ +omit [Fintype V] in /-- The minimum degree in the graph is at most the degree of any particular vertex. -/ -theorem minDegree_le_degree [DecidableRel G.Adj] (v : V) : G.minDegree ≤ G.degree v := by - obtain ⟨t, ht⟩ := Finset.min_of_mem (mem_image_of_mem (fun v => G.degree v) (mem_univ v)) - have := Finset.min_le_of_eq (mem_image_of_mem _ (mem_univ v)) ht - rwa [minDegree, ht] +theorem minDegree_le_degree (v : V) [Finite <| G.neighborSet v] : G.minDegree ≤ G.degree v := + ENat.toNat_le_toNat (iInf_le ..) (Set.encard_ne_top_iff.mpr ‹_›) +omit [Fintype V] in /-- In a nonempty graph, if `k` is at most the degree of every vertex, it is at most the minimum degree. Note the assumption that the graph is nonempty is necessary as long as `G.minDegree` is defined to be a natural. -/ -theorem le_minDegree_of_forall_le_degree [DecidableRel G.Adj] [Nonempty V] (k : ℕ) - (h : ∀ v, k ≤ G.degree v) : k ≤ G.minDegree := by - rcases G.exists_minimal_degree_vertex with ⟨v, hv⟩ - rw [hv] - apply h +theorem le_minDegree_of_forall_le_degree [Nonempty V] (k : ℕ) (h : ∀ v, k ≤ G.degree v) : + k ≤ G.minDegree := by + have ⟨v, hv⟩ := G.exists_minimal_degree_vertex + exact hv ▸ h v +omit [Fintype V] in /-- If there are no vertices then the `minDegree` is zero. -/ @[simp] -lemma minDegree_of_isEmpty [DecidableRel G.Adj] [IsEmpty V] : G.minDegree = 0 := by - rw [minDegree, WithTop.untopD_eq_self_iff] - simp +lemma minDegree_of_isEmpty [IsEmpty V] : G.minDegree = 0 := + ENat.toNat_eq_zero.mpr <| .inr <| iInf_of_empty G.edegree -variable {G} in +omit [Fintype V] in /-- If `G` is a subgraph of `H` then `G.minDegree ≤ H.minDegree`. -/ -lemma minDegree_le_minDegree {H : SimpleGraph V} [DecidableRel G.Adj] [DecidableRel H.Adj] - (hle : G ≤ H) : G.minDegree ≤ H.minDegree := by +lemma minDegree_le_minDegree [Finite V] {G H : SimpleGraph V} (hle : G ≤ H) : + G.minDegree ≤ H.minDegree := by by_cases! hne : Nonempty V · apply le_minDegree_of_forall_le_degree exact fun v ↦ (G.minDegree_le_degree v).trans (G.degree_le_of_le hle) · simp /-- In a nonempty graph, the minimal degree is less than the number of vertices. -/ -theorem minDegree_lt_card [DecidableRel G.Adj] [Nonempty V] : - G.minDegree < Fintype.card V := by +theorem minDegree_lt_card [Nonempty V] : G.minDegree < Fintype.card V := by + classical obtain ⟨v, hδ⟩ := G.exists_minimal_degree_vertex rw [hδ, ← card_neighborFinset_eq_degree, ← card_univ] have h : v ∉ G.neighborFinset v := @@ -375,106 +408,109 @@ theorem minDegree_lt_card [DecidableRel G.Adj] [Nonempty V] : rw [eq_of_subset_of_card_le (subset_univ _) h] exact mem_univ v +/-- The maximum extended degree of all vertices (and `0` if there are no vertices) -/ +noncomputable def emaxDegree : ℕ∞ := + ⨆ v, G.edegree v + /-- The maximum degree of all vertices (and `0` if there are no vertices). The key properties of this are given in `exists_maximal_degree_vertex`, `degree_le_maxDegree` and `maxDegree_le_of_forall_degree_le`. -/ -def maxDegree [DecidableRel G.Adj] : ℕ := - WithBot.unbotD 0 (univ.image fun v => G.degree v).max +noncomputable def maxDegree : ℕ := + G.emaxDegree.toNat +omit [Fintype V] in /-- There exists a vertex of maximal degree. Note the assumption of being nonempty is necessary, as the lemma implies there exists a vertex. -/ -theorem exists_maximal_degree_vertex [DecidableRel G.Adj] [Nonempty V] : - ∃ v, G.maxDegree = G.degree v := by - obtain ⟨t, ht⟩ := max_of_nonempty (univ_nonempty.image fun v => G.degree v) - have ht₂ := mem_of_max ht - simp only [mem_image, mem_univ, true_and] at ht₂ - rcases ht₂ with ⟨v, rfl⟩ - refine ⟨v, ?_⟩ - rw [maxDegree, ht, WithBot.unbotD_coe] +theorem exists_maximal_degree_vertex [Nonempty V] [Finite V] : ∃ v, G.maxDegree = G.degree v := by + have ⟨v, hv⟩ := Set.range_nonempty G.edegree |>.csSup_mem <| Set.finite_range _ + refine ⟨v, congrArg _ hv.symm⟩ +omit [Fintype V] in /-- The maximum degree in the graph is at least the degree of any particular vertex. -/ -theorem degree_le_maxDegree [DecidableRel G.Adj] (v : V) : G.degree v ≤ G.maxDegree := by - obtain ⟨t, ht : _ = _⟩ := Finset.max_of_mem (mem_image_of_mem (fun v => G.degree v) (mem_univ v)) - have := Finset.le_max_of_eq (mem_image_of_mem _ (mem_univ v)) ht - rwa [maxDegree, ht, WithBot.unbotD_coe] +theorem degree_le_maxDegree [Finite V] (v : V) : G.degree v ≤ G.maxDegree := by + refine ENat.toNat_le_toNat (le_iSup G.edegree v) ?_ + exact iSup_ne_top fun _ ↦ Set.encard_ne_top_iff.mpr <| Set.toFinite _ +omit [Fintype V] in @[simp] -lemma maxDegree_of_isEmpty [DecidableRel G.Adj] [IsEmpty V] : G.maxDegree = 0 := by - rw [maxDegree, univ_eq_empty, image_empty, max_empty, WithBot.unbotD_bot] +lemma maxDegree_of_isEmpty [IsEmpty V] : G.maxDegree = 0 := + ENat.toNat_eq_zero.mpr <| .inl <| iSup_of_empty G.edegree +omit [Fintype V] in /-- In a graph, if `k` is at least the degree of every vertex, then it is at least the maximum degree. -/ -theorem maxDegree_le_of_forall_degree_le [DecidableRel G.Adj] (k : ℕ) (h : ∀ v, G.degree v ≤ k) : - G.maxDegree ≤ k := by - by_cases! hV : IsEmpty V - · simp - · obtain ⟨_, hv⟩ := G.exists_maximal_degree_vertex - exact hv ▸ h _ +theorem maxDegree_le_of_forall_degree_le (k : ℕ) (h : ∀ v, G.degree v ≤ k) : G.maxDegree ≤ k := by + by_cases! htop : ∃ v, G.edegree v = ⊤ + · have ⟨v, hv⟩ := htop + exact top_unique (hv ▸ le_iSup G.edegree v) ▸ ENat.toNat_top |>.trans_le <| by simp + exact ENat.toNat_le_of_le_coe <| iSup_le ((WithTop.untopD_le_iff <| htop _).mp <| h ·) +omit [Fintype V] in @[simp] lemma maxDegree_bot_eq_zero : (⊥ : SimpleGraph V).maxDegree = 0 := Nat.le_zero.1 <| maxDegree_le_of_forall_degree_le _ _ (by simp) +omit [Fintype V] in @[simp] -lemma minDegree_le_maxDegree [DecidableRel G.Adj] : G.minDegree ≤ G.maxDegree := by +lemma minDegree_le_maxDegree [Finite V] : G.minDegree ≤ G.maxDegree := by by_cases! he : IsEmpty V · simp · exact he.elim fun v ↦ (minDegree_le_degree _ v).trans (degree_le_maxDegree _ v) +omit [Fintype V] in @[simp] -lemma minDegree_bot_eq_zero : (⊥ : SimpleGraph V).minDegree = 0 := - Nat.le_zero.1 <| (minDegree_le_maxDegree _).trans (by simp) +lemma minDegree_bot_eq_zero : (⊥ : SimpleGraph V).minDegree = 0 := by + cases isEmpty_or_nonempty V + · exact minDegree_of_isEmpty _ + have ⟨v, hv⟩ := (⊥ : SimpleGraph V).exists_minimal_degree_vertex + exact hv ▸ bot_degree v -theorem degree_lt_card_verts [DecidableRel G.Adj] (v : V) : G.degree v < Fintype.card V := by - classical - apply Finset.card_lt_card - rw [Finset.ssubset_iff] - exact ⟨v, by simp, Finset.subset_univ _⟩ +theorem degree_lt_card_verts (v : V) : G.degree v < Fintype.card V := by + rw [Fintype.card_eq_nat_card] + exact Set.ncard_lt_card <| Set.ne_univ_iff_exists_notMem _ |>.mpr ⟨v, G.notMem_neighborSet_self⟩ /-- The maximum degree of a nonempty graph is less than the number of vertices. Note that the assumption that `V` is nonempty is necessary, as otherwise this would assert the existence of a natural number less than zero. -/ -theorem maxDegree_lt_card_verts [DecidableRel G.Adj] [Nonempty V] : - G.maxDegree < Fintype.card V := by - obtain ⟨v, hv⟩ := G.exists_maximal_degree_vertex - rw [hv] - apply G.degree_lt_card_verts v - -theorem card_commonNeighbors_le_degree_left [DecidableRel G.Adj] (v w : V) : - Fintype.card (G.commonNeighbors v w) ≤ G.degree v := by +theorem maxDegree_lt_card_verts [Nonempty V] : G.maxDegree < Fintype.card V := by + have ⟨v, hv⟩ := G.exists_maximal_degree_vertex + exact hv ▸ G.degree_lt_card_verts v + +omit [Fintype V] in +theorem card_commonNeighbors_le_degree_left (v w : V) [Fintype <| G.commonNeighbors v w] + [Finite <| G.neighborSet v] : Fintype.card (G.commonNeighbors v w) ≤ G.degree v := by + have := Fintype.ofFinite <| G.neighborSet v rw [← card_neighborSet_eq_degree] exact Set.card_le_card Set.inter_subset_left -theorem card_commonNeighbors_le_degree_right [DecidableRel G.Adj] (v w : V) : - Fintype.card (G.commonNeighbors v w) ≤ G.degree w := by - simp_rw [commonNeighbors_symm _ v w, card_commonNeighbors_le_degree_left] +omit [Fintype V] in +theorem card_commonNeighbors_le_degree_right (v w : V) [Fintype <| G.commonNeighbors v w] + [Finite <| G.neighborSet w] : Fintype.card (G.commonNeighbors v w) ≤ G.degree w := by + have := Fintype.ofFinite <| G.neighborSet w + rw [← card_neighborSet_eq_degree] + exact Set.card_le_card Set.inter_subset_right -theorem card_commonNeighbors_lt_card_verts [DecidableRel G.Adj] (v w : V) : +theorem card_commonNeighbors_lt_card_verts (v w : V) [Fintype <| G.commonNeighbors v w] : Fintype.card (G.commonNeighbors v w) < Fintype.card V := Nat.lt_of_le_of_lt (G.card_commonNeighbors_le_degree_left _ _) (G.degree_lt_card_verts v) +omit [Fintype V] in +variable {G} in /-- If the condition `G.Adj v w` fails, then `card_commonNeighbors_le_degree` is the best we can do in general. -/ -theorem Adj.card_commonNeighbors_lt_degree {G : SimpleGraph V} [DecidableRel G.Adj] {v w : V} - (h : G.Adj v w) : Fintype.card (G.commonNeighbors v w) < G.degree v := by - classical - rw [← Set.toFinset_card] - apply Finset.card_lt_card - rw [Finset.ssubset_iff] - use w - constructor - · rw [Set.mem_toFinset] - apply notMem_commonNeighbors_right - · rw [Finset.insert_subset_iff] - constructor - · simpa - · rw [neighborFinset, Set.toFinset_subset_toFinset] - exact G.commonNeighbors_subset_neighborSet_left _ _ - -theorem card_commonNeighbors_top [DecidableEq V] {v w : V} (h : v ≠ w) : +theorem Adj.card_commonNeighbors_lt_degree {v w : V} [Fintype <| G.commonNeighbors v w] + [Finite <| G.neighborSet v] (h : G.Adj v w) : + Fintype.card (G.commonNeighbors v w) < G.degree v := by + have := Fintype.ofFinite <| G.neighborSet v + rw [← card_neighborSet_eq_degree] + refine Set.card_lt_card <| Set.ssubset_iff_exists.mpr ⟨Set.inter_subset_left, w, h, ?_⟩ + exact G.notMem_commonNeighbors_right v w + +theorem card_commonNeighbors_top {v w : V} (h : v ≠ w) [Fintype <| commonNeighbors ⊤ v w] : Fintype.card ((⊤ : SimpleGraph V).commonNeighbors v w) = Fintype.card V - 2 := by - simp only [commonNeighbors_top_eq, ← Set.toFinset_card, Set.toFinset_diff] + classical + simp only [commonNeighbors_top_eq, ← Set.toFinset_card] simp [Finset.card_sdiff, h] end Finite @@ -489,86 +525,66 @@ theorem card_edgeFinset_eq (f : G ≃g G') [Fintype G.edgeSet] [Fintype G'.edgeS simp only [Set.mem_toFinset] exact f.mapEdgeSet -@[simp] theorem degree_eq (f : G ≃g G') (x : V) - [Fintype ↑(G.neighborSet x)] [Fintype ↑(G'.neighborSet (f x))] : - G'.degree (f x) = G.degree x := by - rw [← card_neighborSet_eq_degree, ← card_neighborSet_eq_degree, - ← Fintype.card_congr (mapNeighborSet f x).symm] - -variable [Fintype V] [DecidableRel G.Adj] [Fintype W] [DecidableRel G'.Adj] - -theorem minDegree_eq (f : G ≃g G') : G.minDegree = G'.minDegree := by - rcases isEmpty_or_nonempty V - · simp [f.symm.isEmpty] - · have : Nonempty W := f.symm.nonempty - apply le_antisymm - · obtain ⟨x', hx'⟩ := exists_minimal_degree_vertex G' - simpa only [hx', ← degree_eq f.symm x'] using minDegree_le_degree G (f.symm x') - · obtain ⟨x, hx⟩ := exists_minimal_degree_vertex G - simpa only [hx, ← degree_eq f x] using minDegree_le_degree G' (f x) - -theorem maxDegree_eq (f : G ≃g G') : G.maxDegree = G'.maxDegree := by - rcases isEmpty_or_nonempty V - · simp [f.symm.isEmpty] - · have : Nonempty W := f.symm.nonempty - apply le_antisymm - · obtain ⟨x, hx⟩ := exists_maximal_degree_vertex G - simpa only [hx, ← degree_eq f x] using degree_le_maxDegree G' (f x) - · obtain ⟨x', hx'⟩ := exists_maximal_degree_vertex G' - simpa only [hx', ← degree_eq f.symm x'] using degree_le_maxDegree G (f.symm x') +@[simp] +theorem degree_eq (f : G ≃g G') (x : V) : G'.degree (f x) = G.degree x := + Set.ncard_congr' <| mapNeighborSet f x |>.symm + +theorem minDegree_eq (f : G ≃g G') : G.minDegree = G'.minDegree := + congrArg ENat.toNat <| f.surjective.iInf_congr f (Set.encard_congr <| mapNeighborSet f · |>.symm) + +theorem maxDegree_eq (f : G ≃g G') : G.maxDegree = G'.maxDegree := + congrArg ENat.toNat <| f.surjective.iSup_congr f (Set.encard_congr <| mapNeighborSet f · |>.symm) end Iso section Support -variable {s : Set V} [DecidablePred (· ∈ s)] [Fintype V] {G : SimpleGraph V} [DecidableRel G.Adj] +variable {s : Set V} {G} -lemma edgeFinset_subset_sym2_of_support_subset (h : G.support ⊆ s) : +lemma edgeFinset_subset_sym2_of_support_subset [Fintype G.edgeSet] [Fintype s] (h : G.support ⊆ s) : G.edgeFinset ⊆ s.toFinset.sym2 := by simp_rw [subset_iff, Sym2.forall, mem_edgeFinset, mem_edgeSet, mk_mem_sym2_iff, Set.mem_toFinset] intro _ _ hadj exact ⟨h ⟨_, hadj⟩, h ⟨_, hadj.symm⟩⟩ -instance : DecidablePred (· ∈ G.support) := +instance [Fintype V] [DecidableRel G.Adj] : DecidablePred (· ∈ G.support) := inferInstanceAs <| DecidablePred (· ∈ { v | ∃ w, G.Adj v w }) -theorem map_edgeFinset_induce [DecidableEq V] : - (G.induce s).edgeFinset.map (Embedding.subtype s).sym2Map - = G.edgeFinset ∩ s.toFinset.sym2 := by +theorem map_edgeFinset_induce [DecidableEq V] [Fintype G.edgeSet] [Fintype (G.induce s).edgeSet] + [Fintype s] : + (G.induce s).edgeFinset.map (Embedding.subtype s).sym2Map = G.edgeFinset ∩ s.toFinset.sym2 := by simp_rw [Finset.ext_iff, Sym2.forall, mem_inter, mk_mem_sym2_iff, mem_map, Sym2.exists, Set.mem_toFinset, mem_edgeSet, comap_adj, Embedding.sym2Map_apply, Embedding.coe_subtype, Sym2.map_pair_eq, Sym2.eq_iff] - intro v w - constructor - · rintro ⟨x, y, hadj, ⟨hv, hw⟩ | ⟨hw, hv⟩⟩ - all_goals rw [← hv, ← hw] - · exact ⟨hadj, x.prop, y.prop⟩ - · exact ⟨hadj.symm, y.prop, x.prop⟩ - · intro ⟨hadj, hv, hw⟩ - use ⟨v, hv⟩, ⟨w, hw⟩, hadj - tauto - -theorem map_edgeFinset_induce_of_support_subset (h : G.support ⊆ s) : + refine fun v w ↦ ⟨?_, fun ⟨hadj, hv, hw⟩ ↦ ⟨⟨v, hv⟩, ⟨w, hw⟩, hadj, by tauto⟩⟩ + rintro ⟨x, y, hadj, ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩⟩ + exacts [⟨hadj, x.prop, y.prop⟩, ⟨hadj.symm, y.prop, x.prop⟩] + +theorem map_edgeFinset_induce_of_support_subset [Fintype G.edgeSet] [Fintype (G.induce s).edgeSet] + [Finite s] (h : G.support ⊆ s) : (G.induce s).edgeFinset.map (Embedding.subtype s).sym2Map = G.edgeFinset := by classical + have := Fintype.ofFinite s simpa [map_edgeFinset_induce] using edgeFinset_subset_sym2_of_support_subset h /-- If the support of the simple graph `G` is a subset of the set `s`, then the induced subgraph of `s` has the same number of edges as `G`. -/ -theorem card_edgeFinset_induce_of_support_subset (h : G.support ⊆ s) : - #(G.induce s).edgeFinset = #G.edgeFinset := by +theorem card_edgeFinset_induce_of_support_subset [Fintype G.edgeSet] [Fintype (G.induce s).edgeSet] + [Finite s] (h : G.support ⊆ s) : #(G.induce s).edgeFinset = #G.edgeFinset := by rw [← map_edgeFinset_induce_of_support_subset h, card_map] -theorem card_edgeFinset_induce_support : - #(G.induce G.support).edgeFinset = #G.edgeFinset := +theorem card_edgeFinset_induce_support [Fintype G.edgeSet] [Fintype (G.induce G.support).edgeSet] + [Finite G.support] : #(G.induce G.support).edgeFinset = #G.edgeFinset := card_edgeFinset_induce_of_support_subset subset_rfl -theorem map_neighborFinset_induce [DecidableEq V] (v : s) : +theorem map_neighborFinset_induce [DecidableEq V] (v : s) [Fintype <| G.neighborSet v] + [Fintype <| (induce s G).neighborSet v] [Fintype s] : ((G.induce s).neighborFinset v).map (.subtype (· ∈ s)) = G.neighborFinset v ∩ s.toFinset := by ext; simp -theorem map_neighborFinset_induce_of_neighborSet_subset {v : s} (h : G.neighborSet v ⊆ s) : +theorem map_neighborFinset_induce_of_neighborSet_subset {v : s} [Fintype <| G.neighborSet v] + [Fintype <| (induce s G).neighborSet v] [Fintype s] (h : G.neighborSet v ⊆ s) : ((G.induce s).neighborFinset v).map (.subtype s) = G.neighborFinset v := by classical rwa [← Set.toFinset_subset_toFinset, ← neighborFinset_def, ← inter_eq_left, @@ -577,9 +593,8 @@ theorem map_neighborFinset_induce_of_neighborSet_subset {v : s} (h : G.neighborS /-- If the neighbor set of a vertex `v` is a subset of `s`, then the degree of the vertex in the induced subgraph of `s` is the same as in `G`. -/ theorem degree_induce_of_neighborSet_subset {v : s} (h : G.neighborSet v ⊆ s) : - (G.induce s).degree v = G.degree v := by - simp_rw [← card_neighborFinset_eq_degree, - ← map_neighborFinset_induce_of_neighborSet_subset h, card_map] + (G.induce s).degree v = G.degree v := + Set.ncard_congr' <| .mk (fun u ↦ ⟨u, u.prop⟩) (fun u ↦ ⟨⟨u, h u.prop⟩, u.prop⟩) /-- If the support of the simple graph `G` is a subset of the set `s`, then the degree of vertices in the induced subgraph of `s` are the same as in `G`. -/ @@ -596,16 +611,15 @@ end Support section Map -variable [Fintype V] {W : Type*} [Fintype W] [DecidableEq W] +variable {W : Type*} (f : V ↪ W) (G : SimpleGraph V) [Fintype G.edgeSet] [Fintype (G.map f).edgeSet] @[simp] -theorem edgeFinset_map (f : V ↪ W) (G : SimpleGraph V) [DecidableRel G.Adj] : - (G.map f).edgeFinset = G.edgeFinset.map f.sym2Map := by +theorem edgeFinset_map : (G.map f).edgeFinset = G.edgeFinset.map f.sym2Map := by + classical rw [Finset.map_eq_image, ← Set.toFinset_image, Set.toFinset_inj] exact G.edgeSet_map f -theorem card_edgeFinset_map (f : V ↪ W) (G : SimpleGraph V) [DecidableRel G.Adj] : - #(G.map f).edgeFinset = #G.edgeFinset := by +theorem card_edgeFinset_map : #(G.map f).edgeFinset = #G.edgeFinset := by rw [edgeFinset_map] exact G.edgeFinset.card_map f.sym2Map diff --git a/Mathlib/Combinatorics/SimpleGraph/FiveWheelLike.lean b/Mathlib/Combinatorics/SimpleGraph/FiveWheelLike.lean index 4db22d8a5c2910..6ee675294791b1 100644 --- a/Mathlib/Combinatorics/SimpleGraph/FiveWheelLike.lean +++ b/Mathlib/Combinatorics/SimpleGraph/FiveWheelLike.lean @@ -257,7 +257,7 @@ private lemma sum_degree_le_of_le_not_adj [Fintype α] [DecidableEq α] [Decidab (hxc : ∀ y ∈ Xᶜ, j ≤ #{z ∈ W | ¬ G.Adj y z}) : ∑ w ∈ W, G.degree w ≤ #X * (#W - i) + #Xᶜ * (#W - j) := calc _ = ∑ v, #(G.neighborFinset v ∩ W) := by - simp_rw [degree, card_eq_sum_ones] + simp_rw [← card_neighborFinset_eq_degree, card_eq_sum_ones] exact sum_comm' (by simp [and_comm, adj_comm]) _ ≤ _ := by simp_rw [← union_compl X, sum_union disjoint_compl_right (s₁ := X), neighborFinset_eq_filter, @@ -347,12 +347,14 @@ lemma exists_isFiveWheelLike_succ_of_not_adj_le_two (hW : ∀ ⦃y⦄, y ∈ s notMem_mono inter_subset_left hbs, erase_eq_of_notMem <| notMem_mono inter_subset_right hat, card_insert_of_notMem (fun h ↦ G.irrefl (hW h)), hw.card_inter] +omit [DecidableRel G.Adj] in /-- If `G` is a `Kᵣ₊₂`-free graph with `n` vertices containing a `Wᵣ,ₖ` but no `Wᵣ,ₖ₊₁` then `G.minDegree ≤ (2 * r + k) * n / (2 * r + k + 3)` -/ lemma minDegree_le_of_cliqueFree_fiveWheelLikeFree_succ [Fintype α] (hm : G.FiveWheelLikeFree r (k + 1)) : G.minDegree ≤ (2 * r + k) * ‖α‖ / (2 * r + k + 3) := by + classical let X : Finset α := {x | ∀ ⦃y⦄, y ∈ s ∩ t → G.Adj x y} let W := {v} ∪ ({w₁} ∪ ({w₂} ∪ (s ∪ t))) -- Any vertex in `X` has at least 3 non-neighbors in `W` (otherwise we could build a bigger wheel) @@ -418,9 +420,8 @@ If `G` is a `Kᵣ₊₁`-free graph with `n` vertices and `(3 * r - 4) * n / (3 then `G` is `r + 1`-colorable, e.g. if `G` is `K₃`-free and `2 * n / 5 < G.minDegree` then `G` is `2`-colorable. -/ -theorem colorable_of_cliqueFree_lt_minDegree [Fintype α] [DecidableRel G.Adj] - (hf : G.CliqueFree (r + 1)) (hd : (3 * r - 4) * ‖α‖ / (3 * r - 1) < G.minDegree) : - G.Colorable r := by +theorem colorable_of_cliqueFree_lt_minDegree [Fintype α] (hf : G.CliqueFree (r + 1)) + (hd : (3 * r - 4) * ‖α‖ / (3 * r - 1) < G.minDegree) : G.Colorable r := by match r with | 0 | 1 => aesop | r + 2 => diff --git a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean index 2dd48d31b52077..f656ac266e40f8 100644 --- a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean @@ -36,26 +36,30 @@ variable [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] theorem degree_eq_sum_if_adj {R : Type*} [AddCommMonoidWithOne R] (i : V) : (G.degree i : R) = ∑ j : V, if G.Adj i j then 1 else 0 := by - unfold degree neighborFinset neighborSet + rw [← card_neighborFinset_eq_degree] + unfold neighborFinset neighborSet rw [sum_boole, Set.toFinset_setOf] variable [DecidableEq V] /-- The diagonal matrix consisting of the degrees of the vertices in the graph. -/ -def degMatrix [AddMonoidWithOne R] : Matrix V V R := Matrix.diagonal (G.degree ·) +noncomputable def degMatrix [AddMonoidWithOne R] : Matrix V V R := Matrix.diagonal (G.degree ·) /-- The *Laplacian matrix* `lapMatrix G R` of a graph `G` is the matrix `L = D - A` where `D` is the degree and `A` the adjacency matrix of `G`. -/ -def lapMatrix [AddGroupWithOne R] : Matrix V V R := G.degMatrix R - G.adjMatrix R +noncomputable def lapMatrix [AddGroupWithOne R] : Matrix V V R := G.degMatrix R - G.adjMatrix R variable {R} +omit [Fintype V] [DecidableRel G.Adj] in theorem isSymm_degMatrix [AddMonoidWithOne R] : (G.degMatrix R).IsSymm := isSymm_diagonal _ +omit [Fintype V] in theorem isSymm_lapMatrix [AddGroupWithOne R] : (G.lapMatrix R).IsSymm := (isSymm_degMatrix _).sub (isSymm_adjMatrix _) +omit [DecidableRel G.Adj] in theorem degMatrix_mulVec_apply [NonAssocSemiring R] (v : V) (vec : V → R) : (G.degMatrix R *ᵥ vec) v = G.degree v * vec v := by rw [degMatrix, mulVec_diagonal] @@ -70,6 +74,7 @@ theorem lapMatrix_mulVec_const_eq_zero [NonAssocRing R] : rw [lapMatrix_mulVec_apply] simp +omit [DecidableRel G.Adj] in theorem dotProduct_mulVec_degMatrix [CommSemiring R] (x : V → R) : x ⬝ᵥ (G.degMatrix R *ᵥ x) = ∑ i : V, G.degree i * x i * x i := by simp only [dotProduct, degMatrix, mulVec_diagonal, ← mul_assoc, mul_comm] diff --git a/Mathlib/Combinatorics/SimpleGraph/Maps.lean b/Mathlib/Combinatorics/SimpleGraph/Maps.lean index a8ddc15a49e44d..3320f99c71c9ed 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Maps.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Maps.lean @@ -320,6 +320,10 @@ theorem mapEdgeSet.injective (hinj : Function.Injective f) : Function.Injective repeat rw [Subtype.mk_eq_mk] apply Sym2.map.injective hinj +theorem _root_.SimpleGraph.neighborSet_subset (hle : G₁ ≤ G₂) (v : V) : + G₁.neighborSet v ⊆ G₂.neighborSet v := + fun _ h ↦ Hom.ofLE hle |>.apply_mem_neighborSet h + /-- Every graph homomorphism from a complete graph is injective. -/ theorem injective_of_top_hom (f : (⊤ : SimpleGraph V) →g G') : Function.Injective f := by intro v w h diff --git a/Mathlib/Combinatorics/SimpleGraph/Prod.lean b/Mathlib/Combinatorics/SimpleGraph/Prod.lean index d528b5ab5ab18a..da54c34ef543c2 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Prod.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Prod.lean @@ -230,7 +230,8 @@ theorem neighborFinset_boxProd (x : α × β) theorem degree_boxProd (x : α × β) [Fintype (G.neighborSet x.1)] [Fintype (H.neighborSet x.2)] [Fintype ((G □ H).neighborSet x)] : (G □ H).degree x = G.degree x.1 + H.degree x.2 := by - rw [degree, degree, degree, neighborFinset_boxProd, Finset.card_disjUnion] + rw [← card_neighborFinset_eq_degree, ← card_neighborFinset_eq_degree, + ← card_neighborFinset_eq_degree, neighborFinset_boxProd, Finset.card_disjUnion] simp_rw [Finset.card_product, Finset.card_singleton, mul_one, one_mul] lemma reachable_boxProd {x y : α × β} : diff --git a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean index f880d33e03b166..5a675615139dc3 100644 --- a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean +++ b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean @@ -58,7 +58,7 @@ variable {G} {n k ℓ μ : ℕ} for empty graphs, since there are no pairs of adjacent vertices. -/ theorem bot_strongly_regular : (⊥ : SimpleGraph V).IsSRGWith (Fintype.card V) 0 ℓ 0 where card := rfl - regular := bot_degree + regular := .bot of_adj _ _ h := h.elim of_not_adj v w _ := by simp only [card_eq_zero, Fintype.card_ofFinset, forall_true_left, not_false_iff, bot_adj] @@ -78,7 +78,7 @@ theorem IsSRGWith.top : (⊤ : SimpleGraph V).IsSRGWith (Fintype.card V) (Fintype.card V - 1) (Fintype.card V - 2) μ where card := rfl regular := IsRegularOfDegree.top - of_adj _ _ := card_commonNeighbors_top + of_adj _ _ h := card_commonNeighbors_top h of_not_adj v w h h' := (h' ((top_adj v w).2 h)).elim theorem IsSRGWith.card_neighborFinset_union_eq {v w : V} (h : G.IsSRGWith n k ℓ μ) : @@ -115,6 +115,7 @@ theorem sdiff_compl_neighborFinset_inter_eq {v w : V} (h : G.Adj v w) : (G.neighborFinset v)ᶜ ∩ (G.neighborFinset w)ᶜ := by simpa using ⟨(adj_symm _ h), h⟩ +omit [DecidableEq V] in theorem IsSRGWith.compl_is_regular (h : G.IsSRGWith n k ℓ μ) : Gᶜ.IsRegularOfDegree (n - k - 1) := by rw [← h.card, Nat.sub_sub, add_comm, ← Nat.sub_sub] @@ -163,8 +164,8 @@ theorem IsSRGWith.param_eq rw [← h.card, Fintype.card_pos_iff] at hn obtain ⟨v⟩ := hn convert card_mul_eq_card_mul G.Adj (s := G.neighborFinset v) (t := Gᶜ.neighborFinset v) _ _ - · simp [h.regular v] - · simp [h.compl.regular v] + · simp [h.regular.degree_eq v] + · simp [h.compl.regular.degree_eq v] · intro w hw rw [mem_neighborFinset] at hw simp_rw [bipartiteAbove, ← mem_neighborFinset, filter_mem_eq_inter] @@ -175,7 +176,7 @@ theorem IsSRGWith.param_eq card_sdiff_of_subset s, card_singleton, ← sdiff_inter_self_left, card_sdiff_of_subset inter_subset_left] congr - · simp [h.regular w] + · simp [h.regular.degree_eq w] · simp_rw [inter_comm, neighborFinset_def, ← Set.toFinset_inter, ← h.of_adj v w hw, ← Set.toFinset_card] congr! @@ -199,7 +200,7 @@ theorem IsSRGWith.matrix_eq {α : Type*} [Semiring α] (h : G.IsSRGWith n k ℓ rw [Fintype.card_congr (G.walkLengthTwoEquivCommonNeighbors v w)] obtain rfl | hn := eq_or_ne v w · rw [← Set.toFinset_card] - simp [commonNeighbors, ← neighborFinset_def, h.regular v] + simp [commonNeighbors, ← neighborFinset_def, h.regular.degree_eq v] · simp only [Matrix.one_apply_ne' hn.symm, ne_eq, hn] by_cases ha : G.Adj v w <;> simp only [ha, ite_true, ite_false, add_zero, zero_add, nsmul_eq_mul, smul_zero, mul_one, diff --git a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean index db1ed6cb637b82..d6299035d19a3f 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean @@ -852,6 +852,7 @@ end Subgraph theorem card_neighborSet_toSubgraph (G H : SimpleGraph V) (h : H ≤ G) (v : V) [Fintype ↑((toSubgraph H h).neighborSet v)] [Fintype ↑(H.neighborSet v)] : Fintype.card ↑((toSubgraph H h).neighborSet v) = H.degree v := by + rw [← H.card_neighborFinset_eq_degree] refine (Finset.card_eq_of_equiv_fintype ?_).symm simp only [mem_neighborFinset] rfl diff --git a/Mathlib/Combinatorics/SimpleGraph/Trails.lean b/Mathlib/Combinatorics/SimpleGraph/Trails.lean index 87204c8fb6c2bc..7ea6c591d21de0 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Trails.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Trails.lean @@ -123,8 +123,10 @@ theorem IsEulerian.edgesFinset_eq [Fintype G.edgeSet] {u v : V} {p : G.Walk u v} ext e simp [h.mem_edges_iff] -theorem IsEulerian.even_degree_iff {x u v : V} {p : G.Walk u v} (ht : p.IsEulerian) [Fintype V] - [DecidableRel G.Adj] : Even (G.degree x) ↔ u ≠ v → x ≠ u ∧ x ≠ v := by +theorem IsEulerian.even_degree_iff {x u v : V} {p : G.Walk u v} (ht : p.IsEulerian) [Finite V] : + Even (G.degree x) ↔ u ≠ v → x ≠ u ∧ x ≠ v := by + classical + have := Fintype.ofFinite V convert ht.isTrail.even_countP_edges_iff x rw [← Multiset.coe_countP, Multiset.countP_eq_card_filter, ← card_incidenceFinset_eq_degree] change Multiset.card _ = _ @@ -132,9 +134,8 @@ theorem IsEulerian.even_degree_iff {x u v : V} {p : G.Walk u v} (ht : p.IsEuleri convert_to _ = (ht.isTrail.edgesFinset.filter (x ∈ ·)).val rw [ht.edgesFinset_eq, G.incidenceFinset_eq_filter x] -theorem IsEulerian.card_filter_odd_degree [Fintype V] [DecidableRel G.Adj] {u v : V} - {p : G.Walk u v} (ht : p.IsEulerian) {s} - (h : s = (Finset.univ : Finset V).filter fun v => Odd (G.degree v)) : +theorem IsEulerian.card_filter_odd_degree [Fintype V] {u v : V} {p : G.Walk u v} (ht : p.IsEulerian) + {s} (h : s = (Finset.univ : Finset V).filter fun v => Odd (G.degree v)) : s.card = 0 ∨ s.card = 2 := by subst s simp only [← Nat.not_even_iff_odd, Finset.card_eq_zero] @@ -148,8 +149,8 @@ theorem IsEulerian.card_filter_odd_degree [Fintype V] [DecidableRel G.Adj] {u v ext x simp [hn, imp_iff_not_or] -theorem IsEulerian.card_odd_degree [Fintype V] [DecidableRel G.Adj] {u v : V} {p : G.Walk u v} - (ht : p.IsEulerian) : Fintype.card { v : V | Odd (G.degree v) } = 0 ∨ +theorem IsEulerian.card_odd_degree [Fintype V] {u v : V} {p : G.Walk u v} (ht : p.IsEulerian) : + Fintype.card { v : V | Odd (G.degree v) } = 0 ∨ Fintype.card { v : V | Odd (G.degree v) } = 2 := by rw [← Set.toFinset_card] apply IsEulerian.card_filter_odd_degree ht diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index ed78fc393eca8e..6cd930af99c370 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -589,6 +589,10 @@ theorem ncard_eq_toFinset_card' (s : Set α) [Fintype s] : s.ncard = s.toFinset.card := by simp [← _root_.Nat.card_coe_set_eq, Nat.card_eq_fintype_card] +variable (s) in +theorem ncard_eq_card [Fintype s] : s.ncard = Fintype.card s := + s.ncard_eq_toFinset_card'.trans s.toFinset_card + lemma cast_ncard {s : Set α} (hs : s.Finite) : (s.ncard : Cardinal) = Cardinal.mk s := @Nat.cast_card _ hs diff --git a/Mathlib/Data/Set/Insert.lean b/Mathlib/Data/Set/Insert.lean index 5e8c3ac1d66a8e..bedc389e824b16 100644 --- a/Mathlib/Data/Set/Insert.lean +++ b/Mathlib/Data/Set/Insert.lean @@ -258,6 +258,11 @@ theorem eq_singleton_iff_nonempty_unique_mem : s = {a} ↔ s.Nonempty ∧ ∀ x eq_singleton_iff_unique_mem.trans <| and_congr_left fun H => ⟨fun h' => ⟨_, h'⟩, fun ⟨x, h⟩ => H x h ▸ h⟩ +variable (s) in +theorem singleton_iff_unique_mem : (∃ a, s = {a}) ↔ ∃! a, a ∈ s := + ⟨fun ⟨a, ha⟩ ↦ ⟨a, ha ▸ mem_singleton a, fun _ h ↦ mem_singleton_iff.mp <| ha ▸ h⟩, + fun ⟨a, ha, huniq⟩ ↦ ⟨a, eq_singleton_iff_unique_mem.mpr ⟨ha, huniq⟩⟩⟩ + theorem setOf_mem_list_eq_replicate {l : List α} {a : α} : { x | x ∈ l } = {a} ↔ ∃ n > 0, l = List.replicate n a := by simpa +contextual [Set.ext_iff, iff_iff_implies_and_implies, forall_and, List.eq_replicate_iff, diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean index 1fe9530755180a..3513f19852e79c 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -143,6 +143,13 @@ theorem Set.Finite.lt_ciInf_iff {s : Set ι} {f : ι → α} (hs : s.Finite) rw [← hx] exact H _ hmem +theorem iSup_ne_top {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] + (h : ∀ x, f x ≠ ⊤) : iSup f ≠ ⊤ := by + cases isEmpty_or_nonempty ι + · simp + have ⟨x, hx⟩ := Set.range_nonempty f |>.csSup_mem <| Set.finite_range f + exact (hx ▸ h x :) + section ListMultiset lemma List.iSup_mem_map_of_exists_sSup_empty_le {l : List ι} (f : ι → α) From 1988416396f3430c151f531df3b7c30e64f06a26 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sat, 3 Jan 2026 18:09:46 +0200 Subject: [PATCH 02/60] fix Archive & Counterexamples --- .../Wiedijk100Theorems/FriendshipGraphs.lean | 17 ++++++++++------- Archive/Wiedijk100Theorems/Konigsberg.lean | 4 +++- Counterexamples/HeawoodUnitDistance.lean | 2 ++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Archive/Wiedijk100Theorems/FriendshipGraphs.lean b/Archive/Wiedijk100Theorems/FriendshipGraphs.lean index c496a3f0cb949b..dca5567f84b4ed 100644 --- a/Archive/Wiedijk100Theorems/FriendshipGraphs.lean +++ b/Archive/Wiedijk100Theorems/FriendshipGraphs.lean @@ -89,7 +89,8 @@ include hG in We use it to show that nonadjacent vertices have equal degrees. -/ theorem adjMatrix_pow_three_of_not_adj {v w : V} (non_adj : ¬G.Adj v w) : (G.adjMatrix R ^ 3 : Matrix V V R) v w = degree G v := by - rw [pow_succ', adjMatrix_mul_apply, degree, card_eq_sum_ones, Nat.cast_sum] + rw [pow_succ', adjMatrix_mul_apply, ← card_neighborFinset_eq_degree, card_eq_sum_ones, + Nat.cast_sum] apply sum_congr rfl intro x hx rw [adjMatrix_sq_of_ne _ hG, Nat.cast_one] @@ -123,7 +124,7 @@ include hG in theorem adjMatrix_sq_of_regular (hd : G.IsRegularOfDegree d) : G.adjMatrix R ^ 2 = of fun v w => if v = w then (d : R) else (1 : R) := by ext (v w); by_cases h : v = w - · rw [h, sq, adjMatrix_mul_self_apply_self, hd]; simp + · rw [h, sq, adjMatrix_mul_self_apply_self, hd.degree_eq]; simp · rw [adjMatrix_sq_of_ne R hG h, of_apply, if_neg h] open scoped Classical in @@ -147,6 +148,9 @@ theorem isRegularOf_not_existsPolitician (hG' : ¬ExistsPolitician G) : have v := Classical.arbitrary V use G.degree v intro x + rw [← show G.degree x = G.edegree x from + ENat.coe_toNat <| Set.encard_ne_top_iff.mpr <| Set.toFinite _] + congr 1 by_cases hvx : G.Adj v x; swap; · exact (degree_eq_of_not_adj hG hvx).symm dsimp only [Theorems100.ExistsPolitician] at hG' push_neg at hG' @@ -187,7 +191,7 @@ theorem card_of_regular (hd : G.IsRegularOfDegree d) : d + (Fintype.card V - 1) intro x hx; simp [(ne_of_mem_erase hx).symm] · rw [sq, ← mulVec_mulVec] simp only [adjMatrix_mulVec_const_apply_of_regular hd, neighborFinset, - card_neighborSet_eq_degree, hd v, Function.const_def, adjMatrix_mulVec_apply _ _ (mulVec _ _), + card_neighborSet_eq_degree, hd.degree_eq v, Function.const_def, adjMatrix_mulVec_apply, mul_one, sum_const, Set.toFinset_card, smul_eq_mul, Nat.cast_id] open scoped Classical in @@ -208,8 +212,8 @@ open scoped Classical in theorem adjMatrix_sq_mul_const_one_of_regular (hd : G.IsRegularOfDegree d) : G.adjMatrix R * of (fun _ _ => 1) = of (fun _ _ => (d : R)) := by ext x - simp only [← hd x, degree, adjMatrix_mul_apply, sum_const, Nat.smul_one_eq_cast, - of_apply] + simp only [← hd.degree_eq x, ← card_neighborFinset_eq_degree, adjMatrix_mul_apply, sum_const, + Nat.smul_one_eq_cast, of_apply] open scoped Classical in theorem adjMatrix_mul_const_one_mod_p_of_regular {p : ℕ} (dmod : (d : ZMod p) = 1) @@ -303,8 +307,7 @@ theorem neighborFinset_eq_of_degree_eq_two (hd : G.IsRegularOfDegree 2) (v : V) · have hfr := card_of_regular hG hd lia · exact Finset.card_erase_of_mem (Finset.mem_univ _) - · dsimp only [IsRegularOfDegree, degree] at hd - rw [hd] + · rw [card_neighborFinset_eq_degree, hd.degree_eq] open scoped Classical in include hG in diff --git a/Archive/Wiedijk100Theorems/Konigsberg.lean b/Archive/Wiedijk100Theorems/Konigsberg.lean index fd316bcf536fc2..bd1adf57506e3c 100644 --- a/Archive/Wiedijk100Theorems/Konigsberg.lean +++ b/Archive/Wiedijk100Theorems/Konigsberg.lean @@ -65,7 +65,9 @@ def degree : Verts → ℕ | B1 => 2 | B2 => 2 | B3 => 2 | B4 => 2 | B5 => 2 | B6 => 2 | B7 => 2 @[simp] -lemma degree_eq_degree (v : Verts) : graph.degree v = degree v := by cases v <;> rfl +lemma degree_eq_degree (v : Verts) : graph.degree v = degree v := by + rw [← graph.card_neighborFinset_eq_degree] + cases v <;> rfl lemma not_even_degree_iff (w : Verts) : ¬Even (degree w) ↔ w = V1 ∨ w = V2 ∨ w = V3 ∨ w = V4 := by cases w <;> decide diff --git a/Counterexamples/HeawoodUnitDistance.lean b/Counterexamples/HeawoodUnitDistance.lean index 9c712228cc5a92..ad948845bc68a6 100644 --- a/Counterexamples/HeawoodUnitDistance.lean +++ b/Counterexamples/HeawoodUnitDistance.lean @@ -54,6 +54,8 @@ lemma heawoodGraph_neighborFinset (i : Fin 14) : /-- The Heawood graph is 3-regular. -/ lemma isRegularOfDegree_heawoodGraph : heawoodGraph.IsRegularOfDegree 3 := fun i ↦ by + rw [← show heawoodGraph.degree i = heawoodGraph.edegree i from + ENat.coe_toNat <| Set.encard_ne_top_iff.mpr <| Set.toFinite _] rw [← card_neighborFinset_eq_degree, heawoodGraph_neighborFinset]; revert i; decide /-! ### A key number -/ From f1cc8159225c0b470cf6b666dd2de691c8981d39 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sat, 24 Jan 2026 19:07:00 +0200 Subject: [PATCH 03/60] `iInf_ne_bot` --- Mathlib/Order/ConditionallyCompleteLattice/Finset.lean | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean index 6b626c090f6cd0..667a9569a30ac4 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -150,6 +150,13 @@ theorem iSup_ne_top {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] have ⟨x, hx⟩ := Set.range_nonempty f |>.csSup_mem <| Set.finite_range f exact (hx ▸ h x :) +theorem iInf_ne_bot {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] + (h : ∀ x, f x ≠ ⊥) : iInf f ≠ ⊥ := by + cases isEmpty_or_nonempty ι + · simp [iInf_of_empty] + have ⟨x, hx⟩ := Set.range_nonempty f |>.csInf_mem <| Set.finite_range f + exact (hx ▸ h x :) + section ListMultiset lemma List.iSup_mem_map_of_exists_sSup_empty_le {l : List ι} (f : ι → α) From 030f03e152e3b79c70e08352791d989526b1e269 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sat, 24 Jan 2026 19:08:08 +0200 Subject: [PATCH 04/60] `ncard_eq_card` -> `ncard_eq_fintypeCard` --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 2 +- Mathlib/Data/Set/Card.lean | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 8885eb25970acb..87c9634ed5c8d8 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -201,7 +201,7 @@ theorem card_neighborFinset_eq_degree : #(G.neighborFinset v) = G.degree v := @[simp] theorem card_neighborSet_eq_degree : Fintype.card (G.neighborSet v) = G.degree v := - Set.ncard_eq_card _ |>.symm + Set.ncard_eq_fintypeCard _ |>.symm omit [Fintype <| G.neighborSet v] in theorem degree_pos_iff_exists_adj [Finite <| G.neighborSet v] : 0 < G.degree v ↔ ∃ w, G.Adj v w := diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index 1923c8a9ad86de..908933f27d3a40 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -588,7 +588,7 @@ theorem ncard_eq_toFinset_card' (s : Set α) [Fintype s] : simp [← _root_.Nat.card_coe_set_eq, Nat.card_eq_fintype_card] variable (s) in -theorem ncard_eq_card [Fintype s] : s.ncard = Fintype.card s := +theorem ncard_eq_fintypeCard [Fintype s] : s.ncard = Fintype.card s := s.ncard_eq_toFinset_card'.trans s.toFinset_card lemma cast_ncard {s : Set α} (hs : s.Finite) : From a6c75e8fbe285927771fc6c5876b843eb4648337 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sat, 24 Jan 2026 19:20:05 +0200 Subject: [PATCH 05/60] change `IsEulerian` statements --- Mathlib/Combinatorics/SimpleGraph/Trails.lean | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Trails.lean b/Mathlib/Combinatorics/SimpleGraph/Trails.lean index cb24fc4a5948c6..75073c85d84f93 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Trails.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Trails.lean @@ -135,8 +135,7 @@ theorem IsEulerian.even_degree_iff {x u v : V} {p : G.Walk u v} (ht : p.IsEuleri rw [ht.edgesFinset_eq, G.incidenceFinset_eq_filter x] theorem IsEulerian.card_filter_odd_degree [Fintype V] {u v : V} {p : G.Walk u v} (ht : p.IsEulerian) - {s} (h : s = (Finset.univ : Finset V).filter fun v => Odd (G.degree v)) : - s.card = 0 ∨ s.card = 2 := by + {s} (h : s = ({ v | Odd (G.degree v) } : Finset V)) : s.card = 0 ∨ s.card = 2 := by subst s simp only [← Nat.not_even_iff_odd, Finset.card_eq_zero] simp only [ht.even_degree_iff, Ne, not_forall, not_and, Classical.not_not, exists_prop] @@ -149,10 +148,10 @@ theorem IsEulerian.card_filter_odd_degree [Fintype V] {u v : V} {p : G.Walk u v} ext x simp [hn, imp_iff_not_or] -theorem IsEulerian.card_odd_degree [Fintype V] {u v : V} {p : G.Walk u v} (ht : p.IsEulerian) : - Fintype.card { v : V | Odd (G.degree v) } = 0 ∨ - Fintype.card { v : V | Odd (G.degree v) } = 2 := by - rw [← Set.toFinset_card] +theorem IsEulerian.card_odd_degree [Finite V] {u v : V} {p : G.Walk u v} (ht : p.IsEulerian) : + { v : V | Odd (G.degree v) }.ncard = 0 ∨ { v : V | Odd (G.degree v) }.ncard = 2 := by + have := Fintype.ofFinite V + rw [Set.ncard_eq_toFinset_card'] apply IsEulerian.card_filter_odd_degree ht simp From bcbdd1dea645ecc9634b86ade90e5b9881853c53 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sat, 24 Jan 2026 19:24:08 +0200 Subject: [PATCH 06/60] `neighborSet_subset` -> `neighborSet_mono` --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 2 +- Mathlib/Combinatorics/SimpleGraph/Maps.lean | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 87c9634ed5c8d8..e46e8fe4b18d01 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -318,7 +318,7 @@ omit [Fintype <| G.neighborSet v] in lemma degree_le_of_le {H : SimpleGraph V} [Finite <| H.neighborSet v] (hle : G ≤ H) : G.degree v ≤ H.degree v := by have := Fintype.ofFinite <| H.neighborSet v - have := (Set.toFinite _ |>.subset <| neighborSet_subset hle v).fintype + have := (Set.toFinite _ |>.subset <| neighborSet_mono hle v).fintype simp_rw [← card_neighborSet_eq_degree] exact Set.card_le_card fun v hv => hle hv diff --git a/Mathlib/Combinatorics/SimpleGraph/Maps.lean b/Mathlib/Combinatorics/SimpleGraph/Maps.lean index 3320f99c71c9ed..939958363cf331 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Maps.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Maps.lean @@ -320,7 +320,8 @@ theorem mapEdgeSet.injective (hinj : Function.Injective f) : Function.Injective repeat rw [Subtype.mk_eq_mk] apply Sym2.map.injective hinj -theorem _root_.SimpleGraph.neighborSet_subset (hle : G₁ ≤ G₂) (v : V) : +@[gcongr] +theorem _root_.SimpleGraph.neighborSet_mono (hle : G₁ ≤ G₂) (v : V) : G₁.neighborSet v ⊆ G₂.neighborSet v := fun _ h ↦ Hom.ofLE hle |>.apply_mem_neighborSet h From 660b5d4052c6ba670015cfca7f4c3804a39f6a73 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sat, 24 Jan 2026 19:26:44 +0200 Subject: [PATCH 07/60] `Fintype` -> `Finite` in `DegreeSum.lean` --- Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean index c9c4820f1358e0..b6cb36b48dd95d 100644 --- a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean +++ b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean @@ -157,8 +157,9 @@ theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] (v : V) (h : lia · rwa [mem_filter_univ] -theorem exists_ne_odd_degree_of_exists_odd_degree [Fintype V] (v : V) (h : Odd (G.degree v)) : +theorem exists_ne_odd_degree_of_exists_odd_degree [Finite V] (v : V) (h : Odd (G.degree v)) : ∃ w : V, w ≠ v ∧ Odd (G.degree w) := by + have := Fintype.ofFinite V haveI := Classical.decEq V rcases G.odd_card_odd_degree_vertices_ne v h with ⟨k, hg⟩ have hg' : 0 < #{w | w ≠ v ∧ Odd (G.degree w)} := by From ac74c086c015f1c2c34b8633ea7b348df19a7c21 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sat, 31 Jan 2026 18:28:05 +0200 Subject: [PATCH 08/60] fixes for unused fintype linter --- .../Combinatorics/SimpleGraph/Acyclic.lean | 2 +- .../Combinatorics/SimpleGraph/Bipartite.lean | 19 ++++++++++++------- .../SimpleGraph/Connectivity/Connected.lean | 2 +- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 3 ++- .../Combinatorics/SimpleGraph/IncMatrix.lean | 7 ++++--- .../Combinatorics/SimpleGraph/LapMatrix.lean | 4 +++- Mathlib/Combinatorics/SimpleGraph/Prod.lean | 5 ++++- .../Combinatorics/SimpleGraph/Subgraph.lean | 15 +++++++++------ 8 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean index b5e0d9305158e2..35ba76317a7a03 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean @@ -514,7 +514,7 @@ lemma IsTree.exists_vert_degree_one_of_nontrivial [Finite V] [Nontrivial V] (h : /-- The graph resulting from removing a vertex of degree one from a connected graph is connected. -/ lemma Connected.induce_compl_singleton_of_degree_eq_one (hconn : G.Connected) {v : V} - [Fintype ↑(G.neighborSet v)] (hdeg : G.degree v = 1) : (G.induce {v}ᶜ).Connected := by + (hdeg : G.degree v = 1) : (G.induce {v}ᶜ).Connected := by obtain ⟨u, adj_vu, hu⟩ := degree_eq_one_iff_existsUnique_adj.mp hdeg refine (connected_iff _).mpr ⟨?_, u, by aesop⟩ /- There exists a walk between any two vertices w and x in G.induce {v}ᶜ diff --git a/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean b/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean index 54d324c82d3b92..4271acc176da05 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean @@ -201,11 +201,15 @@ theorem isBipartiteWith_neighborFinset_disjoint (h : G.IsBipartiteWith s t) (hv rw [neighborFinset_def, ← disjoint_coe, Set.coe_toFinset] exact isBipartiteWith_neighborSet_disjoint h hv +omit [Fintype <| G.neighborSet v] in /-- If `G.IsBipartiteWith s t` and `v ∈ s`, then the degree of `v` in `G` is at most the size of `t`. -/ theorem isBipartiteWith_degree_le (h : G.IsBipartiteWith s t) (hv : v ∈ s) : G.degree v ≤ #t := by - rw [← card_neighborFinset_eq_degree] - exact card_le_card (isBipartiteWith_neighborFinset_subset h hv) + cases finite_or_infinite <| G.neighborSet v + · have := Fintype.ofFinite <| G.neighborSet v + rw [← card_neighborFinset_eq_degree] + exact card_le_card (isBipartiteWith_neighborFinset_subset h hv) + simp [degree, Set.Infinite.ncard <| Infinite.not_finite] /-- If `G.IsBipartiteWith s t` and `w ∈ t`, then the neighbor finset of `w` is a subset of `s`. -/ theorem isBipartiteWith_neighborFinset_subset' (h : G.IsBipartiteWith s t) (hw : w ∈ t) : @@ -220,11 +224,11 @@ theorem isBipartiteWith_neighborFinset_disjoint' (h : G.IsBipartiteWith s t) (hw rw [neighborFinset_def, ← disjoint_coe, Set.coe_toFinset] exact isBipartiteWith_neighborSet_disjoint' h hw +omit [Fintype <| G.neighborSet w] in /-- If `G.IsBipartiteWith s t` and `w ∈ t`, then the degree of `w` in `G` is at most the size of `s`. -/ -theorem isBipartiteWith_degree_le' (h : G.IsBipartiteWith s t) (hw : w ∈ t) : G.degree w ≤ #s := by - rw [← card_neighborFinset_eq_degree] - exact card_le_card (isBipartiteWith_neighborFinset_subset' h hw) +theorem isBipartiteWith_degree_le' (h : G.IsBipartiteWith s t) (hw : w ∈ t) : G.degree w ≤ #s := + isBipartiteWith_degree_le h.symm hw end @@ -417,12 +421,13 @@ lemma neighborFinset_subset_between_union (hv : v ∈ s) : G.neighborFinset v ⊆ (G.between s sᶜ).neighborFinset v ∪ s := by simpa [neighborFinset_def] using neighborSet_subset_between_union hv -omit [DecidableEq V] [DecidableRel G.Adj] in +omit [Fintype V] [DecidableEq V] [DecidableRel G.Adj] in /-- The degree of `v ∈ s` in `G` is at most the degree in `G.between s sᶜ` plus the excluded vertices from `s`. -/ -theorem degree_le_between_add (hv : v ∈ s) : +theorem degree_le_between_add [Finite V] (hv : v ∈ s) : G.degree v ≤ (G.between s sᶜ).degree v + s.card := by classical + have := Fintype.ofFinite V have h_bipartite : (G.between s sᶜ).IsBipartiteWith s ↑(sᶜ) := by simpa using between_isBipartiteWith disjoint_compl_right simp_rw [← card_neighborFinset_eq_degree, diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean index 318d1a18631659..b52390336c6a8c 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean @@ -240,7 +240,7 @@ lemma Preconnected.support_eq_univ [Nontrivial V] {G : SimpleGraph V} | @cons _ w => exact ⟨w, ‹_›⟩ lemma Preconnected.degree_pos_of_nontrivial [Nontrivial V] {G : SimpleGraph V} (h : G.Preconnected) - (v : V) [Fintype (G.neighborSet v)] : 0 < G.degree v := by + (v : V) [Finite (G.neighborSet v)] : 0 < G.degree v := by simp [degree_pos_iff_mem_support, h.support_eq_univ] lemma Preconnected.minDegree_pos_of_nontrivial [Nontrivial V] [Finite V] {G : SimpleGraph V} diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index e46e8fe4b18d01..0b3a110c9bfc45 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -618,9 +618,10 @@ theorem map_neighborFinset_induce [DecidableEq V] (v : s) [Fintype <| G.neighbor ext; simp theorem map_neighborFinset_induce_of_neighborSet_subset {v : s} [Fintype <| G.neighborSet v] - [Fintype <| (induce s G).neighborSet v] [Fintype s] (h : G.neighborSet v ⊆ s) : + [Fintype <| (induce s G).neighborSet v] [Finite s] (h : G.neighborSet v ⊆ s) : ((G.induce s).neighborFinset v).map (.subtype s) = G.neighborFinset v := by classical + have := Fintype.ofFinite s rwa [← Set.toFinset_subset_toFinset, ← neighborFinset_def, ← inter_eq_left, ← map_neighborFinset_induce v] at h diff --git a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean index 7dce7be3752083..9e5683d4088073 100644 --- a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean @@ -104,11 +104,12 @@ section NonAssocSemiring variable [NonAssocSemiring R] [DecidableEq α] [DecidableRel G.Adj] {a : α} {e : Sym2 α} -theorem sum_incMatrix_apply [Fintype (Sym2 α)] [Fintype (neighborSet G a)] : +theorem sum_incMatrix_apply [Fintype (Sym2 α)] [Finite (neighborSet G a)] : ∑ e, G.incMatrix R a e = G.degree a := by + have := Fintype.ofFinite <| neighborSet G a simp [incMatrix_apply', sum_boole, Set.filter_mem_univ_eq_toFinset] -theorem incMatrix_mul_transpose_diag [Fintype (Sym2 α)] [Fintype (neighborSet G a)] : +theorem incMatrix_mul_transpose_diag [Fintype (Sym2 α)] [Finite (neighborSet G a)] : (G.incMatrix R * (G.incMatrix R)ᵀ) a a = G.degree a := by rw [← sum_incMatrix_apply] simp only [mul_apply, incMatrix_apply', transpose_apply, mul_ite, mul_one, mul_zero] @@ -162,7 +163,7 @@ theorem incMatrix_mul_transpose_apply_of_adj (h : G.Adj a b) : rw [← coe_eq_singleton, coe_filter_univ] exact G.incidenceSet_inter_incidenceSet_of_adj h -theorem incMatrix_mul_transpose [∀ a, Fintype (neighborSet G a)] : +theorem incMatrix_mul_transpose [∀ a, Finite (neighborSet G a)] : G.incMatrix R * (G.incMatrix R)ᵀ = of fun a b => if a = b then (G.degree a : R) else if G.Adj a b then 1 else 0 := by ext a b diff --git a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean index a1e94f9de4ac1f..1e17863fb9c206 100644 --- a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean @@ -98,9 +98,11 @@ theorem lapMatrix_toLinearMap₂' [Field R] [CharZero R] (x : V → R) : congr 2 with j ring_nf +omit [Fintype V] in /-- The Laplacian matrix is positive semidefinite -/ theorem posSemidef_lapMatrix [Field R] [LinearOrder R] [IsStrictOrderedRing R] [StarRing R] - [TrivialStar R] : PosSemidef (G.lapMatrix R) := by + [TrivialStar R] [Finite V] : PosSemidef (G.lapMatrix R) := by + have := Fintype.ofFinite V refine .of_dotProduct_mulVec_nonneg ?_ (fun x ↦ ?_) · rw [IsHermitian, conjTranspose_eq_transpose_of_trivial, isSymm_lapMatrix] · rw [star_trivial, ← toLinearMap₂'_apply', lapMatrix_toLinearMap₂'] diff --git a/Mathlib/Combinatorics/SimpleGraph/Prod.lean b/Mathlib/Combinatorics/SimpleGraph/Prod.lean index f189b0844d9448..1b2567bc961252 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Prod.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Prod.lean @@ -247,8 +247,11 @@ theorem neighborFinset_boxProd (x : α × β) exact Eq.trans (Finset.map_map _ _ _) Finset.attach_map_val theorem degree_boxProd (x : α × β) - [Fintype (G.neighborSet x.1)] [Fintype (H.neighborSet x.2)] [Fintype ((G □ H).neighborSet x)] : + [Finite (G.neighborSet x.1)] [Finite (H.neighborSet x.2)] [Finite ((G □ H).neighborSet x)] : (G □ H).degree x = G.degree x.1 + H.degree x.2 := by + have := Fintype.ofFinite <| G.neighborSet x.fst + have := Fintype.ofFinite <| H.neighborSet x.snd + have := Fintype.ofFinite <| (G □ H).neighborSet x rw [← card_neighborFinset_eq_degree, ← card_neighborFinset_eq_degree, ← card_neighborFinset_eq_degree, neighborFinset_boxProd, Finset.card_disjUnion] simp_rw [Finset.card_product, Finset.card_singleton, mul_one, one_mul] diff --git a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean index d6299035d19a3f..66702e27d7e2c1 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean @@ -787,7 +787,8 @@ theorem degree_of_notMem_verts {G' : Subgraph G} {v : V} [Fintype (G'.neighborSe exact h hw.fst_mem theorem degree_le (G' : Subgraph G) (v : V) [Fintype (G'.neighborSet v)] - [Fintype (G.neighborSet v)] : G'.degree v ≤ G.degree v := by + [Finite (G.neighborSet v)] : G'.degree v ≤ G.degree v := by + have := Fintype.ofFinite <| G.neighborSet v rw [← card_neighborSet_eq_degree] exact Set.card_le_card (G'.neighborSet_subset v) @@ -796,14 +797,15 @@ theorem degree_le' (G' G'' : Subgraph G) (h : G' ≤ G'') (v : V) [Fintype (G'.n Set.card_le_card (neighborSet_subset_of_subgraph h v) @[simp] -theorem coe_degree (G' : Subgraph G) (v : G'.verts) [Fintype (G'.coe.neighborSet v)] - [Fintype (G'.neighborSet v)] : G'.coe.degree v = G'.degree v := by +theorem coe_degree (G' : Subgraph G) (v : G'.verts) [Fintype (G'.neighborSet v)] : + G'.coe.degree v = G'.degree v := by rw [← card_neighborSet_eq_degree] exact Fintype.card_congr (coeNeighborSetEquiv v) @[simp] theorem degree_spanningCoe {G' : G.Subgraph} (v : V) [Fintype (G'.neighborSet v)] - [Fintype (G'.spanningCoe.neighborSet v)] : G'.spanningCoe.degree v = G'.degree v := by + [Finite (G'.spanningCoe.neighborSet v)] : G'.spanningCoe.degree v = G'.degree v := by + have := Fintype.ofFinite <| G'.spanningCoe.neighborSet v rw [← card_neighborSet_eq_degree, Subgraph.degree] congr! @@ -850,8 +852,9 @@ end Subgraph @[simp] theorem card_neighborSet_toSubgraph (G H : SimpleGraph V) (h : H ≤ G) - (v : V) [Fintype ↑((toSubgraph H h).neighborSet v)] [Fintype ↑(H.neighborSet v)] : + (v : V) [Fintype ↑((toSubgraph H h).neighborSet v)] [Finite (H.neighborSet v)] : Fintype.card ↑((toSubgraph H h).neighborSet v) = H.degree v := by + have := Fintype.ofFinite <| H.neighborSet v rw [← H.card_neighborFinset_eq_degree] refine (Finset.card_eq_of_equiv_fintype ?_).symm simp only [mem_neighborFinset] @@ -859,7 +862,7 @@ theorem card_neighborSet_toSubgraph (G H : SimpleGraph V) (h : H ≤ G) @[simp] lemma degree_toSubgraph (G H : SimpleGraph V) (h : H ≤ G) {v : V} - [Fintype ↑((toSubgraph H h).neighborSet v)] [Fintype ↑(H.neighborSet v)] : + [Fintype ↑((toSubgraph H h).neighborSet v)] [Finite (H.neighborSet v)] : (toSubgraph H h).degree v = H.degree v := by simp [Subgraph.degree] From a4b2a38685d4ad808532e1753792c66adc5b8fc1 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sat, 31 Jan 2026 19:03:42 +0200 Subject: [PATCH 09/60] fix `Archive/Wiedijk100Theorems/Konigsberg` --- Archive/Wiedijk100Theorems/Konigsberg.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Archive/Wiedijk100Theorems/Konigsberg.lean b/Archive/Wiedijk100Theorems/Konigsberg.lean index bd1adf57506e3c..bce0663b71ecf5 100644 --- a/Archive/Wiedijk100Theorems/Konigsberg.lean +++ b/Archive/Wiedijk100Theorems/Konigsberg.lean @@ -81,7 +81,6 @@ lemma setOf_odd_degree_eq : theorem not_isEulerian {u v : Verts} (p : graph.Walk u v) (h : p.IsEulerian) : False := by have h := h.card_odd_degree have h' := setOf_odd_degree_eq - apply_fun Fintype.card at h' rw [h'] at h simp at h From 4801dd13d4eb6ffc7330b144d2bb64ac234831fc Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 3 Apr 2026 08:05:23 +0300 Subject: [PATCH 10/60] Revert to master This reverts commits a4b2a38685 ac74c086c0 660b5d4052 bcbdd1dea6 a6c75e8fbe 030f03e152 f1cc815922 79191508f6 1988416396 56adbb5055. --- .../Wiedijk100Theorems/FriendshipGraphs.lean | 17 +- Archive/Wiedijk100Theorems/Konigsberg.lean | 5 +- Counterexamples/HeawoodUnitDistance.lean | 2 - .../Combinatorics/SimpleGraph/Acyclic.lean | 12 +- .../Combinatorics/SimpleGraph/AdjMatrix.lean | 2 +- .../Combinatorics/SimpleGraph/Bipartite.lean | 21 +- .../Combinatorics/SimpleGraph/Circulant.lean | 2 +- .../SimpleGraph/Connectivity/Connected.lean | 8 +- .../Combinatorics/SimpleGraph/DegreeSum.lean | 12 +- .../SimpleGraph/Extremal/Turan.lean | 11 +- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 403 ++++++++---------- .../SimpleGraph/FiveWheelLike.lean | 9 +- .../Combinatorics/SimpleGraph/IncMatrix.lean | 7 +- .../Combinatorics/SimpleGraph/LapMatrix.lean | 15 +- Mathlib/Combinatorics/SimpleGraph/Maps.lean | 5 - Mathlib/Combinatorics/SimpleGraph/Prod.lean | 8 +- .../SimpleGraph/StronglyRegular.lean | 13 +- .../Combinatorics/SimpleGraph/Subgraph.lean | 16 +- Mathlib/Combinatorics/SimpleGraph/Trails.lean | 20 +- Mathlib/Data/Set/Card.lean | 4 - Mathlib/Data/Set/Insert.lean | 5 - .../ConditionallyCompleteLattice/Finset.lean | 14 - 22 files changed, 259 insertions(+), 352 deletions(-) diff --git a/Archive/Wiedijk100Theorems/FriendshipGraphs.lean b/Archive/Wiedijk100Theorems/FriendshipGraphs.lean index dca5567f84b4ed..c496a3f0cb949b 100644 --- a/Archive/Wiedijk100Theorems/FriendshipGraphs.lean +++ b/Archive/Wiedijk100Theorems/FriendshipGraphs.lean @@ -89,8 +89,7 @@ include hG in We use it to show that nonadjacent vertices have equal degrees. -/ theorem adjMatrix_pow_three_of_not_adj {v w : V} (non_adj : ¬G.Adj v w) : (G.adjMatrix R ^ 3 : Matrix V V R) v w = degree G v := by - rw [pow_succ', adjMatrix_mul_apply, ← card_neighborFinset_eq_degree, card_eq_sum_ones, - Nat.cast_sum] + rw [pow_succ', adjMatrix_mul_apply, degree, card_eq_sum_ones, Nat.cast_sum] apply sum_congr rfl intro x hx rw [adjMatrix_sq_of_ne _ hG, Nat.cast_one] @@ -124,7 +123,7 @@ include hG in theorem adjMatrix_sq_of_regular (hd : G.IsRegularOfDegree d) : G.adjMatrix R ^ 2 = of fun v w => if v = w then (d : R) else (1 : R) := by ext (v w); by_cases h : v = w - · rw [h, sq, adjMatrix_mul_self_apply_self, hd.degree_eq]; simp + · rw [h, sq, adjMatrix_mul_self_apply_self, hd]; simp · rw [adjMatrix_sq_of_ne R hG h, of_apply, if_neg h] open scoped Classical in @@ -148,9 +147,6 @@ theorem isRegularOf_not_existsPolitician (hG' : ¬ExistsPolitician G) : have v := Classical.arbitrary V use G.degree v intro x - rw [← show G.degree x = G.edegree x from - ENat.coe_toNat <| Set.encard_ne_top_iff.mpr <| Set.toFinite _] - congr 1 by_cases hvx : G.Adj v x; swap; · exact (degree_eq_of_not_adj hG hvx).symm dsimp only [Theorems100.ExistsPolitician] at hG' push_neg at hG' @@ -191,7 +187,7 @@ theorem card_of_regular (hd : G.IsRegularOfDegree d) : d + (Fintype.card V - 1) intro x hx; simp [(ne_of_mem_erase hx).symm] · rw [sq, ← mulVec_mulVec] simp only [adjMatrix_mulVec_const_apply_of_regular hd, neighborFinset, - card_neighborSet_eq_degree, hd.degree_eq v, Function.const_def, adjMatrix_mulVec_apply, + card_neighborSet_eq_degree, hd v, Function.const_def, adjMatrix_mulVec_apply _ _ (mulVec _ _), mul_one, sum_const, Set.toFinset_card, smul_eq_mul, Nat.cast_id] open scoped Classical in @@ -212,8 +208,8 @@ open scoped Classical in theorem adjMatrix_sq_mul_const_one_of_regular (hd : G.IsRegularOfDegree d) : G.adjMatrix R * of (fun _ _ => 1) = of (fun _ _ => (d : R)) := by ext x - simp only [← hd.degree_eq x, ← card_neighborFinset_eq_degree, adjMatrix_mul_apply, sum_const, - Nat.smul_one_eq_cast, of_apply] + simp only [← hd x, degree, adjMatrix_mul_apply, sum_const, Nat.smul_one_eq_cast, + of_apply] open scoped Classical in theorem adjMatrix_mul_const_one_mod_p_of_regular {p : ℕ} (dmod : (d : ZMod p) = 1) @@ -307,7 +303,8 @@ theorem neighborFinset_eq_of_degree_eq_two (hd : G.IsRegularOfDegree 2) (v : V) · have hfr := card_of_regular hG hd lia · exact Finset.card_erase_of_mem (Finset.mem_univ _) - · rw [card_neighborFinset_eq_degree, hd.degree_eq] + · dsimp only [IsRegularOfDegree, degree] at hd + rw [hd] open scoped Classical in include hG in diff --git a/Archive/Wiedijk100Theorems/Konigsberg.lean b/Archive/Wiedijk100Theorems/Konigsberg.lean index bce0663b71ecf5..fd316bcf536fc2 100644 --- a/Archive/Wiedijk100Theorems/Konigsberg.lean +++ b/Archive/Wiedijk100Theorems/Konigsberg.lean @@ -65,9 +65,7 @@ def degree : Verts → ℕ | B1 => 2 | B2 => 2 | B3 => 2 | B4 => 2 | B5 => 2 | B6 => 2 | B7 => 2 @[simp] -lemma degree_eq_degree (v : Verts) : graph.degree v = degree v := by - rw [← graph.card_neighborFinset_eq_degree] - cases v <;> rfl +lemma degree_eq_degree (v : Verts) : graph.degree v = degree v := by cases v <;> rfl lemma not_even_degree_iff (w : Verts) : ¬Even (degree w) ↔ w = V1 ∨ w = V2 ∨ w = V3 ∨ w = V4 := by cases w <;> decide @@ -81,6 +79,7 @@ lemma setOf_odd_degree_eq : theorem not_isEulerian {u v : Verts} (p : graph.Walk u v) (h : p.IsEulerian) : False := by have h := h.card_odd_degree have h' := setOf_odd_degree_eq + apply_fun Fintype.card at h' rw [h'] at h simp at h diff --git a/Counterexamples/HeawoodUnitDistance.lean b/Counterexamples/HeawoodUnitDistance.lean index ad948845bc68a6..9c712228cc5a92 100644 --- a/Counterexamples/HeawoodUnitDistance.lean +++ b/Counterexamples/HeawoodUnitDistance.lean @@ -54,8 +54,6 @@ lemma heawoodGraph_neighborFinset (i : Fin 14) : /-- The Heawood graph is 3-regular. -/ lemma isRegularOfDegree_heawoodGraph : heawoodGraph.IsRegularOfDegree 3 := fun i ↦ by - rw [← show heawoodGraph.degree i = heawoodGraph.edegree i from - ENat.coe_toNat <| Set.encard_ne_top_iff.mpr <| Set.toFinite _] rw [← card_neighborFinset_eq_degree, heawoodGraph_neighborFinset]; revert i; decide /-! ### A key number -/ diff --git a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean index 35ba76317a7a03..468212a6e9aed5 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean @@ -489,10 +489,8 @@ lemma isTree_iff_connected_and_card [Finite V] : exact Finset.card_lt_card <| by simpa [deleteEdges, edgeFinset] /-- The minimum degree of all vertices in a nontrivial tree is one. -/ -lemma IsTree.minDegree_eq_one_of_nontrivial (h : G.IsTree) [Finite V] [Nontrivial V] : - G.minDegree = 1 := by - classical - have := Fintype.ofFinite V +lemma IsTree.minDegree_eq_one_of_nontrivial (h : G.IsTree) [Fintype V] [Nontrivial V] + [DecidableRel G.Adj] : G.minDegree = 1 := by by_cases q : 2 ≤ G.minDegree · have := h.card_edgeFinset have := G.sum_degrees_eq_twice_card_edges @@ -505,8 +503,8 @@ lemma IsTree.minDegree_eq_one_of_nontrivial (h : G.IsTree) [Finite V] [Nontrivia lia /-- A nontrivial tree has a vertex of degree one. -/ -lemma IsTree.exists_vert_degree_one_of_nontrivial [Finite V] [Nontrivial V] (h : G.IsTree) : - ∃ v, G.degree v = 1 := by +lemma IsTree.exists_vert_degree_one_of_nontrivial [Fintype V] [Nontrivial V] [DecidableRel G.Adj] + (h : G.IsTree) : ∃ v, G.degree v = 1 := by obtain ⟨v, hv⟩ := G.exists_minimal_degree_vertex use v rw [← hv] @@ -514,7 +512,7 @@ lemma IsTree.exists_vert_degree_one_of_nontrivial [Finite V] [Nontrivial V] (h : /-- The graph resulting from removing a vertex of degree one from a connected graph is connected. -/ lemma Connected.induce_compl_singleton_of_degree_eq_one (hconn : G.Connected) {v : V} - (hdeg : G.degree v = 1) : (G.induce {v}ᶜ).Connected := by + [Fintype ↑(G.neighborSet v)] (hdeg : G.degree v = 1) : (G.induce {v}ᶜ).Connected := by obtain ⟨u, adj_vu, hu⟩ := degree_eq_one_iff_existsUnique_adj.mp hdeg refine (connected_iff _).mpr ⟨?_, u, by aesop⟩ /- There exists a walk between any two vertices w and x in G.induce {v}ᶜ diff --git a/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean index fbf1391fdd5239..3c1968ba4cdeed 100644 --- a/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/AdjMatrix.lean @@ -232,7 +232,7 @@ theorem adjMatrix_mulVec_const_apply [NonAssocSemiring α] {a : α} {v : V} : theorem adjMatrix_mulVec_const_apply_of_regular [NonAssocSemiring α] {d : ℕ} {a : α} (hd : G.IsRegularOfDegree d) {v : V} : (G.adjMatrix α *ᵥ Function.const _ a) v = d * a := by - simp [hd.degree_eq v] + simp [hd v] theorem adjMatrix_pow_apply_eq_card_walk [DecidableEq V] [Semiring α] (n : ℕ) (u v : V) : (G.adjMatrix α ^ n) u v = Fintype.card { p : G.Walk u v | p.length = n } := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean b/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean index 4271acc176da05..1bd5c30b0cb3ab 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Bipartite.lean @@ -201,15 +201,11 @@ theorem isBipartiteWith_neighborFinset_disjoint (h : G.IsBipartiteWith s t) (hv rw [neighborFinset_def, ← disjoint_coe, Set.coe_toFinset] exact isBipartiteWith_neighborSet_disjoint h hv -omit [Fintype <| G.neighborSet v] in /-- If `G.IsBipartiteWith s t` and `v ∈ s`, then the degree of `v` in `G` is at most the size of `t`. -/ theorem isBipartiteWith_degree_le (h : G.IsBipartiteWith s t) (hv : v ∈ s) : G.degree v ≤ #t := by - cases finite_or_infinite <| G.neighborSet v - · have := Fintype.ofFinite <| G.neighborSet v - rw [← card_neighborFinset_eq_degree] - exact card_le_card (isBipartiteWith_neighborFinset_subset h hv) - simp [degree, Set.Infinite.ncard <| Infinite.not_finite] + rw [← card_neighborFinset_eq_degree] + exact card_le_card (isBipartiteWith_neighborFinset_subset h hv) /-- If `G.IsBipartiteWith s t` and `w ∈ t`, then the neighbor finset of `w` is a subset of `s`. -/ theorem isBipartiteWith_neighborFinset_subset' (h : G.IsBipartiteWith s t) (hw : w ∈ t) : @@ -224,11 +220,11 @@ theorem isBipartiteWith_neighborFinset_disjoint' (h : G.IsBipartiteWith s t) (hw rw [neighborFinset_def, ← disjoint_coe, Set.coe_toFinset] exact isBipartiteWith_neighborSet_disjoint' h hw -omit [Fintype <| G.neighborSet w] in /-- If `G.IsBipartiteWith s t` and `w ∈ t`, then the degree of `w` in `G` is at most the size of `s`. -/ -theorem isBipartiteWith_degree_le' (h : G.IsBipartiteWith s t) (hw : w ∈ t) : G.degree w ≤ #s := - isBipartiteWith_degree_le h.symm hw +theorem isBipartiteWith_degree_le' (h : G.IsBipartiteWith s t) (hw : w ∈ t) : G.degree w ≤ #s := by + rw [← card_neighborFinset_eq_degree] + exact card_le_card (isBipartiteWith_neighborFinset_subset' h hw) end @@ -421,13 +417,10 @@ lemma neighborFinset_subset_between_union (hv : v ∈ s) : G.neighborFinset v ⊆ (G.between s sᶜ).neighborFinset v ∪ s := by simpa [neighborFinset_def] using neighborSet_subset_between_union hv -omit [Fintype V] [DecidableEq V] [DecidableRel G.Adj] in /-- The degree of `v ∈ s` in `G` is at most the degree in `G.between s sᶜ` plus the excluded vertices from `s`. -/ -theorem degree_le_between_add [Finite V] (hv : v ∈ s) : +theorem degree_le_between_add (hv : v ∈ s) : G.degree v ≤ (G.between s sᶜ).degree v + s.card := by - classical - have := Fintype.ofFinite V have h_bipartite : (G.between s sᶜ).IsBipartiteWith s ↑(sᶜ) := by simpa using between_isBipartiteWith disjoint_compl_right simp_rw [← card_neighborFinset_eq_degree, @@ -440,12 +433,10 @@ lemma neighborFinset_subset_between_union_compl (hw : w ∈ sᶜ) : G.neighborFinset w ⊆ (G.between s sᶜ).neighborFinset w ∪ sᶜ := by simpa [neighborFinset_def] using G.neighborSet_subset_between_union_compl (by simpa using hw) -omit [DecidableRel G.Adj] in /-- The degree of `w ∈ sᶜ` in `G` is at most the degree in `G.between s sᶜ` plus the excluded vertices from `sᶜ`. -/ theorem degree_le_between_add_compl (hw : w ∈ sᶜ) : G.degree w ≤ (G.between s sᶜ).degree w + sᶜ.card := by - classical have h_bipartite : (G.between s sᶜ).IsBipartiteWith s ↑(sᶜ) := by simpa using between_isBipartiteWith disjoint_compl_right simp_rw [← card_neighborFinset_eq_degree, diff --git a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean index 801ccee36276ca..24d370c21c22bd 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean @@ -111,7 +111,7 @@ theorem cycleGraph_neighborFinset {n : ℕ} {v : Fin (n + 2)} : theorem cycleGraph_degree_two_le {n : ℕ} {v : Fin (n + 2)} : (cycleGraph (n + 2)).degree v = Finset.card {v - 1, v + 1} := by - rw [← card_neighborFinset_eq_degree, cycleGraph_neighborFinset] + rw [SimpleGraph.degree, cycleGraph_neighborFinset] theorem cycleGraph_degree_three_le {n : ℕ} {v : Fin (n + 3)} : (cycleGraph (n + 3)).degree v = 2 := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean index b52390336c6a8c..fb0664f8019ef5 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean @@ -240,13 +240,11 @@ lemma Preconnected.support_eq_univ [Nontrivial V] {G : SimpleGraph V} | @cons _ w => exact ⟨w, ‹_›⟩ lemma Preconnected.degree_pos_of_nontrivial [Nontrivial V] {G : SimpleGraph V} (h : G.Preconnected) - (v : V) [Finite (G.neighborSet v)] : 0 < G.degree v := by + (v : V) [Fintype (G.neighborSet v)] : 0 < G.degree v := by simp [degree_pos_iff_mem_support, h.support_eq_univ] -lemma Preconnected.minDegree_pos_of_nontrivial [Nontrivial V] [Finite V] {G : SimpleGraph V} - (h : G.Preconnected) : 0 < G.minDegree := by - classical - have := Fintype.ofFinite V +lemma Preconnected.minDegree_pos_of_nontrivial [Nontrivial V] [Fintype V] {G : SimpleGraph V} + [DecidableRel G.Adj] (h : G.Preconnected) : 0 < G.minDegree := by obtain ⟨v, hv⟩ := G.exists_minimal_degree_vertex rw [hv] exact h.degree_pos_of_nontrivial v diff --git a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean index b6cb36b48dd95d..abfa2203d1a863 100644 --- a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean +++ b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean @@ -123,7 +123,8 @@ theorem sum_degrees_support_eq_twice_card_edges : end DegreeSum /-- The handshaking lemma. See also `SimpleGraph.sum_degrees_eq_twice_card_edges`. -/ -theorem even_card_odd_degree_vertices [Fintype V] : Even #{v | Odd (G.degree v)} := by +theorem even_card_odd_degree_vertices [Fintype V] [DecidableRel G.Adj] : + Even #{v | Odd (G.degree v)} := by classical have h := congr_arg (fun n => ↑n : ℕ → ZMod 2) G.sum_degrees_eq_twice_card_edges simp only [ZMod.natCast_self, zero_mul, Nat.cast_mul] at h @@ -138,8 +139,8 @@ theorem even_card_odd_degree_vertices [Fintype V] : Even #{v | Odd (G.degree v)} ← Nat.not_even_iff_odd] tauto -theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] (v : V) (h : Odd (G.degree v)) : - Odd #{w | w ≠ v ∧ Odd (G.degree w)} := by +theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] [DecidableRel G.Adj] (v : V) + (h : Odd (G.degree v)) : Odd #{w | w ≠ v ∧ Odd (G.degree w)} := by rcases G.even_card_odd_degree_vertices with ⟨k, hg⟩ have hk : 0 < k := by have hh : Finset.Nonempty {v : V | Odd (G.degree v)} := by @@ -157,9 +158,8 @@ theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] (v : V) (h : lia · rwa [mem_filter_univ] -theorem exists_ne_odd_degree_of_exists_odd_degree [Finite V] (v : V) (h : Odd (G.degree v)) : - ∃ w : V, w ≠ v ∧ Odd (G.degree w) := by - have := Fintype.ofFinite V +theorem exists_ne_odd_degree_of_exists_odd_degree [Fintype V] [DecidableRel G.Adj] (v : V) + (h : Odd (G.degree v)) : ∃ w : V, w ≠ v ∧ Odd (G.degree w) := by haveI := Classical.decEq V rcases G.odd_card_odd_degree_vertices_ne v h with ⟨k, hg⟩ have hg' : 0 < #{w | w ≠ v ∧ Odd (G.degree w)} := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Extremal/Turan.lean b/Mathlib/Combinatorics/SimpleGraph/Extremal/Turan.lean index aed77c3ad2d10e..a8ea3d976b773d 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Extremal/Turan.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Extremal/Turan.lean @@ -141,15 +141,13 @@ lemma not_adj_trans (h : G.IsTuranMaximal r) (hts : ¬G.Adj t s) (hsu : ¬G.Adj rw [card_edgeFinset_replaceVertex_of_not_adj _ this, card_edgeFinset_replaceVertex_of_not_adj _ hst, dst, Nat.add_sub_cancel] have l1 : (G.replaceVertex s t).degree s = G.degree s := by - rw [← card_neighborFinset_eq_degree, ← card_neighborFinset_eq_degree] - congr 1; ext v + unfold degree; congr 1; ext v simp_rw [mem_neighborFinset] by_cases eq : v = t · simpa only [eq, not_adj_replaceVertex_same, false_iff] · rw [G.adj_replaceVertex_iff_of_ne s nst eq] have l2 : (G.replaceVertex s t).degree u = G.degree u - 1 := by - rw [← card_neighborFinset_eq_degree, ← card_neighborFinset_eq_degree, ← card_singleton t, - ← card_sdiff_of_subset (by simp [h.symm])] + rw [degree, degree, ← card_singleton t, ← card_sdiff_of_subset (by simp [h.symm])] congr 1; ext v simp_rw [mem_neighborFinset, mem_sdiff, mem_singleton, replaceVertex] split_ifs <;> simp_all [adj_comm] @@ -350,8 +348,8 @@ lemma card_edgeFinset_turanGraph_add : #(turanGraph (n + r) r).edgeFinset = #(turanGraph n r).edgeFinset + n * (r - 1) + r.choose 2 := by rw [← mul_right_inj' two_ne_zero] - simp_rw [mul_add, ← sum_degrees_eq_twice_card_edges, ← card_neighborFinset_eq_degree, - neighborFinset_eq_filter, turanGraph, card_filter] + simp_rw [mul_add, ← sum_degrees_eq_twice_card_edges, + degree, neighborFinset_eq_filter, turanGraph, card_filter] conv_lhs => enter [2, v] rw [Fin.sum_univ_eq_sum_range fun w ↦ if v % r ≠ w % r then 1 else 0, sum_range_add] @@ -410,6 +408,7 @@ theorem mul_card_edgeFinset_turanGraph_le : grw [card_edgeFinset_turanGraph, mul_add, Nat.mul_div_le] rw [tsub_mul, ← Nat.sub_add_comm]; swap · grw [Nat.mod_le] + exact Nat.zero_le _ rw [Nat.sub_le_iff_le_add, mul_comm, Nat.add_le_add_iff_left, Nat.choose_two_right, ← Nat.mul_div_assoc _ (Nat.even_mul_pred_self _).two_dvd, mul_assoc, mul_div_cancel_left₀ _ two_ne_zero, ← mul_assoc, ← mul_rotate, sq, ← mul_rotate (r - 1)] diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 0b3a110c9bfc45..5fd2e19091f47b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -6,8 +6,7 @@ Authors: Aaron Anderson, Jalex Stark, Kyle Miller, Alena Gusakov module public import Mathlib.Combinatorics.SimpleGraph.Maps -public import Mathlib.Data.ENat.Lattice -public import Mathlib.Data.Set.Card +public import Mathlib.Data.Finset.Max public import Mathlib.Data.Sym.Card /-! @@ -187,91 +186,69 @@ theorem neighborFinset_disjoint_singleton : Disjoint (G.neighborFinset v) {v} := theorem singleton_disjoint_neighborFinset : Disjoint {v} (G.neighborFinset v) := Finset.disjoint_singleton_left.mpr <| notMem_neighborFinset_self _ _ -/-- `G.edegree v` is the number of vertices adjacent to `v`, or `⊤` if there are infinitely many -/ -noncomputable def edegree : ℕ∞ := - G.neighborSet v |>.encard - -/-- `G.degree v` is the number of vertices adjacent to `v`, or `0` if there are infinitely many -/ -noncomputable def degree : ℕ := - G.neighborSet v |>.ncard +/-- `G.degree v` is the number of vertices adjacent to `v`. -/ +def degree : ℕ := #(G.neighborFinset v) @[simp] -theorem card_neighborFinset_eq_degree : #(G.neighborFinset v) = G.degree v := - Set.ncard_eq_toFinset_card' _ |>.symm +theorem card_neighborFinset_eq_degree : #(G.neighborFinset v) = G.degree v := rfl @[simp] theorem card_neighborSet_eq_degree : Fintype.card (G.neighborSet v) = G.degree v := - Set.ncard_eq_fintypeCard _ |>.symm + (Set.toFinset_card _).symm -omit [Fintype <| G.neighborSet v] in -theorem degree_pos_iff_exists_adj [Finite <| G.neighborSet v] : 0 < G.degree v ↔ ∃ w, G.Adj v w := - Set.ncard_pos +theorem degree_pos_iff_exists_adj : 0 < G.degree v ↔ ∃ w, G.Adj v w := by + simp only [degree, card_pos, Finset.Nonempty, mem_neighborFinset] -omit [Fintype <| G.neighborSet v] in variable {G v} in -theorem degree_pos_iff_nonempty [Finite <| G.neighborSet v] : - 0 < G.degree v ↔ (G.neighborSet v).Nonempty := +theorem degree_pos_iff_nonempty : 0 < G.degree v ↔ (G.neighborSet v).Nonempty := G.degree_pos_iff_exists_adj v -omit [Fintype <| G.neighborSet v] in variable {G v} in -theorem Adj.degree_pos_left [Finite <| G.neighborSet v] {w : V} (h : G.Adj v w) : 0 < G.degree v := +theorem Adj.degree_pos_left {w : V} (h : G.Adj v w) : 0 < G.degree v := G.degree_pos_iff_nonempty.mpr ⟨_, h⟩ -omit [Fintype <| G.neighborSet v] in variable {G v} in -theorem Adj.degree_pos_right [Finite <| G.neighborSet v] {w : V} (h : G.Adj w v) : 0 < G.degree v := +theorem Adj.degree_pos_right {w : V} (h : G.Adj w v) : 0 < G.degree v := h.symm.degree_pos_left -omit [Fintype <| G.neighborSet v] in -theorem degree_pos_iff_mem_support [Finite <| G.neighborSet v] : - 0 < G.degree v ↔ v ∈ G.support := by +theorem degree_pos_iff_mem_support : 0 < G.degree v ↔ v ∈ G.support := by rw [G.degree_pos_iff_exists_adj v, mem_support] -omit [Fintype <| G.neighborSet v] in -theorem degree_eq_zero_iff_notMem_support [Finite <| G.neighborSet v] : - G.degree v = 0 ↔ v ∉ G.support := by +theorem degree_eq_zero_iff_notMem_support : G.degree v = 0 ↔ v ∉ G.support := by rw [← G.degree_pos_iff_mem_support v, Nat.pos_iff_ne_zero, not_ne_iff] -variable {G} in @[simp] -theorem degree_eq_zero_of_subsingleton (v : V) [Subsingleton V] : G.degree v = 0 := by +theorem degree_eq_zero_of_subsingleton {G : SimpleGraph V} (v : V) [Fintype (G.neighborSet v)] + [Subsingleton V] : G.degree v = 0 := by have := G.degree_pos_iff_exists_adj v simp_all [subsingleton_iff_forall_eq v] -omit [Fintype <| G.neighborSet v] in -variable {G} in -theorem degree_eq_one_iff_existsUnique_adj {v : V} : G.degree v = 1 ↔ ∃! w : V, G.Adj v w := by - rw [degree, Set.ncard_eq_one, Set.singleton_iff_unique_mem] - rfl +theorem degree_eq_one_iff_existsUnique_adj {G : SimpleGraph V} {v : V} [Fintype (G.neighborSet v)] : + G.degree v = 1 ↔ ∃! w : V, G.Adj v w := by + rw [degree, Finset.card_eq_one, Finset.singleton_iff_unique_mem] + simp only [mem_neighborFinset] -variable {G} in -theorem nontrivial_of_degree_ne_zero {v : V} (h : G.degree v ≠ 0) : Nontrivial V := by +theorem nontrivial_of_degree_ne_zero {G : SimpleGraph V} {v : V} [Fintype (G.neighborSet v)] + (h : G.degree v ≠ 0) : Nontrivial V := by by_contra! simp_all [degree_eq_zero_of_subsingleton] -omit [Fintype <| G.neighborSet v] in -theorem degree_compl [Fintype V] : Gᶜ.degree v = Fintype.card V - 1 - G.degree v := by +theorem degree_compl [Fintype (Gᶜ.neighborSet v)] [Fintype V] : + Gᶜ.degree v = Fintype.card V - 1 - G.degree v := by classical - have := Fintype.ofFinite <| G.neighborSet v - have := Fintype.ofFinite <| Gᶜ.neighborSet v - 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))] + 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))] instance incidenceSetFintype [DecidableEq V] : Fintype (G.incidenceSet v) := Fintype.ofEquiv (G.neighborSet v) (G.incidenceSetEquivNeighborSet v).symm -omit [Fintype <| G.neighborSet v] in /-- This is the `Finset` version of `incidenceSet`. -/ -def incidenceFinset [Fintype <| G.incidenceSet v] : Finset (Sym2 V) := +def incidenceFinset [DecidableEq V] : Finset (Sym2 V) := (G.incidenceSet v).toFinset -omit [Fintype <| G.neighborSet v] in @[simp] -theorem card_incidenceSet_eq_degree [Fintype <| G.incidenceSet v] : +theorem card_incidenceSet_eq_degree [DecidableEq V] : Fintype.card (G.incidenceSet v) = G.degree v := by - classical - have := Fintype.ofEquiv _ <| G.incidenceSetEquivNeighborSet v rw [Fintype.card_congr (G.incidenceSetEquivNeighborSet v)] simp @@ -280,45 +257,38 @@ theorem coe_incidenceFinset [DecidableEq V] : (G.incidenceFinset v : Set (Sym2 V)) = G.incidenceSet v := by simp [incidenceFinset] -omit [Fintype <| G.neighborSet v] in @[simp] -theorem card_incidenceFinset_eq_degree [Fintype <| G.incidenceSet v] : - #(G.incidenceFinset v) = G.degree v := by +theorem card_incidenceFinset_eq_degree [DecidableEq V] : #(G.incidenceFinset v) = G.degree v := by rw [← G.card_incidenceSet_eq_degree] apply Set.toFinset_card -omit [Fintype <| G.neighborSet v] in @[simp] -theorem mem_incidenceFinset [Fintype <| G.incidenceSet v] (e : Sym2 V) : +theorem mem_incidenceFinset [DecidableEq V] (e : Sym2 V) : e ∈ G.incidenceFinset v ↔ e ∈ G.incidenceSet v := Set.mem_toFinset -omit [Fintype <| G.neighborSet v] in -theorem incidenceFinset_eq_filter [DecidableEq V] [Fintype <| G.incidenceSet v] - [Fintype G.edgeSet] : G.incidenceFinset v = {e ∈ G.edgeFinset | v ∈ e} := by +theorem incidenceFinset_eq_filter [DecidableEq V] [Fintype G.edgeSet] : + G.incidenceFinset v = {e ∈ G.edgeFinset | v ∈ e} := by ext e induction e simp [mk'_mem_incidenceSet_iff] -omit [Fintype <| G.neighborSet v] in -theorem incidenceFinset_subset [Fintype <| G.incidenceSet v] [Fintype G.edgeSet] : +theorem incidenceFinset_subset [DecidableEq V] [Fintype G.edgeSet] : G.incidenceFinset v ⊆ G.edgeFinset := Set.toFinset_subset_toFinset.mpr (G.incidenceSet_subset v) -omit [Fintype <| G.neighborSet v] in /-- The degree of a vertex is at most the number of edges. -/ -theorem degree_le_card_edgeFinset [Fintype G.edgeSet] : G.degree v ≤ #G.edgeFinset := by - have := @Fintype.ofFinite _ <| Finite.Set.subset _ <| G.incidenceSet_subset v - exact G.card_incidenceFinset_eq_degree v ▸ card_le_card (G.incidenceFinset_subset v) +theorem degree_le_card_edgeFinset [Fintype G.edgeSet] : + G.degree v ≤ #G.edgeFinset := by + classical + rw [← card_incidenceFinset_eq_degree] + exact card_le_card (G.incidenceFinset_subset v) variable {G v} -omit [Fintype <| G.neighborSet v] in /-- If `G ≤ H` then `G.degree v ≤ H.degree v` for any vertex `v`. -/ -lemma degree_le_of_le {H : SimpleGraph V} [Finite <| H.neighborSet v] (hle : G ≤ H) : +lemma degree_le_of_le {H : SimpleGraph V} [Fintype (H.neighborSet v)] (hle : G ≤ H) : G.degree v ≤ H.degree v := by - have := Fintype.ofFinite <| H.neighborSet v - have := (Set.toFinite _ |>.subset <| neighborSet_mono hle v).fintype simp_rw [← card_neighborSet_eq_degree] exact Set.card_le_card fun v hv => hle hv @@ -330,20 +300,21 @@ section LocallyFinite abbrev LocallyFinite := ∀ v : V, Fintype (G.neighborSet v) -/-- A simple graph is regular of degree `d` if every vertex has degree `d`. -/ +variable [LocallyFinite G] + +/-- A locally finite simple graph is regular of degree `d` if every vertex has degree `d`. -/ def IsRegularOfDegree (d : ℕ) : Prop := - ∀ v : V, G.edegree v = d + ∀ v : V, G.degree v = d variable {G} theorem IsRegularOfDegree.degree_eq {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : G.degree v = d := - congrArg _ <| h v + h v -theorem IsRegularOfDegree.compl [Fintype V] {k : ℕ} (h : G.IsRegularOfDegree k) : - Gᶜ.IsRegularOfDegree (Fintype.card V - 1 - k) := by +theorem IsRegularOfDegree.compl [Fintype V] [DecidableEq V] {G : SimpleGraph V} [DecidableRel G.Adj] + {k : ℕ} (h : G.IsRegularOfDegree k) : Gᶜ.IsRegularOfDegree (Fintype.card V - 1 - k) := by intro v - have : Gᶜ.degree v = Gᶜ.edegree v := ENat.coe_toNat <| Set.encard_ne_top_iff.mpr <| Set.toFinite _ - rw [← this, degree_compl, h.degree_eq] + rw [degree_compl, h v] end LocallyFinite @@ -361,83 +332,74 @@ instance neighborSetFintype [DecidableRel G.Adj] (v : V) : Fintype (G.neighborSe theorem neighborFinset_eq_filter {v : V} [DecidableRel G.Adj] : G.neighborFinset v = ({w | G.Adj v w} : Finset _) := by ext; simp -theorem neighborFinset_compl [DecidableEq V] (v : V) [Fintype <| G.neighborSet v] - [Fintype <| Gᶜ.neighborSet v] : Gᶜ.neighborFinset v = (G.neighborFinset v)ᶜ \ {v} := by - classical +theorem neighborFinset_compl [DecidableEq V] [DecidableRel G.Adj] (v : V) : + Gᶜ.neighborFinset v = (G.neighborFinset v)ᶜ \ {v} := by simp only [neighborFinset, neighborSet_compl, Set.toFinset_diff, Set.toFinset_compl, Set.toFinset_singleton] @[simp] -theorem complete_graph_degree (v : V) : degree ⊤ v = Fintype.card V - 1 := by - classical - simp_rw [← card_neighborFinset_eq_degree, neighborFinset_eq_filter, top_adj, filter_ne] +theorem complete_graph_degree [DecidableEq V] (v : V) : + (completeGraph V).degree v = Fintype.card V - 1 := by + simp_rw [degree, neighborFinset_eq_filter, top_adj, filter_ne] rw [card_erase_of_mem (mem_univ v), card_univ] -omit [Fintype V] in @[simp] -theorem bot_degree (v : V) : degree ⊥ v = 0 := by - simp [degree, neighborSet] - -theorem IsRegularOfDegree.top : (⊤ : SimpleGraph V).IsRegularOfDegree (Fintype.card V - 1) := by - intro v - have : degree ⊤ v = edegree ⊤ v := ENat.coe_toNat <| Set.encard_ne_top_iff.mpr <| Set.toFinite _ - simp [← this] +theorem bot_degree (v : V) : (⊥ : SimpleGraph V).degree v = 0 := by + simp_rw [degree, neighborFinset_eq_filter, bot_adj, filter_false] + exact Finset.card_empty -omit [Fintype V] in -theorem IsRegularOfDegree.bot : (⊥ : SimpleGraph V).IsRegularOfDegree 0 := by +theorem IsRegularOfDegree.top [DecidableEq V] : + (⊤ : SimpleGraph V).IsRegularOfDegree (Fintype.card V - 1) := by intro v - have : degree ⊥ v = edegree ⊥ v := ENat.coe_toNat <| Set.encard_ne_top_iff.mpr Set.finite_empty - simp [← this] - -/-- The minimum extended degree of all vertices (and `⊤` if there are no vertices) -/ -noncomputable def eminDegree : ℕ∞ := - ⨅ v, G.edegree v + simp /-- The minimum degree of all vertices (and `0` if there are no vertices). The key properties of this are given in `exists_minimal_degree_vertex`, `minDegree_le_degree` and `le_minDegree_of_forall_le_degree`. -/ -noncomputable def minDegree : ℕ := - G.eminDegree.toNat +def minDegree [DecidableRel G.Adj] : ℕ := + WithTop.untopD 0 (univ.image fun v => G.degree v).min -omit [Fintype V] in /-- There exists a vertex of minimal degree. Note the assumption of being nonempty is necessary, as the lemma implies there exists a vertex. -/ -theorem exists_minimal_degree_vertex [Nonempty V] : ∃ v, G.minDegree = G.degree v := by - have ⟨v, hv⟩ := ciInf_mem G.edegree - exact ⟨v, congrArg _ hv.symm⟩ +theorem exists_minimal_degree_vertex [DecidableRel G.Adj] [Nonempty V] : + ∃ v, G.minDegree = G.degree v := by + obtain ⟨t, ht : _ = _⟩ := min_of_nonempty (univ_nonempty.image fun v => G.degree v) + obtain ⟨v, _, rfl⟩ := mem_image.mp (mem_of_min ht) + exact ⟨v, by simp [minDegree, ht]⟩ -omit [Fintype V] in /-- The minimum degree in the graph is at most the degree of any particular vertex. -/ -theorem minDegree_le_degree (v : V) [Finite <| G.neighborSet v] : G.minDegree ≤ G.degree v := - ENat.toNat_le_toNat (iInf_le ..) (Set.encard_ne_top_iff.mpr ‹_›) +theorem minDegree_le_degree [DecidableRel G.Adj] (v : V) : G.minDegree ≤ G.degree v := by + obtain ⟨t, ht⟩ := Finset.min_of_mem (mem_image_of_mem (fun v => G.degree v) (mem_univ v)) + have := Finset.min_le_of_eq (mem_image_of_mem _ (mem_univ v)) ht + rwa [minDegree, ht] -omit [Fintype V] in /-- In a nonempty graph, if `k` is at most the degree of every vertex, it is at most the minimum degree. Note the assumption that the graph is nonempty is necessary as long as `G.minDegree` is defined to be a natural. -/ -theorem le_minDegree_of_forall_le_degree [Nonempty V] (k : ℕ) (h : ∀ v, k ≤ G.degree v) : - k ≤ G.minDegree := by - have ⟨v, hv⟩ := G.exists_minimal_degree_vertex - exact hv ▸ h v +theorem le_minDegree_of_forall_le_degree [DecidableRel G.Adj] [Nonempty V] (k : ℕ) + (h : ∀ v, k ≤ G.degree v) : k ≤ G.minDegree := by + rcases G.exists_minimal_degree_vertex with ⟨v, hv⟩ + rw [hv] + apply h -omit [Fintype V] in /-- If there are no vertices then the `minDegree` is zero. -/ @[simp] -lemma minDegree_of_isEmpty [IsEmpty V] : G.minDegree = 0 := - ENat.toNat_eq_zero.mpr <| .inr <| iInf_of_empty G.edegree +lemma minDegree_of_isEmpty [DecidableRel G.Adj] [IsEmpty V] : G.minDegree = 0 := by + rw [minDegree, WithTop.untopD_eq_self_iff] + simp -omit [Fintype V] in +variable {G} in /-- If `G` is a subgraph of `H` then `G.minDegree ≤ H.minDegree`. -/ -lemma minDegree_le_minDegree [Finite V] {G H : SimpleGraph V} (hle : G ≤ H) : - G.minDegree ≤ H.minDegree := by +lemma minDegree_le_minDegree {H : SimpleGraph V} [DecidableRel G.Adj] [DecidableRel H.Adj] + (hle : G ≤ H) : G.minDegree ≤ H.minDegree := by by_cases! hne : Nonempty V · apply le_minDegree_of_forall_le_degree exact fun v ↦ (G.minDegree_le_degree v).trans (G.degree_le_of_le hle) · simp /-- In a nonempty graph, the minimal degree is less than the number of vertices. -/ -theorem minDegree_lt_card [Nonempty V] : G.minDegree < Fintype.card V := by - classical +theorem minDegree_lt_card [DecidableRel G.Adj] [Nonempty V] : + G.minDegree < Fintype.card V := by obtain ⟨v, hδ⟩ := G.exists_minimal_degree_vertex rw [hδ, ← card_neighborFinset_eq_degree, ← card_univ] have h : v ∉ G.neighborFinset v := @@ -446,109 +408,106 @@ theorem minDegree_lt_card [Nonempty V] : G.minDegree < Fintype.card V := by rw [eq_of_subset_of_card_le (subset_univ _) h] exact mem_univ v -/-- The maximum extended degree of all vertices (and `0` if there are no vertices) -/ -noncomputable def emaxDegree : ℕ∞ := - ⨆ v, G.edegree v - /-- The maximum degree of all vertices (and `0` if there are no vertices). The key properties of this are given in `exists_maximal_degree_vertex`, `degree_le_maxDegree` and `maxDegree_le_of_forall_degree_le`. -/ -noncomputable def maxDegree : ℕ := - G.emaxDegree.toNat +def maxDegree [DecidableRel G.Adj] : ℕ := + WithBot.unbotD 0 (univ.image fun v => G.degree v).max -omit [Fintype V] in /-- There exists a vertex of maximal degree. Note the assumption of being nonempty is necessary, as the lemma implies there exists a vertex. -/ -theorem exists_maximal_degree_vertex [Nonempty V] [Finite V] : ∃ v, G.maxDegree = G.degree v := by - have ⟨v, hv⟩ := Set.range_nonempty G.edegree |>.csSup_mem <| Set.finite_range _ - refine ⟨v, congrArg _ hv.symm⟩ +theorem exists_maximal_degree_vertex [DecidableRel G.Adj] [Nonempty V] : + ∃ v, G.maxDegree = G.degree v := by + obtain ⟨t, ht⟩ := max_of_nonempty (univ_nonempty.image fun v => G.degree v) + have ht₂ := mem_of_max ht + simp only [mem_image, mem_univ, true_and] at ht₂ + rcases ht₂ with ⟨v, rfl⟩ + refine ⟨v, ?_⟩ + rw [maxDegree, ht, WithBot.unbotD_coe] -omit [Fintype V] in /-- The maximum degree in the graph is at least the degree of any particular vertex. -/ -theorem degree_le_maxDegree [Finite V] (v : V) : G.degree v ≤ G.maxDegree := by - refine ENat.toNat_le_toNat (le_iSup G.edegree v) ?_ - exact iSup_ne_top fun _ ↦ Set.encard_ne_top_iff.mpr <| Set.toFinite _ +theorem degree_le_maxDegree [DecidableRel G.Adj] (v : V) : G.degree v ≤ G.maxDegree := by + obtain ⟨t, ht : _ = _⟩ := Finset.max_of_mem (mem_image_of_mem (fun v => G.degree v) (mem_univ v)) + have := Finset.le_max_of_eq (mem_image_of_mem _ (mem_univ v)) ht + rwa [maxDegree, ht, WithBot.unbotD_coe] -omit [Fintype V] in @[simp] -lemma maxDegree_of_isEmpty [IsEmpty V] : G.maxDegree = 0 := - ENat.toNat_eq_zero.mpr <| .inl <| iSup_of_empty G.edegree +lemma maxDegree_of_isEmpty [DecidableRel G.Adj] [IsEmpty V] : G.maxDegree = 0 := by + rw [maxDegree, univ_eq_empty, image_empty, max_empty, WithBot.unbotD_bot] -omit [Fintype V] in /-- In a graph, if `k` is at least the degree of every vertex, then it is at least the maximum degree. -/ -theorem maxDegree_le_of_forall_degree_le (k : ℕ) (h : ∀ v, G.degree v ≤ k) : G.maxDegree ≤ k := by - by_cases! htop : ∃ v, G.edegree v = ⊤ - · have ⟨v, hv⟩ := htop - exact top_unique (hv ▸ le_iSup G.edegree v) ▸ ENat.toNat_top |>.trans_le <| by simp - exact ENat.toNat_le_of_le_coe <| iSup_le ((WithTop.untopD_le_iff <| htop _).mp <| h ·) +theorem maxDegree_le_of_forall_degree_le [DecidableRel G.Adj] (k : ℕ) (h : ∀ v, G.degree v ≤ k) : + G.maxDegree ≤ k := by + by_cases! hV : IsEmpty V + · simp + · obtain ⟨_, hv⟩ := G.exists_maximal_degree_vertex + exact hv ▸ h _ -omit [Fintype V] in @[simp] lemma maxDegree_bot_eq_zero : (⊥ : SimpleGraph V).maxDegree = 0 := Nat.le_zero.1 <| maxDegree_le_of_forall_degree_le _ _ (by simp) -omit [Fintype V] in @[simp] -lemma minDegree_le_maxDegree [Finite V] : G.minDegree ≤ G.maxDegree := by +lemma minDegree_le_maxDegree [DecidableRel G.Adj] : G.minDegree ≤ G.maxDegree := by by_cases! he : IsEmpty V · simp · exact he.elim fun v ↦ (minDegree_le_degree _ v).trans (degree_le_maxDegree _ v) -omit [Fintype V] in @[simp] -lemma minDegree_bot_eq_zero : (⊥ : SimpleGraph V).minDegree = 0 := by - cases isEmpty_or_nonempty V - · exact minDegree_of_isEmpty _ - have ⟨v, hv⟩ := (⊥ : SimpleGraph V).exists_minimal_degree_vertex - exact hv ▸ bot_degree v +lemma minDegree_bot_eq_zero : (⊥ : SimpleGraph V).minDegree = 0 := + Nat.le_zero.1 <| (minDegree_le_maxDegree _).trans (by simp) -theorem degree_lt_card_verts (v : V) : G.degree v < Fintype.card V := by - rw [Fintype.card_eq_nat_card] - exact Set.ncard_lt_card <| Set.ne_univ_iff_exists_notMem _ |>.mpr ⟨v, G.notMem_neighborSet_self⟩ +theorem degree_lt_card_verts [DecidableRel G.Adj] (v : V) : G.degree v < Fintype.card V := by + classical + apply Finset.card_lt_card + rw [Finset.ssubset_iff] + exact ⟨v, by simp, Finset.subset_univ _⟩ /-- The maximum degree of a nonempty graph is less than the number of vertices. Note that the assumption that `V` is nonempty is necessary, as otherwise this would assert the existence of a natural number less than zero. -/ -theorem maxDegree_lt_card_verts [Nonempty V] : G.maxDegree < Fintype.card V := by - have ⟨v, hv⟩ := G.exists_maximal_degree_vertex - exact hv ▸ G.degree_lt_card_verts v - -omit [Fintype V] in -theorem card_commonNeighbors_le_degree_left (v w : V) [Fintype <| G.commonNeighbors v w] - [Finite <| G.neighborSet v] : Fintype.card (G.commonNeighbors v w) ≤ G.degree v := by - have := Fintype.ofFinite <| G.neighborSet v +theorem maxDegree_lt_card_verts [DecidableRel G.Adj] [Nonempty V] : + G.maxDegree < Fintype.card V := by + obtain ⟨v, hv⟩ := G.exists_maximal_degree_vertex + rw [hv] + apply G.degree_lt_card_verts v + +theorem card_commonNeighbors_le_degree_left [DecidableRel G.Adj] (v w : V) : + Fintype.card (G.commonNeighbors v w) ≤ G.degree v := by rw [← card_neighborSet_eq_degree] exact Set.card_le_card Set.inter_subset_left -omit [Fintype V] in -theorem card_commonNeighbors_le_degree_right (v w : V) [Fintype <| G.commonNeighbors v w] - [Finite <| G.neighborSet w] : Fintype.card (G.commonNeighbors v w) ≤ G.degree w := by - have := Fintype.ofFinite <| G.neighborSet w - rw [← card_neighborSet_eq_degree] - exact Set.card_le_card Set.inter_subset_right +theorem card_commonNeighbors_le_degree_right [DecidableRel G.Adj] (v w : V) : + Fintype.card (G.commonNeighbors v w) ≤ G.degree w := by + simp_rw [commonNeighbors_symm _ v w, card_commonNeighbors_le_degree_left] -theorem card_commonNeighbors_lt_card_verts (v w : V) [Fintype <| G.commonNeighbors v w] : +theorem card_commonNeighbors_lt_card_verts [DecidableRel G.Adj] (v w : V) : Fintype.card (G.commonNeighbors v w) < Fintype.card V := Nat.lt_of_le_of_lt (G.card_commonNeighbors_le_degree_left _ _) (G.degree_lt_card_verts v) -omit [Fintype V] in -variable {G} in /-- If the condition `G.Adj v w` fails, then `card_commonNeighbors_le_degree` is the best we can do in general. -/ -theorem Adj.card_commonNeighbors_lt_degree {v w : V} [Fintype <| G.commonNeighbors v w] - [Finite <| G.neighborSet v] (h : G.Adj v w) : - Fintype.card (G.commonNeighbors v w) < G.degree v := by - have := Fintype.ofFinite <| G.neighborSet v - rw [← card_neighborSet_eq_degree] - refine Set.card_lt_card <| Set.ssubset_iff_exists.mpr ⟨Set.inter_subset_left, w, h, ?_⟩ - exact G.notMem_commonNeighbors_right v w - -theorem card_commonNeighbors_top {v w : V} (h : v ≠ w) [Fintype <| commonNeighbors ⊤ v w] : - Fintype.card ((⊤ : SimpleGraph V).commonNeighbors v w) = Fintype.card V - 2 := by +theorem Adj.card_commonNeighbors_lt_degree {G : SimpleGraph V} [DecidableRel G.Adj] {v w : V} + (h : G.Adj v w) : Fintype.card (G.commonNeighbors v w) < G.degree v := by classical - simp only [commonNeighbors_top_eq, ← Set.toFinset_card] + rw [← Set.toFinset_card] + apply Finset.card_lt_card + rw [Finset.ssubset_iff] + use w + constructor + · rw [Set.mem_toFinset] + apply notMem_commonNeighbors_right + · rw [Finset.insert_subset_iff] + constructor + · simpa + · rw [neighborFinset, Set.toFinset_subset_toFinset] + exact G.commonNeighbors_subset_neighborSet_left _ _ + +theorem card_commonNeighbors_top [DecidableEq V] {v w : V} (h : v ≠ w) : + Fintype.card ((⊤ : SimpleGraph V).commonNeighbors v w) = Fintype.card V - 2 := by + simp only [commonNeighbors_top_eq, ← Set.toFinset_card, Set.toFinset_diff] simp [Finset.card_sdiff, h] end Finite @@ -563,73 +522,86 @@ theorem card_edgeFinset_eq (f : G ≃g G') [Fintype G.edgeSet] [Fintype G'.edgeS simp only [mem_edgeFinset] exact f.mapEdgeSet -@[simp] -theorem degree_eq (f : G ≃g G') (x : V) : G'.degree (f x) = G.degree x := - Set.ncard_congr' <| mapNeighborSet f x |>.symm - -theorem minDegree_eq (f : G ≃g G') : G.minDegree = G'.minDegree := - congrArg ENat.toNat <| f.surjective.iInf_congr f (Set.encard_congr <| mapNeighborSet f · |>.symm) - -theorem maxDegree_eq (f : G ≃g G') : G.maxDegree = G'.maxDegree := - congrArg ENat.toNat <| f.surjective.iSup_congr f (Set.encard_congr <| mapNeighborSet f · |>.symm) +@[simp] theorem degree_eq (f : G ≃g G') (x : V) + [Fintype ↑(G.neighborSet x)] [Fintype ↑(G'.neighborSet (f x))] : + G'.degree (f x) = G.degree x := by + rw [← card_neighborSet_eq_degree, ← card_neighborSet_eq_degree, + ← Fintype.card_congr (mapNeighborSet f x).symm] + +variable [Fintype V] [DecidableRel G.Adj] [Fintype W] [DecidableRel G'.Adj] + +theorem minDegree_eq (f : G ≃g G') : G.minDegree = G'.minDegree := by + rcases isEmpty_or_nonempty V + · simp [f.symm.isEmpty] + · have : Nonempty W := f.symm.nonempty + apply le_antisymm + · obtain ⟨x', hx'⟩ := exists_minimal_degree_vertex G' + simpa only [hx', ← degree_eq f.symm x'] using minDegree_le_degree G (f.symm x') + · obtain ⟨x, hx⟩ := exists_minimal_degree_vertex G + simpa only [hx, ← degree_eq f x] using minDegree_le_degree G' (f x) + +theorem maxDegree_eq (f : G ≃g G') : G.maxDegree = G'.maxDegree := by + rcases isEmpty_or_nonempty V + · simp [f.symm.isEmpty] + · have : Nonempty W := f.symm.nonempty + apply le_antisymm + · obtain ⟨x, hx⟩ := exists_maximal_degree_vertex G + simpa only [hx, ← degree_eq f x] using degree_le_maxDegree G' (f x) + · obtain ⟨x', hx'⟩ := exists_maximal_degree_vertex G' + simpa only [hx', ← degree_eq f.symm x'] using degree_le_maxDegree G (f.symm x') end Iso section Support -variable {s : Set V} {G} +variable {s : Set V} [DecidablePred (· ∈ s)] [Fintype V] {G : SimpleGraph V} [DecidableRel G.Adj] -lemma edgeFinset_subset_sym2_of_support_subset [Fintype G.edgeSet] [Fintype s] (h : G.support ⊆ s) : +lemma edgeFinset_subset_sym2_of_support_subset (h : G.support ⊆ s) : G.edgeFinset ⊆ s.toFinset.sym2 := by simp_rw [subset_iff, Sym2.forall, mem_edgeFinset, mem_edgeSet, mk_mem_sym2_iff, Set.mem_toFinset] intro _ _ hadj exact ⟨h ⟨_, hadj⟩, h ⟨_, hadj.symm⟩⟩ -instance [Fintype V] [DecidableRel G.Adj] : DecidablePred (· ∈ G.support) := +instance : DecidablePred (· ∈ G.support) := inferInstanceAs <| DecidablePred (· ∈ { v | ∃ w, G.Adj v w }) -theorem map_edgeFinset_induce [DecidableEq V] [Fintype G.edgeSet] [Fintype (G.induce s).edgeSet] - [Fintype s] : - (G.induce s).edgeFinset.map (Embedding.subtype (· ∈ s)).sym2Map = G.edgeFinset ∩ s.toFinset.sym2 - := by +theorem map_edgeFinset_induce [DecidableEq V] : + (G.induce s).edgeFinset.map (Embedding.subtype (· ∈ s)).sym2Map + = G.edgeFinset ∩ s.toFinset.sym2 := by aesop (add simp [Finset.ext_iff, Sym2.exists, Sym2.forall, adj_comm]) -theorem map_edgeFinset_induce_of_support_subset [Fintype G.edgeSet] [Fintype (G.induce s).edgeSet] - [Finite s] (h : G.support ⊆ s) : +theorem map_edgeFinset_induce_of_support_subset (h : G.support ⊆ s) : (G.induce s).edgeFinset.map (Embedding.subtype (· ∈ s)).sym2Map = G.edgeFinset := by classical - have := Fintype.ofFinite s simpa [map_edgeFinset_induce] using edgeFinset_subset_sym2_of_support_subset h /-- If the support of the simple graph `G` is a subset of the set `s`, then the induced subgraph of `s` has the same number of edges as `G`. -/ -theorem card_edgeFinset_induce_of_support_subset [Fintype G.edgeSet] [Fintype (G.induce s).edgeSet] - [Finite s] (h : G.support ⊆ s) : #(G.induce s).edgeFinset = #G.edgeFinset := by +theorem card_edgeFinset_induce_of_support_subset (h : G.support ⊆ s) : + #(G.induce s).edgeFinset = #G.edgeFinset := by rw [← map_edgeFinset_induce_of_support_subset h, card_map] -theorem card_edgeFinset_induce_support [Fintype G.edgeSet] [Fintype (G.induce G.support).edgeSet] - [Finite G.support] : #(G.induce G.support).edgeFinset = #G.edgeFinset := +theorem card_edgeFinset_induce_support : + #(G.induce G.support).edgeFinset = #G.edgeFinset := card_edgeFinset_induce_of_support_subset subset_rfl -theorem map_neighborFinset_induce [DecidableEq V] (v : s) [Fintype <| G.neighborSet v] - [Fintype <| (induce s G).neighborSet v] [Fintype s] : +theorem map_neighborFinset_induce [DecidableEq V] (v : s) : ((G.induce s).neighborFinset v).map (.subtype (· ∈ s)) = G.neighborFinset v ∩ s.toFinset := by ext; simp -theorem map_neighborFinset_induce_of_neighborSet_subset {v : s} [Fintype <| G.neighborSet v] - [Fintype <| (induce s G).neighborSet v] [Finite s] (h : G.neighborSet v ⊆ s) : +theorem map_neighborFinset_induce_of_neighborSet_subset {v : s} (h : G.neighborSet v ⊆ s) : ((G.induce s).neighborFinset v).map (.subtype s) = G.neighborFinset v := by classical - have := Fintype.ofFinite s rwa [← Set.toFinset_subset_toFinset, ← neighborFinset_def, ← inter_eq_left, ← map_neighborFinset_induce v] at h /-- If the neighbor set of a vertex `v` is a subset of `s`, then the degree of the vertex in the induced subgraph of `s` is the same as in `G`. -/ theorem degree_induce_of_neighborSet_subset {v : s} (h : G.neighborSet v ⊆ s) : - (G.induce s).degree v = G.degree v := - Set.ncard_congr' <| .mk (fun u ↦ ⟨u, u.prop⟩) (fun u ↦ ⟨⟨u, h u.prop⟩, u.prop⟩) + (G.induce s).degree v = G.degree v := by + simp_rw [← card_neighborFinset_eq_degree, + ← map_neighborFinset_induce_of_neighborSet_subset h, card_map] /-- If the support of the simple graph `G` is a subset of the set `s`, then the degree of vertices in the induced subgraph of `s` are the same as in `G`. -/ @@ -646,16 +618,17 @@ end Support section Map -variable {W : Type*} (f : V ↪ W) (G : SimpleGraph V) [Fintype G.edgeSet] [Fintype (G.map f).edgeSet] +variable [Fintype V] {W : Type*} [Fintype W] [DecidableEq W] @[simp] -theorem edgeFinset_map : (G.map f).edgeFinset = G.edgeFinset.map f.sym2Map := by - classical +theorem edgeFinset_map (f : V ↪ W) (G : SimpleGraph V) [DecidableRel G.Adj] : + (G.map f).edgeFinset = G.edgeFinset.map f.sym2Map := by rw [← Finset.coe_inj] push_cast exact G.edgeSet_map f -theorem card_edgeFinset_map : #(G.map f).edgeFinset = #G.edgeFinset := by +theorem card_edgeFinset_map (f : V ↪ W) (G : SimpleGraph V) [DecidableRel G.Adj] : + #(G.map f).edgeFinset = #G.edgeFinset := by rw [edgeFinset_map] exact G.edgeFinset.card_map f.sym2Map diff --git a/Mathlib/Combinatorics/SimpleGraph/FiveWheelLike.lean b/Mathlib/Combinatorics/SimpleGraph/FiveWheelLike.lean index 2067d8e764dd95..60badadf343a1a 100644 --- a/Mathlib/Combinatorics/SimpleGraph/FiveWheelLike.lean +++ b/Mathlib/Combinatorics/SimpleGraph/FiveWheelLike.lean @@ -256,7 +256,7 @@ private lemma sum_degree_le_of_le_not_adj [Fintype α] [DecidableEq α] [Decidab (hxc : ∀ y ∈ Xᶜ, j ≤ #{z ∈ W | ¬ G.Adj y z}) : ∑ w ∈ W, G.degree w ≤ #X * (#W - i) + #Xᶜ * (#W - j) := calc _ = ∑ v, #(G.neighborFinset v ∩ W) := by - simp_rw [← card_neighborFinset_eq_degree, card_eq_sum_ones] + simp_rw [degree, card_eq_sum_ones] exact sum_comm' (by simp [and_comm, adj_comm]) _ ≤ _ := by simp_rw [← union_compl X, sum_union disjoint_compl_right (s₁ := X), neighborFinset_eq_filter, @@ -346,14 +346,12 @@ lemma exists_isFiveWheelLike_succ_of_not_adj_le_two (hW : ∀ ⦃y⦄, y ∈ s notMem_mono inter_subset_left hbs, erase_eq_of_notMem <| notMem_mono inter_subset_right hat, card_insert_of_notMem (fun h ↦ G.irrefl (hW h)), hw.card_inter] -omit [DecidableRel G.Adj] in /-- If `G` is a `Kᵣ₊₂`-free graph with `n` vertices containing a `Wᵣ,ₖ` but no `Wᵣ,ₖ₊₁` then `G.minDegree ≤ (2 * r + k) * n / (2 * r + k + 3)` -/ lemma minDegree_le_of_cliqueFree_fiveWheelLikeFree_succ [Fintype α] (hm : G.FiveWheelLikeFree r (k + 1)) : G.minDegree ≤ (2 * r + k) * ‖α‖ / (2 * r + k + 3) := by - classical let X : Finset α := {x | ∀ ⦃y⦄, y ∈ s ∩ t → G.Adj x y} let W := {v} ∪ ({w₁} ∪ ({w₂} ∪ (s ∪ t))) -- Any vertex in `X` has at least 3 non-neighbors in `W` (otherwise we could build a bigger wheel) @@ -417,8 +415,9 @@ If `G` is a `Kᵣ₊₁`-free graph with `n` vertices and `(3 * r - 4) * n / (3 then `G` is `r + 1`-colorable, e.g. if `G` is `K₃`-free and `2 * n / 5 < G.minDegree` then `G` is `2`-colorable. -/ -theorem colorable_of_cliqueFree_lt_minDegree [Fintype α] (hf : G.CliqueFree (r + 1)) - (hd : (3 * r - 4) * ‖α‖ / (3 * r - 1) < G.minDegree) : G.Colorable r := by +theorem colorable_of_cliqueFree_lt_minDegree [Fintype α] [DecidableRel G.Adj] + (hf : G.CliqueFree (r + 1)) (hd : (3 * r - 4) * ‖α‖ / (3 * r - 1) < G.minDegree) : + G.Colorable r := by match r with | 0 | 1 => aesop | r + 2 => diff --git a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean index 9e5683d4088073..7dce7be3752083 100644 --- a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean @@ -104,12 +104,11 @@ section NonAssocSemiring variable [NonAssocSemiring R] [DecidableEq α] [DecidableRel G.Adj] {a : α} {e : Sym2 α} -theorem sum_incMatrix_apply [Fintype (Sym2 α)] [Finite (neighborSet G a)] : +theorem sum_incMatrix_apply [Fintype (Sym2 α)] [Fintype (neighborSet G a)] : ∑ e, G.incMatrix R a e = G.degree a := by - have := Fintype.ofFinite <| neighborSet G a simp [incMatrix_apply', sum_boole, Set.filter_mem_univ_eq_toFinset] -theorem incMatrix_mul_transpose_diag [Fintype (Sym2 α)] [Finite (neighborSet G a)] : +theorem incMatrix_mul_transpose_diag [Fintype (Sym2 α)] [Fintype (neighborSet G a)] : (G.incMatrix R * (G.incMatrix R)ᵀ) a a = G.degree a := by rw [← sum_incMatrix_apply] simp only [mul_apply, incMatrix_apply', transpose_apply, mul_ite, mul_one, mul_zero] @@ -163,7 +162,7 @@ theorem incMatrix_mul_transpose_apply_of_adj (h : G.Adj a b) : rw [← coe_eq_singleton, coe_filter_univ] exact G.incidenceSet_inter_incidenceSet_of_adj h -theorem incMatrix_mul_transpose [∀ a, Finite (neighborSet G a)] : +theorem incMatrix_mul_transpose [∀ a, Fintype (neighborSet G a)] : G.incMatrix R * (G.incMatrix R)ᵀ = of fun a b => if a = b then (G.degree a : R) else if G.Adj a b then 1 else 0 := by ext a b diff --git a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean index 1e17863fb9c206..8ec675edaa9ce7 100644 --- a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean @@ -36,30 +36,26 @@ variable [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] theorem degree_eq_sum_if_adj {R : Type*} [AddCommMonoidWithOne R] (i : V) : (G.degree i : R) = ∑ j : V, if G.Adj i j then 1 else 0 := by - rw [← card_neighborFinset_eq_degree] - unfold neighborFinset neighborSet + unfold degree neighborFinset neighborSet rw [sum_boole, Set.toFinset_setOf] variable [DecidableEq V] /-- The diagonal matrix consisting of the degrees of the vertices in the graph. -/ -noncomputable def degMatrix [AddMonoidWithOne R] : Matrix V V R := Matrix.diagonal (G.degree ·) +def degMatrix [AddMonoidWithOne R] : Matrix V V R := Matrix.diagonal (G.degree ·) /-- The *Laplacian matrix* `lapMatrix G R` of a graph `G` is the matrix `L = D - A` where `D` is the degree and `A` the adjacency matrix of `G`. -/ -noncomputable def lapMatrix [AddGroupWithOne R] : Matrix V V R := G.degMatrix R - G.adjMatrix R +def lapMatrix [AddGroupWithOne R] : Matrix V V R := G.degMatrix R - G.adjMatrix R variable {R} -omit [Fintype V] [DecidableRel G.Adj] in theorem isSymm_degMatrix [AddMonoidWithOne R] : (G.degMatrix R).IsSymm := isSymm_diagonal _ -omit [Fintype V] in theorem isSymm_lapMatrix [AddGroupWithOne R] : (G.lapMatrix R).IsSymm := (isSymm_degMatrix _).sub (isSymm_adjMatrix _) -omit [DecidableRel G.Adj] in theorem degMatrix_mulVec_apply [NonAssocSemiring R] (v : V) (vec : V → R) : (G.degMatrix R *ᵥ vec) v = G.degree v * vec v := by rw [degMatrix, mulVec_diagonal] @@ -74,7 +70,6 @@ theorem lapMatrix_mulVec_const_eq_zero [NonAssocRing R] : rw [lapMatrix_mulVec_apply] simp -omit [DecidableRel G.Adj] in theorem dotProduct_mulVec_degMatrix [CommSemiring R] (x : V → R) : x ⬝ᵥ (G.degMatrix R *ᵥ x) = ∑ i : V, G.degree i * x i * x i := by simp only [dotProduct, degMatrix, mulVec_diagonal, ← mul_assoc, mul_comm] @@ -98,11 +93,9 @@ theorem lapMatrix_toLinearMap₂' [Field R] [CharZero R] (x : V → R) : congr 2 with j ring_nf -omit [Fintype V] in /-- The Laplacian matrix is positive semidefinite -/ theorem posSemidef_lapMatrix [Field R] [LinearOrder R] [IsStrictOrderedRing R] [StarRing R] - [TrivialStar R] [Finite V] : PosSemidef (G.lapMatrix R) := by - have := Fintype.ofFinite V + [TrivialStar R] : PosSemidef (G.lapMatrix R) := by refine .of_dotProduct_mulVec_nonneg ?_ (fun x ↦ ?_) · rw [IsHermitian, conjTranspose_eq_transpose_of_trivial, isSymm_lapMatrix] · rw [star_trivial, ← toLinearMap₂'_apply', lapMatrix_toLinearMap₂'] diff --git a/Mathlib/Combinatorics/SimpleGraph/Maps.lean b/Mathlib/Combinatorics/SimpleGraph/Maps.lean index 939958363cf331..a8ddc15a49e44d 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Maps.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Maps.lean @@ -320,11 +320,6 @@ theorem mapEdgeSet.injective (hinj : Function.Injective f) : Function.Injective repeat rw [Subtype.mk_eq_mk] apply Sym2.map.injective hinj -@[gcongr] -theorem _root_.SimpleGraph.neighborSet_mono (hle : G₁ ≤ G₂) (v : V) : - G₁.neighborSet v ⊆ G₂.neighborSet v := - fun _ h ↦ Hom.ofLE hle |>.apply_mem_neighborSet h - /-- Every graph homomorphism from a complete graph is injective. -/ theorem injective_of_top_hom (f : (⊤ : SimpleGraph V) →g G') : Function.Injective f := by intro v w h diff --git a/Mathlib/Combinatorics/SimpleGraph/Prod.lean b/Mathlib/Combinatorics/SimpleGraph/Prod.lean index 1b2567bc961252..e1cdd3727f6036 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Prod.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Prod.lean @@ -247,13 +247,9 @@ theorem neighborFinset_boxProd (x : α × β) exact Eq.trans (Finset.map_map _ _ _) Finset.attach_map_val theorem degree_boxProd (x : α × β) - [Finite (G.neighborSet x.1)] [Finite (H.neighborSet x.2)] [Finite ((G □ H).neighborSet x)] : + [Fintype (G.neighborSet x.1)] [Fintype (H.neighborSet x.2)] [Fintype ((G □ H).neighborSet x)] : (G □ H).degree x = G.degree x.1 + H.degree x.2 := by - have := Fintype.ofFinite <| G.neighborSet x.fst - have := Fintype.ofFinite <| H.neighborSet x.snd - have := Fintype.ofFinite <| (G □ H).neighborSet x - rw [← card_neighborFinset_eq_degree, ← card_neighborFinset_eq_degree, - ← card_neighborFinset_eq_degree, neighborFinset_boxProd, Finset.card_disjUnion] + rw [degree, degree, degree, neighborFinset_boxProd, Finset.card_disjUnion] simp_rw [Finset.card_product, Finset.card_singleton, mul_one, one_mul] lemma reachable_boxProd {x y : α × β} : diff --git a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean index 5a675615139dc3..f880d33e03b166 100644 --- a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean +++ b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean @@ -58,7 +58,7 @@ variable {G} {n k ℓ μ : ℕ} for empty graphs, since there are no pairs of adjacent vertices. -/ theorem bot_strongly_regular : (⊥ : SimpleGraph V).IsSRGWith (Fintype.card V) 0 ℓ 0 where card := rfl - regular := .bot + regular := bot_degree of_adj _ _ h := h.elim of_not_adj v w _ := by simp only [card_eq_zero, Fintype.card_ofFinset, forall_true_left, not_false_iff, bot_adj] @@ -78,7 +78,7 @@ theorem IsSRGWith.top : (⊤ : SimpleGraph V).IsSRGWith (Fintype.card V) (Fintype.card V - 1) (Fintype.card V - 2) μ where card := rfl regular := IsRegularOfDegree.top - of_adj _ _ h := card_commonNeighbors_top h + of_adj _ _ := card_commonNeighbors_top of_not_adj v w h h' := (h' ((top_adj v w).2 h)).elim theorem IsSRGWith.card_neighborFinset_union_eq {v w : V} (h : G.IsSRGWith n k ℓ μ) : @@ -115,7 +115,6 @@ theorem sdiff_compl_neighborFinset_inter_eq {v w : V} (h : G.Adj v w) : (G.neighborFinset v)ᶜ ∩ (G.neighborFinset w)ᶜ := by simpa using ⟨(adj_symm _ h), h⟩ -omit [DecidableEq V] in theorem IsSRGWith.compl_is_regular (h : G.IsSRGWith n k ℓ μ) : Gᶜ.IsRegularOfDegree (n - k - 1) := by rw [← h.card, Nat.sub_sub, add_comm, ← Nat.sub_sub] @@ -164,8 +163,8 @@ theorem IsSRGWith.param_eq rw [← h.card, Fintype.card_pos_iff] at hn obtain ⟨v⟩ := hn convert card_mul_eq_card_mul G.Adj (s := G.neighborFinset v) (t := Gᶜ.neighborFinset v) _ _ - · simp [h.regular.degree_eq v] - · simp [h.compl.regular.degree_eq v] + · simp [h.regular v] + · simp [h.compl.regular v] · intro w hw rw [mem_neighborFinset] at hw simp_rw [bipartiteAbove, ← mem_neighborFinset, filter_mem_eq_inter] @@ -176,7 +175,7 @@ theorem IsSRGWith.param_eq card_sdiff_of_subset s, card_singleton, ← sdiff_inter_self_left, card_sdiff_of_subset inter_subset_left] congr - · simp [h.regular.degree_eq w] + · simp [h.regular w] · simp_rw [inter_comm, neighborFinset_def, ← Set.toFinset_inter, ← h.of_adj v w hw, ← Set.toFinset_card] congr! @@ -200,7 +199,7 @@ theorem IsSRGWith.matrix_eq {α : Type*} [Semiring α] (h : G.IsSRGWith n k ℓ rw [Fintype.card_congr (G.walkLengthTwoEquivCommonNeighbors v w)] obtain rfl | hn := eq_or_ne v w · rw [← Set.toFinset_card] - simp [commonNeighbors, ← neighborFinset_def, h.regular.degree_eq v] + simp [commonNeighbors, ← neighborFinset_def, h.regular v] · simp only [Matrix.one_apply_ne' hn.symm, ne_eq, hn] by_cases ha : G.Adj v w <;> simp only [ha, ite_true, ite_false, add_zero, zero_add, nsmul_eq_mul, smul_zero, mul_one, diff --git a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean index 66702e27d7e2c1..db1ed6cb637b82 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean @@ -787,8 +787,7 @@ theorem degree_of_notMem_verts {G' : Subgraph G} {v : V} [Fintype (G'.neighborSe exact h hw.fst_mem theorem degree_le (G' : Subgraph G) (v : V) [Fintype (G'.neighborSet v)] - [Finite (G.neighborSet v)] : G'.degree v ≤ G.degree v := by - have := Fintype.ofFinite <| G.neighborSet v + [Fintype (G.neighborSet v)] : G'.degree v ≤ G.degree v := by rw [← card_neighborSet_eq_degree] exact Set.card_le_card (G'.neighborSet_subset v) @@ -797,15 +796,14 @@ theorem degree_le' (G' G'' : Subgraph G) (h : G' ≤ G'') (v : V) [Fintype (G'.n Set.card_le_card (neighborSet_subset_of_subgraph h v) @[simp] -theorem coe_degree (G' : Subgraph G) (v : G'.verts) [Fintype (G'.neighborSet v)] : - G'.coe.degree v = G'.degree v := by +theorem coe_degree (G' : Subgraph G) (v : G'.verts) [Fintype (G'.coe.neighborSet v)] + [Fintype (G'.neighborSet v)] : G'.coe.degree v = G'.degree v := by rw [← card_neighborSet_eq_degree] exact Fintype.card_congr (coeNeighborSetEquiv v) @[simp] theorem degree_spanningCoe {G' : G.Subgraph} (v : V) [Fintype (G'.neighborSet v)] - [Finite (G'.spanningCoe.neighborSet v)] : G'.spanningCoe.degree v = G'.degree v := by - have := Fintype.ofFinite <| G'.spanningCoe.neighborSet v + [Fintype (G'.spanningCoe.neighborSet v)] : G'.spanningCoe.degree v = G'.degree v := by rw [← card_neighborSet_eq_degree, Subgraph.degree] congr! @@ -852,17 +850,15 @@ end Subgraph @[simp] theorem card_neighborSet_toSubgraph (G H : SimpleGraph V) (h : H ≤ G) - (v : V) [Fintype ↑((toSubgraph H h).neighborSet v)] [Finite (H.neighborSet v)] : + (v : V) [Fintype ↑((toSubgraph H h).neighborSet v)] [Fintype ↑(H.neighborSet v)] : Fintype.card ↑((toSubgraph H h).neighborSet v) = H.degree v := by - have := Fintype.ofFinite <| H.neighborSet v - rw [← H.card_neighborFinset_eq_degree] refine (Finset.card_eq_of_equiv_fintype ?_).symm simp only [mem_neighborFinset] rfl @[simp] lemma degree_toSubgraph (G H : SimpleGraph V) (h : H ≤ G) {v : V} - [Fintype ↑((toSubgraph H h).neighborSet v)] [Finite (H.neighborSet v)] : + [Fintype ↑((toSubgraph H h).neighborSet v)] [Fintype ↑(H.neighborSet v)] : (toSubgraph H h).degree v = H.degree v := by simp [Subgraph.degree] diff --git a/Mathlib/Combinatorics/SimpleGraph/Trails.lean b/Mathlib/Combinatorics/SimpleGraph/Trails.lean index 75073c85d84f93..64df5dd832d3b3 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Trails.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Trails.lean @@ -123,10 +123,8 @@ theorem IsEulerian.edgesFinset_eq [Fintype G.edgeSet] {u v : V} {p : G.Walk u v} ext e simp [h.mem_edges_iff] -theorem IsEulerian.even_degree_iff {x u v : V} {p : G.Walk u v} (ht : p.IsEulerian) [Finite V] : - Even (G.degree x) ↔ u ≠ v → x ≠ u ∧ x ≠ v := by - classical - have := Fintype.ofFinite V +theorem IsEulerian.even_degree_iff {x u v : V} {p : G.Walk u v} (ht : p.IsEulerian) [Fintype V] + [DecidableRel G.Adj] : Even (G.degree x) ↔ u ≠ v → x ≠ u ∧ x ≠ v := by convert ht.isTrail.even_countP_edges_iff x rw [← Multiset.coe_countP, Multiset.countP_eq_card_filter, ← card_incidenceFinset_eq_degree] change Multiset.card _ = _ @@ -134,8 +132,10 @@ theorem IsEulerian.even_degree_iff {x u v : V} {p : G.Walk u v} (ht : p.IsEuleri convert_to _ = (ht.isTrail.edgesFinset.filter (x ∈ ·)).val rw [ht.edgesFinset_eq, G.incidenceFinset_eq_filter x] -theorem IsEulerian.card_filter_odd_degree [Fintype V] {u v : V} {p : G.Walk u v} (ht : p.IsEulerian) - {s} (h : s = ({ v | Odd (G.degree v) } : Finset V)) : s.card = 0 ∨ s.card = 2 := by +theorem IsEulerian.card_filter_odd_degree [Fintype V] [DecidableRel G.Adj] {u v : V} + {p : G.Walk u v} (ht : p.IsEulerian) {s} + (h : s = (Finset.univ : Finset V).filter fun v => Odd (G.degree v)) : + s.card = 0 ∨ s.card = 2 := by subst s simp only [← Nat.not_even_iff_odd, Finset.card_eq_zero] simp only [ht.even_degree_iff, Ne, not_forall, not_and, Classical.not_not, exists_prop] @@ -148,10 +148,10 @@ theorem IsEulerian.card_filter_odd_degree [Fintype V] {u v : V} {p : G.Walk u v} ext x simp [hn, imp_iff_not_or] -theorem IsEulerian.card_odd_degree [Finite V] {u v : V} {p : G.Walk u v} (ht : p.IsEulerian) : - { v : V | Odd (G.degree v) }.ncard = 0 ∨ { v : V | Odd (G.degree v) }.ncard = 2 := by - have := Fintype.ofFinite V - rw [Set.ncard_eq_toFinset_card'] +theorem IsEulerian.card_odd_degree [Fintype V] [DecidableRel G.Adj] {u v : V} {p : G.Walk u v} + (ht : p.IsEulerian) : Fintype.card { v : V | Odd (G.degree v) } = 0 ∨ + Fintype.card { v : V | Odd (G.degree v) } = 2 := by + rw [← Set.toFinset_card] apply IsEulerian.card_filter_odd_degree ht simp diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index 908933f27d3a40..b0d23abaceebb8 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -587,10 +587,6 @@ theorem ncard_eq_toFinset_card' (s : Set α) [Fintype s] : s.ncard = s.toFinset.card := by simp [← _root_.Nat.card_coe_set_eq, Nat.card_eq_fintype_card] -variable (s) in -theorem ncard_eq_fintypeCard [Fintype s] : s.ncard = Fintype.card s := - s.ncard_eq_toFinset_card'.trans s.toFinset_card - lemma cast_ncard {s : Set α} (hs : s.Finite) : (s.ncard : Cardinal) = Cardinal.mk s := @Nat.cast_card _ hs diff --git a/Mathlib/Data/Set/Insert.lean b/Mathlib/Data/Set/Insert.lean index 44bbf5581d924c..3a84620338fa81 100644 --- a/Mathlib/Data/Set/Insert.lean +++ b/Mathlib/Data/Set/Insert.lean @@ -258,11 +258,6 @@ theorem eq_singleton_iff_nonempty_unique_mem : s = {a} ↔ s.Nonempty ∧ ∀ x eq_singleton_iff_unique_mem.trans <| and_congr_left fun H => ⟨fun h' => ⟨_, h'⟩, fun ⟨x, h⟩ => H x h ▸ h⟩ -variable (s) in -theorem singleton_iff_unique_mem : (∃ a, s = {a}) ↔ ∃! a, a ∈ s := - ⟨fun ⟨a, ha⟩ ↦ ⟨a, ha ▸ mem_singleton a, fun _ h ↦ mem_singleton_iff.mp <| ha ▸ h⟩, - fun ⟨a, ha, huniq⟩ ↦ ⟨a, eq_singleton_iff_unique_mem.mpr ⟨ha, huniq⟩⟩⟩ - theorem setOf_mem_list_eq_replicate {l : List α} {a : α} : { x | x ∈ l } = {a} ↔ ∃ n > 0, l = List.replicate n a := by simpa +contextual [Set.ext_iff, iff_iff_implies_and_implies, forall_and, List.eq_replicate_iff, diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean index 667a9569a30ac4..49408105146c2d 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -143,20 +143,6 @@ theorem Set.Finite.lt_ciInf_iff {s : Set ι} {f : ι → α} (hs : s.Finite) rw [← hx] exact H _ hmem -theorem iSup_ne_top {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] - (h : ∀ x, f x ≠ ⊤) : iSup f ≠ ⊤ := by - cases isEmpty_or_nonempty ι - · simp - have ⟨x, hx⟩ := Set.range_nonempty f |>.csSup_mem <| Set.finite_range f - exact (hx ▸ h x :) - -theorem iInf_ne_bot {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] - (h : ∀ x, f x ≠ ⊥) : iInf f ≠ ⊥ := by - cases isEmpty_or_nonempty ι - · simp [iInf_of_empty] - have ⟨x, hx⟩ := Set.range_nonempty f |>.csInf_mem <| Set.finite_range f - exact (hx ▸ h x :) - section ListMultiset lemma List.iSup_mem_map_of_exists_sSup_empty_le {l : List ι} (f : ι → α) From 70348b422848ef713fa929929092cb74838aff18 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 3 Apr 2026 08:35:17 +0300 Subject: [PATCH 11/60] add `edegree` --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 8 ++ Mathlib/Combinatorics/SimpleGraph/Degree.lean | 130 ++++++++++++++++++ Mathlib/Combinatorics/SimpleGraph/Finite.lean | 10 +- Mathlib/Data/Set/Insert.lean | 7 +- 4 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 Mathlib/Combinatorics/SimpleGraph/Degree.lean diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index b4f4ed87355684..33b9f01ba42ffc 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -776,6 +776,14 @@ theorem neighborSet_compl (G : SimpleGraph V) (v : V) : ext w simp [and_comm, eq_comm] +@[simp] +theorem neighborSet_top : neighborSet ⊤ v = {v}ᶜ := by + grind [mem_neighborSet, top_adj] + +@[simp] +theorem neighborSet_bot : neighborSet ⊥ v = ∅ := by + grind + /-- The set of common neighbors between two vertices `v` and `w` in a graph `G` is the intersection of the neighbor sets of `v` and `w`. -/ def commonNeighbors (v w : V) : Set V := diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean new file mode 100644 index 00000000000000..9f57d87f824618 --- /dev/null +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -0,0 +1,130 @@ +/- +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.Copy +public import Mathlib.Data.ENat.Lattice + +/-! +# Degrees + +## Main definitions + +* `G.edegree v`: The extended degree of `v` in `G`: the number of vertices adjacent to `v`, + or `⊤` if there are infinitely many. +-/ + +public section + +namespace SimpleGraph + +variable {V W : Type*} (G G' : SimpleGraph V) (H : SimpleGraph W) (u v : V) + +/-- `G.edegree v` is the extended degree of `v` in `G`: the number of vertices adjacent to `v`, +or `⊤` if there are infinitely many. -/ +noncomputable def edegree : ℕ∞ := + G.neighborSet v |>.encard + +@[simp] +theorem encard_neighborSet : (G.neighborSet v).encard = G.edegree v := by + rfl + +variable {G v} in +theorem edegree_eq_zero_iff_neighborSet_eq_empty : G.edegree v = 0 ↔ G.neighborSet v = ∅ := + Set.encard_eq_zero + +variable {G v} in +theorem edegree_ne_zero_iff_nonempty_neighborSet : G.edegree v ≠ 0 ↔ (G.neighborSet v).Nonempty := + Set.encard_ne_zero + +variable {G v} in +theorem edegree_ne_zero_iff_exists_adj : G.edegree v ≠ 0 ↔ ∃ u, G.Adj v u := + edegree_ne_zero_iff_nonempty_neighborSet + +variable {G u v} in +theorem Adj.edegree_ne_zero_left (h : G.Adj u v) : G.edegree u ≠ 0 := + edegree_ne_zero_iff_nonempty_neighborSet.mpr ⟨_, h⟩ + +variable {G u v} in +theorem Adj.edegree_ne_zero_right (h : G.Adj u v) : G.edegree v ≠ 0 := + h.symm.edegree_ne_zero_left + +variable {G v} in +theorem edegree_ne_zero_iff_mem_support : G.edegree v ≠ 0 ↔ v ∈ G.support := by + rw [edegree_ne_zero_iff_exists_adj, mem_support] + +variable {G v} in +theorem edegree_eq_zero_iff_notMem_support : G.edegree v = 0 ↔ v ∉ G.support := by + rw [← edegree_ne_zero_iff_mem_support, not_ne_iff] + +variable {G v} in +theorem nontrivial_of_edegree_ne_zero (h : G.edegree v ≠ 0) : Nontrivial V := by + have ⟨u, hadj⟩ := edegree_ne_zero_iff_exists_adj.mp h + exact ⟨_, _, hadj.ne⟩ + +@[simp] +theorem edegree_eq_zero_of_subsingleton [Subsingleton V] : G.edegree v = 0 := by + by_contra! + exact not_nontrivial V <| nontrivial_of_edegree_ne_zero this + +variable {G v} in +theorem edegree_eq_one_iff_existsUnique_adj : G.edegree v = 1 ↔ ∃! u, G.Adj v u := by + simp [← encard_neighborSet, Set.encard_eq_one, Set.singleton_iff_unique_mem] + +theorem coe_degree_eq_edegree [Fintype <| G.neighborSet v] : G.degree v = G.edegree v := by + simp [← encard_neighborSet, ← card_neighborSet_eq_degree] + +variable {G v} in +theorem edegree_eq_coe_iff [Fintype <| G.neighborSet v] {n : ℕ} : + G.edegree v = n ↔ G.degree v = n := by + simp [← encard_neighborSet, ← Set.coe_fintypeCard] + +variable {G v} in +theorem edegree_ne_top_iff_finite_neighborSet : G.edegree v ≠ ⊤ ↔ (G.neighborSet v).Finite := + Set.encard_ne_top_iff + +theorem edegree_eq_toNat_edegree_of_finite_neighborSet (h : G.neighborSet v |>.Finite) : + G.edegree v = (G.edegree v).toNat := + h.encard_eq_coe + +@[simp] +theorem toNat_edegree [Fintype <| G.neighborSet v] : (G.edegree v).toNat = G.degree v := by + simp [← encard_neighborSet, ← Set.ncard_def] + +theorem edegree_le_enatCard : G.edegree v ≤ ENat.card V := by + grw [← encard_neighborSet, Set.encard_le_card] + +@[simp] +theorem encard_incidenceSet : (G.incidenceSet v).encard = G.edegree v := by + classical + simp [Set.encard_congr <| G.incidenceSetEquivNeighborSet v] + +theorem degree_le_card_edgeSet : G.edegree v ≤ G.edgeSet.encard := by + grw [← encard_incidenceSet, incidenceSet_subset] + +variable {G H} in +theorem Copy.edegree_le (f : Copy G H) (v : V) : G.edegree v ≤ H.edegree (f v) := + f.mapNeighborSet v |>.encard_le + +variable {G G' v} in +lemma edegree_le_of_le (hle : G ≤ G') : G.edegree v ≤ G'.edegree v := + Set.encard_le_encard fun _ hadj ↦ hle hadj + +variable {G} in +theorem IsRegularOfDegree.edegree_eq [G.LocallyFinite] {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : + G.edegree v = d := + edegree_eq_coe_iff.mpr <| h.degree_eq v + +@[simp] +theorem edegree_top : edegree ⊤ v = ENat.card V - 1 := by + rw [← encard_neighborSet, neighborSet_top, ← Set.encard_ne_add_one v, ← Set.compl_singleton_eq] + cases Set.encard {v}ᶜ <;> norm_cast + +@[simp] +theorem edegree_bot : edegree ⊥ v = 0 := by + simp [← encard_neighborSet] + +end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index a111f858a1b79c..a6087d7e4e2983 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -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 /-! @@ -196,6 +197,10 @@ theorem card_neighborFinset_eq_degree : #(G.neighborFinset v) = G.degree v := rf theorem card_neighborSet_eq_degree : Fintype.card (G.neighborSet v) = G.degree v := (Set.toFinset_card _).symm +@[simp] +theorem ncard_neighborSet : (G.neighborSet v).ncard = G.degree v := by + simp [Set.ncard_eq_toFinset_card'] + theorem degree_pos_iff_exists_adj : 0 < G.degree v ↔ ∃ w, G.Adj v w := by simp only [degree, card_pos, Finset.Nonempty, mem_neighborFinset] @@ -233,6 +238,9 @@ theorem nontrivial_of_degree_ne_zero {G : SimpleGraph V} {v : V} [Fintype (G.nei by_contra! simp_all [degree_eq_zero_of_subsingleton] +theorem degree_le_enatCard [Fintype V] : G.degree v ≤ Fintype.card V := by + grw [← card_neighborSet_eq_degree, set_fintype_card_le_univ] + theorem degree_compl [Fintype (Gᶜ.neighborSet v)] [Fintype V] : Gᶜ.degree v = Fintype.card V - 1 - G.degree v := by classical @@ -365,7 +373,7 @@ theorem exists_minimal_degree_vertex [DecidableRel G.Adj] [Nonempty V] : ∃ v, G.minDegree = G.degree v := by obtain ⟨t, ht : _ = _⟩ := min_of_nonempty (univ_nonempty.image fun v => G.degree v) obtain ⟨v, _, rfl⟩ := mem_image.mp (mem_of_min ht) - exact ⟨v, by simp [minDegree, ht]⟩ + exact ⟨v, by simp [minDegree, ht, -ENat.some_eq_coe]⟩ /-- The minimum degree in the graph is at most the degree of any particular vertex. -/ theorem minDegree_le_degree [DecidableRel G.Adj] (v : V) : G.minDegree ≤ G.degree v := by diff --git a/Mathlib/Data/Set/Insert.lean b/Mathlib/Data/Set/Insert.lean index f42ae05cba7e8e..6bdd77ecfaf5b8 100644 --- a/Mathlib/Data/Set/Insert.lean +++ b/Mathlib/Data/Set/Insert.lean @@ -250,13 +250,16 @@ theorem notMem_singleton_empty {s : Set α} : s ∉ ({∅} : Set (Set α)) ↔ s instance uniqueSingleton (a : α) : Unique (↥({a} : Set α)) := ⟨⟨⟨a, mem_singleton a⟩⟩, fun ⟨_, h⟩ => Subtype.ext h⟩ -theorem eq_singleton_iff_unique_mem : s = {a} ↔ a ∈ s ∧ ∀ x ∈ s, x = a := - Subset.antisymm_iff.trans <| and_comm.trans <| and_congr_left' singleton_subset_iff +theorem eq_singleton_iff_unique_mem : s = {a} ↔ a ∈ s ∧ ∀ x ∈ s, x = a := by + grind theorem eq_singleton_iff_nonempty_unique_mem : s = {a} ↔ s.Nonempty ∧ ∀ x ∈ s, x = a := eq_singleton_iff_unique_mem.trans <| and_congr_left fun H => ⟨fun h' => ⟨_, h'⟩, fun ⟨x, h⟩ => H x h ▸ h⟩ +theorem singleton_iff_unique_mem : (∃ a, s = {a}) ↔ ∃! a, a ∈ s := + ⟨fun ⟨a, h⟩ ↦ ⟨a, by grind⟩, fun ⟨a, h⟩ ↦ ⟨a, by grind⟩⟩ + theorem setOf_mem_list_eq_replicate {l : List α} {a : α} : { x | x ∈ l } = {a} ↔ ∃ n > 0, l = List.replicate n a := by simpa +contextual [Set.ext_iff, iff_iff_implies_and_implies, forall_and, List.eq_replicate_iff, From 328375d7beef685fb7353e461315dc22916f8aa4 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:39:33 +0300 Subject: [PATCH 12/60] `mk_all` --- Mathlib.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib.lean b/Mathlib.lean index 5cfac1df523bc2..c817fde7f91b21 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3494,6 +3494,7 @@ public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Represents public import Mathlib.Combinatorics.SimpleGraph.Connectivity.Subgraph public import Mathlib.Combinatorics.SimpleGraph.Copy public import Mathlib.Combinatorics.SimpleGraph.Dart +public import Mathlib.Combinatorics.SimpleGraph.Degree public import Mathlib.Combinatorics.SimpleGraph.DegreeSum public import Mathlib.Combinatorics.SimpleGraph.DeleteEdges public import Mathlib.Combinatorics.SimpleGraph.Density From 02f42bfe603511e72abce442081869e55f254704 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:42:57 +0300 Subject: [PATCH 13/60] cleanup --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 8 +++--- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 26 +++++++------------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 9f57d87f824618..458a4371ed6c88 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -94,7 +94,7 @@ theorem edegree_eq_toNat_edegree_of_finite_neighborSet (h : G.neighborSet v |>.F theorem toNat_edegree [Fintype <| G.neighborSet v] : (G.edegree v).toNat = G.degree v := by simp [← encard_neighborSet, ← Set.ncard_def] -theorem edegree_le_enatCard : G.edegree v ≤ ENat.card V := by +theorem edegree_le_card : G.edegree v ≤ ENat.card V := by grw [← encard_neighborSet, Set.encard_le_card] @[simp] @@ -102,15 +102,15 @@ theorem encard_incidenceSet : (G.incidenceSet v).encard = G.edegree v := by classical simp [Set.encard_congr <| G.incidenceSetEquivNeighborSet v] -theorem degree_le_card_edgeSet : G.edegree v ≤ G.edgeSet.encard := by +theorem edegree_le_encard_edgeSet : G.edegree v ≤ G.edgeSet.encard := by grw [← encard_incidenceSet, incidenceSet_subset] variable {G H} in theorem Copy.edegree_le (f : Copy G H) (v : V) : G.edegree v ≤ H.edegree (f v) := f.mapNeighborSet v |>.encard_le -variable {G G' v} in -lemma edegree_le_of_le (hle : G ≤ G') : G.edegree v ≤ G'.edegree v := +variable {G G'} in +lemma edegree_le_of_le (hle : G ≤ G') (v : V) : G.edegree v ≤ G'.edegree v := Set.encard_le_encard fun _ hadj ↦ hle hadj variable {G} in diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index a6087d7e4e2983..4ec762b210e0a2 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -238,9 +238,6 @@ theorem nontrivial_of_degree_ne_zero {G : SimpleGraph V} {v : V} [Fintype (G.nei by_contra! simp_all [degree_eq_zero_of_subsingleton] -theorem degree_le_enatCard [Fintype V] : G.degree v ≤ Fintype.card V := by - grw [← card_neighborSet_eq_degree, set_fintype_card_le_univ] - theorem degree_compl [Fintype (Gᶜ.neighborSet v)] [Fintype V] : Gᶜ.degree v = Fintype.card V - 1 - G.degree v := by classical @@ -300,6 +297,13 @@ lemma degree_le_of_le {H : SimpleGraph V} [Fintype (H.neighborSet v)] (hle : G simp_rw [← card_neighborSet_eq_degree] exact Set.card_le_card fun v hv => hle hv +theorem degree_lt_card_verts [Fintype V] [DecidableRel G.Adj] (v : V) : + G.degree v < Fintype.card V := by + classical + apply Finset.card_lt_card + rw [Finset.ssubset_iff] + exact ⟨v, by simp, Finset.subset_univ _⟩ + end FiniteAt section LocallyFinite @@ -408,13 +412,9 @@ lemma minDegree_le_minDegree {H : SimpleGraph V} [DecidableRel G.Adj] [Decidable /-- In a nonempty graph, the minimal degree is less than the number of vertices. -/ theorem minDegree_lt_card [DecidableRel G.Adj] [Nonempty V] : G.minDegree < Fintype.card V := by - obtain ⟨v, hδ⟩ := G.exists_minimal_degree_vertex - rw [hδ, ← card_neighborFinset_eq_degree, ← card_univ] - have h : v ∉ G.neighborFinset v := - (G.mem_neighborFinset v v).not.mpr (G.loopless.irrefl v) - contrapose! h - rw [eq_of_subset_of_card_le (subset_univ _) h] - exact mem_univ v + have ⟨v, hv⟩ := G.exists_minimal_degree_vertex + rw [hv] + apply degree_lt_card_verts /-- The maximum degree of all vertices (and `0` if there are no vertices). The key properties of this are given in `exists_maximal_degree_vertex`, `degree_le_maxDegree` @@ -466,12 +466,6 @@ lemma minDegree_le_maxDegree [DecidableRel G.Adj] : G.minDegree ≤ G.maxDegree lemma minDegree_bot_eq_zero : (⊥ : SimpleGraph V).minDegree = 0 := Nat.le_zero.1 <| (minDegree_le_maxDegree _).trans (by simp) -theorem degree_lt_card_verts [DecidableRel G.Adj] (v : V) : G.degree v < Fintype.card V := by - classical - apply Finset.card_lt_card - rw [Finset.ssubset_iff] - exact ⟨v, by simp, Finset.subset_univ _⟩ - /-- The maximum degree of a nonempty graph is less than the number of vertices. Note that the assumption that `V` is nonempty is necessary, as otherwise this would assert the existence of a From b774b7c70617f8cd2399cde65b927f43278890e7 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:41:22 +0300 Subject: [PATCH 14/60] a few more lemmas --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 14 ++++++++++++++ Mathlib/Combinatorics/SimpleGraph/Degree.lean | 15 +++++++++++++-- Mathlib/Data/Set/Card.lean | 3 +++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 33b9f01ba42ffc..6a30ce6b609a0b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -776,6 +776,20 @@ theorem neighborSet_compl (G : SimpleGraph V) (v : V) : ext w simp [and_comm, eq_comm] +variable (v) in +theorem neighborSet_subset_compl : G.neighborSet v ⊆ {v}ᶜ := by + simp + +variable (v) in +theorem neighborSet_ne_univ : G.neighborSet v ≠ .univ := + Set.ne_univ_iff_exists_notMem _ |>.mpr ⟨v, G.notMem_neighborSet_self⟩ + +variable {G} in +@[gcongr] +theorem neighborSet_mono {G' : SimpleGraph V} (hle : G ≤ G') (v : V) : + G.neighborSet v ⊆ G'.neighborSet v := + fun _ hadj ↦ hle hadj + @[simp] theorem neighborSet_top : neighborSet ⊤ v = {v}ᶜ := by grind [mem_neighborSet, top_adj] diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 458a4371ed6c88..66f29752451302 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -86,6 +86,9 @@ variable {G v} in theorem edegree_ne_top_iff_finite_neighborSet : G.edegree v ≠ ⊤ ↔ (G.neighborSet v).Finite := Set.encard_ne_top_iff +theorem edegree_ne_top_of_finite [Finite V] : G.edegree v ≠ ⊤ := + edegree_ne_top_iff_finite_neighborSet.mpr <| Set.toFinite _ + theorem edegree_eq_toNat_edegree_of_finite_neighborSet (h : G.neighborSet v |>.Finite) : G.edegree v = (G.edegree v).toNat := h.encard_eq_coe @@ -97,6 +100,9 @@ theorem toNat_edegree [Fintype <| G.neighborSet v] : (G.edegree v).toNat = G.deg theorem edegree_le_card : G.edegree v ≤ ENat.card V := by grw [← encard_neighborSet, Set.encard_le_card] +theorem edegree_lt_card_of_ne_top (h : G.edegree v ≠ ⊤) : G.edegree v < ENat.card V := + edegree_ne_top_iff_finite_neighborSet.mp h |>.encard_lt_card <| G.neighborSet_ne_univ v + @[simp] theorem encard_incidenceSet : (G.incidenceSet v).encard = G.edegree v := by classical @@ -109,9 +115,14 @@ variable {G H} in theorem Copy.edegree_le (f : Copy G H) (v : V) : G.edegree v ≤ H.edegree (f v) := f.mapNeighborSet v |>.encard_le +@[simp] +theorem Iso.edegree_eq (f : G ≃g H) (v : V) : G.edegree v = H.edegree (f v) := by + rw [← encard_neighborSet, ← encard_neighborSet, Set.encard_congr <| f.mapNeighborSet v] + variable {G G'} in -lemma edegree_le_of_le (hle : G ≤ G') (v : V) : G.edegree v ≤ G'.edegree v := - Set.encard_le_encard fun _ hadj ↦ hle hadj +@[gcongr] +theorem edegree_mono (hle : G ≤ G') (v : V) : G.edegree v ≤ G'.edegree v := + Set.encard_le_encard <| neighborSet_mono hle v variable {G} in theorem IsRegularOfDegree.edegree_eq [G.LocallyFinite] {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index 1ca79eb8302a1a..dfb477355784ab 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -262,6 +262,9 @@ theorem Finite.eq_of_subset_of_encard_le (hs : s.Finite) (hst : s ⊆ t) theorem Finite.encard_lt_encard (hs : s.Finite) (h : s ⊂ t) : s.encard < t.encard := (encard_mono h.subset).lt_of_ne fun he ↦ h.ne (hs.eq_of_subset_of_encard_le h.subset he.symm.le) +theorem Finite.encard_lt_card (hfin : s.Finite) (hne : s ≠ univ) : s.encard < ENat.card α := + encard_univ α ▸ hfin.encard_lt_encard (ssubset_univ_iff.mpr hne) + theorem encard_strictMono [Finite α] : StrictMono (encard : Set α → ℕ∞) := fun _ _ h ↦ (toFinite _).encard_lt_encard h From 06351857070dbf182fab90d54df208458dc30e2a Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 5 Apr 2026 01:56:35 +0300 Subject: [PATCH 15/60] cleanup --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 66f29752451302..e7da853a0f233e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -74,6 +74,13 @@ variable {G v} in theorem edegree_eq_one_iff_existsUnique_adj : G.edegree v = 1 ↔ ∃! u, G.Adj v u := by simp [← encard_neighborSet, Set.encard_eq_one, Set.singleton_iff_unique_mem] +variable {G v} in +theorem edegree_ne_top_iff_finite_neighborSet : G.edegree v ≠ ⊤ ↔ (G.neighborSet v).Finite := + Set.encard_ne_top_iff + +theorem edegree_ne_top_of_finite [Finite V] : G.edegree v ≠ ⊤ := + edegree_ne_top_iff_finite_neighborSet.mpr <| Set.toFinite _ + theorem coe_degree_eq_edegree [Fintype <| G.neighborSet v] : G.degree v = G.edegree v := by simp [← encard_neighborSet, ← card_neighborSet_eq_degree] @@ -82,16 +89,9 @@ theorem edegree_eq_coe_iff [Fintype <| G.neighborSet v] {n : ℕ} : G.edegree v = n ↔ G.degree v = n := by simp [← encard_neighborSet, ← Set.coe_fintypeCard] -variable {G v} in -theorem edegree_ne_top_iff_finite_neighborSet : G.edegree v ≠ ⊤ ↔ (G.neighborSet v).Finite := - Set.encard_ne_top_iff - -theorem edegree_ne_top_of_finite [Finite V] : G.edegree v ≠ ⊤ := - edegree_ne_top_iff_finite_neighborSet.mpr <| Set.toFinite _ - -theorem edegree_eq_toNat_edegree_of_finite_neighborSet (h : G.neighborSet v |>.Finite) : - G.edegree v = (G.edegree v).toNat := - h.encard_eq_coe +theorem coe_toNat_edegree_of_finite_neighborSet (h : G.neighborSet v |>.Finite) : + (G.edegree v).toNat = G.edegree v := + h.encard_eq_coe.symm @[simp] theorem toNat_edegree [Fintype <| G.neighborSet v] : (G.edegree v).toNat = G.degree v := by @@ -115,19 +115,15 @@ variable {G H} in theorem Copy.edegree_le (f : Copy G H) (v : V) : G.edegree v ≤ H.edegree (f v) := f.mapNeighborSet v |>.encard_le +variable {G H} in @[simp] -theorem Iso.edegree_eq (f : G ≃g H) (v : V) : G.edegree v = H.edegree (f v) := by - rw [← encard_neighborSet, ← encard_neighborSet, Set.encard_congr <| f.mapNeighborSet v] +theorem Iso.edegree_eq (f : G ≃g H) (v : V) : H.edegree (f v) = G.edegree v := + (Set.encard_congr <| f.mapNeighborSet v).symm variable {G G'} in @[gcongr] theorem edegree_mono (hle : G ≤ G') (v : V) : G.edegree v ≤ G'.edegree v := - Set.encard_le_encard <| neighborSet_mono hle v - -variable {G} in -theorem IsRegularOfDegree.edegree_eq [G.LocallyFinite] {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : - G.edegree v = d := - edegree_eq_coe_iff.mpr <| h.degree_eq v + Copy.ofLE G G' hle |>.edegree_le v @[simp] theorem edegree_top : edegree ⊤ v = ENat.card V - 1 := by @@ -138,4 +134,9 @@ theorem edegree_top : edegree ⊤ v = ENat.card V - 1 := by theorem edegree_bot : edegree ⊥ v = 0 := by simp [← encard_neighborSet] +variable {G} in +theorem IsRegularOfDegree.edegree_eq [G.LocallyFinite] {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : + G.edegree v = d := + edegree_eq_coe_iff.mpr <| h.degree_eq v + end SimpleGraph From dfd75602da5b91286efd73c3312bd0200a7f1ec4 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 5 Apr 2026 02:02:30 +0300 Subject: [PATCH 16/60] add `maxEDegree` and `minEDegree` --- Mathlib/Combinatorics/SimpleGraph/Copy.lean | 14 ++ Mathlib/Combinatorics/SimpleGraph/Degree.lean | 120 ++++++++++++++++++ Mathlib/Combinatorics/SimpleGraph/Finite.lean | 1 + 3 files changed, 135 insertions(+) diff --git a/Mathlib/Combinatorics/SimpleGraph/Copy.lean b/Mathlib/Combinatorics/SimpleGraph/Copy.lean index 1917eb1bfe5a9a..a46564de95f07c 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Copy.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Copy.lean @@ -327,6 +327,20 @@ theorem IsContained.max_degree_le [Fintype V] [Fintype W] [DecidableRel G.Adj] [ have ⟨f⟩ := h exact f.max_degree_le +@[gcongr] +lemma maxDegree_mono {H : SimpleGraph V} [Fintype V] [DecidableRel G.Adj] [DecidableRel H.Adj] + (hle : G ≤ H) : G.maxDegree ≤ H.maxDegree := + IsContained.of_le hle |>.max_degree_le + +theorem Copy.minDegree_le [Fintype V] [Fintype W] [DecidableRel G.Adj] [DecidableRel H.Adj] + {f : Copy G H} (hf : Function.Surjective f) : G.minDegree ≤ H.minDegree := by + cases isEmpty_or_nonempty W + · have := Function.isEmpty f + simp + refine H.le_minDegree_of_forall_le_degree _ fun w ↦ ?_ + obtain ⟨v, rfl⟩ := hf w + grw [← f.degree_le, ← minDegree_le_degree] + end IsContained section Free diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index e7da853a0f233e..292c9a13b9e053 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -15,6 +15,8 @@ public import Mathlib.Data.ENat.Lattice * `G.edegree v`: The extended degree of `v` in `G`: the number of vertices adjacent to `v`, or `⊤` if there are infinitely many. +* `G.maxEDegree`: The maximum extended degree of all vertices, or `0` if there are no vertices. +* `G.minEDegree`: The minimum extended degree of all vertices, or `⊤` if there are no vertices. -/ public section @@ -139,4 +141,122 @@ theorem IsRegularOfDegree.edegree_eq [G.LocallyFinite] {d : ℕ} (h : G.IsRegula G.edegree v = d := edegree_eq_coe_iff.mpr <| h.degree_eq v +/-- The maximum extended degree of all vertices, or `0` if there are no vertices -/ +noncomputable def maxEDegree : ℕ∞ := + ⨆ v, G.edegree v + +/-- The minimum extended degree of all vertices, or `⊤` if there are no vertices -/ +noncomputable def minEDegree : ℕ∞ := + ⨅ v, G.edegree v + +theorem maxEDegree_eq_iSup : G.maxEDegree = ⨆ v, G.edegree v := by + rfl + +theorem minEDegree_eq_iInf : G.minEDegree = ⨅ v, G.edegree v := by + rfl + +theorem exists_edegree_eq_minEDegree [Nonempty V] : ∃ v, G.edegree v = G.minEDegree := + ciInf_mem G.edegree + +theorem edegree_le_maxEDegree : G.edegree v ≤ G.maxEDegree := + le_iSup G.edegree v + +theorem minEDegree_le_edegree : G.minEDegree ≤ G.edegree v := + iInf_le G.edegree v + +variable {v} in +theorem maxEDegree_eq_top_of_edegree_eq_top (h : G.edegree v = ⊤) : G.maxEDegree = ⊤ := + eq_top_iff.mpr <| G.edegree_le_maxEDegree v |>.trans_eq' h + +variable {v} in +theorem minEDegree_eq_zero_of_edegree_eq_zero (h : G.edegree v = 0) : G.minEDegree = 0 := + nonpos_iff_eq_zero.mp <| G.minEDegree_le_edegree v |>.trans_eq h + +theorem maxEDegree_le_of_forall_edegree_le {n : ℕ∞} (h : ∀ v, G.edegree v ≤ n) : G.maxEDegree ≤ n := + iSup_le h + +theorem le_minEDegree_of_forall_le_edegree {n : ℕ∞} (h : ∀ v, n ≤ G.edegree v) : n ≤ G.minEDegree := + le_iInf h + +@[simp] +theorem maxEDegree_of_subsingleton [Subsingleton V] : G.maxEDegree = 0 := by + simp [maxEDegree_eq_iSup] + +@[simp] +theorem minEDegree_of_isEmpty [IsEmpty V] : G.minEDegree = ⊤ := + iInf_of_empty G.edegree + +@[simp] +theorem minEDegree_of_subsingleton_of_nonempty [Subsingleton V] [Nonempty V] : + G.minEDegree = 0 := by + simp [minEDegree_eq_iInf] + +theorem minEDegree_ne_top_of_finite [Nonempty V] [Finite V] : G.minEDegree ≠ ⊤ := by + rw [minEDegree_eq_iInf, ne_eq, iInf_eq_top, not_forall] + have ⟨v⟩ := ‹Nonempty V› + exact ⟨v, G.edegree_ne_top_of_finite v⟩ + +variable {G H} in +theorem IsContained.maxEDegree_le (h : G ⊑ H) : G.maxEDegree ≤ H.maxEDegree := by + refine G.maxEDegree_le_of_forall_edegree_le fun v ↦ ?_ + grw [h.some.edegree_le, edegree_le_maxEDegree] + +variable {G H} in +theorem Copy.minEDegree_le {f : Copy G H} (hf : Function.Surjective f) : + G.minEDegree ≤ H.minEDegree := by + refine H.le_minEDegree_of_forall_le_edegree fun w ↦ ?_ + obtain ⟨v, rfl⟩ := hf w + grw [← f.edegree_le, ← minEDegree_le_edegree] + +variable {G H} in +@[gcongr] +theorem Iso.maxEDegree_eq (f : G ≃g H) : G.maxEDegree = H.maxEDegree := + f.toEquiv.iSup_congr f.edegree_eq + +variable {G H} in +@[gcongr] +theorem Iso.minEDegree_eq (f : G ≃g H) : G.minEDegree = H.minEDegree := + f.toEquiv.iInf_congr f.edegree_eq + +variable {G G'} in +@[gcongr] +theorem maxEDegree_mono (hle : G ≤ G') : G.maxEDegree ≤ G'.maxEDegree := + IsContained.of_le hle |>.maxEDegree_le + +variable {G G'} in +@[gcongr] +theorem minEDegree_mono (hle : G ≤ G') : G.minEDegree ≤ G'.minEDegree := + Copy.minEDegree_le (f := .ofLE G G' hle) Function.surjective_id + +theorem maxEDegree_le_card : G.maxEDegree ≤ ENat.card V := + G.maxEDegree_le_of_forall_edegree_le G.edegree_le_card + +theorem minEDegree_le_card [Nonempty V] : G.minEDegree ≤ ENat.card V := by + have ⟨v⟩ := ‹Nonempty V› + grw [G.minEDegree_le_edegree v, edegree_le_card] + +variable {G} in +theorem minEDegree_lt_card_of_ne_top (h : G.minEDegree ≠ ⊤) : G.minEDegree < ENat.card V := by + cases isEmpty_or_nonempty V + · simp at h + have ⟨v, hv⟩ := G.exists_edegree_eq_minEDegree + rw [← hv] at h ⊢ + exact G.edegree_lt_card_of_ne_top v h + +theorem minEDegree_le_encard_edgeSet [Nonempty V] : G.minEDegree ≤ G.edgeSet.encard := by + have ⟨v, hv⟩ := G.exists_edegree_eq_minEDegree + exact hv ▸ G.edegree_le_encard_edgeSet v + +theorem minEDegree_le_maxEDegree [Nonempty V] : G.minEDegree ≤ G.maxEDegree := by + have ⟨v⟩ := ‹Nonempty V› + grw [G.minEDegree_le_edegree v, edegree_le_maxEDegree] + +@[simp] +theorem maxEDegree_bot : (⊥ : SimpleGraph V).maxEDegree = 0 := by + simp [maxEDegree_eq_iSup] + +@[simp] +theorem minEDegree_bot [Nonempty V] : (⊥ : SimpleGraph V).minEDegree = 0 := by + simp [minEDegree_eq_iInf] + end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 4ec762b210e0a2..3bb96d69a6dd24 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -402,6 +402,7 @@ lemma minDegree_of_isEmpty [DecidableRel G.Adj] [IsEmpty V] : G.minDegree = 0 := variable {G} in /-- If `G` is a subgraph of `H` then `G.minDegree ≤ H.minDegree`. -/ +@[gcongr] lemma minDegree_le_minDegree {H : SimpleGraph V} [DecidableRel G.Adj] [DecidableRel H.Adj] (hle : G ≤ H) : G.minDegree ≤ H.minDegree := by by_cases! hne : Nonempty V From b520223dda14022f5c6bf793642fe07c78ddef91 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 5 Apr 2026 02:49:32 +0300 Subject: [PATCH 17/60] generalize `maxDegree`/`minDegree` triviality lemmas from `IsEmpty` to `Subsingleton` --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 3bb96d69a6dd24..f33ff28f37ed3e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -394,11 +394,12 @@ theorem le_minDegree_of_forall_le_degree [DecidableRel G.Adj] [Nonempty V] (k : rw [hv] apply h -/-- If there are no vertices then the `minDegree` is zero. -/ @[simp] -lemma minDegree_of_isEmpty [DecidableRel G.Adj] [IsEmpty V] : G.minDegree = 0 := by - rw [minDegree, WithTop.untopD_eq_self_iff] - simp +lemma minDegree_of_subsingleton [DecidableRel G.Adj] [Subsingleton V] : G.minDegree = 0 := by + cases isEmpty_or_nonempty V <;> + simp [minDegree, Finset.image_const] + +@[deprecated (since := "2026-04-05")] alias minDegree_of_isEmpty := minDegree_of_subsingleton variable {G} in /-- If `G` is a subgraph of `H` then `G.minDegree ≤ H.minDegree`. -/ @@ -441,8 +442,11 @@ theorem degree_le_maxDegree [DecidableRel G.Adj] (v : V) : G.degree v ≤ G.maxD rwa [maxDegree, ht, WithBot.unbotD_coe] @[simp] -lemma maxDegree_of_isEmpty [DecidableRel G.Adj] [IsEmpty V] : G.maxDegree = 0 := by - rw [maxDegree, univ_eq_empty, image_empty, max_empty, WithBot.unbotD_bot] +lemma maxDegree_of_subsingleton [DecidableRel G.Adj] [Subsingleton V] : G.maxDegree = 0 := by + cases isEmpty_or_nonempty V <;> + simp [maxDegree, Finset.image_const] + +@[deprecated (since := "2026-04-05")] alias maxDegree_of_isEmpty := maxDegree_of_subsingleton /-- In a graph, if `k` is at least the degree of every vertex, then it is at least the maximum degree. -/ @@ -535,7 +539,7 @@ variable [Fintype V] [DecidableRel G.Adj] [Fintype W] [DecidableRel G'.Adj] theorem minDegree_eq (f : G ≃g G') : G.minDegree = G'.minDegree := by rcases isEmpty_or_nonempty V - · simp [f.symm.isEmpty] + · simp [f.symm.subsingleton] · have : Nonempty W := f.symm.nonempty apply le_antisymm · obtain ⟨x', hx'⟩ := exists_minimal_degree_vertex G' @@ -545,7 +549,7 @@ theorem minDegree_eq (f : G ≃g G') : G.minDegree = G'.minDegree := by theorem maxDegree_eq (f : G ≃g G') : G.maxDegree = G'.maxDegree := by rcases isEmpty_or_nonempty V - · simp [f.symm.isEmpty] + · simp [f.symm.subsingleton] · have : Nonempty W := f.symm.nonempty apply le_antisymm · obtain ⟨x, hx⟩ := exists_maximal_degree_vertex G From df24d2d78b38f8099fd64a0fd9af093f0014d33e Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 5 Apr 2026 02:50:34 +0300 Subject: [PATCH 18/60] golf `Iso.{min,max}Degree_eq` --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index f33ff28f37ed3e..80943f8e4db702 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -538,24 +538,14 @@ theorem card_edgeFinset_eq (f : G ≃g G') [Fintype G.edgeSet] [Fintype G'.edgeS variable [Fintype V] [DecidableRel G.Adj] [Fintype W] [DecidableRel G'.Adj] theorem minDegree_eq (f : G ≃g G') : G.minDegree = G'.minDegree := by - rcases isEmpty_or_nonempty V - · simp [f.symm.subsingleton] - · have : Nonempty W := f.symm.nonempty - apply le_antisymm - · obtain ⟨x', hx'⟩ := exists_minimal_degree_vertex G' - simpa only [hx', ← degree_eq f.symm x'] using minDegree_le_degree G (f.symm x') - · obtain ⟨x, hx⟩ := exists_minimal_degree_vertex G - simpa only [hx, ← degree_eq f x] using minDegree_le_degree G' (f x) + classical + rw [minDegree, minDegree, ← show (G'.degree ·) ∘ f = (G.degree ·) from funext (f.degree_eq ·), + ← image_image, Finset.image_univ_of_surjective f.surjective] theorem maxDegree_eq (f : G ≃g G') : G.maxDegree = G'.maxDegree := by - rcases isEmpty_or_nonempty V - · simp [f.symm.subsingleton] - · have : Nonempty W := f.symm.nonempty - apply le_antisymm - · obtain ⟨x, hx⟩ := exists_maximal_degree_vertex G - simpa only [hx, ← degree_eq f x] using degree_le_maxDegree G' (f x) - · obtain ⟨x', hx'⟩ := exists_maximal_degree_vertex G' - simpa only [hx', ← degree_eq f.symm x'] using degree_le_maxDegree G (f.symm x') + classical + rw [maxDegree, maxDegree, ← show (G'.degree ·) ∘ f = (G.degree ·) from funext (f.degree_eq ·), + ← image_image, Finset.image_univ_of_surjective f.surjective] end Iso From 6457cec065311dbb0587a662cb2c9c7f1f3c878a Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 5 Apr 2026 04:58:12 +0300 Subject: [PATCH 19/60] various "eq bot iff" lemmas --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 3 ++ Mathlib/Combinatorics/SimpleGraph/Degree.lean | 12 ++++++++ Mathlib/Combinatorics/SimpleGraph/Finite.lean | 28 +++++++++++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 6a30ce6b609a0b..60a25287582481 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -798,6 +798,9 @@ theorem neighborSet_top : neighborSet ⊤ v = {v}ᶜ := by theorem neighborSet_bot : neighborSet ⊥ v = ∅ := by grind +theorem eq_bot_iff_neighborSet : G = ⊥ ↔ ∀ v, G.neighborSet v = ∅ := by + simp [eq_bot_iff_forall_not_adj, Set.eq_empty_iff_forall_notMem] + /-- The set of common neighbors between two vertices `v` and `w` in a graph `G` is the intersection of the neighbor sets of `v` and `w`. -/ def commonNeighbors (v w : V) : Set V := diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 292c9a13b9e053..03c1e82576d041 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -136,6 +136,9 @@ theorem edegree_top : edegree ⊤ v = ENat.card V - 1 := by theorem edegree_bot : edegree ⊥ v = 0 := by simp [← encard_neighborSet] +theorem eq_bot_iff_edegree : G = ⊥ ↔ ∀ v, G.edegree v = 0 := by + simp [eq_bot_iff_neighborSet, edegree_eq_zero_iff_neighborSet_eq_empty] + variable {G} in theorem IsRegularOfDegree.edegree_eq [G.LocallyFinite] {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : G.edegree v = d := @@ -155,6 +158,15 @@ theorem maxEDegree_eq_iSup : G.maxEDegree = ⨆ v, G.edegree v := by theorem minEDegree_eq_iInf : G.minEDegree = ⨅ v, G.edegree v := by rfl +variable {G} in +@[simp] +theorem maxEDegree_eq_zero_iff_eq_bot : G.maxEDegree = 0 ↔ G = ⊥ := by + simp [maxEDegree_eq_iSup, eq_bot_iff_edegree] + +variable {G} in +theorem minEDegree_eq_zero_iff_support_ne : G.minEDegree = 0 ↔ G.support ≠ .univ := by + simp [minEDegree_eq_iInf, Set.ne_univ_iff_exists_notMem, edegree_eq_zero_iff_notMem_support] + theorem exists_edegree_eq_minEDegree [Nonempty V] : ∃ v, G.edegree v = G.minEDegree := ciInf_mem G.edegree diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 80943f8e4db702..361f544b5d306b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -208,6 +208,10 @@ variable {G v} in theorem degree_pos_iff_nonempty : 0 < G.degree v ↔ (G.neighborSet v).Nonempty := G.degree_pos_iff_exists_adj v +variable {G v} in +theorem degree_eq_zero_iff_neighborSet_eq_empty : G.degree v = 0 ↔ G.neighborSet v = ∅ := by + rw [← ncard_neighborSet, Set.ncard_eq_zero] + variable {G v} in theorem Adj.degree_pos_left {w : V} (h : G.Adj v w) : 0 < G.degree v := G.degree_pos_iff_nonempty.mpr ⟨_, h⟩ @@ -357,8 +361,11 @@ theorem complete_graph_degree [DecidableEq V] (v : V) : @[simp] theorem bot_degree (v : V) : (⊥ : SimpleGraph V).degree v = 0 := by - simp_rw [degree, neighborFinset_eq_filter, bot_adj, filter_false] - exact Finset.card_empty + simp [degree_eq_zero_iff_neighborSet_eq_empty] + +omit [Fintype V] in +theorem eq_bot_iff_degree [G.LocallyFinite] : G = ⊥ ↔ ∀ v, G.degree v = 0 := by + simp [eq_bot_iff_neighborSet, degree_eq_zero_iff_neighborSet_eq_empty] theorem IsRegularOfDegree.top [DecidableEq V] : (⊤ : SimpleGraph V).IsRegularOfDegree (Fintype.card V - 1) := by @@ -461,6 +468,16 @@ theorem maxDegree_le_of_forall_degree_le [DecidableRel G.Adj] (k : ℕ) (h : ∀ lemma maxDegree_bot_eq_zero : (⊥ : SimpleGraph V).maxDegree = 0 := Nat.le_zero.1 <| maxDegree_le_of_forall_degree_le _ _ (by simp) +variable {G} in +@[simp] +theorem maxDegree_eq_zero_iff [DecidableRel G.Adj] : G.maxDegree = 0 ↔ G = ⊥ := by + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · rw [eq_bot_iff_degree] + intro v + grind [G.degree_le_maxDegree v] + · convert maxDegree_bot_eq_zero + assumption + @[simp] lemma minDegree_le_maxDegree [DecidableRel G.Adj] : G.minDegree ≤ G.maxDegree := by by_cases! he : IsEmpty V @@ -471,6 +488,13 @@ lemma minDegree_le_maxDegree [DecidableRel G.Adj] : G.minDegree ≤ G.maxDegree lemma minDegree_bot_eq_zero : (⊥ : SimpleGraph V).minDegree = 0 := Nat.le_zero.1 <| (minDegree_le_maxDegree _).trans (by simp) +variable {G} in +theorem minDegree_eq_zero_iff [DecidableRel G.Adj] [Nonempty V] : + G.minDegree = 0 ↔ ∃ v, G.degree v = 0 := by + refine ⟨fun h ↦ ?_, fun ⟨v, hv⟩ ↦ ?_⟩ + · grind [G.exists_minimal_degree_vertex] + · grind [G.minDegree_le_degree v] + /-- The maximum degree of a nonempty graph is less than the number of vertices. Note that the assumption that `V` is nonempty is necessary, as otherwise this would assert the existence of a From 4b7f0450dc594df8b74826aedf1a59d6d8bfe83b Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 5 Apr 2026 05:14:12 +0300 Subject: [PATCH 20/60] min/max degrees of top and regular graphs --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 03c1e82576d041..a0a28238621e1b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -263,6 +263,16 @@ theorem minEDegree_le_maxEDegree [Nonempty V] : G.minEDegree ≤ G.maxEDegree := have ⟨v⟩ := ‹Nonempty V› grw [G.minEDegree_le_edegree v, edegree_le_maxEDegree] +@[simp] +theorem maxEDegree_top : (⊤ : SimpleGraph V).maxEDegree = ENat.card V - 1 := by + cases isEmpty_or_nonempty V + · simp [ENat.card_eq_zero_iff_empty V |>.mpr ‹_›] + simp [maxEDegree_eq_iSup] + +@[simp] +theorem minEDegree_top [Nonempty V] : (⊤ : SimpleGraph V).minEDegree = ENat.card V - 1 := by + simp [minEDegree_eq_iInf] + @[simp] theorem maxEDegree_bot : (⊥ : SimpleGraph V).maxEDegree = 0 := by simp [maxEDegree_eq_iSup] @@ -271,4 +281,14 @@ theorem maxEDegree_bot : (⊥ : SimpleGraph V).maxEDegree = 0 := by theorem minEDegree_bot [Nonempty V] : (⊥ : SimpleGraph V).minEDegree = 0 := by simp [minEDegree_eq_iInf] +variable {G} in +theorem IsRegularOfDegree.maxEDegree_eq [Nonempty V] [G.LocallyFinite] {d : ℕ} + (h : G.IsRegularOfDegree d) : G.maxEDegree = d := by + simp [maxEDegree_eq_iSup, h.edegree_eq] + +variable {G} in +theorem IsRegularOfDegree.minEDegree_eq [Nonempty V] [G.LocallyFinite] {d : ℕ} + (h : G.IsRegularOfDegree d) : G.minEDegree = d := by + simp [minEDegree_eq_iInf, h.edegree_eq] + end SimpleGraph From 8a6f87d49279f8b23b7ab6658fba00032a0ba4a2 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 5 Apr 2026 05:55:57 +0300 Subject: [PATCH 21/60] adj mem support and some `commonNeighbors` --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 12 ++++++++++++ Mathlib/Combinatorics/SimpleGraph/Degree.lean | 3 ++- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 5 +++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 60a25287582481..1eb3871c7290a0 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -406,6 +406,14 @@ def support : Set V := theorem mem_support {v : V} : v ∈ G.support ↔ ∃ w, G.Adj v w := Iff.rfl +variable {G} in +theorem Adj.mem_support_left (hadj : G.Adj u v) : u ∈ G.support := + G.mem_support.mpr ⟨v, hadj⟩ + +variable {G} in +theorem Adj.mem_support_right (hadj : G.Adj u v) : v ∈ G.support := + hadj.symm.mem_support_left + theorem support_mono {G G' : SimpleGraph V} (h : G ≤ G') : G.support ⊆ G'.support := SetRel.dom_mono fun _uv huv ↦ h huv @@ -838,6 +846,10 @@ theorem commonNeighbors_top_eq {v w : V} : ext u simp [commonNeighbors, eq_comm, not_or] +@[simp] +theorem commonNeighbors_bot_eq : commonNeighbors ⊥ u v = ∅ := by + simp [commonNeighbors] + section Incidence variable [DecidableEq V] diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index a0a28238621e1b..1d812cdac5487a 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -102,6 +102,7 @@ theorem toNat_edegree [Fintype <| G.neighborSet v] : (G.edegree v).toNat = G.deg theorem edegree_le_card : G.edegree v ≤ ENat.card V := by grw [← encard_neighborSet, Set.encard_le_card] +variable {v} in theorem edegree_lt_card_of_ne_top (h : G.edegree v ≠ ⊤) : G.edegree v < ENat.card V := edegree_ne_top_iff_finite_neighborSet.mp h |>.encard_lt_card <| G.neighborSet_ne_univ v @@ -253,7 +254,7 @@ theorem minEDegree_lt_card_of_ne_top (h : G.minEDegree ≠ ⊤) : G.minEDegree < · simp at h have ⟨v, hv⟩ := G.exists_edegree_eq_minEDegree rw [← hv] at h ⊢ - exact G.edegree_lt_card_of_ne_top v h + exact G.edegree_lt_card_of_ne_top h theorem minEDegree_le_encard_edgeSet [Nonempty V] : G.minEDegree ≤ G.edgeSet.encard := by have ⟨v, hv⟩ := G.exists_edegree_eq_minEDegree diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 361f544b5d306b..cbbf1446aa4e95 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -541,6 +541,11 @@ theorem card_commonNeighbors_top [DecidableEq V] {v w : V} (h : v ≠ w) : simp only [commonNeighbors_top_eq, ← Set.toFinset_card, Set.toFinset_diff] simp [Finset.card_sdiff, h] +omit [Fintype V] +theorem encard_commonNeighbors_top {u v : V} (h : u ≠ v) : + (commonNeighbors ⊤ u v).encard = ENat.card V - 2 := by + simp [commonNeighbors_top_eq, Set.encard_diff, Set.encard_pair h] + end Finite namespace Iso From 9e03748fbd73ddfd2b3b7abe6c817408af5f917d Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 5 Apr 2026 06:33:30 +0300 Subject: [PATCH 22/60] a few more --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 1d812cdac5487a..208baae869e051 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -91,9 +91,9 @@ theorem edegree_eq_coe_iff [Fintype <| G.neighborSet v] {n : ℕ} : G.edegree v = n ↔ G.degree v = n := by simp [← encard_neighborSet, ← Set.coe_fintypeCard] -theorem coe_toNat_edegree_of_finite_neighborSet (h : G.neighborSet v |>.Finite) : - (G.edegree v).toNat = G.edegree v := - h.encard_eq_coe.symm +theorem coe_toNat_edegree_eq_self : + (G.edegree v).toNat = G.edegree v ↔ (G.neighborSet v).Finite := by + simp [edegree_ne_top_iff_finite_neighborSet] @[simp] theorem toNat_edegree [Fintype <| G.neighborSet v] : (G.edegree v).toNat = G.degree v := by @@ -168,6 +168,10 @@ variable {G} in theorem minEDegree_eq_zero_iff_support_ne : G.minEDegree = 0 ↔ G.support ≠ .univ := by simp [minEDegree_eq_iInf, Set.ne_univ_iff_exists_notMem, edegree_eq_zero_iff_notMem_support] +variable {G} in +theorem minEDegree_eq_top_iff : G.minEDegree = ⊤ ↔ ∀ v, G.edegree v = ⊤ := + iInf_eq_top + theorem exists_edegree_eq_minEDegree [Nonempty V] : ∃ v, G.edegree v = G.minEDegree := ciInf_mem G.edegree From bfeebcb0183f82d266fe1d61b21955b321280143 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 9 Apr 2026 05:43:18 +0300 Subject: [PATCH 23/60] fix `neighborSet_bot` --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index efba34206d9c2d..a0aa7e58ed8ab1 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -811,7 +811,7 @@ theorem neighborSet_top : neighborSet ⊤ v = {v}ᶜ := by @[simp] theorem neighborSet_bot : neighborSet ⊥ v = ∅ := by - grind + grind [mem_neighborSet, bot_adj] theorem eq_bot_iff_neighborSet : G = ⊥ ↔ ∀ v, G.neighborSet v = ∅ := by simp [eq_bot_iff_forall_not_adj, Set.eq_empty_iff_forall_notMem] From e0f05a3b15a90640542b679f4127c10d41b59d49 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 9 Apr 2026 05:45:12 +0300 Subject: [PATCH 24/60] use `coe_degree_eq_edegree` to prove `edegree_eq_coe_iff`/`toNat_edegree` --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 208baae869e051..409d1dea5fabdd 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -89,16 +89,16 @@ theorem coe_degree_eq_edegree [Fintype <| G.neighborSet v] : G.degree v = G.edeg variable {G v} in theorem edegree_eq_coe_iff [Fintype <| G.neighborSet v] {n : ℕ} : G.edegree v = n ↔ G.degree v = n := by - simp [← encard_neighborSet, ← Set.coe_fintypeCard] + simp [← coe_degree_eq_edegree] + +@[simp] +theorem toNat_edegree [Fintype <| G.neighborSet v] : (G.edegree v).toNat = G.degree v := by + simp [← coe_degree_eq_edegree] theorem coe_toNat_edegree_eq_self : (G.edegree v).toNat = G.edegree v ↔ (G.neighborSet v).Finite := by simp [edegree_ne_top_iff_finite_neighborSet] -@[simp] -theorem toNat_edegree [Fintype <| G.neighborSet v] : (G.edegree v).toNat = G.degree v := by - simp [← encard_neighborSet, ← Set.ncard_def] - theorem edegree_le_card : G.edegree v ≤ ENat.card V := by grw [← encard_neighborSet, Set.encard_le_card] From a3e8b99e2435214b09380e91d0f1ebb428bdde73 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 9 Apr 2026 05:47:55 +0300 Subject: [PATCH 25/60] try to put instance hypotheses first even when there's a `variable` --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 409d1dea5fabdd..b4e21b3f9fcb0a 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -68,7 +68,8 @@ theorem nontrivial_of_edegree_ne_zero (h : G.edegree v ≠ 0) : Nontrivial V := exact ⟨_, _, hadj.ne⟩ @[simp] -theorem edegree_eq_zero_of_subsingleton [Subsingleton V] : G.edegree v = 0 := by +theorem edegree_eq_zero_of_subsingleton [Subsingleton V] (G : SimpleGraph V) (v : V) : + G.edegree v = 0 := by by_contra! exact not_nontrivial V <| nontrivial_of_edegree_ne_zero this @@ -80,7 +81,7 @@ variable {G v} in theorem edegree_ne_top_iff_finite_neighborSet : G.edegree v ≠ ⊤ ↔ (G.neighborSet v).Finite := Set.encard_ne_top_iff -theorem edegree_ne_top_of_finite [Finite V] : G.edegree v ≠ ⊤ := +theorem edegree_ne_top_of_finite [Finite V] (G : SimpleGraph V) (v : V) : G.edegree v ≠ ⊤ := edegree_ne_top_iff_finite_neighborSet.mpr <| Set.toFinite _ theorem coe_degree_eq_edegree [Fintype <| G.neighborSet v] : G.degree v = G.edegree v := by @@ -172,7 +173,8 @@ variable {G} in theorem minEDegree_eq_top_iff : G.minEDegree = ⊤ ↔ ∀ v, G.edegree v = ⊤ := iInf_eq_top -theorem exists_edegree_eq_minEDegree [Nonempty V] : ∃ v, G.edegree v = G.minEDegree := +theorem exists_edegree_eq_minEDegree [Nonempty V] (G : SimpleGraph V) : + ∃ v, G.edegree v = G.minEDegree := ciInf_mem G.edegree theorem edegree_le_maxEDegree : G.edegree v ≤ G.maxEDegree := @@ -196,19 +198,20 @@ theorem le_minEDegree_of_forall_le_edegree {n : ℕ∞} (h : ∀ v, n ≤ G.edeg le_iInf h @[simp] -theorem maxEDegree_of_subsingleton [Subsingleton V] : G.maxEDegree = 0 := by +theorem maxEDegree_of_subsingleton [Subsingleton V] (G : SimpleGraph V) : G.maxEDegree = 0 := by simp [maxEDegree_eq_iSup] @[simp] -theorem minEDegree_of_isEmpty [IsEmpty V] : G.minEDegree = ⊤ := +theorem minEDegree_of_isEmpty [IsEmpty V] (G : SimpleGraph V) : G.minEDegree = ⊤ := iInf_of_empty G.edegree @[simp] -theorem minEDegree_of_subsingleton_of_nonempty [Subsingleton V] [Nonempty V] : +theorem minEDegree_of_subsingleton_of_nonempty [Subsingleton V] [Nonempty V] (G : SimpleGraph V) : G.minEDegree = 0 := by simp [minEDegree_eq_iInf] -theorem minEDegree_ne_top_of_finite [Nonempty V] [Finite V] : G.minEDegree ≠ ⊤ := by +theorem minEDegree_ne_top_of_finite [Nonempty V] [Finite V] (G : SimpleGraph V) : + G.minEDegree ≠ ⊤ := by rw [minEDegree_eq_iInf, ne_eq, iInf_eq_top, not_forall] have ⟨v⟩ := ‹Nonempty V› exact ⟨v, G.edegree_ne_top_of_finite v⟩ @@ -248,7 +251,7 @@ theorem minEDegree_mono (hle : G ≤ G') : G.minEDegree ≤ G'.minEDegree := theorem maxEDegree_le_card : G.maxEDegree ≤ ENat.card V := G.maxEDegree_le_of_forall_edegree_le G.edegree_le_card -theorem minEDegree_le_card [Nonempty V] : G.minEDegree ≤ ENat.card V := by +theorem minEDegree_le_card [Nonempty V] (G : SimpleGraph V) : G.minEDegree ≤ ENat.card V := by have ⟨v⟩ := ‹Nonempty V› grw [G.minEDegree_le_edegree v, edegree_le_card] @@ -260,30 +263,32 @@ theorem minEDegree_lt_card_of_ne_top (h : G.minEDegree ≠ ⊤) : G.minEDegree < rw [← hv] at h ⊢ exact G.edegree_lt_card_of_ne_top h -theorem minEDegree_le_encard_edgeSet [Nonempty V] : G.minEDegree ≤ G.edgeSet.encard := by +theorem minEDegree_le_encard_edgeSet [Nonempty V] (G : SimpleGraph V) : + G.minEDegree ≤ G.edgeSet.encard := by have ⟨v, hv⟩ := G.exists_edegree_eq_minEDegree exact hv ▸ G.edegree_le_encard_edgeSet v -theorem minEDegree_le_maxEDegree [Nonempty V] : G.minEDegree ≤ G.maxEDegree := by +theorem minEDegree_le_maxEDegree [Nonempty V] (G : SimpleGraph V) : + G.minEDegree ≤ G.maxEDegree := by have ⟨v⟩ := ‹Nonempty V› grw [G.minEDegree_le_edegree v, edegree_le_maxEDegree] @[simp] -theorem maxEDegree_top : (⊤ : SimpleGraph V).maxEDegree = ENat.card V - 1 := by +theorem maxEDegree_top : (completeGraph V).maxEDegree = ENat.card V - 1 := by cases isEmpty_or_nonempty V · simp [ENat.card_eq_zero_iff_empty V |>.mpr ‹_›] simp [maxEDegree_eq_iSup] @[simp] -theorem minEDegree_top [Nonempty V] : (⊤ : SimpleGraph V).minEDegree = ENat.card V - 1 := by +theorem minEDegree_top [Nonempty V] : (completeGraph V).minEDegree = ENat.card V - 1 := by simp [minEDegree_eq_iInf] @[simp] -theorem maxEDegree_bot : (⊥ : SimpleGraph V).maxEDegree = 0 := by +theorem maxEDegree_bot : (emptyGraph V).maxEDegree = 0 := by simp [maxEDegree_eq_iSup] @[simp] -theorem minEDegree_bot [Nonempty V] : (⊥ : SimpleGraph V).minEDegree = 0 := by +theorem minEDegree_bot [Nonempty V] : (emptyGraph V).minEDegree = 0 := by simp [minEDegree_eq_iInf] variable {G} in From e55b5c477e7b191be4c31df227f2fa8deae16f99 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 9 Apr 2026 05:49:38 +0300 Subject: [PATCH 26/60] more `{min/max}EDegree` theorems --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 60 +++++++++++++++++++ .../ConditionallyCompleteLattice/Finset.lean | 20 +++++++ 2 files changed, 80 insertions(+) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index b4e21b3f9fcb0a..585a1fa103dcea 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -173,6 +173,10 @@ variable {G} in theorem minEDegree_eq_top_iff : G.minEDegree = ⊤ ↔ ∀ v, G.edegree v = ⊤ := iInf_eq_top +theorem exists_edegree_eq_maxEDegree [Nonempty V] (G : SimpleGraph V) (h : G.maxEDegree ≠ ⊤) : + ∃ v, G.edegree v = G.maxEDegree := + Set.range_nonempty G.edegree |>.csSup_mem <| ENat.finite_of_sSup_lt_top h.lt_top + theorem exists_edegree_eq_minEDegree [Nonempty V] (G : SimpleGraph V) : ∃ v, G.edegree v = G.minEDegree := ciInf_mem G.edegree @@ -210,12 +214,58 @@ theorem minEDegree_of_subsingleton_of_nonempty [Subsingleton V] [Nonempty V] (G G.minEDegree = 0 := by simp [minEDegree_eq_iInf] +theorem maxEDegree_ne_top_of_finite [Finite V] (G : SimpleGraph V) : G.maxEDegree ≠ ⊤ := + iSup_ne_top G.edegree_ne_top_of_finite + theorem minEDegree_ne_top_of_finite [Nonempty V] [Finite V] (G : SimpleGraph V) : G.minEDegree ≠ ⊤ := by rw [minEDegree_eq_iInf, ne_eq, iInf_eq_top, not_forall] have ⟨v⟩ := ‹Nonempty V› exact ⟨v, G.edegree_ne_top_of_finite v⟩ +theorem coe_maxDegree_eq_maxEDegree [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] : + G.maxDegree = G.maxEDegree := by + cases isEmpty_or_nonempty V + · simp + rw [maxEDegree_eq_iSup, maxDegree, ← Finset.coe_max' <| by simp, Finset.max'_eq_sup', + Finset.sup'_image, Finset.sup'_univ_eq_ciSup] + simpa [← coe_degree_eq_edegree] using ENat.coe_iSup <| Set.finite_range _ |>.bddAbove + +theorem coe_minDegree_eq_minEDegree [Nonempty V] [Fintype V] (G : SimpleGraph V) + [DecidableRel G.Adj] : G.minDegree = G.minEDegree := by + rw [minEDegree_eq_iInf, minDegree, ← Finset.coe_min' <| by simp, Finset.min'_eq_inf', + Finset.inf'_image, Finset.inf'_univ_eq_ciInf] + simpa [← coe_degree_eq_edegree] using ENat.coe_iInf + +variable {G} in +theorem maxEDegree_eq_coe_iff [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] {n : ℕ} : + G.maxEDegree = n ↔ G.maxDegree = n := by + simp [← coe_maxDegree_eq_maxEDegree] + +variable {G} in +theorem minEDegree_eq_coe_iff [Nonempty V] [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] + {n : ℕ} : G.minEDegree = n ↔ G.minDegree = n := by + simp [← coe_minDegree_eq_minEDegree] + +variable {G} in +theorem minEDegree_eq_coe_iff_of_neZero [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] {n : ℕ} + [NeZero n] : G.minEDegree = n ↔ G.minDegree = n := by + cases isEmpty_or_nonempty V + · simpa using NeZero.ne' n + simp [← coe_minDegree_eq_minEDegree] + +@[simp] +theorem toNat_maxEDegree [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] : + G.maxEDegree.toNat = G.maxDegree := by + simp [← coe_maxDegree_eq_maxEDegree] + +@[simp] +theorem toNat_minEDegree [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] : + G.minEDegree.toNat = G.minDegree := by + cases isEmpty_or_nonempty V + · simp + simp [← coe_minDegree_eq_minEDegree] + variable {G H} in theorem IsContained.maxEDegree_le (h : G ⊑ H) : G.maxEDegree ≤ H.maxEDegree := by refine G.maxEDegree_le_of_forall_edegree_le fun v ↦ ?_ @@ -255,6 +305,13 @@ theorem minEDegree_le_card [Nonempty V] (G : SimpleGraph V) : G.minEDegree ≤ E have ⟨v⟩ := ‹Nonempty V› grw [G.minEDegree_le_edegree v, edegree_le_card] +variable {G} in +theorem maxEDegree_lt_card_of_ne_top [Nonempty V] (G : SimpleGraph V) (h : G.maxEDegree ≠ ⊤) : + G.maxEDegree < ENat.card V := by + have ⟨v, hv⟩ := G.exists_edegree_eq_maxEDegree h + rw [← hv] at h ⊢ + exact G.edegree_lt_card_of_ne_top h + variable {G} in theorem minEDegree_lt_card_of_ne_top (h : G.minEDegree ≠ ⊤) : G.minEDegree < ENat.card V := by cases isEmpty_or_nonempty V @@ -268,6 +325,9 @@ theorem minEDegree_le_encard_edgeSet [Nonempty V] (G : SimpleGraph V) : have ⟨v, hv⟩ := G.exists_edegree_eq_minEDegree exact hv ▸ G.edegree_le_encard_edgeSet v +theorem maxEDegree_le_encard_edgeSet : G.maxEDegree ≤ G.edgeSet.encard := + maxEDegree_le_of_forall_edegree_le _ G.edegree_le_encard_edgeSet + theorem minEDegree_le_maxEDegree [Nonempty V] (G : SimpleGraph V) : G.minEDegree ≤ G.maxEDegree := by have ⟨v⟩ := ‹Nonempty V› diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean index c599c1dc089154..d72cb14dea732c 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -143,6 +143,26 @@ theorem Set.Finite.lt_ciInf_iff {s : Set ι} {f : ι → α} (hs : s.Finite) rw [← hx] exact H _ hmem +theorem sSup_ne_top {α : Type*} [Nontrivial α] [CompleteLinearOrder α] {s : Set α} (hfin : s.Finite) + (htop : ⊤ ∉ s) : sSup s ≠ ⊤ := by + rcases s.eq_empty_or_nonempty with rfl | hnonempty + · simp + exact (htop <| · ▸ hnonempty.csSup_mem hfin) + +theorem sInf_ne_bot {α : Type*} [Nontrivial α] [CompleteLinearOrder α] {s : Set α} (hfin : s.Finite) + (hbot : ⊥ ∉ s) : sInf s ≠ ⊥ := by + rcases s.eq_empty_or_nonempty with rfl | hnonempty + · simp + exact (hbot <| · ▸ hnonempty.csInf_mem hfin) + +theorem iSup_ne_top {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] + (h : ∀ x, f x ≠ ⊤) : iSup f ≠ ⊤ := + sSup_ne_top (Set.finite_range f) (by grind) + +theorem iInf_ne_bot {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] + (h : ∀ x, f x ≠ ⊥) : iInf f ≠ ⊥ := + sInf_ne_bot (Set.finite_range f) (by grind) + section ListMultiset lemma List.iSup_mem_map_of_exists_sSup_empty_le {l : List ι} (f : ι → α) From 88009373b76d8cd0165ec43ed2973bcbaeff5ff7 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 9 Apr 2026 07:46:09 +0300 Subject: [PATCH 27/60] fix `simp` call --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 86052fb79d9595..22e76724c09493 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -505,7 +505,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 := From f246a08a85a5960672835d06ae435c4b5aaedd2a Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 9 Apr 2026 08:43:06 +0300 Subject: [PATCH 28/60] fix `StronglyRegular.lean` --- Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean index e859c6ac8fbe66..2880d8107f98e9 100644 --- a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean +++ b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean @@ -64,7 +64,7 @@ theorem bot_strongly_regular : (⊥ : SimpleGraph V).IsSRGWith (Fintype.card V) of_not_adj v w _ := by simp only [card_eq_zero, Fintype.card_ofFinset, forall_true_left, not_false_iff, bot_adj] ext - simp [mem_commonNeighbors] + simp /-- **Conway's 99-graph problem** (from https://oeis.org/A248380/a248380.pdf) can be reformulated as the existence of a strongly regular graph with params (99, 14, 1, 2). From e76d506daf9a59912cd38addf71c28ed543d0b74 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 9 Apr 2026 12:17:40 +0300 Subject: [PATCH 29/60] add some `Basic` theorems to simplify degree theorems --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 26 +++++++++++++++++++ Mathlib/Combinatorics/SimpleGraph/Degree.lean | 10 +++---- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index a0aa7e58ed8ab1..a93432805382e4 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -449,6 +449,10 @@ theorem support_of_subsingleton [Subsingleton V] : G.support = ∅ := /-- `G.neighborSet v` is the set of vertices adjacent to `v` in `G`. -/ def neighborSet (v : V) : Set V := {w | G.Adj v w} +variable {G} in +theorem nonempty_neighborSet : (G.neighborSet v).Nonempty ↔ ∃ u, G.Adj v u := + .rfl + instance neighborSet.memDecidable (v : V) [DecidableRel G.Adj] : DecidablePred (· ∈ G.neighborSet v) := inferInstanceAs <| DecidablePred (Adj G v) @@ -805,6 +809,14 @@ theorem neighborSet_mono {G' : SimpleGraph V} (hle : G ≤ G') (v : V) : G.neighborSet v ⊆ G'.neighborSet v := fun _ hadj ↦ hle hadj +variable {G} in +theorem mem_support_iff_nonempty_neighborSet : v ∈ G.support ↔ (G.neighborSet v).Nonempty := + .rfl + +variable {G} in +theorem notMem_support_iff_neighborSet_eq_empty : v ∉ G.support ↔ G.neighborSet v = ∅ := by + rw [mem_support_iff_nonempty_neighborSet, Set.not_nonempty_iff_eq_empty] + @[simp] theorem neighborSet_top : neighborSet ⊤ v = {v}ᶜ := by grind [mem_neighborSet, top_adj] @@ -816,6 +828,20 @@ theorem neighborSet_bot : neighborSet ⊥ v = ∅ := by theorem eq_bot_iff_neighborSet : G = ⊥ ↔ ∀ v, G.neighborSet v = ∅ := by simp [eq_bot_iff_forall_not_adj, Set.eq_empty_iff_forall_notMem] +variable {G} in +theorem Adj.nontrivial (hadj : G.Adj u v) : Nontrivial V := + ⟨u, v, hadj.ne⟩ + +variable {G} in +theorem nontrivial_of_nonempty_neighborSet (h : (G.neighborSet v).Nonempty) : Nontrivial V := + h.elim fun _ ↦ Adj.nontrivial + +@[simp] +theorem neighborSet_eq_empty_of_subsingleton [Subsingleton V] (G : SimpleGraph V) (v : V) : + G.neighborSet v = ∅ := by + by_contra! + exact not_nontrivial V <| nontrivial_of_nonempty_neighborSet this + /-- The set of common neighbors between two vertices `v` and `w` in a graph `G` is the intersection of the neighbor sets of `v` and `w`. -/ def commonNeighbors (v w : V) : Set V := diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 585a1fa103dcea..9f622726ebf1ca 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -63,15 +63,13 @@ theorem edegree_eq_zero_iff_notMem_support : G.edegree v = 0 ↔ v ∉ G.support rw [← edegree_ne_zero_iff_mem_support, not_ne_iff] variable {G v} in -theorem nontrivial_of_edegree_ne_zero (h : G.edegree v ≠ 0) : Nontrivial V := by - have ⟨u, hadj⟩ := edegree_ne_zero_iff_exists_adj.mp h - exact ⟨_, _, hadj.ne⟩ +theorem nontrivial_of_edegree_ne_zero (h : G.edegree v ≠ 0) : Nontrivial V := + G.nontrivial_of_nonempty_neighborSet <| edegree_ne_zero_iff_nonempty_neighborSet.mp h @[simp] theorem edegree_eq_zero_of_subsingleton [Subsingleton V] (G : SimpleGraph V) (v : V) : - G.edegree v = 0 := by - by_contra! - exact not_nontrivial V <| nontrivial_of_edegree_ne_zero this + G.edegree v = 0 := + edegree_eq_zero_iff_neighborSet_eq_empty.mpr <| G.neighborSet_eq_empty_of_subsingleton v variable {G v} in theorem edegree_eq_one_iff_existsUnique_adj : G.edegree v = 1 ↔ ∃! u, G.Adj v u := by From dcc0b021d57b07cb2f05852e50b6a4aaf7c99a38 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Tue, 14 Apr 2026 03:27:26 +0300 Subject: [PATCH 30/60] cleanup using the new `IsIsolated` predicate --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 34 +++++++++---------- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 31 +++++------------ 2 files changed, 24 insertions(+), 41 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 8f5fc34b61367e..1515aeccba4ec0 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -808,14 +808,6 @@ theorem neighborSet_mono {G' : SimpleGraph V} (hle : G ≤ G') (v : V) : G.neighborSet v ⊆ G'.neighborSet v := fun _ hadj ↦ hle hadj -variable {G} in -theorem mem_support_iff_nonempty_neighborSet : v ∈ G.support ↔ (G.neighborSet v).Nonempty := - .rfl - -variable {G} in -theorem notMem_support_iff_neighborSet_eq_empty : v ∉ G.support ↔ G.neighborSet v = ∅ := by - rw [mem_support_iff_nonempty_neighborSet, Set.not_nonempty_iff_eq_empty] - @[simp] theorem neighborSet_top : neighborSet ⊤ v = {v}ᶜ := by grind [mem_neighborSet, top_adj] @@ -831,16 +823,6 @@ variable {G} in theorem Adj.nontrivial (hadj : G.Adj u v) : Nontrivial V := ⟨u, v, hadj.ne⟩ -variable {G} in -theorem nontrivial_of_nonempty_neighborSet (h : (G.neighborSet v).Nonempty) : Nontrivial V := - h.elim fun _ ↦ Adj.nontrivial - -@[simp] -theorem neighborSet_eq_empty_of_subsingleton [Subsingleton V] (G : SimpleGraph V) (v : V) : - G.neighborSet v = ∅ := by - by_contra! - exact not_nontrivial V <| nontrivial_of_nonempty_neighborSet this - /-- The set of common neighbors between two vertices `v` and `w` in a graph `G` is the intersection of the neighbor sets of `v` and `w`. -/ def commonNeighbors (v w : V) : Set V := @@ -969,4 +951,20 @@ attribute [simp] IsIsolated.neighborSet_eq_empty lemma mem_support_iff_not_isIsolated : v ∈ G.support ↔ ¬ G.IsIsolated v := by simp [mem_support, IsIsolated] +theorem notMem_support_iff_isIsolated : v ∉ G.support ↔ G.IsIsolated v := by + simp [mem_support_iff_not_isIsolated] + +variable {G} in +theorem exists_adj_iff_not_isIsolated : (∃ u, G.Adj v u) ↔ ¬G.IsIsolated v := by + simp [IsIsolated] + +@[simp] +theorem IsIsolated.of_subsingleton [Subsingleton V] (G : SimpleGraph V) (v : V) : + G.IsIsolated v := + fun _ hadj ↦ not_nontrivial V <| hadj.nontrivial + +variable {G} in +theorem nontrivial_of_not_isIsolated (h : ¬G.IsIsolated v) : Nontrivial V := + exists_adj_iff_not_isIsolated.mpr h |>.elim fun _ ↦ Adj.nontrivial + end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 9f622726ebf1ca..0f4cd8abc60a75 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -35,41 +35,26 @@ theorem encard_neighborSet : (G.neighborSet v).encard = G.edegree v := by rfl variable {G v} in -theorem edegree_eq_zero_iff_neighborSet_eq_empty : G.edegree v = 0 ↔ G.neighborSet v = ∅ := - Set.encard_eq_zero - -variable {G v} in -theorem edegree_ne_zero_iff_nonempty_neighborSet : G.edegree v ≠ 0 ↔ (G.neighborSet v).Nonempty := - Set.encard_ne_zero - -variable {G v} in -theorem edegree_ne_zero_iff_exists_adj : G.edegree v ≠ 0 ↔ ∃ u, G.Adj v u := - edegree_ne_zero_iff_nonempty_neighborSet +@[simp] +theorem edegree_eq_zero_iff_isIsolated : G.edegree v = 0 ↔ G.IsIsolated v := by + simp [← encard_neighborSet] variable {G u v} in theorem Adj.edegree_ne_zero_left (h : G.Adj u v) : G.edegree u ≠ 0 := - edegree_ne_zero_iff_nonempty_neighborSet.mpr ⟨_, h⟩ + edegree_eq_zero_iff_isIsolated.not.mpr <| exists_adj_iff_not_isIsolated.mp ⟨_, h⟩ variable {G u v} in theorem Adj.edegree_ne_zero_right (h : G.Adj u v) : G.edegree v ≠ 0 := h.symm.edegree_ne_zero_left -variable {G v} in -theorem edegree_ne_zero_iff_mem_support : G.edegree v ≠ 0 ↔ v ∈ G.support := by - rw [edegree_ne_zero_iff_exists_adj, mem_support] - -variable {G v} in -theorem edegree_eq_zero_iff_notMem_support : G.edegree v = 0 ↔ v ∉ G.support := by - rw [← edegree_ne_zero_iff_mem_support, not_ne_iff] - variable {G v} in theorem nontrivial_of_edegree_ne_zero (h : G.edegree v ≠ 0) : Nontrivial V := - G.nontrivial_of_nonempty_neighborSet <| edegree_ne_zero_iff_nonempty_neighborSet.mp h + nontrivial_of_not_isIsolated <| edegree_eq_zero_iff_isIsolated.not.mp h @[simp] theorem edegree_eq_zero_of_subsingleton [Subsingleton V] (G : SimpleGraph V) (v : V) : G.edegree v = 0 := - edegree_eq_zero_iff_neighborSet_eq_empty.mpr <| G.neighborSet_eq_empty_of_subsingleton v + edegree_eq_zero_iff_isIsolated.mpr <| .of_subsingleton G v variable {G v} in theorem edegree_eq_one_iff_existsUnique_adj : G.edegree v = 1 ↔ ∃! u, G.Adj v u := by @@ -137,7 +122,7 @@ theorem edegree_bot : edegree ⊥ v = 0 := by simp [← encard_neighborSet] theorem eq_bot_iff_edegree : G = ⊥ ↔ ∀ v, G.edegree v = 0 := by - simp [eq_bot_iff_neighborSet, edegree_eq_zero_iff_neighborSet_eq_empty] + simp [eq_bot_iff_neighborSet, edegree_eq_zero_iff_isIsolated] variable {G} in theorem IsRegularOfDegree.edegree_eq [G.LocallyFinite] {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : @@ -165,7 +150,7 @@ theorem maxEDegree_eq_zero_iff_eq_bot : G.maxEDegree = 0 ↔ G = ⊥ := by variable {G} in theorem minEDegree_eq_zero_iff_support_ne : G.minEDegree = 0 ↔ G.support ≠ .univ := by - simp [minEDegree_eq_iInf, Set.ne_univ_iff_exists_notMem, edegree_eq_zero_iff_notMem_support] + simp [minEDegree_eq_iInf, Set.ne_univ_iff_exists_notMem, notMem_support_iff_isIsolated] variable {G} in theorem minEDegree_eq_top_iff : G.minEDegree = ⊤ ↔ ∀ v, G.edegree v = ⊤ := From 54f82b8fdf54780dac9460e60b9a1fdc5a399870 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:05:59 +0300 Subject: [PATCH 31/60] simp fixes in `Finite.lean` --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 1fefcf46781486..c0e516a33642a2 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -244,22 +244,19 @@ theorem degree_pos_iff_mem_support : 0 < G.degree v ↔ v ∈ G.support := by theorem degree_eq_zero_iff_notMem_support : G.degree v = 0 ↔ v ∉ G.support := by rw [← G.degree_pos_iff_mem_support v, Nat.pos_iff_ne_zero, not_ne_iff] -@[simp] theorem degree_eq_zero_of_subsingleton {G : SimpleGraph V} (v : V) [Fintype (G.neighborSet v)] [Subsingleton V] : G.degree v = 0 := by - have := G.degree_pos_iff_exists_adj v - simp_all [subsingleton_iff_forall_eq v] + simp + +theorem nontrivial_of_degree_ne_zero {G : SimpleGraph V} {v : V} [Fintype (G.neighborSet v)] + (h : G.degree v ≠ 0) : Nontrivial V := + not_subsingleton_iff_nontrivial.mp fun _ ↦ h <| G.degree_eq_zero_of_subsingleton v theorem degree_eq_one_iff_existsUnique_adj {G : SimpleGraph V} {v : V} [Fintype (G.neighborSet v)] : G.degree v = 1 ↔ ∃! w : V, G.Adj v w := by rw [degree, Finset.card_eq_one, Finset.singleton_iff_unique_mem] simp only [mem_neighborFinset] -theorem nontrivial_of_degree_ne_zero {G : SimpleGraph V} {v : V} [Fintype (G.neighborSet v)] - (h : G.degree v ≠ 0) : Nontrivial V := by - by_contra! - simp_all [degree_eq_zero_of_subsingleton] - theorem degree_compl [Fintype (Gᶜ.neighborSet v)] [Fintype V] : Gᶜ.degree v = Fintype.card V - 1 - G.degree v := by classical @@ -708,3 +705,4 @@ theorem card_edgeFinset_map (f : V ↪ W) (G : SimpleGraph V) [DecidableRel G.Ad end Map end SimpleGraph +#lint From 41bcb974b827a7bc7446a0de962630869b921db8 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:17:12 +0300 Subject: [PATCH 32/60] oops --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index c0e516a33642a2..6d4c9705c169aa 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -250,7 +250,7 @@ theorem degree_eq_zero_of_subsingleton {G : SimpleGraph V} (v : V) [Fintype (G.n theorem nontrivial_of_degree_ne_zero {G : SimpleGraph V} {v : V} [Fintype (G.neighborSet v)] (h : G.degree v ≠ 0) : Nontrivial V := - not_subsingleton_iff_nontrivial.mp fun _ ↦ h <| G.degree_eq_zero_of_subsingleton v + nontrivial_of_not_isIsolated <| G.degree_eq_zero v |>.not.mp h theorem degree_eq_one_iff_existsUnique_adj {G : SimpleGraph V} {v : V} [Fintype (G.neighborSet v)] : G.degree v = 1 ↔ ∃! w : V, G.Adj v w := by @@ -705,4 +705,3 @@ theorem card_edgeFinset_map (f : V ↪ W) (G : SimpleGraph V) [DecidableRel G.Ad end Map end SimpleGraph -#lint From 21843e4bff75d522c5c842878e6c2124b89f1192 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 19 Apr 2026 04:52:45 +0300 Subject: [PATCH 33/60] `maxEDegree_eq_top_iff_{lt/le}` which requires a bunch of lattice material --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 8 +++ Mathlib/Order/CompleteLattice/Defs.lean | 10 ++- .../Order/SuccPred/CompleteLinearOrder.lean | 65 +++++++++++++++++++ Mathlib/Order/WithBot.lean | 5 ++ 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 0f4cd8abc60a75..2f3a1f48162c9e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -152,6 +152,14 @@ variable {G} in theorem minEDegree_eq_zero_iff_support_ne : G.minEDegree = 0 ↔ G.support ≠ .univ := by simp [minEDegree_eq_iInf, Set.ne_univ_iff_exists_notMem, notMem_support_iff_isIsolated] +variable {G} in +theorem maxEDegree_eq_top_iff_lt : G.maxEDegree = ⊤ ↔ ∀ n : ℕ, ∃ v, n < G.edegree v := + WithTop.iSup_eq_top_iff_lt + +variable {G} in +theorem maxEDegree_eq_top_iff_le : G.maxEDegree = ⊤ ↔ ∀ n : ℕ, ∃ v, n ≤ G.edegree v := + WithTop.iSup_eq_top_iff_le + variable {G} in theorem minEDegree_eq_top_iff : G.minEDegree = ⊤ ↔ ∀ v, G.edegree v = ⊤ := iInf_eq_top diff --git a/Mathlib/Order/CompleteLattice/Defs.lean b/Mathlib/Order/CompleteLattice/Defs.lean index 32e5078bcb9529..ab553694a3cec8 100644 --- a/Mathlib/Order/CompleteLattice/Defs.lean +++ b/Mathlib/Order/CompleteLattice/Defs.lean @@ -291,7 +291,7 @@ end OrderDual section CompleteLinearOrder -variable [CompleteLinearOrder α] {s : Set α} {a b : α} +variable [CompleteLinearOrder α] {s : Set α} {a b : α} {f : ι → α} @[to_dual sInf_lt_iff] theorem lt_sSup_iff : b < sSup s ↔ ∃ a ∈ s, b < a := @@ -313,6 +313,14 @@ theorem lt_iSup_iff {f : ι → α} : a < iSup f ↔ ∃ i, a < f i := theorem lt_biSup_iff {s : Set β} {f : β → α} : a < ⨆ i ∈ s, f i ↔ ∃ i ∈ s, a < f i := by simp [lt_iSup_iff] +@[to_dual sInf_le_iff_forall_lt] +theorem le_sSup_iff_forall_lt {l : α} : l ≤ sSup s ↔ ∀ b < l, ∃ a ∈ s, b < a := by + grind [le_sSup_iff, mem_upperBounds, not_le, not_lt] + +@[to_dual iInf_le_iff_forall_lt] +theorem le_iSup_iff_forall_lt {l : α} : l ≤ iSup f ↔ ∀ b < l, ∃ i, b < f i := + le_sSup_iff_forall_lt.trans <| forall₂_congr fun _ _ ↦ exists_range_iff + end CompleteLinearOrder end diff --git a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean index d514475c7b9f9a..e3bddb7ac798b6 100644 --- a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean +++ b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean @@ -154,4 +154,69 @@ lemma exists_eq_iInf_of_not_isPredPrelimit (hf : ¬ IsPredPrelimit (⨅ i, f i)) ∃ i, f i = ⨅ i, f i := sInf_mem_of_not_isPredPrelimit hf +@[to_dual lt_sInf_iff_of_not_isSuccPrelimit] +theorem sSup_lt_iff_of_not_isSuccPrelimit {l : α} (h : ¬IsSuccPrelimit l) : + sSup s < l ↔ ∀ a ∈ s, a < l := by + have ⟨l', hl'⟩ := not_forall_not.mp h + simp_rw [← hl'.le_iff_lt_left] + exact sSup_le_iff + +@[to_dual lt_iInf_iff_of_not_isSuccPrelimit] +theorem iSup_lt_iff_of_not_isSuccPrelimit {l : α} (h : ¬IsSuccPrelimit l) : + iSup f < l ↔ ∀ i, f i < l := + sSup_lt_iff_of_not_isSuccPrelimit h |>.trans forall_mem_range + +@[to_dual sInf_le_iff_of_not_isSuccPrelimit] +theorem le_sSup_iff_of_not_isSuccPrelimit {l : α} (h : ¬IsSuccPrelimit l) : + l ≤ sSup s ↔ ∃ a ∈ s, l ≤ a := by + have ⟨l', hl'⟩ := not_forall_not.mp h + simp_rw [hl'.le_iff_lt_right] + exact lt_sSup_iff + +@[to_dual iInf_le_iff_of_not_isSuccPrelimit] +theorem le_iSup_iff_of_not_isSuccPrelimit {l : α} (h : ¬IsSuccPrelimit l) : + l ≤ iSup f ↔ ∃ i, l ≤ f i := + le_sSup_iff_of_not_isSuccPrelimit h |>.trans exists_range_iff + +theorem Order.IsSuccPrelimit.le_sSup_iff {l : α} (h : IsSuccPrelimit l) : + l ≤ sSup s ↔ IsCofinalFor (Iio l) s := by + refine ⟨fun hls b hbl ↦ ?_, fun hls ↦ ?_⟩ + · have ⟨a, has, hba⟩ := lt_sSup_iff.mp <| hbl.trans_le hls + exact ⟨a, has, hba.le⟩ + · rw [← h.sSup_Iio] + exact sSup_le_sSup_of_isCofinalFor hls + +theorem Order.IsSuccPrelimit.le_iSup_iff {l : α} (h : IsSuccPrelimit l) : + l ≤ iSup f ↔ ∀ a < l, ∃ i, a ≤ f i := + h.le_sSup_iff.trans <| forall₂_congr fun _ _ ↦ exists_range_iff + end CompleteLinearOrder + +namespace WithTop + +@[to_dual] +theorem isSuccPrelimit_top [LT α] [NoMaxOrder α] : IsSuccPrelimit (⊤ : WithTop α) := by + intro a ha + obtain ⟨a, rfl⟩ := ne_top_iff_exists.mp <| WithTop.lt_top_iff_ne_top.mp ha.lt + have ⟨b, hab⟩ := NoMaxOrder.exists_gt a + exact ha.right (coe_lt_coe.mpr hab) (coe_lt_top b) + +variable [ConditionallyCompleteLinearOrderBot α] + +theorem sSup_eq_top_iff_lt {s : Set (WithTop α)} : sSup s = ⊤ ↔ ∀ a : α, ∃ b ∈ s, a < b := by + rw [sSup_eq_top] + exact forall_lt_top + +theorem iSup_eq_top_iff_lt {f : ι → WithTop α} : iSup f = ⊤ ↔ ∀ a : α, ∃ i, a < f i := + sSup_eq_top_iff_lt.trans <| forall_congr' fun _ ↦ exists_range_iff + +theorem sSup_eq_top_iff_le [NoMaxOrder α] {s : Set (WithTop α)} : + sSup s = ⊤ ↔ ∀ a : α, ∃ b ∈ s, a ≤ b := by + rw [eq_top_iff, isSuccPrelimit_top.le_sSup_iff] + exact forall_lt_top + +theorem iSup_eq_top_iff_le [NoMaxOrder α] {f : ι → WithTop α} : + iSup f = ⊤ ↔ ∀ a : α, ∃ i, a ≤ f i := + sSup_eq_top_iff_le.trans <| forall_congr' fun _ ↦ exists_range_iff + +end WithTop diff --git a/Mathlib/Order/WithBot.lean b/Mathlib/Order/WithBot.lean index fc2b3dcc8c90d0..696d1886b0bd2a 100644 --- a/Mathlib/Order/WithBot.lean +++ b/Mathlib/Order/WithBot.lean @@ -514,6 +514,11 @@ lemma lt_unbotA_iff [Nonempty α] (hx : x ≠ ⊥) : a < x.unbotA ↔ a < x := l lemma unbotA_lt_iff [Nonempty α] (hx : x ≠ ⊥) : x.unbotA < a ↔ x < a := by lift x to α using hx; simp +@[to_dual forall_lt_top] +theorem forall_bot_lt {p : WithBot α → Prop} : (∀ a, ⊥ < a → p a) ↔ (∀ a : α, p a) := by + simp_rw [WithBot.bot_lt_iff_ne_bot] + exact forall_ne_bot + end LT @[to_dual] From 2dff06abffbf4d2c596b03ce6a713b25b44a8d58 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 19 Apr 2026 05:13:48 +0300 Subject: [PATCH 34/60] `Adj.not_isIsolated_{left/right}` --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 8 ++++++++ Mathlib/Combinatorics/SimpleGraph/Degree.lean | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 1515aeccba4ec0..9232b61221eb73 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -967,4 +967,12 @@ variable {G} in theorem nontrivial_of_not_isIsolated (h : ¬G.IsIsolated v) : Nontrivial V := exists_adj_iff_not_isIsolated.mpr h |>.elim fun _ ↦ Adj.nontrivial +variable {G} in +theorem Adj.not_isIsolated_left (h : G.Adj u v) : ¬G.IsIsolated u := + exists_adj_iff_not_isIsolated.mp ⟨_, h⟩ + +variable {G} in +theorem Adj.not_isIsolated_right (h : G.Adj u v) : ¬G.IsIsolated v := + h.symm.not_isIsolated_left + end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 2f3a1f48162c9e..2df5038c05befd 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -41,7 +41,7 @@ theorem edegree_eq_zero_iff_isIsolated : G.edegree v = 0 ↔ G.IsIsolated v := b variable {G u v} in theorem Adj.edegree_ne_zero_left (h : G.Adj u v) : G.edegree u ≠ 0 := - edegree_eq_zero_iff_isIsolated.not.mpr <| exists_adj_iff_not_isIsolated.mp ⟨_, h⟩ + edegree_eq_zero_iff_isIsolated.not.mpr h.not_isIsolated_left variable {G u v} in theorem Adj.edegree_ne_zero_right (h : G.Adj u v) : G.edegree v ≠ 0 := From 8df8f6b6a855401d8cfa57189b04953016a5743a Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Sun, 19 Apr 2026 05:14:10 +0300 Subject: [PATCH 35/60] `IsIsolated.edegree_eq` --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 2df5038c05befd..7a25c22300efd4 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -39,6 +39,8 @@ variable {G v} in theorem edegree_eq_zero_iff_isIsolated : G.edegree v = 0 ↔ G.IsIsolated v := by simp [← encard_neighborSet] +alias ⟨_, IsIsolated.edegree_eq⟩ := edegree_eq_zero_iff_isIsolated + variable {G u v} in theorem Adj.edegree_ne_zero_left (h : G.Adj u v) : G.edegree u ≠ 0 := edegree_eq_zero_iff_isIsolated.not.mpr h.not_isIsolated_left From 243d00d4647feffded70afad43b82c648d8f72d6 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 23 Apr 2026 00:28:24 +0300 Subject: [PATCH 36/60] ungolf `eq_singleton_iff_unique_mem` --- Mathlib/Data/Set/Insert.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Data/Set/Insert.lean b/Mathlib/Data/Set/Insert.lean index 6bdd77ecfaf5b8..de8be95e501570 100644 --- a/Mathlib/Data/Set/Insert.lean +++ b/Mathlib/Data/Set/Insert.lean @@ -250,8 +250,8 @@ theorem notMem_singleton_empty {s : Set α} : s ∉ ({∅} : Set (Set α)) ↔ s instance uniqueSingleton (a : α) : Unique (↥({a} : Set α)) := ⟨⟨⟨a, mem_singleton a⟩⟩, fun ⟨_, h⟩ => Subtype.ext h⟩ -theorem eq_singleton_iff_unique_mem : s = {a} ↔ a ∈ s ∧ ∀ x ∈ s, x = a := by - grind +theorem eq_singleton_iff_unique_mem : s = {a} ↔ a ∈ s ∧ ∀ x ∈ s, x = a := + Subset.antisymm_iff.trans <| and_comm.trans <| and_congr_left' singleton_subset_iff theorem eq_singleton_iff_nonempty_unique_mem : s = {a} ↔ s.Nonempty ∧ ∀ x ∈ s, x = a := eq_singleton_iff_unique_mem.trans <| From fb38cac0b8e5090a73f8ee1fd9caaaff9d941167 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 23 Apr 2026 00:28:43 +0300 Subject: [PATCH 37/60] `Hom.minEDegree_le` --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 7a25c22300efd4..a5a713e849327f 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -271,6 +271,10 @@ theorem Copy.minEDegree_le {f : Copy G H} (hf : Function.Surjective f) : obtain ⟨v, rfl⟩ := hf w grw [← f.edegree_le, ← minEDegree_le_edegree] +variable {G H} in +theorem Hom.minEDegree_le {f : G →g H} (hf : Function.Bijective f) : G.minEDegree ≤ H.minEDegree := + Copy.minEDegree_le (f := ⟨f, hf.injective⟩) hf.surjective + variable {G H} in @[gcongr] theorem Iso.maxEDegree_eq (f : G ≃g H) : G.maxEDegree = H.maxEDegree := @@ -289,7 +293,7 @@ theorem maxEDegree_mono (hle : G ≤ G') : G.maxEDegree ≤ G'.maxEDegree := variable {G G'} in @[gcongr] theorem minEDegree_mono (hle : G ≤ G') : G.minEDegree ≤ G'.minEDegree := - Copy.minEDegree_le (f := .ofLE G G' hle) Function.surjective_id + Hom.ofLE hle |>.minEDegree_le Function.bijective_id theorem maxEDegree_le_card : G.maxEDegree ≤ ENat.card V := G.maxEDegree_le_of_forall_edegree_le G.edegree_le_card From cf8782aa49956cf6f8b88f74c7bb080991834bba Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 24 Apr 2026 03:48:40 +0300 Subject: [PATCH 38/60] fix `Copy.minDegree_le` because `G.minDegree = 0` now requires `Subsingleton` instead of `IsEmpty` --- Mathlib/Combinatorics/SimpleGraph/Copy.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Copy.lean b/Mathlib/Combinatorics/SimpleGraph/Copy.lean index 80ff36db037e4a..50fc71d8e92183 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Copy.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Copy.lean @@ -335,7 +335,8 @@ lemma maxDegree_mono {H : SimpleGraph V} [Fintype V] [DecidableRel G.Adj] [Decid theorem Copy.minDegree_le [Fintype V] [Fintype W] [DecidableRel G.Adj] [DecidableRel H.Adj] {f : Copy G H} (hf : Function.Surjective f) : G.minDegree ≤ H.minDegree := by cases isEmpty_or_nonempty W - · simp [Function.isEmpty f] + · have := Function.isEmpty f + simp refine H.le_minDegree_of_forall_le_degree _ fun w ↦ ?_ obtain ⟨v, rfl⟩ := hf w grw [← f.degree_le, ← minDegree_le_degree] From b27d781587f966e05dfd2791f49cf62abb6a95d5 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 24 Apr 2026 04:36:43 +0300 Subject: [PATCH 39/60] delete `le_sSup_iff_forall_lt`/`le_iSup_iff_forall_lt` (extracted to a separate PR but we don't need them here) --- Mathlib/Order/CompleteLattice/Defs.lean | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Mathlib/Order/CompleteLattice/Defs.lean b/Mathlib/Order/CompleteLattice/Defs.lean index ab553694a3cec8..32e5078bcb9529 100644 --- a/Mathlib/Order/CompleteLattice/Defs.lean +++ b/Mathlib/Order/CompleteLattice/Defs.lean @@ -291,7 +291,7 @@ end OrderDual section CompleteLinearOrder -variable [CompleteLinearOrder α] {s : Set α} {a b : α} {f : ι → α} +variable [CompleteLinearOrder α] {s : Set α} {a b : α} @[to_dual sInf_lt_iff] theorem lt_sSup_iff : b < sSup s ↔ ∃ a ∈ s, b < a := @@ -313,14 +313,6 @@ theorem lt_iSup_iff {f : ι → α} : a < iSup f ↔ ∃ i, a < f i := theorem lt_biSup_iff {s : Set β} {f : β → α} : a < ⨆ i ∈ s, f i ↔ ∃ i ∈ s, a < f i := by simp [lt_iSup_iff] -@[to_dual sInf_le_iff_forall_lt] -theorem le_sSup_iff_forall_lt {l : α} : l ≤ sSup s ↔ ∀ b < l, ∃ a ∈ s, b < a := by - grind [le_sSup_iff, mem_upperBounds, not_le, not_lt] - -@[to_dual iInf_le_iff_forall_lt] -theorem le_iSup_iff_forall_lt {l : α} : l ≤ iSup f ↔ ∀ b < l, ∃ i, b < f i := - le_sSup_iff_forall_lt.trans <| forall₂_congr fun _ _ ↦ exists_range_iff - end CompleteLinearOrder end From 653958601a84e420536c2babd5d138b71dcedfd2 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 27 Apr 2026 04:54:03 +0300 Subject: [PATCH 40/60] delete `neighborSet_mono` since we moved it to `Basic.lean` --- Mathlib/Combinatorics/SimpleGraph/Maps.lean | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Maps.lean b/Mathlib/Combinatorics/SimpleGraph/Maps.lean index 783c16dc29d92a..e1080923ad96ce 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Maps.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Maps.lean @@ -390,11 +390,6 @@ theorem mapEdgeSet.injective (hinj : Function.Injective f) : Function.Injective repeat rw [Subtype.mk_eq_mk] apply Sym2.map.injective hinj -@[gcongr] -theorem _root_.SimpleGraph.neighborSet_mono (hle : G₁ ≤ G₂) (v : V) : - G₁.neighborSet v ⊆ G₂.neighborSet v := - subset_preimage_neighborSet v <| .ofLE hle - /-- Every graph homomorphism from a complete graph is injective. -/ theorem injective_of_top_hom (f : (⊤ : SimpleGraph V) →g G') : Function.Injective f := by intro v w h From dc1b3f5dfebb4863f881e16695adfa284e324f69 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 27 Apr 2026 05:01:15 +0300 Subject: [PATCH 41/60] add PR references --- Mathlib/Order/ConditionallyCompleteLattice/Finset.lean | 4 ++++ Mathlib/Order/SuccPred/CompleteLinearOrder.lean | 1 + 2 files changed, 5 insertions(+) diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean index d72cb14dea732c..024be0f0b8bf83 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -143,22 +143,26 @@ theorem Set.Finite.lt_ciInf_iff {s : Set ι} {f : ι → α} (hs : s.Finite) rw [← hx] exact H _ hmem +-- #38356 theorem sSup_ne_top {α : Type*} [Nontrivial α] [CompleteLinearOrder α] {s : Set α} (hfin : s.Finite) (htop : ⊤ ∉ s) : sSup s ≠ ⊤ := by rcases s.eq_empty_or_nonempty with rfl | hnonempty · simp exact (htop <| · ▸ hnonempty.csSup_mem hfin) +-- #38356 theorem sInf_ne_bot {α : Type*} [Nontrivial α] [CompleteLinearOrder α] {s : Set α} (hfin : s.Finite) (hbot : ⊥ ∉ s) : sInf s ≠ ⊥ := by rcases s.eq_empty_or_nonempty with rfl | hnonempty · simp exact (hbot <| · ▸ hnonempty.csInf_mem hfin) +-- #38356 theorem iSup_ne_top {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] (h : ∀ x, f x ≠ ⊤) : iSup f ≠ ⊤ := sSup_ne_top (Set.finite_range f) (by grind) +-- #38356 theorem iInf_ne_bot {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] (h : ∀ x, f x ≠ ⊥) : iInf f ≠ ⊥ := sInf_ne_bot (Set.finite_range f) (by grind) diff --git a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean index a72bfa6c574d35..9929077f83d526 100644 --- a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean +++ b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean @@ -194,6 +194,7 @@ end CompleteLinearOrder namespace WithTop +-- #38244 @[to_dual] theorem isSuccPrelimit_top [LT α] [NoMaxOrder α] : IsSuccPrelimit (⊤ : WithTop α) := by intro a ha From f94a8b0ae0db73ff8ba0e4a018a0e423a9a03f12 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Tue, 28 Apr 2026 13:03:17 +0300 Subject: [PATCH 42/60] update dependencies references --- .../ConditionallyCompleteLattice/Finset.lean | 25 +++---------- .../Order/SuccPred/CompleteLinearOrder.lean | 36 ++----------------- 2 files changed, 7 insertions(+), 54 deletions(-) diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean index 024be0f0b8bf83..15860c0fa92c27 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -143,29 +143,12 @@ theorem Set.Finite.lt_ciInf_iff {s : Set ι} {f : ι → α} (hs : s.Finite) rw [← hx] exact H _ hmem --- #38356 -theorem sSup_ne_top {α : Type*} [Nontrivial α] [CompleteLinearOrder α] {s : Set α} (hfin : s.Finite) - (htop : ⊤ ∉ s) : sSup s ≠ ⊤ := by - rcases s.eq_empty_or_nonempty with rfl | hnonempty - · simp - exact (htop <| · ▸ hnonempty.csSup_mem hfin) - --- #38356 -theorem sInf_ne_bot {α : Type*} [Nontrivial α] [CompleteLinearOrder α] {s : Set α} (hfin : s.Finite) - (hbot : ⊥ ∉ s) : sInf s ≠ ⊥ := by - rcases s.eq_empty_or_nonempty with rfl | hnonempty - · simp - exact (hbot <| · ▸ hnonempty.csInf_mem hfin) - -- #38356 theorem iSup_ne_top {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] - (h : ∀ x, f x ≠ ⊤) : iSup f ≠ ⊤ := - sSup_ne_top (Set.finite_range f) (by grind) - --- #38356 -theorem iInf_ne_bot {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] - (h : ∀ x, f x ≠ ⊥) : iInf f ≠ ⊥ := - sInf_ne_bot (Set.finite_range f) (by grind) + (h : ∀ x, f x ≠ ⊤) : iSup f ≠ ⊤ := by + rcases Set.range f |>.eq_empty_or_nonempty with hempty | hnonempty + · simp [iSup, hempty] + grind [iSup, hnonempty.csSup_mem <| Set.finite_range f] section ListMultiset diff --git a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean index 9929077f83d526..63b38cab888bd0 100644 --- a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean +++ b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean @@ -154,41 +154,11 @@ lemma exists_eq_iInf_of_not_isPredPrelimit (hf : ¬ IsPredPrelimit (⨅ i, f i)) ∃ i, f i = ⨅ i, f i := sInf_mem_of_not_isPredPrelimit hf -@[to_dual lt_sInf_iff_of_not_isSuccPrelimit] -theorem sSup_lt_iff_of_not_isSuccPrelimit {l : α} (h : ¬IsSuccPrelimit l) : - sSup s < l ↔ ∀ a ∈ s, a < l := by - have ⟨l', hl'⟩ := not_forall_not.mp h - simp_rw [← hl'.le_iff_lt_left] - exact sSup_le_iff - -@[to_dual lt_iInf_iff_of_not_isSuccPrelimit] -theorem iSup_lt_iff_of_not_isSuccPrelimit {l : α} (h : ¬IsSuccPrelimit l) : - iSup f < l ↔ ∀ i, f i < l := - sSup_lt_iff_of_not_isSuccPrelimit h |>.trans forall_mem_range - -@[to_dual sInf_le_iff_of_not_isSuccPrelimit] -theorem le_sSup_iff_of_not_isSuccPrelimit {l : α} (h : ¬IsSuccPrelimit l) : - l ≤ sSup s ↔ ∃ a ∈ s, l ≤ a := by - have ⟨l', hl'⟩ := not_forall_not.mp h - simp_rw [hl'.le_iff_lt_right] - exact lt_sSup_iff - -@[to_dual iInf_le_iff_of_not_isSuccPrelimit] -theorem le_iSup_iff_of_not_isSuccPrelimit {l : α} (h : ¬IsSuccPrelimit l) : - l ≤ iSup f ↔ ∃ i, l ≤ f i := - le_sSup_iff_of_not_isSuccPrelimit h |>.trans exists_range_iff - +-- #38612 theorem Order.IsSuccPrelimit.le_sSup_iff {l : α} (h : IsSuccPrelimit l) : l ≤ sSup s ↔ IsCofinalFor (Iio l) s := by - refine ⟨fun hls b hbl ↦ ?_, fun hls ↦ ?_⟩ - · have ⟨a, has, hba⟩ := lt_sSup_iff.mp <| hbl.trans_le hls - exact ⟨a, has, hba.le⟩ - · rw [← h.sSup_Iio] - exact sSup_le_sSup_of_isCofinalFor hls - -theorem Order.IsSuccPrelimit.le_iSup_iff {l : α} (h : IsSuccPrelimit l) : - l ≤ iSup f ↔ ∀ a < l, ∃ i, a ≤ f i := - h.le_sSup_iff.trans <| forall₂_congr fun _ _ ↦ exists_range_iff + simp_rw [le_sSup_iff_forall_lt, IsCofinalFor, mem_Iio] + grind [lt_iff_exists_lt] end CompleteLinearOrder From 04ee30f09aba7fa8de912572c5b1e5752dc19daf Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Tue, 28 Apr 2026 14:06:09 +0300 Subject: [PATCH 43/60] ungolf `Finite.lean`, extracted to separate PR --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 6d4c9705c169aa..5cd671c147b282 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -316,13 +316,6 @@ lemma degree_le_of_le {H : SimpleGraph V} [Fintype (H.neighborSet v)] (hle : G simp_rw [← card_neighborSet_eq_degree] exact Set.card_le_card fun v hv => hle hv -theorem degree_lt_card_verts [Fintype V] [DecidableRel G.Adj] (v : V) : - G.degree v < Fintype.card V := by - classical - apply Finset.card_lt_card - rw [Finset.ssubset_iff] - exact ⟨v, by simp, Finset.subset_univ _⟩ - end FiniteAt section LocallyFinite @@ -445,9 +438,13 @@ lemma minDegree_le_minDegree {H : SimpleGraph V} [DecidableRel G.Adj] [Decidable /-- In a nonempty graph, the minimal degree is less than the number of vertices. -/ theorem minDegree_lt_card [DecidableRel G.Adj] [Nonempty V] : G.minDegree < Fintype.card V := by - have ⟨v, hv⟩ := G.exists_minimal_degree_vertex - rw [hv] - apply degree_lt_card_verts + obtain ⟨v, hδ⟩ := G.exists_minimal_degree_vertex + rw [hδ, ← card_neighborFinset_eq_degree, ← card_univ] + have h : v ∉ G.neighborFinset v := + (G.mem_neighborFinset v v).not.mpr (G.loopless.irrefl v) + contrapose! h + rw [eq_of_subset_of_card_le (subset_univ _) h] + exact mem_univ v /-- The maximum degree of all vertices (and `0` if there are no vertices). The key properties of this are given in `exists_maximal_degree_vertex`, `degree_le_maxDegree` @@ -539,6 +536,12 @@ lemma minDegree_top [DecidableEq V] : (⊤ : SimpleGraph V).minDegree = Fintype. · simp exact IsRegularOfDegree.top.minDegree_eq +theorem degree_lt_card_verts [DecidableRel G.Adj] (v : V) : G.degree v < Fintype.card V := by + classical + apply Finset.card_lt_card + rw [Finset.ssubset_iff] + exact ⟨v, by simp, Finset.subset_univ _⟩ + /-- The maximum degree of a nonempty graph is less than the number of vertices. Note that the assumption that `V` is nonempty is necessary, as otherwise this would assert the existence of a @@ -611,14 +614,24 @@ theorem card_edgeFinset_eq (f : G ≃g G') [Fintype G.edgeSet] [Fintype G'.edgeS variable [Fintype V] [DecidableRel G.Adj] [Fintype W] [DecidableRel G'.Adj] theorem minDegree_eq (f : G ≃g G') : G.minDegree = G'.minDegree := by - classical - rw [minDegree, minDegree, ← show (G'.degree ·) ∘ f = (G.degree ·) from funext (f.degree_eq ·), - ← image_image, Finset.image_univ_of_surjective f.surjective] + rcases isEmpty_or_nonempty V + · simp [f.symm.subsingleton] + · have : Nonempty W := f.symm.nonempty + apply le_antisymm + · obtain ⟨x', hx'⟩ := exists_minimal_degree_vertex G' + simpa only [hx', ← degree_eq f.symm x'] using minDegree_le_degree G (f.symm x') + · obtain ⟨x, hx⟩ := exists_minimal_degree_vertex G + simpa only [hx, ← degree_eq f x] using minDegree_le_degree G' (f x) theorem maxDegree_eq (f : G ≃g G') : G.maxDegree = G'.maxDegree := by - classical - rw [maxDegree, maxDegree, ← show (G'.degree ·) ∘ f = (G.degree ·) from funext (f.degree_eq ·), - ← image_image, Finset.image_univ_of_surjective f.surjective] + rcases isEmpty_or_nonempty V + · simp [f.symm.subsingleton] + · have : Nonempty W := f.symm.nonempty + apply le_antisymm + · obtain ⟨x, hx⟩ := exists_maximal_degree_vertex G + simpa only [hx, ← degree_eq f x] using degree_le_maxDegree G' (f x) + · obtain ⟨x', hx'⟩ := exists_maximal_degree_vertex G' + simpa only [hx', ← degree_eq f.symm x'] using degree_le_maxDegree G (f.symm x') end Iso From d3b8fdebb8b8bf73b26885bb72ca02b749f3c7b1 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Wed, 29 Apr 2026 06:26:34 +0300 Subject: [PATCH 44/60] golf `minDegree_le_degree` --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 5a06b2824d5a0c..fa972ff43664db 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -400,10 +400,8 @@ theorem exists_minimal_degree_vertex [DecidableRel G.Adj] [Nonempty V] : grind [minDegree, WithTop.untopD_coe, min_mem_image_coe <| univ_nonempty.image (G.degree ·)] /-- The minimum degree in the graph is at most the degree of any particular vertex. -/ -theorem minDegree_le_degree [DecidableRel G.Adj] (v : V) : G.minDegree ≤ G.degree v := by - obtain ⟨t, ht⟩ := Finset.min_of_mem (mem_image_of_mem (fun v => G.degree v) (mem_univ v)) - have := Finset.min_le_of_eq (mem_image_of_mem _ (mem_univ v)) ht - rwa [minDegree, ht] +theorem minDegree_le_degree [DecidableRel G.Adj] (v : V) : G.minDegree ≤ G.degree v := + WithTop.untopD_le <| Finset.min_le <| mem_image_of_mem (G.degree ·) <| mem_univ v /-- In a nonempty graph, if `k` is at most the degree of every vertex, it is at most the minimum degree. Note the assumption that the graph is nonempty is necessary as long as `G.minDegree` is From cb2a7a30989e401234b0cfb3dc0ada656b25b3a4 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 30 Apr 2026 05:55:34 +0300 Subject: [PATCH 45/60] extract `Basic.lean` stuff to separate PR --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 39 ++++++------------- Mathlib/Combinatorics/SimpleGraph/Maps.lean | 5 +++ .../SimpleGraph/StronglyRegular.lean | 1 + 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 9232b61221eb73..d8324ce0b0bc4f 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -406,14 +406,6 @@ def support : Set V := theorem mem_support {v : V} : v ∈ G.support ↔ ∃ w, G.Adj v w := Iff.rfl -variable {G} in -theorem Adj.mem_support_left (hadj : G.Adj u v) : u ∈ G.support := - G.mem_support.mpr ⟨v, hadj⟩ - -variable {G} in -theorem Adj.mem_support_right (hadj : G.Adj u v) : v ∈ G.support := - hadj.symm.mem_support_left - @[gcongr] theorem support_mono {G G' : SimpleGraph V} (h : G ≤ G') : G.support ⊆ G'.support := SetRel.dom_mono fun _uv huv ↦ h huv @@ -448,10 +440,6 @@ theorem support_of_subsingleton [Subsingleton V] : G.support = ∅ := /-- `G.neighborSet v` is the set of vertices adjacent to `v` in `G`. -/ def neighborSet (v : V) : Set V := {w | G.Adj v w} -variable {G} in -theorem nonempty_neighborSet : (G.neighborSet v).Nonempty ↔ ∃ u, G.Adj v u := - .rfl - instance neighborSet.memDecidable (v : V) [DecidableRel G.Adj] : DecidablePred (· ∈ G.neighborSet v) := inferInstanceAs <| DecidablePred (Adj G v) @@ -794,31 +782,26 @@ theorem neighborSet_compl (G : SimpleGraph V) (v : V) : ext w simp [and_comm, eq_comm] -variable (v) in -theorem neighborSet_subset_compl : G.neighborSet v ⊆ {v}ᶜ := by - simp - +-- #38747 variable (v) in theorem neighborSet_ne_univ : G.neighborSet v ≠ .univ := Set.ne_univ_iff_exists_notMem _ |>.mpr ⟨v, G.notMem_neighborSet_self⟩ -variable {G} in -@[gcongr] -theorem neighborSet_mono {G' : SimpleGraph V} (hle : G ≤ G') (v : V) : - G.neighborSet v ⊆ G'.neighborSet v := - fun _ hadj ↦ hle hadj - +-- #38747 @[simp] theorem neighborSet_top : neighborSet ⊤ v = {v}ᶜ := by grind [mem_neighborSet, top_adj] +-- #38747 @[simp] theorem neighborSet_bot : neighborSet ⊥ v = ∅ := by grind [mem_neighborSet, bot_adj] +-- #38747 theorem eq_bot_iff_neighborSet : G = ⊥ ↔ ∀ v, G.neighborSet v = ∅ := by simp [eq_bot_iff_forall_not_adj, Set.eq_empty_iff_forall_notMem] +-- #38747 variable {G} in theorem Adj.nontrivial (hadj : G.Adj u v) : Nontrivial V := ⟨u, v, hadj.ne⟩ @@ -860,10 +843,6 @@ theorem commonNeighbors_top_eq {v w : V} : ext u simp [commonNeighbors, eq_comm, not_or] -@[simp] -theorem commonNeighbors_bot_eq : commonNeighbors ⊥ u v = ∅ := by - simp [commonNeighbors] - section Incidence variable [DecidableEq V] @@ -951,26 +930,32 @@ attribute [simp] IsIsolated.neighborSet_eq_empty lemma mem_support_iff_not_isIsolated : v ∈ G.support ↔ ¬ G.IsIsolated v := by simp [mem_support, IsIsolated] +-- #38747 theorem notMem_support_iff_isIsolated : v ∉ G.support ↔ G.IsIsolated v := by simp [mem_support_iff_not_isIsolated] +-- #38747 variable {G} in theorem exists_adj_iff_not_isIsolated : (∃ u, G.Adj v u) ↔ ¬G.IsIsolated v := by simp [IsIsolated] +-- #38747 @[simp] theorem IsIsolated.of_subsingleton [Subsingleton V] (G : SimpleGraph V) (v : V) : G.IsIsolated v := - fun _ hadj ↦ not_nontrivial V <| hadj.nontrivial + fun _ hadj ↦ not_nontrivial V hadj.nontrivial +-- #38747 variable {G} in theorem nontrivial_of_not_isIsolated (h : ¬G.IsIsolated v) : Nontrivial V := exists_adj_iff_not_isIsolated.mpr h |>.elim fun _ ↦ Adj.nontrivial +-- #38747 variable {G} in theorem Adj.not_isIsolated_left (h : G.Adj u v) : ¬G.IsIsolated u := exists_adj_iff_not_isIsolated.mp ⟨_, h⟩ +-- #38747 variable {G} in theorem Adj.not_isIsolated_right (h : G.Adj u v) : ¬G.IsIsolated v := h.symm.not_isIsolated_left diff --git a/Mathlib/Combinatorics/SimpleGraph/Maps.lean b/Mathlib/Combinatorics/SimpleGraph/Maps.lean index b760f165dc594b..f0994631307343 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Maps.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Maps.lean @@ -390,6 +390,11 @@ theorem mapEdgeSet.injective (hinj : Function.Injective f) : Function.Injective repeat rw [Subtype.mk_eq_mk] apply Sym2.map.injective hinj +@[gcongr] +theorem _root_.SimpleGraph.neighborSet_mono (hle : G₁ ≤ G₂) (v : V) : + G₁.neighborSet v ⊆ G₂.neighborSet v := + subset_preimage_neighborSet v <| .ofLE hle + /-- Every graph homomorphism from a complete graph is injective. -/ theorem injective_of_top_hom (f : (⊤ : SimpleGraph V) →g G') : Function.Injective f := by intro v w h diff --git a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean index 9d7b7869c2de56..d9cb9312fa1601 100644 --- a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean +++ b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean @@ -64,6 +64,7 @@ theorem bot_strongly_regular : (⊥ : SimpleGraph V).IsSRGWith (Fintype.card V) of_not_adj v w _ := by simp only [card_eq_zero, Fintype.card_ofFinset, forall_true_left, not_false_iff, bot_adj] ext + -- #38747 simp theorem IsSRGWith.ediam_eq_two [Nontrivial V] (h : G.IsSRGWith n k ℓ μ) (ht : G ≠ ⊤) (hm : μ ≠ 0) : From 035f7b00058170edbd68944613398a5d24175556 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 30 Apr 2026 06:08:06 +0300 Subject: [PATCH 46/60] fix `StronglyRegular.lean` --- Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean index d9cb9312fa1601..6e3ff1b129500f 100644 --- a/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean +++ b/Mathlib/Combinatorics/SimpleGraph/StronglyRegular.lean @@ -64,8 +64,7 @@ theorem bot_strongly_regular : (⊥ : SimpleGraph V).IsSRGWith (Fintype.card V) of_not_adj v w _ := by simp only [card_eq_zero, Fintype.card_ofFinset, forall_true_left, not_false_iff, bot_adj] ext - -- #38747 - simp + simp [mem_commonNeighbors] theorem IsSRGWith.ediam_eq_two [Nontrivial V] (h : G.IsSRGWith n k ℓ μ) (ht : G ≠ ⊤) (hm : μ ≠ 0) : G.ediam = 2 := by From 8f0c410f3bf260050935b9a5e3ca3119e78ae36c Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Thu, 30 Apr 2026 20:38:38 +0300 Subject: [PATCH 47/60] use `IsIsolated` more --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 13 +++++++++---- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 5 +---- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 15 +++------------ 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index d8324ce0b0bc4f..e4e50a2506cddc 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -797,10 +797,6 @@ theorem neighborSet_top : neighborSet ⊤ v = {v}ᶜ := by theorem neighborSet_bot : neighborSet ⊥ v = ∅ := by grind [mem_neighborSet, bot_adj] --- #38747 -theorem eq_bot_iff_neighborSet : G = ⊥ ↔ ∀ v, G.neighborSet v = ∅ := by - simp [eq_bot_iff_forall_not_adj, Set.eq_empty_iff_forall_notMem] - -- #38747 variable {G} in theorem Adj.nontrivial (hadj : G.Adj u v) : Nontrivial V := @@ -960,4 +956,13 @@ variable {G} in theorem Adj.not_isIsolated_right (h : G.Adj u v) : ¬G.IsIsolated v := h.symm.not_isIsolated_left +-- #38747 +@[simp] +theorem isIsolated_bot : IsIsolated ⊥ v := by + simp [← neighborSet_eq_empty] + +-- #38747 +theorem eq_bot_iff_isIsolated : G = ⊥ ↔ ∀ v, G.IsIsolated v := by + simp [eq_bot_iff_forall_not_adj, ← neighborSet_eq_empty, Set.eq_empty_iff_forall_notMem] + end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index a5a713e849327f..df926702f8b1d3 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -123,9 +123,6 @@ theorem edegree_top : edegree ⊤ v = ENat.card V - 1 := by theorem edegree_bot : edegree ⊥ v = 0 := by simp [← encard_neighborSet] -theorem eq_bot_iff_edegree : G = ⊥ ↔ ∀ v, G.edegree v = 0 := by - simp [eq_bot_iff_neighborSet, edegree_eq_zero_iff_isIsolated] - variable {G} in theorem IsRegularOfDegree.edegree_eq [G.LocallyFinite] {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : G.edegree v = d := @@ -148,7 +145,7 @@ theorem minEDegree_eq_iInf : G.minEDegree = ⨅ v, G.edegree v := by variable {G} in @[simp] theorem maxEDegree_eq_zero_iff_eq_bot : G.maxEDegree = 0 ↔ G = ⊥ := by - simp [maxEDegree_eq_iSup, eq_bot_iff_edegree] + simp [maxEDegree_eq_iSup, eq_bot_iff_isIsolated] variable {G} in theorem minEDegree_eq_zero_iff_support_ne : G.minEDegree = 0 ↔ G.support ≠ .univ := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index fa972ff43664db..a3b63c4d8414f1 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -226,10 +226,6 @@ variable {G v} in theorem degree_pos_iff_nonempty : 0 < G.degree v ↔ (G.neighborSet v).Nonempty := G.degree_pos_iff_exists_adj v -variable {G v} in -theorem degree_eq_zero_iff_neighborSet_eq_empty : G.degree v = 0 ↔ G.neighborSet v = ∅ := by - rw [← ncard_neighborSet, Set.ncard_eq_zero] - variable {G v} in theorem Adj.degree_pos_left {w : V} (h : G.Adj v w) : 0 < G.degree v := G.degree_pos_iff_nonempty.mpr ⟨_, h⟩ @@ -371,13 +367,8 @@ theorem complete_graph_degree [DecidableEq V] (v : V) : simp_rw [degree, neighborFinset_eq_filter, top_adj, filter_ne] rw [card_erase_of_mem (mem_univ v), card_univ] -@[simp] theorem bot_degree (v : V) : (⊥ : SimpleGraph V).degree v = 0 := by - simp [degree_eq_zero_iff_neighborSet_eq_empty] - -omit [Fintype V] in -theorem eq_bot_iff_degree [G.LocallyFinite] : G = ⊥ ↔ ∀ v, G.degree v = 0 := by - simp [eq_bot_iff_neighborSet, degree_eq_zero_iff_neighborSet_eq_empty] + simp theorem IsRegularOfDegree.top [DecidableEq V] : (⊤ : SimpleGraph V).IsRegularOfDegree (Fintype.card V - 1) := by @@ -480,9 +471,9 @@ variable {G} in @[simp] theorem maxDegree_eq_zero_iff [DecidableRel G.Adj] : G.maxDegree = 0 ↔ G = ⊥ := by refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ - · rw [eq_bot_iff_degree] + · rw [eq_bot_iff_isIsolated] intro v - grind [G.degree_le_maxDegree v] + grind [degree_eq_zero, G.degree_le_maxDegree v] · convert maxDegree_bot_eq_zero assumption From 727ab1047facd08cacdf574438f3518230a59509 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 1 May 2026 00:54:45 +0300 Subject: [PATCH 48/60] fix `#lint` --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 5 ++--- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index e4e50a2506cddc..3d62cf635e0ffa 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -793,7 +793,6 @@ theorem neighborSet_top : neighborSet ⊤ v = {v}ᶜ := by grind [mem_neighborSet, top_adj] -- #38747 -@[simp] theorem neighborSet_bot : neighborSet ⊥ v = ∅ := by grind [mem_neighborSet, bot_adj] @@ -958,8 +957,8 @@ theorem Adj.not_isIsolated_right (h : G.Adj u v) : ¬G.IsIsolated v := -- #38747 @[simp] -theorem isIsolated_bot : IsIsolated ⊥ v := by - simp [← neighborSet_eq_empty] +theorem isIsolated_bot : IsIsolated ⊥ v := + neighborSet_eq_empty _ |>.mp neighborSet_bot -- #38747 theorem eq_bot_iff_isIsolated : G = ⊥ ↔ ∀ v, G.IsIsolated v := by diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index a3b63c4d8414f1..9f4ffc429edaa2 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -367,6 +367,7 @@ theorem complete_graph_degree [DecidableEq V] (v : V) : simp_rw [degree, neighborFinset_eq_filter, top_adj, filter_ne] rw [card_erase_of_mem (mem_univ v), card_univ] +-- #38747 theorem bot_degree (v : V) : (⊥ : SimpleGraph V).degree v = 0 := by simp From ebeb0dba926edc1bbf90473846538367a285b8aa Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 1 May 2026 03:06:16 +0300 Subject: [PATCH 49/60] `@[simp]` fixes and min degree = 0 iff corrections --- Mathlib/Combinatorics/SimpleGraph/Basic.lean | 1 + Mathlib/Combinatorics/SimpleGraph/Degree.lean | 13 ++++++++----- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 11 ++++++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 3d62cf635e0ffa..a670f89616fcdc 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -926,6 +926,7 @@ lemma mem_support_iff_not_isIsolated : v ∈ G.support ↔ ¬ G.IsIsolated v := simp [mem_support, IsIsolated] -- #38747 +@[simp] theorem notMem_support_iff_isIsolated : v ∉ G.support ↔ G.IsIsolated v := by simp [mem_support_iff_not_isIsolated] diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index df926702f8b1d3..889caf66527275 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -39,6 +39,7 @@ variable {G v} in theorem edegree_eq_zero_iff_isIsolated : G.edegree v = 0 ↔ G.IsIsolated v := by simp [← encard_neighborSet] +@[simp] alias ⟨_, IsIsolated.edegree_eq⟩ := edegree_eq_zero_iff_isIsolated variable {G u v} in @@ -53,10 +54,9 @@ variable {G v} in theorem nontrivial_of_edegree_ne_zero (h : G.edegree v ≠ 0) : Nontrivial V := nontrivial_of_not_isIsolated <| edegree_eq_zero_iff_isIsolated.not.mp h -@[simp] theorem edegree_eq_zero_of_subsingleton [Subsingleton V] (G : SimpleGraph V) (v : V) : - G.edegree v = 0 := - edegree_eq_zero_iff_isIsolated.mpr <| .of_subsingleton G v + G.edegree v = 0 := by + simp variable {G v} in theorem edegree_eq_one_iff_existsUnique_adj : G.edegree v = 1 ↔ ∃! u, G.Adj v u := by @@ -119,9 +119,8 @@ theorem edegree_top : edegree ⊤ v = ENat.card V - 1 := by rw [← encard_neighborSet, neighborSet_top, ← Set.encard_ne_add_one v, ← Set.compl_singleton_eq] cases Set.encard {v}ᶜ <;> norm_cast -@[simp] theorem edegree_bot : edegree ⊥ v = 0 := by - simp [← encard_neighborSet] + simp variable {G} in theorem IsRegularOfDegree.edegree_eq [G.LocallyFinite] {d : ℕ} (h : G.IsRegularOfDegree d) (v : V) : @@ -147,6 +146,10 @@ variable {G} in theorem maxEDegree_eq_zero_iff_eq_bot : G.maxEDegree = 0 ↔ G = ⊥ := by simp [maxEDegree_eq_iSup, eq_bot_iff_isIsolated] +variable {G} in +theorem minEDegree_eq_zero_iff_isIsolated : G.minEDegree = 0 ↔ ∃ v, G.IsIsolated v := by + simp [minEDegree_eq_iInf] + variable {G} in theorem minEDegree_eq_zero_iff_support_ne : G.minEDegree = 0 ↔ G.support ≠ .univ := by simp [minEDegree_eq_iInf, Set.ne_univ_iff_exists_notMem, notMem_support_iff_isIsolated] diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 9f4ffc429edaa2..caabf61f25e6bf 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -500,10 +500,15 @@ lemma minDegree_bot_eq_zero : (⊥ : SimpleGraph V).minDegree = 0 := variable {G} in theorem minDegree_eq_zero_iff [DecidableRel G.Adj] [Nonempty V] : - G.minDegree = 0 ↔ ∃ v, G.degree v = 0 := by + G.minDegree = 0 ↔ ∃ v, G.IsIsolated v := by refine ⟨fun h ↦ ?_, fun ⟨v, hv⟩ ↦ ?_⟩ - · grind [G.exists_minimal_degree_vertex] - · grind [G.minDegree_le_degree v] + · grind [G.exists_minimal_degree_vertex, degree_eq_zero] + · grind [G.minDegree_le_degree v, degree_eq_zero] + +variable {G} in +theorem minDegree_eq_zero_iff_support_ne [DecidableRel G.Adj] [Nonempty V] : + G.minDegree = 0 ↔ G.support ≠ .univ := by + simp [Set.ne_univ_iff_exists_notMem, minDegree_eq_zero_iff] @[simp] lemma minDegree_top [DecidableEq V] : (⊤ : SimpleGraph V).minDegree = Fintype.card V - 1 := by From 5096e0bd202ece01da83ff2d29a1374acb5c10d6 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 1 May 2026 03:30:11 +0300 Subject: [PATCH 50/60] degrees of `G.induce s` --- Mathlib/Combinatorics/SimpleGraph/Copy.lean | 9 +++++ Mathlib/Combinatorics/SimpleGraph/Degree.lean | 37 +++++++++++++++++-- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 11 ++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Copy.lean b/Mathlib/Combinatorics/SimpleGraph/Copy.lean index 81680efada20c7..fbba11c57539fb 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Copy.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Copy.lean @@ -345,6 +345,15 @@ theorem Hom.minDegree_le [Fintype V] [Fintype W] [DecidableRel G.Adj] [Decidable {f : G →g H} (hf : Function.Bijective f) : G.minDegree ≤ H.minDegree := Copy.minDegree_le (f := ⟨f, hf.injective⟩) hf.surjective +theorem maxDegree_induce_of_support_subset [Fintype V] [DecidableRel G.Adj] {s : Set V} + [DecidablePred (· ∈ s)] (h : G.support ⊆ s) : (G.induce s).maxDegree = G.maxDegree := by + apply le_antisymm <| Copy.max_degree_le <| Embedding.induce s |>.toCopy + refine G.maxDegree_le_of_forall_degree_le _ fun v ↦ ?_ + by_cases hv : G.IsIsolated v + · simp [hv] + grw [← degree_le_maxDegree _ ⟨v, h <| G.mem_support_iff_not_isIsolated.mpr hv⟩, + degree_induce_of_neighborSet_subset <| G.neighborSet_subset_support v |>.trans h] + end IsContained section Free diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 889caf66527275..6715b585562c04 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -180,17 +180,19 @@ theorem edegree_le_maxEDegree : G.edegree v ≤ G.maxEDegree := theorem minEDegree_le_edegree : G.minEDegree ≤ G.edegree v := iInf_le G.edegree v -variable {v} in +variable {G v} in theorem maxEDegree_eq_top_of_edegree_eq_top (h : G.edegree v = ⊤) : G.maxEDegree = ⊤ := eq_top_iff.mpr <| G.edegree_le_maxEDegree v |>.trans_eq' h -variable {v} in +variable {G v} in theorem minEDegree_eq_zero_of_edegree_eq_zero (h : G.edegree v = 0) : G.minEDegree = 0 := nonpos_iff_eq_zero.mp <| G.minEDegree_le_edegree v |>.trans_eq h +variable {G} in theorem maxEDegree_le_of_forall_edegree_le {n : ℕ∞} (h : ∀ v, G.edegree v ≤ n) : G.maxEDegree ≤ n := iSup_le h +variable {G} in theorem le_minEDegree_of_forall_le_edegree {n : ℕ∞} (h : ∀ v, n ≤ G.edegree v) : n ≤ G.minEDegree := le_iInf h @@ -323,7 +325,7 @@ theorem minEDegree_le_encard_edgeSet [Nonempty V] (G : SimpleGraph V) : exact hv ▸ G.edegree_le_encard_edgeSet v theorem maxEDegree_le_encard_edgeSet : G.maxEDegree ≤ G.edgeSet.encard := - maxEDegree_le_of_forall_edegree_le _ G.edegree_le_encard_edgeSet + maxEDegree_le_of_forall_edegree_le G.edegree_le_encard_edgeSet theorem minEDegree_le_maxEDegree [Nonempty V] (G : SimpleGraph V) : G.minEDegree ≤ G.maxEDegree := by @@ -358,4 +360,33 @@ theorem IsRegularOfDegree.minEDegree_eq [Nonempty V] [G.LocallyFinite] {d : ℕ} (h : G.IsRegularOfDegree d) : G.minEDegree = d := by simp [minEDegree_eq_iInf, h.edegree_eq] +section Induce + +variable {s : Set V} + +variable {G} in +theorem edegree_induce_of_neighborSet_subset {v : s} (h : G.neighborSet v ⊆ s) : + (G.induce s).edegree v = G.edegree v := by + rw [← encard_neighborSet, ← encard_neighborSet, neighborSet_induce, + Set.encard_preimage_of_injective_subset_range Subtype.val_injective <| by simpa] + +variable {G} in +theorem maxEDegree_induce_of_support_subset (h : G.support ⊆ s) : + (G.induce s).maxEDegree = G.maxEDegree := by + apply le_antisymm <| Embedding.induce s |>.isContained.maxEDegree_le + refine G.maxEDegree_le_of_forall_edegree_le fun v ↦ ?_ + by_cases hv : G.IsIsolated v + · simp [hv] + grw [← edegree_le_maxEDegree _ ⟨v, h <| G.mem_support_iff_not_isIsolated.mpr hv⟩, + edegree_induce_of_neighborSet_subset <| G.neighborSet_subset_support v |>.trans h] + +variable {G} in +theorem le_minEDegree_induce_of_support_subset (h : G.support ⊆ s) : + G.minEDegree ≤ (G.induce s).minEDegree := by + refine le_minEDegree_of_forall_le_edegree fun v ↦ ?_ + grw [G.minEDegree_le_edegree v, edegree_induce_of_neighborSet_subset] + grw [neighborSet_subset_support, h] + +end Induce + end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index caabf61f25e6bf..67ec096d877761 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -652,6 +652,17 @@ theorem degree_induce_support (v : G.support) : (G.induce G.support).degree v = G.degree v := degree_induce_of_support_subset subset_rfl v +theorem le_minDegree_induce_of_support_subset (h : G.support ⊆ s) : + G.minDegree ≤ (G.induce s).minDegree := by + cases isEmpty_or_nonempty V + · simp + rcases s.eq_empty_or_nonempty with (rfl | hs) + · simp [minDegree_eq_zero_iff_support_ne, Set.subset_empty_iff.mp h, Set.empty_ne_univ] + have := hs.to_subtype + refine le_minDegree_of_forall_le_degree _ _ fun v ↦ ?_ + grw [G.minDegree_le_degree v, degree_induce_of_neighborSet_subset] + grw [neighborSet_subset_support, h] + end Support section Map From 369216c1289fe5a3d284a62abfe31092618761e3 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Fri, 1 May 2026 21:25:15 +0300 Subject: [PATCH 51/60] update dependencies after merge --- Mathlib/Order/SuccPred/CompleteLinearOrder.lean | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean index 63b38cab888bd0..851faf3b1db7bf 100644 --- a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean +++ b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean @@ -164,28 +164,24 @@ end CompleteLinearOrder namespace WithTop --- #38244 -@[to_dual] -theorem isSuccPrelimit_top [LT α] [NoMaxOrder α] : IsSuccPrelimit (⊤ : WithTop α) := by - intro a ha - obtain ⟨a, rfl⟩ := ne_top_iff_exists.mp <| WithTop.lt_top_iff_ne_top.mp ha.lt - have ⟨b, hab⟩ := NoMaxOrder.exists_gt a - exact ha.right (coe_lt_coe.mpr hab) (coe_lt_top b) - variable [ConditionallyCompleteLinearOrderBot α] +-- TODO: extract after #38612 theorem sSup_eq_top_iff_lt {s : Set (WithTop α)} : sSup s = ⊤ ↔ ∀ a : α, ∃ b ∈ s, a < b := by rw [sSup_eq_top] exact forall_lt_top +-- TODO: extract after #38612 theorem iSup_eq_top_iff_lt {f : ι → WithTop α} : iSup f = ⊤ ↔ ∀ a : α, ∃ i, a < f i := sSup_eq_top_iff_lt.trans <| forall_congr' fun _ ↦ exists_range_iff +-- TODO: extract after #38612 theorem sSup_eq_top_iff_le [NoMaxOrder α] {s : Set (WithTop α)} : sSup s = ⊤ ↔ ∀ a : α, ∃ b ∈ s, a ≤ b := by rw [eq_top_iff, isSuccPrelimit_top.le_sSup_iff] exact forall_lt_top +-- TODO: extract after #38612 theorem iSup_eq_top_iff_le [NoMaxOrder α] {f : ι → WithTop α} : iSup f = ⊤ ↔ ∀ a : α, ∃ i, a ≤ f i := sSup_eq_top_iff_le.trans <| forall_congr' fun _ ↦ exists_range_iff From 12ef01d52ce7e3fc0297f28f27f5943085b478ab Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:26:41 +0300 Subject: [PATCH 52/60] update dependencies after merge --- Mathlib/Order/ConditionallyCompleteLattice/Finset.lean | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean index 64d006010716dd..386e4e5f5ff243 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -143,13 +143,6 @@ theorem Set.Finite.lt_ciInf_iff {s : Set ι} {f : ι → α} (hs : s.Finite) rw [← hx] exact H _ hmem --- #38356 -theorem iSup_ne_top {ι α : Type*} {f : ι → α} [Finite ι] [Nontrivial α] [CompleteLinearOrder α] - (h : ∀ x, f x ≠ ⊤) : iSup f ≠ ⊤ := by - rcases Set.range f |>.eq_empty_or_nonempty with hempty | hnonempty - · simp [iSup, hempty] - grind [iSup, hnonempty.csSup_mem <| Set.finite_range f] - section ListMultiset lemma List.iSup_mem_map_of_exists_sSup_empty_le {l : List ι} (f : ι → α) From 0b4f0e460839148fa51ca75161e2d1c8e697c110 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:47:09 +0300 Subject: [PATCH 53/60] extracted `WithTop` `sSup` theorems --- Mathlib/Order/SuccPred/CompleteLinearOrder.lean | 8 ++++---- Mathlib/Order/WithBot.lean | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean index cce71199825d93..e3c21e97600cff 100644 --- a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean +++ b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean @@ -178,22 +178,22 @@ namespace WithTop variable [ConditionallyCompleteLinearOrderBot α] --- TODO: extract after #38612 +-- #40620 theorem sSup_eq_top_iff_lt {s : Set (WithTop α)} : sSup s = ⊤ ↔ ∀ a : α, ∃ b ∈ s, a < b := by rw [sSup_eq_top] exact forall_lt_top --- TODO: extract after #38612 +-- #40620 theorem iSup_eq_top_iff_lt {f : ι → WithTop α} : iSup f = ⊤ ↔ ∀ a : α, ∃ i, a < f i := sSup_eq_top_iff_lt.trans <| forall_congr' fun _ ↦ exists_range_iff --- TODO: extract after #38612 +-- #40620 theorem sSup_eq_top_iff_le [NoMaxOrder α] {s : Set (WithTop α)} : sSup s = ⊤ ↔ ∀ a : α, ∃ b ∈ s, a ≤ b := by rw [eq_top_iff, isSuccPrelimit_top.le_sSup_iff] exact forall_lt_top --- TODO: extract after #38612 +-- #40620 theorem iSup_eq_top_iff_le [NoMaxOrder α] {f : ι → WithTop α} : iSup f = ⊤ ↔ ∀ a : α, ∃ i, a ≤ f i := sSup_eq_top_iff_le.trans <| forall_congr' fun _ ↦ exists_range_iff diff --git a/Mathlib/Order/WithBot.lean b/Mathlib/Order/WithBot.lean index 628777e4324436..be56b681baa290 100644 --- a/Mathlib/Order/WithBot.lean +++ b/Mathlib/Order/WithBot.lean @@ -514,6 +514,7 @@ lemma lt_unbotA_iff [Nonempty α] (hx : x ≠ ⊥) : a < x.unbotA ↔ a < x := l lemma unbotA_lt_iff [Nonempty α] (hx : x ≠ ⊥) : x.unbotA < a ↔ x < a := by lift x to α using hx; simp +-- #40620 @[to_dual forall_lt_top] theorem forall_bot_lt {p : WithBot α → Prop} : (∀ a, ⊥ < a → p a) ↔ (∀ a : α, p a) := by simp_rw [WithBot.bot_lt_iff_ne_bot] From 0a035d1699e0a88bb2cad84756e8140e0d14842b Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:53:58 +0300 Subject: [PATCH 54/60] fix `simp`s --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 3c73f5c9d9e523..02edb7bdcf826a 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -126,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] @@ -208,7 +208,7 @@ theorem card_neighborSet_eq_degree : Fintype.card (G.neighborSet v) = G.degree v @[simp] theorem ncard_neighborSet : (G.neighborSet v).ncard = G.degree v := by - simp [Set.ncard_eq_toFinset_card'] + simp [Set.ncard_eq_toFinset_card', card_neighborSet_eq_degree, -Set.fintypeCard_eq_ncard] lemma degree_eq_zero : G.degree v = 0 ↔ G.IsIsolated v := by simp [← card_neighborFinset_eq_degree] lemma degree_pos : 0 < G.degree v ↔ ¬ G.IsIsolated v := by simp [← card_neighborFinset_eq_degree] @@ -255,8 +255,7 @@ theorem degree_compl [Fintype (Gᶜ.neighborSet v)] [Fintype V] : Gᶜ.degree v = Fintype.card V - 1 - G.degree v := by 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] + simp [card_union_of_disjoint (Set.disjoint_toFinset.mpr (compl_neighborSet_disjoint G v))] instance incidenceSetFintype [DecidableEq V] : Fintype (G.incidenceSet v) := Fintype.ofEquiv (G.neighborSet v) (G.incidenceSetEquivNeighborSet v).symm @@ -550,12 +549,13 @@ 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] omit [Fintype V] theorem encard_commonNeighbors_top {u v : V} (h : u ≠ v) : (commonNeighbors ⊤ u v).encard = ENat.card V - 2 := by - simp [commonNeighbors_top_eq, Set.encard_diff, Set.encard_pair h] + simp [commonNeighbors_top_eq, Set.encard_sdiff, Set.encard_pair h] end Finite From da71f8267174d4d861621530dff5a7a17f753108 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:58:00 +0300 Subject: [PATCH 55/60] fix usage of deprecated name --- Mathlib/Combinatorics/SimpleGraph/Copy.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Copy.lean b/Mathlib/Combinatorics/SimpleGraph/Copy.lean index 69521599f0cee1..9d1a1aeca11775 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Copy.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Copy.lean @@ -357,7 +357,7 @@ theorem Hom.minDegree_mono [Fintype V] [Fintype W] [DecidableRel G.Adj] [Decidab theorem maxDegree_induce_of_support_subset [Fintype V] [DecidableRel G.Adj] {s : Set V} [DecidablePred (· ∈ s)] (h : G.support ⊆ s) : (G.induce s).maxDegree = G.maxDegree := by - apply le_antisymm <| Copy.max_degree_le <| Embedding.induce s |>.toCopy + apply le_antisymm <| Copy.maxDegree_mono <| Embedding.induce s |>.toCopy refine G.maxDegree_le_of_forall_degree_le _ fun v ↦ ?_ by_cases hv : G.IsIsolated v · simp [hv] From 835833fed4ed9d5b7897faf5a37889617723826a Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:58:53 +0300 Subject: [PATCH 56/60] update deprecation dates --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 02edb7bdcf826a..212c67a36b59a6 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -406,7 +406,7 @@ lemma minDegree_of_subsingleton [DecidableRel G.Adj] [Subsingleton V] : G.minDeg cases isEmpty_or_nonempty V <;> simp [minDegree, Finset.image_const] -@[deprecated (since := "2026-04-05")] alias minDegree_of_isEmpty := minDegree_of_subsingleton +@[deprecated (since := "2026-06-15")] alias minDegree_of_isEmpty := minDegree_of_subsingleton variable {G} in /-- If `G` is a subgraph of `H` then `G.minDegree ≤ H.minDegree`. -/ @@ -446,7 +446,7 @@ lemma maxDegree_of_subsingleton [DecidableRel G.Adj] [Subsingleton V] : G.maxDeg cases isEmpty_or_nonempty V <;> simp [maxDegree, Finset.image_const] -@[deprecated (since := "2026-04-05")] alias maxDegree_of_isEmpty := maxDegree_of_subsingleton +@[deprecated (since := "2026-06-15")] alias maxDegree_of_isEmpty := maxDegree_of_subsingleton /-- In a graph, if `k` is at least the degree of every vertex, then it is at least the maximum degree. -/ From ac9cb009fb049a98ec5968de40b3a89c822a5d2f Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 15 Jun 2026 12:35:40 +0300 Subject: [PATCH 57/60] extracted most `Finite.lean` changes to a separate PR --- Mathlib/Combinatorics/SimpleGraph/Copy.lean | 12 +--- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 58 ++++--------------- 2 files changed, 13 insertions(+), 57 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Copy.lean b/Mathlib/Combinatorics/SimpleGraph/Copy.lean index 9d1a1aeca11775..7ec6f8e34559ab 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Copy.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Copy.lean @@ -341,8 +341,7 @@ lemma maxDegree_mono {H : SimpleGraph V} [Fintype V] [DecidableRel G.Adj] [Decid theorem Copy.minDegree_mono [Fintype V] [Fintype W] [DecidableRel G.Adj] [DecidableRel H.Adj] {f : Copy G H} (hf : Function.Surjective f) : G.minDegree ≤ H.minDegree := by cases isEmpty_or_nonempty W - · have := Function.isEmpty f - simp + · simp [Function.isEmpty f] refine H.le_minDegree_of_forall_le_degree _ fun w ↦ ?_ obtain ⟨v, rfl⟩ := hf w grw [← f.degree_le, ← minDegree_le_degree] @@ -355,15 +354,6 @@ theorem Hom.minDegree_mono [Fintype V] [Fintype W] [DecidableRel G.Adj] [Decidab @[deprecated (since := "2026-05-20")] alias Hom.minDegree_le := Hom.minDegree_mono -theorem maxDegree_induce_of_support_subset [Fintype V] [DecidableRel G.Adj] {s : Set V} - [DecidablePred (· ∈ s)] (h : G.support ⊆ s) : (G.induce s).maxDegree = G.maxDegree := by - apply le_antisymm <| Copy.maxDegree_mono <| Embedding.induce s |>.toCopy - refine G.maxDegree_le_of_forall_degree_le _ fun v ↦ ?_ - by_cases hv : G.IsIsolated v - · simp [hv] - grw [← degree_le_maxDegree _ ⟨v, h <| G.mem_support_iff_not_isIsolated.mpr hv⟩, - degree_induce_of_neighborSet_subset <| G.neighborSet_subset_support v |>.trans h] - end IsContained section Free diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index 212c67a36b59a6..b5e50f3ae9bac1 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -206,6 +206,7 @@ theorem card_neighborFinset_eq_degree : #(G.neighborFinset v) = G.degree v := rf theorem card_neighborSet_eq_degree : Fintype.card (G.neighborSet v) = G.degree v := (Set.toFinset_card _).symm +-- TODO: extract to a separate PR @[simp] theorem ncard_neighborSet : (G.neighborSet v).ncard = G.degree v := by simp [Set.ncard_eq_toFinset_card', card_neighborSet_eq_degree, -Set.fintypeCard_eq_ncard] @@ -389,8 +390,10 @@ theorem exists_minimal_degree_vertex [DecidableRel G.Adj] [Nonempty V] : grind [minDegree, WithTop.untopD_coe, min_mem_image_coe <| univ_nonempty.image (G.degree ·)] /-- The minimum degree in the graph is at most the degree of any particular vertex. -/ -theorem minDegree_le_degree [DecidableRel G.Adj] (v : V) : G.minDegree ≤ G.degree v := - WithTop.untopD_le <| Finset.min_le <| mem_image_of_mem (G.degree ·) <| mem_univ v +theorem minDegree_le_degree [DecidableRel G.Adj] (v : V) : G.minDegree ≤ G.degree v := by + obtain ⟨t, ht⟩ := Finset.min_of_mem (mem_image_of_mem (fun v => G.degree v) (mem_univ v)) + have := Finset.min_le_of_eq (mem_image_of_mem _ (mem_univ v)) ht + rwa [minDegree, ht] /-- In a nonempty graph, if `k` is at most the degree of every vertex, it is at most the minimum degree. Note the assumption that the graph is nonempty is necessary as long as `G.minDegree` is @@ -401,16 +404,14 @@ theorem le_minDegree_of_forall_le_degree [DecidableRel G.Adj] [Nonempty V] (k : rw [hv] apply h +/-- If there are no vertices then the `minDegree` is zero. -/ @[simp] -lemma minDegree_of_subsingleton [DecidableRel G.Adj] [Subsingleton V] : G.minDegree = 0 := by - cases isEmpty_or_nonempty V <;> - simp [minDegree, Finset.image_const] - -@[deprecated (since := "2026-06-15")] alias minDegree_of_isEmpty := minDegree_of_subsingleton +lemma minDegree_of_isEmpty [DecidableRel G.Adj] [IsEmpty V] : G.minDegree = 0 := by + rw [minDegree, WithTop.untopD_eq_self_iff] + simp variable {G} in /-- If `G` is a subgraph of `H` then `G.minDegree ≤ H.minDegree`. -/ -@[gcongr] lemma minDegree_le_minDegree {H : SimpleGraph V} [DecidableRel G.Adj] [DecidableRel H.Adj] (hle : G ≤ H) : G.minDegree ≤ H.minDegree := by cases isEmpty_or_nonempty V @@ -442,11 +443,8 @@ theorem degree_le_maxDegree [DecidableRel G.Adj] (v : V) : G.degree v ≤ G.maxD WithBot.le_unbotD <| Finset.le_max <| mem_image_of_mem (G.degree ·) <| mem_univ v @[simp] -lemma maxDegree_of_subsingleton [DecidableRel G.Adj] [Subsingleton V] : G.maxDegree = 0 := by - cases isEmpty_or_nonempty V <;> - simp [maxDegree, Finset.image_const] - -@[deprecated (since := "2026-06-15")] alias maxDegree_of_isEmpty := maxDegree_of_subsingleton +lemma maxDegree_of_isEmpty [DecidableRel G.Adj] [IsEmpty V] : G.maxDegree = 0 := by + rw [maxDegree, univ_eq_empty, image_empty, max_empty, WithBot.unbotD_bot] /-- In a graph, if `k` is at least the degree of every vertex, then it is at least the maximum degree. -/ @@ -465,16 +463,6 @@ theorem IsRegularOfDegree.maxDegree_eq [Nonempty V] [DecidableRel G.Adj] {d : lemma maxDegree_bot_eq_zero : (⊥ : SimpleGraph V).maxDegree = 0 := Nat.le_zero.1 <| maxDegree_le_of_forall_degree_le _ _ (by simp) -variable {G} in -@[simp] -theorem maxDegree_eq_zero_iff [DecidableRel G.Adj] : G.maxDegree = 0 ↔ G = ⊥ := by - refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ - · rw [eq_bot_iff_isIsolated] - intro v - grind [degree_eq_zero, G.degree_le_maxDegree v] - · convert maxDegree_bot_eq_zero - assumption - @[simp] lemma maxDegree_top [DecidableEq V] : (⊤ : SimpleGraph V).maxDegree = Fintype.card V - 1 := by cases isEmpty_or_nonempty V @@ -495,18 +483,6 @@ theorem IsRegularOfDegree.minDegree_eq [Nonempty V] [DecidableRel G.Adj] {d : lemma minDegree_bot_eq_zero : (⊥ : SimpleGraph V).minDegree = 0 := Nat.le_zero.1 <| (minDegree_le_maxDegree _).trans (by simp) -variable {G} in -theorem minDegree_eq_zero_iff [DecidableRel G.Adj] [Nonempty V] : - G.minDegree = 0 ↔ ∃ v, G.IsIsolated v := by - refine ⟨fun h ↦ ?_, fun ⟨v, hv⟩ ↦ ?_⟩ - · grind [G.exists_minimal_degree_vertex, degree_eq_zero] - · grind [G.minDegree_le_degree v, degree_eq_zero] - -variable {G} in -theorem minDegree_eq_zero_iff_support_ne [DecidableRel G.Adj] [Nonempty V] : - G.minDegree = 0 ↔ G.support ≠ .univ := by - simp [Set.ne_univ_iff_exists_notMem, minDegree_eq_zero_iff] - @[simp] lemma minDegree_top [DecidableEq V] : (⊤ : SimpleGraph V).minDegree = Fintype.card V - 1 := by cases isEmpty_or_nonempty V @@ -552,6 +528,7 @@ theorem card_commonNeighbors_top [DecidableEq V] {v w : V} (h : v ≠ w) : simp [commonNeighbors_top_eq, ← Set.toFinset_card, Finset.card_sdiff, h, -Set.fintypeCard_eq_ncard] +-- TODO: extract to a separate PR omit [Fintype V] theorem encard_commonNeighbors_top {u v : V} (h : u ≠ v) : (commonNeighbors ⊤ u v).encard = ENat.card V - 2 := by @@ -648,17 +625,6 @@ theorem degree_induce_support (v : G.support) : (G.induce G.support).degree v = G.degree v := degree_induce_of_support_subset subset_rfl v -theorem le_minDegree_induce_of_support_subset (h : G.support ⊆ s) : - G.minDegree ≤ (G.induce s).minDegree := by - cases isEmpty_or_nonempty V - · simp - rcases s.eq_empty_or_nonempty with (rfl | hs) - · simp [minDegree_eq_zero_iff_support_ne, Set.subset_empty_iff.mp h, Set.empty_ne_univ] - have := hs.to_subtype - refine le_minDegree_of_forall_le_degree _ _ fun v ↦ ?_ - grw [G.minDegree_le_degree v, degree_induce_of_neighborSet_subset] - grw [neighborSet_subset_support, h] - end Support section Map From 1fb554344d19780a8dad6f4d4735262d88ea66db Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:07:49 +0300 Subject: [PATCH 58/60] fixes after merging master --- Mathlib/Combinatorics/SimpleGraph/Degree.lean | 6 ++---- Mathlib/Combinatorics/SimpleGraph/Subgraph.lean | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Degree.lean b/Mathlib/Combinatorics/SimpleGraph/Degree.lean index 6715b585562c04..7fcf4abbf62f76 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Degree.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Degree.lean @@ -70,7 +70,7 @@ theorem edegree_ne_top_of_finite [Finite V] (G : SimpleGraph V) (v : V) : G.edeg edegree_ne_top_iff_finite_neighborSet.mpr <| Set.toFinite _ theorem coe_degree_eq_edegree [Fintype <| G.neighborSet v] : G.degree v = G.edegree v := by - simp [← encard_neighborSet, ← card_neighborSet_eq_degree] + simp [encard_neighborSet, ← ncard_neighborSet] variable {G v} in theorem edegree_eq_coe_iff [Fintype <| G.neighborSet v] {n : ℕ} : @@ -230,7 +230,7 @@ theorem coe_minDegree_eq_minEDegree [Nonempty V] [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] : G.minDegree = G.minEDegree := by rw [minEDegree_eq_iInf, minDegree, ← Finset.coe_min' <| by simp, Finset.min'_eq_inf', Finset.inf'_image, Finset.inf'_univ_eq_ciInf] - simpa [← coe_degree_eq_edegree] using ENat.coe_iInf + simpa [← coe_degree_eq_edegree] using! ENat.coe_iInf variable {G} in theorem maxEDegree_eq_coe_iff [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] {n : ℕ} : @@ -278,12 +278,10 @@ theorem Hom.minEDegree_le {f : G →g H} (hf : Function.Bijective f) : G.minEDeg Copy.minEDegree_le (f := ⟨f, hf.injective⟩) hf.surjective variable {G H} in -@[gcongr] theorem Iso.maxEDegree_eq (f : G ≃g H) : G.maxEDegree = H.maxEDegree := f.toEquiv.iSup_congr f.edegree_eq variable {G H} in -@[gcongr] theorem Iso.minEDegree_eq (f : G ≃g H) : G.minEDegree = H.minEDegree := f.toEquiv.iInf_congr f.edegree_eq diff --git a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean index bc9ccfecd07846..7caefefe14ed3c 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean @@ -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 From 7c231b90f40362fc331d3fa916311383634e0f23 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:13:36 +0300 Subject: [PATCH 59/60] fix `IncMatrix.lean` --- Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean index b95034f8a5fc9c..d92a15ea0e729b 100644 --- a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean @@ -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 From 6831c523ad7fc4b2d9eab8d6efe16be3ff22e1c4 Mon Sep 17 00:00:00 2001 From: Snir Broshi <26556598+SnirBroshi@users.noreply.github.com> Date: Mon, 15 Jun 2026 19:04:05 +0300 Subject: [PATCH 60/60] extracted last `Finite.lean` changes to PR --- Mathlib/Combinatorics/SimpleGraph/Finite.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index b5e50f3ae9bac1..4e9ee69163112d 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -206,7 +206,7 @@ theorem card_neighborFinset_eq_degree : #(G.neighborFinset v) = G.degree v := rf theorem card_neighborSet_eq_degree : Fintype.card (G.neighborSet v) = G.degree v := (Set.toFinset_card _).symm --- TODO: extract to a separate PR +-- #40624 @[simp] theorem ncard_neighborSet : (G.neighborSet v).ncard = G.degree v := by simp [Set.ncard_eq_toFinset_card', card_neighborSet_eq_degree, -Set.fintypeCard_eq_ncard] @@ -528,8 +528,8 @@ theorem card_commonNeighbors_top [DecidableEq V] {v w : V} (h : v ≠ w) : simp [commonNeighbors_top_eq, ← Set.toFinset_card, Finset.card_sdiff, h, -Set.fintypeCard_eq_ncard] --- TODO: extract to a separate PR -omit [Fintype V] +-- #40624 +omit [Fintype V] in theorem encard_commonNeighbors_top {u v : V} (h : u ≠ v) : (commonNeighbors ⊤ u v).encard = ENat.card V - 2 := by simp [commonNeighbors_top_eq, Set.encard_sdiff, Set.encard_pair h]