Skip to content

feat(Combinatorics/SimpleGraph/Bipartite): Prove upper bound of edge set cardinality of bipartite graph#34315

Open
LessnessRandomness wants to merge 17 commits intoleanprover-community:masterfrom
LessnessRandomness:bipartite_edgeSet_encard
Open

feat(Combinatorics/SimpleGraph/Bipartite): Prove upper bound of edge set cardinality of bipartite graph#34315
LessnessRandomness wants to merge 17 commits intoleanprover-community:masterfrom
LessnessRandomness:bipartite_edgeSet_encard

Conversation

@LessnessRandomness
Copy link
Copy Markdown
Collaborator

@LessnessRandomness LessnessRandomness commented Jan 23, 2026

Two ways to express upper bound of the edge set of bipartite graph:

  1. If the cardinalities of both parts/sets, that make bipartite graph, are known, then the upper bound is equal to product of the cardinalities of both parts;
  2. Four times of the cardinality of the edge set is less or equal to squared cardinality of vertex set.

Open in Gitpod

@github-actions github-actions bot added the t-combinatorics Combinatorics label Jan 23, 2026
@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

LessnessRandomness commented Jan 23, 2026

  1. Is it okay to add these proofs to this file, instead of making some new file? 🤔 My proofs are a bit longer than I expected.
  2. Need help with English in docstrings... 😅 [Edit: asked a friend for help and a bit later will change docstrings to better versions.]

@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 23, 2026

PR summary 84442bd12f

Import changes for modified files

No significant changes to the import graph

Import changes for all files
Files Import difference

Declarations diff

+ IsBipartite.four_mul_encard_edgeSet_le
+ IsBipartiteWith.edgeSetEmbeddingCompleteBipartiteGraph
+ IsBipartiteWith.encard_edgeSet_le
+ completeBipartiteGraph_edgeSet
+ completeBipartiteGraph_edgeSet_encard

You can run this locally as follows
## summary with just the declaration names:
./scripts/pr_summary/declarations_diff.sh <optional_commit>

## more verbose report:
./scripts/pr_summary/declarations_diff.sh long <optional_commit>

The doc-module for scripts/pr_summary/declarations_diff.sh contains some details about this script.


No changes to technical debt.

You can run this locally as

./scripts/reporting/technical-debt-metrics.sh pr_summary
  • The relative value is the weighted sum of the differences with weight given by the inverse of the current value of the statistic.
  • The absolute value is the relative value divided by the total sum of the inverses of the current values (i.e. the weighted average of the differences).

@LessnessRandomness LessnessRandomness changed the title feat(Combinatorics/SimpleGraph/Bipartite): Prove upper limit to cardinality of edge set of bipartite graph feat(Combinatorics/SimpleGraph/Bipartite): Prove upper bound of edge set cardinality of bipartite graph Jan 23, 2026
Copy link
Copy Markdown
Collaborator

@vlad902 vlad902 left a comment

Choose a reason for hiding this comment

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

Just a few comments, I haven't looked through everything. I wonder if it might be easier to show this by showing that the complete bipartite graph has cardinality equal to s*t and that every bipartite graph embeds into it and hence has cardinality bounded by that value, but I haven't looked at trying it.

@LessnessRandomness LessnessRandomness added the awaiting-author A reviewer has asked the author a question or requested changes. label Jan 24, 2026
@vlad902
Copy link
Copy Markdown
Collaborator

vlad902 commented Jan 24, 2026

Out of curiosity I tried to outline this approach. It's messy and I'm not sure what the exact right form is but here's what I got before running out of time

import Mathlib

namespace SimpleGraph

variable {V W₁ W₂ : Type*} (G : SimpleGraph V) {s t : Set V}

theorem eq_sym2_out (v : Sym2 V) : v = s(v.out.1, v.out.2) := by
  ext
  simp

theorem edgeSet_eq : G.edgeSet = { x | ∃ v w : V, x = s(v, w) ∧ G.Adj v w } := by
  refine Set.ext fun x ↦ ⟨fun h ↦ ?_, by grind [mem_edgeSet]⟩
  exact ⟨x.out.1, x.out.2, by simp [G.mem_edgeSet.mp <| eq_sym2_out x ▸ h]⟩

theorem completeBipartiteGraph_edgeSet : (completeBipartiteGraph W₁ W₂).edgeSet = Set.range (fun x : W₁ × W₂ ↦ s(.inl x.1, .inr x.2)) := by
  refine Set.ext fun x ↦ ⟨fun h ↦ ?_, fun h ↦ ?_⟩
  · simp only [edgeSet_eq, completeBipartiteGraph_adj, Sum.exists, Sum.isRight_inl,
      Bool.false_eq_true, and_false, Sum.isLeft_inl, and_true, false_or, exists_and_right,
      Sum.isRight_inr, Sum.isLeft_inr, or_false, Set.mem_setOf_eq] at h
    cases h with | inl h' | inr h' <;> obtain ⟨u,v,huv⟩ := h' <;> simp_all
  · obtain ⟨u, v, huv⟩ := h
    simp

theorem completeBipartiteGraph_edgeSet_encard : (completeBipartiteGraph W₁ W₂).edgeSet.encard = ENat.card W₁ * ENat.card W₂ := by
  let g (x : W₁ × W₂) : Sym2 (W₁ ⊕ W₂) := s(.inl x.1, .inr x.2)
  have : Function.Injective g := fun _ _ _ ↦ by grind
  have := this.encard_image Set.univ
  simpa [completeBipartiteGraph_edgeSet, this]

theorem IsBipartiteWith.encard_edgeSet_le {s t : Set V} (hG : G.IsBipartiteWith s t) :
    G.edgeSet.encard ≤ s.encard * t.encard := by
  have : G.edgeSet.encard ≤ (completeBipartiteGraph s t).edgeSet.encard := by
    refine Function.Embedding.encard_le ?_
    sorry
  grw [this, completeBipartiteGraph_edgeSet_encard]
  simp

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

Thank you! It definitely looks shorter and better than my current attempt to implement your suggestion.

I will try to fill the sorry.

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

LessnessRandomness commented Jan 24, 2026

I kind of filled the sorry... 🤔 But I had to use G.induce (s ∪ t) instead, because with simply G I had no progress.
The result is kinda lengthy. 😓

import Mathlib

namespace SimpleGraph

variable {V W₁ W₂ : Type*} (G : SimpleGraph V) {s t : Set V}

theorem eq_sym2_out (v : Sym2 V) : v = s(v.out.1, v.out.2) := by
  ext
  simp

theorem edgeSet_eq : G.edgeSet = { x | ∃ v w : V, x = s(v, w) ∧ G.Adj v w } := by
  refine Set.ext fun x ↦ ⟨fun h ↦ ?_, by grind [mem_edgeSet]⟩
  exact ⟨x.out.1, x.out.2, by simp [G.mem_edgeSet.mp <| eq_sym2_out x ▸ h]⟩

theorem completeBipartiteGraph_edgeSet : (completeBipartiteGraph W₁ W₂).edgeSet = Set.range (fun x : W₁ × W₂ ↦ s(.inl x.1, .inr x.2)) := by
  refine Set.ext fun x ↦ ⟨fun h ↦ ?_, fun h ↦ ?_⟩
  · simp only [edgeSet_eq, completeBipartiteGraph_adj, Sum.exists, Sum.isRight_inl,
      Bool.false_eq_true, and_false, Sum.isLeft_inl, and_true, false_or, exists_and_right,
      Sum.isRight_inr, Sum.isLeft_inr, or_false, Set.mem_setOf_eq] at h
    cases h with | inl h' | inr h' <;> obtain ⟨u,v,huv⟩ := h' <;> simp_all
  · obtain ⟨u, v, huv⟩ := h
    simp

theorem completeBipartiteGraph_edgeSet_encard : (completeBipartiteGraph W₁ W₂).edgeSet.encard = ENat.card W₁ * ENat.card W₂ := by
  let g (x : W₁ × W₂) : Sym2 (W₁ ⊕ W₂) := s(.inl x.1, .inr x.2)
  have : Function.Injective g := fun _ _ _ ↦ by grind
  have := this.encard_image Set.univ
  simpa [completeBipartiteGraph_edgeSet, this]

theorem IsBipartiteWith.induce_encard_edgeSet_le {s t : Set V} (hG : G.IsBipartiteWith s t) :
    (G.induce (s ∪ t)).edgeSet.encard ≤ s.encard * t.encard := by
  have : (G.induce (s ∪ t)).edgeSet.encard ≤ (completeBipartiteGraph s t).edgeSet.encard := by
    refine Function.Embedding.encard_le ?_
    classical
    set f : ↑(s ∪ t) → (↑s ⊕ ↑t) :=
      fun h => if h₀ : ↑h ∈ s then Sum.inl ⟨↑h, h₀⟩ else Sum.inr ⟨↑h, by grind⟩
    set f₀ : ↑(induce (s ∪ t) G).edgeSet → ↑(completeBipartiteGraph ↑s ↑t).edgeSet := by
      rintro ⟨e, he⟩
      use e.map f
      simp [f]
      cases e with | h x y =>
      simp only [mem_edgeSet, comap_adj, Function.Embedding.subtype_apply] at he
      simp only [Sym2.map_pair_eq, mem_edgeSet, completeBipartiteGraph_adj]
      by_cases h : ↑x ∈ s
      · have h₀ := hG.mem_of_adj he
        have h₁ := hG.disjoint
        grind
      · simp only [h, ↓reduceDIte, Sum.isLeft_inr, Bool.false_eq_true, false_and, Sum.isRight_inr,
        true_and, false_or]
        have h₀ := hG.mem_of_adj he
        grind
    use f₀
    intros x y hxy
    simp only [Subtype.mk.injEq, f₀, f] at hxy
    cases x with | mk x hx =>
    cases y with | mk y hy =>
    cases x with | h x₁ x₂ =>
    cases y with | h y₁ y₂ =>
    simp_all
    grind
  grw [this, completeBipartiteGraph_edgeSet_encard]
  simp

theorem IsBipartiteWith.induce_edgeSet_eq_edgeSet {s t : Set V} (hG : G.IsBipartiteWith s t) :
    G.edgeSet.encard = (G.induce (s ∪ t)).edgeSet.encard := by
  have h : G.edgeSet = (fun e => e.map (fun x => x.val)) '' (G.induce (s ∪ t)).edgeSet := by
    ext e
    cases e with | h x y =>
    simp only [mem_edgeSet, induce, Function.Embedding.coe_subtype, Set.mem_image]
    constructor
    · intro hxy
      have h₀ := hG.mem_of_adj hxy
      use s(⟨x, by grind⟩, ⟨y, by grind⟩)
      simp [hxy]
    · intros he
      obtain ⟨e, h₀, h₁⟩ := he
      cases e with | h x₁ y₁ =>
      simp only [mem_edgeSet, comap_adj] at h₀
      simp only [Sym2.map_pair_eq, Sym2.eq, Sym2.rel_iff', Prod.mk.injEq, Prod.swap_prod_mk] at h₁
      obtain h₁ | h₁ := h₁
      · grind
      · symm
        grind
  rw [h]
  apply Function.Injective.encard_image
  intros e₁ e₂ he
  simp only at he
  cases e₁ with | h x₁ y₁ =>
  cases e₂ with | h x₂ y₂ =>
  simp_all
  grind

theorem IsBipartiteWith.encard_edgeSet_le {s t : Set V} (hG : G.IsBipartiteWith s t) :
    G.edgeSet.encard ≤ s.encard * t.encard := by
  rw [induce_edgeSet_eq_edgeSet G hG]
  exact induce_encard_edgeSet_le G hG

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

Probably it can be shortened in many ways, but I will postpone my attempts at that until tomorrow.

@vlad902
Copy link
Copy Markdown
Collaborator

vlad902 commented Jan 24, 2026

This compiles though I don't love myembedding. I'm also not sure how to improve it

import Mathlib

variable {V W₁ W₂ : Type*} (G : SimpleGraph V) {s t : Set V}

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

namespace SimpleGraph

theorem edgeSet_eq : G.edgeSet = { x | ∃ v w : V, x = s(v, w) ∧ G.Adj v w } := by
  refine Set.ext fun x ↦ ⟨fun h ↦ ?_, by grind [mem_edgeSet]⟩
  exact ⟨x.out.1, x.out.2, by simp [G.mem_edgeSet.mp <| x.eq_out ▸ h]⟩

theorem completeBipartiteGraph_edgeSet : (completeBipartiteGraph W₁ W₂).edgeSet = Set.range (fun x : W₁ × W₂ ↦ s(.inl x.1, .inr x.2)) := by
  refine Set.ext fun x ↦ ⟨fun h ↦ ?_, fun h ↦ ?_⟩
  · simp only [edgeSet_eq, completeBipartiteGraph_adj, Sum.exists, Sum.isRight_inl,
      Bool.false_eq_true, and_false, Sum.isLeft_inl, and_true, false_or, exists_and_right,
      Sum.isRight_inr, Sum.isLeft_inr, or_false, Set.mem_setOf_eq] at h
    rcases h with ⟨_, _, _⟩ | ⟨_, _, _⟩ <;> simp_all
  · obtain ⟨_, _, _⟩ := h
    simp

theorem completeBipartiteGraph_edgeSet_encard : (completeBipartiteGraph W₁ W₂).edgeSet.encard = ENat.card W₁ * ENat.card W₂ := by
  let g (x : W₁ × W₂) : Sym2 (W₁ ⊕ W₂) := s(.inl x.1, .inr x.2)
  have : Function.Injective g := fun _ _ _ ↦ by grind
  have := this.encard_image Set.univ
  simpa [completeBipartiteGraph_edgeSet, this]

theorem myembedding (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, edgeSet_eq, 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, edgeSet_eq, Sym2.eq_out]
  · grind [Sym2.eq_out]

theorem IsBipartiteWith.encard_edgeSet_le {s t : Set V} (hG : G.IsBipartiteWith s t) :
    G.edgeSet.encard ≤ s.encard * t.encard := by
  grw [Classical.choice (myembedding G hG) |>.encard_le, completeBipartiteGraph_edgeSet_encard]
  simp

There was a recent discussion about IsBipartiteWith not forcing the two partitions to equal to Set.univ and this does make this uglier. If s ∪ t = Set.univ we could use IsContained and get an injection that way and I think it would be nicer. (Otherwise, everything not in s ∪ t has no edges but still must be mapped to something breaking injectivity into completeBipartiteGraph s t.) I guess this formulation gives you a tighter bound when you have isolated vertices 🤷

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

I have so much to learn... 🤔 Thank you.

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

May I use/copy-paste your proof in this PR, instead of mine? Adding you as author, of course.

@vlad902
Copy link
Copy Markdown
Collaborator

vlad902 commented Jan 25, 2026

Please do

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

I did it. Also added IsBipartite.four_mul_encard_edgeSet_le (but only that) back, as I thought it is short enough.

Comment on lines +468 to +474
theorem completeBipartiteGraph_edgeSet_encard :
(completeBipartiteGraph W₁ W₂).edgeSet.encard =
ENat.card W₁ * ENat.card W₂ := by
let g (x : W₁ × W₂) : Sym2 (W₁ ⊕ W₂) := s(.inl x.1, .inr x.2)
have : Function.Injective g := fun _ _ _ ↦ by grind
have := this.encard_image Set.univ
simpa [completeBipartiteGraph_edgeSet, this]
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.

Suggested change
theorem completeBipartiteGraph_edgeSet_encard :
(completeBipartiteGraph W₁ W₂).edgeSet.encard =
ENat.card W₁ * ENat.card W₂ := by
let g (x : W₁ × W₂) : Sym2 (W₁ ⊕ W₂) := s(.inl x.1, .inr x.2)
have : Function.Injective g := fun _ _ _ ↦ by grind
have := this.encard_image Set.univ
simpa [completeBipartiteGraph_edgeSet, this]
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

Also I think it would be great to add a lemma that combines Function.Injective.encard_image with Set.image_univ creating (Set.range f).encard = (Set.univ : α).encard for an injective f : α → β, though I'm not sure what it should be called since Function.Injective.encard_image already exists.

Copy link
Copy Markdown
Collaborator Author

@LessnessRandomness LessnessRandomness Jan 26, 2026

Choose a reason for hiding this comment

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

Maybe Function.Injective.encard_range? 🤔

Although it seems to be very simple (too simple?), if I understood everything correctly. Almost the same as Function.Injective.encard_image.

import Mathlib

lemma Function.Injective.encard_range {α β} {f : α → β} (hf : Function.Injective f) :
    (Set.range f).encard = (Set.univ : Set α).encard :=
  Set.image_univ.symm ▸ Function.Injective.encard_image hf Set.univ

@LessnessRandomness LessnessRandomness removed the awaiting-author A reviewer has asked the author a question or requested changes. label Jan 26, 2026
Comment on lines +463 to +473
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)

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

Sorry for disappearing, caught some flu 😓 Now getting back on my feet.

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

Is there something more I can do on this PR?

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

Oh, by simp no more works in eq_out of Mathlib\Data\Sym\Sym2.lean. I will try to fix this (and maybe other problems that appear after that) few hours later.

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

Oh, by simp no more works in eq_out of Mathlib\Data\Sym\Sym2.lean. I will try to fix this (and maybe other problems that appear after that) few hours later.

Nope, it seems I'm too dumb and need help. My apologies. 😓

@SnirBroshi
Copy link
Copy Markdown
Collaborator

Oh, by simp no more works in eq_out of Mathlib\Data\Sym\Sym2.lean. I will try to fix this (and maybe other problems that appear after that) few hours later.

Nope, it seems I'm too dumb and need help. My apologies. 😓

Do you mean a proof for Sym2.eq_out? If so then e.out_eq.symm works.
I think the equality in that lemma should be flipped, then you can just e.out_eq.

btw my suggestion above alleviates the need for Sym2.eq_out.

@LessnessRandomness
Copy link
Copy Markdown
Collaborator Author

Applied suggestion by SnirBroshi, and, hoorah, everything is back to working state! Thank you.

@mathlib-merge-conflicts
Copy link
Copy Markdown

This pull request has conflicts, please merge master and resolve them.

@mathlib-merge-conflicts mathlib-merge-conflicts bot added the merge-conflict The PR has a merge conflict with master, and needs manual merging. (this label is managed by a bot) label Mar 21, 2026
@github-actions github-actions bot removed the merge-conflict The PR has a merge conflict with master, and needs manual merging. (this label is managed by a bot) label Mar 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-combinatorics Combinatorics

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants