Zulip Chat Archive

Stream: Is there code for X?

Topic: Bijection A -> B from A+X -> B+X


Timothy Mou (Jul 21 2025 at 00:38):

Hi folks, not sure what this theorem is called, but it goes like given a bijection f : A + X -> B + X where X is finite, we can constructively obtain a bijection A -> B. The idea is you repeatedly apply f until you get something that lands in B, and you cannot get stuck in a loop in X because f is injective and X is finite (pigeonhole principle). Felt like this is something that would be in the Mathlib but could not find it or did not know how to search. Thanks!

Chris Hughes (Jul 21 2025 at 02:02):

I think you'd need an explicit bijectionX ≃ Fin n for this to work, I don't think either Finite, nor Fintype would be good enough. I proved a similar thing for option years ago, but never PRed it. I thought I'd generalize it today. I wouldn't be at all surprised if it wasn't in mathlib.

def option_fun_aux {α β : Type*} (h : Option α  Option β) (a : α) : Option β :=
  Option.elim (h (some a)) (h none) some

def option_fun_aux_isSome {α β : Type*} (e : Option α  Option β) (a : α) :
    (option_fun_aux e a).isSome := by
  rw [option_fun_aux]
  match h : e (some a) with
  | some x => simp
  | none =>
    simp only [Option.elim_none, Option.isSome_iff_ne_none]
    rw [ h]
    simp only [ne_eq, EmbeddingLike.apply_eq_iff_eq, reduceCtorEq, not_false_eq_true]

def option_fun {α β : Type*} (e : Option α  Option β) (a : α) : β :=
  Option.get _ (option_fun_aux_isSome e a)

def option_fun_option_fun {α β : Type*} (e : Option α  Option β) (a : α) :
    option_fun e.symm (option_fun e a) = a := by
  simp [option_fun, option_fun_aux]
  apply Option.some_injective
  simp only [Option.some_get]
  match h : e (some a) with
  | none =>
    simp only [Option.elim_none, Equiv.symm_apply_apply]
    rw [ h]
    simp
  | some x =>
    simp only [Option.elim_some]
    rw [ h]
    simp

def option_inj_aux {α β : Type*} (e : Option α  Option β) : α  β where
  toFun := option_fun e
  invFun := option_fun e.symm
  left_inv := option_fun_option_fun _
  right_inv := option_fun_option_fun e.symm

def optionSumEquivSumOption {α β : Type*} : (α  Option β)  Option (α  β) where
  toFun := Sum.elim (some  Sum.inl) (fun x => x.map Sum.inr)
  invFun := fun x => Option.elim x (Sum.inr none) (Sum.map id some)
  left_inv := by rintro (_ | _ | _) <;> simp
  right_inv := by rintro (_ | _ | _) <;> simp

def addFinEquiv {α β : Type*} :  {n : }, (α  Fin n)  (β  Fin n)  α  β
  | 0, e => ((Equiv.sumEmpty _ _).symm.trans e).trans (Equiv.sumEmpty _ _)
  | n + 1, e =>
    have : Option (α  (Fin n))  Option (β  (Fin n)) := calc
      Option (α  (Fin n))  (α  Option (Fin n)) := optionSumEquivSumOption.symm
      _  α  Fin (n + 1) := Equiv.sumCongr (Equiv.refl _) (finSuccEquiv _).symm
      _  β  Fin (n + 1) := e
      _  (β  Option (Fin n)) := Equiv.sumCongr (Equiv.refl _) (finSuccEquiv _)
      _  Option (β  (Fin n)) := optionSumEquivSumOption
    addFinEquiv (option_inj_aux this)

Yaël Dillies (Jul 21 2025 at 05:57):

@Bhavik Mehta and I talked about this years ago. I don't remember if we ended up formalising anything


Last updated: Dec 20 2025 at 21:32 UTC