Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions Mathlib/Combinatorics/SimpleGraph/Bipartite.lean
Original file line number Diff line number Diff line change
Expand Up @@ -445,4 +445,56 @@ theorem degree_le_between_add_compl (hw : w ∈ sᶜ) :

end Between

section completeBipartiteGraph

variable {W₁ W₂ : Type*}

theorem completeBipartiteGraph_edgeSet : (completeBipartiteGraph W₁ W₂).edgeSet =
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
theorem completeBipartiteGraph_edgeSet : (completeBipartiteGraph W₁ W₂).edgeSet =
theorem edgeSet_completeBipartiteGraph : (completeBipartiteGraph W₁ W₂).edgeSet =

same below

Set.range (fun x : W₁ × W₂ ↦ s(.inl x.1, .inr x.2)) := by
Comment on lines +456 to +457
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
theorem completeBipartiteGraph_edgeSet : (completeBipartiteGraph W₁ W₂).edgeSet =
Set.range (fun x : W₁ × W₂ ↦ s(.inl x.1, .inr x.2)) := by
theorem completeBipartiteGraph_edgeSet :
(completeBipartiteGraph W₁ W₂).edgeSet =
.range (fun x : W₁ × W₂ ↦ s(.inl x.1, .inr x.2)) := by

refine Set.ext <| Sym2.ind fun u v ↦ ⟨fun h ↦ ?_, fun ⟨⟨a, b⟩, z⟩ ↦ ?_⟩
· cases u <;> cases v <;> simp_all
· grind [completeBipartiteGraph_adj, mem_edgeSet]

theorem completeBipartiteGraph_edgeSet_encard :
(completeBipartiteGraph W₁ W₂).edgeSet.encard = ENat.card W₁ * ENat.card W₂ := by
rw [completeBipartiteGraph_edgeSet, ← ENat.card_prod, ← Set.encard_univ, ← Set.image_univ]
exact Function.Injective.encard_image (by grind [Function.Injective]) Set.univ

theorem IsBipartiteWith.nonempty_embedding_completeBipartiteGraph_edgeSet
(hG : G.IsBipartiteWith s t) :
Nonempty (G.edgeSet ↪ (completeBipartiteGraph s t).edgeSet) := by
refine ⟨⟨fun ⟨x, hx⟩ ↦ ?_, fun _ _ _ ↦ ?_⟩⟩
· by_cases! h : x.out.1 ∈ s
· refine ⟨s(.inl ⟨x.out.1, h⟩, .inr ⟨x.out.2, ?_⟩), by simp⟩
grind [hG.disjoint, hG.mem_of_adj, mem_edgeSet, Sym2.eq_out]
· refine ⟨s(.inr ⟨x.out.1, ?_⟩, .inl ⟨x.out.2, ?_⟩), by simp⟩
· grind [hG.mem_of_adj <| G.mem_edgeSet.mpr <| x.eq_out ▸ hx]
· grind [hG.disjoint, hG.mem_of_adj, mem_edgeSet, Sym2.eq_out]
· grind [Sym2.eq_out]
Copy link
Copy Markdown
Collaborator

@SnirBroshi SnirBroshi Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative version with a computable function, that might be useful:

Suggested change
theorem IsBipartiteWith.nonempty_embedding_completeBipartiteGraph_edgeSet
(hG : G.IsBipartiteWith s t) :
Nonempty (G.edgeSet ↪ (completeBipartiteGraph s t).edgeSet) := by
refine ⟨⟨fun ⟨x, hx⟩ ↦ ?_, fun _ _ _ ↦ ?_⟩⟩
· by_cases! h : x.out.1 ∈ s
· refine ⟨s(.inl ⟨x.out.1, h⟩, .inr ⟨x.out.2, ?_⟩), by simp⟩
grind [hG.disjoint, hG.mem_of_adj, mem_edgeSet, Sym2.eq_out]
· refine ⟨s(.inr ⟨x.out.1, ?_⟩, .inl ⟨x.out.2, ?_⟩), by simp⟩
· grind [hG.mem_of_adj <| G.mem_edgeSet.mpr <| x.eq_out ▸ hx]
· grind [hG.disjoint, hG.mem_of_adj, mem_edgeSet, Sym2.eq_out]
· grind [Sym2.eq_out]
/-- An embedding of the edges of a bipartite graph into the edges of the complete bipartite graph -/
def IsBipartiteWith.edgeSetEmbeddingCompleteBipartiteGraph [DecidableRel (· ∈ · : V → Set V → _)]
(hG : G.IsBipartiteWith s t) : G.edgeSet ↪ (completeBipartiteGraph s t).edgeSet where
toFun := fun ⟨e, he⟩ ↦
e.hrec (fun u v h ↦ hG.mem_of_adj h |>.by_cases
(fun h ↦ ⟨s(.inl ⟨u, h.left⟩, .inr ⟨v, h.right⟩), .inl ⟨rfl, rfl⟩⟩)
(fun h ↦ ⟨s(.inl ⟨v, h.right⟩, .inr ⟨u, h.left⟩), .inl ⟨rfl, rfl⟩⟩)
) (fun _ _ ↦ Function.hfunext (by grind) <| by grind [Or.by_cases, hG.disjoint]) he
inj' := by
rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩
change (if _ : _ then _ else _) = (if _ : _ then _ else _) → _
grind

The theorem that uses this just needs to call classical before to satisfy the DecidableRel
(edit: fixed after the signature of Sym2.hrec was changed, requires merging master)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we adopt this we can also get rid of Sym2.eq_out, though stylistically I'm unsure which one is preferable.

Copy link
Copy Markdown
Collaborator Author

@LessnessRandomness LessnessRandomness Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer this version (with a computable function), but I'm not sure too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's generally better to use recursion on the quotient rather than .out, and in this case actually not for computability reasons!

Copy link
Copy Markdown
Contributor

@b-mehta b-mehta Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think I have a lemma somewhere which combines Sym2.hrec with the hfunext call, let me go looking

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also have a def that combines the two, I inlined it before posting the code above.
Just PRed it in #34909 if you're interested (but it shouldn't block this PR)


end completeBipartiteGraph
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
end completeBipartiteGraph
end completeBipartiteGraph


section

/-- The cardinality of the edge set of a bipartite graph is upper bounded by the product
of the cardinality of the two partitions. -/
theorem IsBipartiteWith.encard_edgeSet_le (hG : G.IsBipartiteWith s t) :
G.edgeSet.encard ≤ s.encard * t.encard := by
grw [hG.nonempty_embedding_completeBipartiteGraph_edgeSet.some.encard_le]
simp [completeBipartiteGraph_edgeSet_encard]

/-- Four times the cardinality of the edge set of a bipartite graph is upper bounded by
the square of cardinality of the vertex set. -/
theorem IsBipartite.four_mul_encard_edgeSet_le (h : G.IsBipartite) :
4 * G.edgeSet.encard ≤ ENat.card V ^ 2 := by
refine finite_or_infinite V |>.elim (fun hv ↦ ?_) (fun _ ↦ by simp)
have ⟨s, t, h⟩ := h.exists_isBipartiteWith
grw [h.encard_edgeSet_le]
have := Set.encard_union_eq h.disjoint ▸ Set.encard_le_card
rw [ENat.card_eq_coe_natCard, ← s.toFinite.cast_ncard_eq, ← t.toFinite.cast_ncard_eq] at this ⊢
norm_cast at this ⊢
grind [Nat.pow_le_pow_left this 2, four_mul_le_sq_add s.ncard t.ncard]

end

end SimpleGraph
2 changes: 2 additions & 0 deletions Mathlib/Data/Sym/Sym2.lean
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@ theorem out_fst_mem (e : Sym2 α) : e.out.1 ∈ e :=
theorem out_snd_mem (e : Sym2 α) : e.out.2 ∈ e :=
⟨e.out.1, by rw [eq_swap, Sym2.mk, e.out_eq]⟩

theorem eq_out (e : Sym2 α) : e = s(e.out.1, e.out.2) := Sym2.ext (by simp)

theorem ball {p : α → Prop} {a b : α} : (∀ c ∈ s(a, b), p c) ↔ p a ∧ p b := by
simp

Expand Down