Zulip Chat Archive
Stream: Is there code for X?
Topic: Quotient of a quotient
Vincent Beffara (Jan 12 2022 at 23:08):
I would like to show that the quotient
of a quotient
of V : Type
can be written as a quotient
of V
, and although I manage to prove something in this direction, the proof I am getting is extremely awkward (see left_inv
and right_inv
below). Would what I am looking for already be somewhere in mathlib? If not, what would be the "right" way to write this proof?
import init.function data.quot tactic
open function classical quotient
lemma toto : ∀ (V : Type) (s : setoid V) (s' : setoid (quotient s)),
∃ (s'' : setoid V) (φ : quotient s'' -> quotient s'), bijective φ
:= by { intros, cases s with r hᵣ, cases s' with r' hᵣ',
let r'' := λ x y, r' (quot.mk r x) (quot.mk r y),
have eqv : equivalence r''
:= ⟨λ _, hᵣ'.1 _, λ _ _ h, hᵣ'.2.1 h, λ x y z h1 h2, hᵣ'.2.2 h1 h2⟩,
have eqv_r' : eqv_gen r' = r' := equivalence.eqv_gen_eq hᵣ',
have eqv_r'' : eqv_gen r'' = r'' := equivalence.eqv_gen_eq eqv,
let φ := λ xx, quot.mk r' (quot.mk r (quot.out xx)),
let ψ := λ xx, quot.mk r'' (quot.out (quot.out xx)),
have left_inv : left_inverse ψ φ, by {
intro x, simp only [φ,ψ],
refine eq.trans _ (quot.out_eq x),
apply quot.eq.mpr,
rw eqv_r'', simp only [r''], rw <-eqv_r',
apply quot.eq.mp,
rw [eqv_r',quot.out_eq,quot.out_eq] },
have right_inv : right_inverse ψ φ, by {
intro x, simp only [φ,ψ],
have h0: ∀ {x y}, r'' x y = r' (quot.mk r x) (quot.mk r y) := λ x y, rfl,
have h1 := quot.out_eq x,
have h2 := quot.out_eq x.out,
rw <-h1, rw <-h2,
apply quot.eq.mpr,
rw eqv_r', rw <-h0, rw <-eqv_r'',
apply quot.eq.mp,
rw [eqv_r'',quot.out_eq,quot.out_eq,quot.out_eq] },
have : bijective φ
:= ⟨left_inverse.injective left_inv, right_inverse.surjective right_inv⟩,
exact ⟨⟨r'',eqv⟩,φ,this⟩
}
Thomas Browning (Jan 12 2022 at 23:13):
I feel like you should be able to prove this quicker in terms of composition of surjective functions.
Adam Topaz (Jan 12 2022 at 23:15):
Or you could come up with the relation for the associated setoid directly.
Adam Topaz (Jan 12 2022 at 23:22):
E.g.
import init.function data.quot tactic
open function classical quotient
lemma setoid.compose {V : Type*} (s : setoid V) (t : setoid (quotient s)) :
setoid V :=
{ r := λ a b, @setoid.r (quotient s) t (quotient.mk' a) (quotient.mk' b),
iseqv := begin
refine ⟨_,_,_⟩,
{ intros a, rw ← quotient.eq' },
{ intros a b h, rw ← quotient.eq' at *, exact h.symm },
{ intros a b c h1 h2, rw ← quotient.eq' at *, cc }
end }
def setoid.quotient_compose_equiv {V : Type*} (s : setoid V) (t : setoid (quotient s)) :
quotient (s.compose t) ≃ quotient t :=
{ to_fun := λ i, quotient.lift_on' i (λ v, quotient.mk' $ quotient.mk' v) sorry,
inv_fun := λ j, quotient.lift_on' j (λ k, quotient.lift_on' k (λ v, quotient.mk' v) sorry) sorry,
left_inv := sorry,
right_inv := sorry }
Adam Topaz (Jan 12 2022 at 23:23):
I would be surprised if we don't already have something similar.
Vincent Beffara (Jan 12 2022 at 23:27):
The relation itself is clear enough (λ x y, r' (quot.mk r x) (quot.mk r y)
), it's the proofs of left_inv
and right_inv
that I have trouble with. I will try your suggestion :-)
Thomas Browning (Jan 12 2022 at 23:27):
Here's a slightly different way
lemma toto (V : Type) (s : setoid V) (s' : setoid (quotient s)) :
∃ (s'' : setoid V) (φ : quotient s'' → quotient s'), bijective φ :=
begin
let f : V → quotient s := quotient.mk,
let g : quotient s → quotient s' := quotient.mk,
let h := setoid.quotient_ker_equiv_of_surjective (g ∘ f)
((surjective_quotient_mk (quotient s)).comp (surjective_quotient_mk V)),
exact ⟨setoid.ker (g ∘ f), h, h.bijective⟩,
end
Adam Topaz (Jan 12 2022 at 23:29):
What I'm mostly saying is that it doesn't make sense to have an existential statement, when you can construct the relation itself, and obtain a useful bijection between the quotients, not just the fact that some random bijection exists.
Adam Topaz (Jan 12 2022 at 23:33):
(my definition of setoid.compose
should be a def
not a lemma
)
Vincent Beffara (Jan 12 2022 at 23:55):
Mixing the two:
import tactic
variables {V : Type*} (s : setoid V) (t : setoid (quotient s))
def setoid.comp (s : setoid V) (t : setoid (quotient s)) : setoid V :=
let f : V → quotient s := quotient.mk,
g : quotient s → quotient t := quotient.mk
in setoid.ker (g ∘ f)
noncomputable def setoid.comp.iso : quotient (setoid.comp s t) ≃ quotient t :=
let f : V → quotient s := quotient.mk,
g : quotient s → quotient t := quotient.mk
in setoid.quotient_ker_equiv_of_surjective (g ∘ f)
((surjective_quotient_mk (quotient s)).comp (surjective_quotient_mk V))
noncomputable def setoid.comp.iso' : quotient (setoid.comp s t) ≃ quotient t :=
let gof : V -> quotient t := quotient.mk ∘ quotient.mk
in setoid.quotient_ker_equiv_of_surjective gof
((surjective_quotient_mk (quotient s)).comp (surjective_quotient_mk V))
Adam Topaz (Jan 12 2022 at 23:56):
You can make everything computable if you don't use setoid.ker_equiv_of_surjective
Eric Wieser (Jan 13 2022 at 00:02):
Is compose
just docs#setoid.comap quotient.mk?
Adam Topaz (Jan 13 2022 at 00:03):
@Eric Wieser yes, that's right
Vincent Beffara (Jan 26 2022 at 14:16):
Hi again, so I managed to make a computable version like this:
import data.setoid.basic
def setoid.comp {V : Type} (s : setoid V) (t : setoid (quotient s)) : setoid V :=
let f : V → quotient s := quotient.mk,
g : quotient s → quotient t := quotient.mk
in setoid.ker (g ∘ f)
def setoid.comp.iso {V : Type} {s : setoid V} {t : setoid (quotient s)} :
quotient (s.comp t) ≃ quotient t :=
by {
let f : V -> quotient s := quotient.mk,
let g : quotient s -> quotient t := quotient.mk',
let h : V -> quotient (s.comp t) := quotient.mk',
have p₁ : ∀ {a b}, f a = f b <-> s.rel a b := λ a b, quotient.eq',
have p₂ : ∀ {a b}, g a = g b <-> t.rel a b := λ a b, quotient.eq',
have p₃ : ∀ {a b}, h a = h b <-> (s.comp t).rel a b := λ a b, quotient.eq',
have p₄ : ∀ {a b}, (s.comp t).rel a b <-> g (f a) = g (f b) := λ a b, setoid.ker_def,
have p₅ : ∀ a b, s.rel a b -> h a = h b := λ a b, by { rw [p₃,p₄,<-p₁], exact congr_arg g },
let ζ : quotient s -> quotient (s.comp t) := λ y, y.lift_on' h p₅,
have p₆ : ∀ a b, t.rel a b -> ζ a = ζ b := λ a b, by {
refine a.induction_on' (λ x, _),
refine b.induction_on' (λ y, _),
rw [<-p₂], change g (f x) = g (f y) -> h x = h y, rw [p₃,p₄], exact id
},
exact {
to_fun := λ x, x.lift_on' (g ∘ f) (λ _ _, id),
inv_fun := λ y, y.lift_on' (λ y, y.lift_on' h p₅) p₆,
left_inv := λ x, quotient.induction_on' x (λ _, rfl),
right_inv := λ y, quotient.induction_on' y (λ a, quotient.induction_on' a (λ b, rfl)),
}
}
It kind of works but there are too many quotient.eq'
s and quotient.mk'
s for my taste. Am I missing something?
Last updated: Dec 20 2023 at 11:08 UTC