Zulip Chat Archive

Stream: Is there code for X?

Topic: Lifting dependent functions to quotient map


Kin Yau James Wong (May 15 2025 at 17:12):

Hello all, I've been working on trying to lift a function f : (a : α) → (b : α) → P a → P b → β to the quotient map
f' : (a : Quotient s) → (b : Quotient s) → P' a → P' b → β where P is a predicate that also respects the equivalence relation defined by the Setoid, s (and consequently lifts to P'), but I've had little success with using the theorems in the Quotient module. Many thanks for the advice :pray:

(p.s. I'm trying to avoid using Quotient.out)

Junyan Xu (May 15 2025 at 17:18):

Maybe you want to use Equiv.subtypeQuotientEquivQuotientSubtype to reduce your problem to lifting a non-dependent function?

Aaron Liu (May 15 2025 at 17:25):

Try using Quotient.rec?

Aaron Liu (May 15 2025 at 18:16):

import Mathlib

-- there must be a better name
def Quotient.liftProp {α β : Type*} {s : Setoid α} {P : Quotient s  Prop}
    (f : (a : α)  P (Quotient.mk s a)  β)
    (sound :  a b ha hb, a  b  f a ha = f b hb)
    (a : Quotient s) (ha : P a) : β :=
  @Quotient.rec α s (fun u => P u  β) f (fun u v huv =>
    eq_of_heq (eqRec_heq_iff.mpr
      (Function.hfunext (congrArg P (Quotient.sound huv)) fun hu hv _ =>
        heq_of_eq (sound u v hu hv huv)))) a ha

theorem Quotient.liftProp_mk {α β : Type*} {s : Setoid α} {P : Quotient s  Prop}
    (f : (a : α)  P (Quotient.mk s a)  β)
    (sound :  a b ha hb, a  b  f a ha = f b hb)
    (a : α) (ha : P (Quotient.mk s a)) :
    Quotient.liftProp f sound (Quotient.mk s a) ha = f a ha := rfl

def Quotient.liftProp₂ {α β : Type*} {s : Setoid α} {P : Quotient s  Prop}
    (f : (a : α)  (b : α)  P (Quotient.mk s a)  P (Quotient.mk s b)  β)
    (sound :  a b c d ha hb hc hd, a  c  b  d  f a b ha hb = f c d hc hd)
    (a b : Quotient s) (ha : P a) (hb : P b) : β :=
  Quotient.liftProp (fun c hc =>
    Quotient.liftProp (fun d hd => f c d hc hd) (fun u v hu hv huv =>
      sound c u c v hc hu hc hv (Setoid.refl c) huv) b hb) (fun u v hu hv huv =>
        Quotient.ind (motive := fun b =>  (hb : P b),
          Quotient.liftProp (fun d hd => f u d hu hd) _ b hb =
          Quotient.liftProp (fun d hd => f v d hv hd) _ b hb)
          (fun b hb => sound u b v b hu hb hv hb huv (Setoid.refl b)) b hb) a ha

def Quotient.liftProp₂_mk {α β : Type*} {s : Setoid α} {P : Quotient s  Prop}
    (f : (a : α)  (b : α)  P (Quotient.mk s a)  P (Quotient.mk s b)  β)
    (sound :  a b c d ha hb hc hd, a  c  b  d  f a b ha hb = f c d hc hd)
    (a b : α) (ha : P (Quotient.mk s a)) (hb : P (Quotient.mk s b)) :
    Quotient.liftProp₂ f sound (Quotient.mk s a) (Quotient.mk s b) ha hb = f a b ha hb := rfl

Kin Yau James Wong (May 16 2025 at 03:14):

Thanks! Is this something you might push to Mathlib?

Aaron Liu (May 16 2025 at 10:20):

Maybe if someone comes up with a better name and a use case

Robin Arnez (May 16 2025 at 12:14):

I encountered the same problem while developing ExtHashMaps, so I added Quotient.pliftOn and Quot.pliftOn:

structure MyType where
  value : Nat

def MyType.P : MyType  Prop := fun n => n.value % 2 = 0

opaque fn : (a : MyType)  (b : MyType)  a.P  b.P  Nat

def MyType.rel : MyType  MyType  Prop := fun a b => a.value % 2 = b.value % 2

theorem MyType.P_congr {x y : MyType} (h : x.rel y) : x.P  y.P := by
  unfold rel at h
  simp [P, h]

def MyType.P' : Quot MyType.rel  Prop := Quot.lift MyType.P (fun _ _ h => propext (MyType.P_congr h))

def f' (a : Quot MyType.rel) (b : Quot MyType.rel) (h : MyType.P' a) (h' : MyType.P' b) : Nat :=
  a.pliftOn (fun a' ha => b.pliftOn (fun b' hb => fn a' b' (ha  h :) (hb  h' :)) sorry) sorry

Robin Arnez (May 16 2025 at 12:19):

Should be available since v4.20.0

Kin Yau James Wong (May 18 2025 at 15:11):

ah this is perfect - thanks!


Last updated: Dec 20 2025 at 21:32 UTC