Zulip Chat Archive

Stream: maths

Topic: Lifting an equivalence to sym2


Yaël Dillies (Dec 25 2021 at 23:34):

docs#sym2.lift allows to lift symmetric maps f : α → α → β to functions sym2 α → β. Now, I want to define the unoriented edges of a multiset, so instead of the equality f a b = f b a, I have an equivalence f a b ≃ f b a. How do I lift that to a function from sym2?

import data.sym.sym2

universes u
variables {α : Type*}

namespace sym2

def lift_sort (f : α  α  Sort u) (e : Π a b, f a b  f b a) (he :  a b, (e a b).symm = e b a) :
  sym2 α  Sort u := sorry

variables (f : α  α  Sort u) (e : Π a b, f a b  f b a) (he :  a b, (e a b).symm = e b a)

def lift_sort_equiv (a b : α) : lift_sort f e he (a, b)  f a b :=
sorry

-- maybe some lemma along the lines of
-- `(lift_sort_equiv f e a b).symm.trans (lift_sort_equiv f e b a) = e a b`?

end sym2

Note that I don't know how to handle the diagonal. If we consider that an edge should always come from two darts, then lift_sort_equiv should take a ≠ b as assumption.
But really any progress would help. I've been stuck on that for several days now.

Maybe @Kyle Miller can help?

Bhavik Mehta (Dec 25 2021 at 23:37):

import data.sym.sym2

universes u
variables {α : Type*}

namespace sym2

variables (f : α  α  Sort u) (e : Π a b, f a b  f b a) (he :  a b, (e a b).symm = e b a)

def lift_sort (f : α  α  Sort u) :
  sym2 α  Sort u :=
λ x, f (quotient.out x).1 (quotient.out x).2

lemma out_eq (a b : α) : (a, b)⟧.out = (a, b)  (a, b)⟧.out = (b, a) :=
begin
  have : ((a, b)⟧.out.1, (a, b)⟧.out.2) = (a, b),
  { simp },
  rw sym2.eq_iff at this,
  rwa [prod.ext_iff, prod.ext_iff],
end

open_locale classical

noncomputable def lift_sort_equiv (f : α  α  Sort u) (e : Π a b, f a b  f b a)
  (he :  a b, (e a b).symm = e b a) (a b : α) :
  lift_sort f (a, b)  f a b :=
dite ((a, b)⟧.out = (a, b))
  (λ h, equiv.cast (by { change f _ _ = _, rw h }))
  (λ h, (equiv.cast (by { change f _ _ = _, rw (out_eq _ _).resolve_left h })).trans (e _ _))

end sym2

Bhavik Mehta (Dec 25 2021 at 23:39):

I'm not sure what your lemma is meant to be describing, I can't make it typecheck

Bhavik Mehta (Dec 25 2021 at 23:48):

Ah, maybe you mean

lemma lift_sort_equiv_symm_trans {a b : α} :
  (lift_sort_equiv f e _ _).symm.trans (equiv.trans (equiv.cast (by rw sym2.eq_swap)) (lift_sort_equiv f e b a)) = e a b :=

Yaël Dillies (Dec 25 2021 at 23:48):

Yes exactly

Bhavik Mehta (Dec 25 2021 at 23:49):

When a = b, this lemma implies equiv.refl (f a a) = e a a

Bhavik Mehta (Dec 25 2021 at 23:52):

And with that assumption, it's not too tricky to prove:

lemma lift_sort_equiv_symm_trans {a b : α}
  (he :  a b, (e a b).symm = e b a) (hf : equiv.refl (f a a) = e a a) :
  (lift_sort_equiv f e _ _).symm.trans
    ((equiv.cast (by rw sym2.eq_swap)).trans (lift_sort_equiv f e b a)) = e a b :=
begin
  rw [lift_sort_equiv, lift_sort_equiv],
  rcases eq_or_ne a b with rfl | hab,
  { simpa },
  cases out_eq a b,
  { rw [dif_pos h, dif_neg],
    { ext x,
      simp },
    rw [sym2.eq_swap, h],
    simp [hab] },
  { rw [dif_neg, dif_pos],
    { ext x,
      simp [he] },
    { rwa [sym2.eq_swap] },
    rw h,
    simp [hab] }
end

Yaël Dillies (Dec 25 2021 at 23:53):

So Kyle, what do you think of making this sym2 α → Sort u edges map the primitive for multigraph? It seems quite hard to build it from the α → α → Sort u homs. The other way around is trivial and can be handled by the typeclasses I'm offering.

Reid Barton (Dec 26 2021 at 00:02):

Surprisingly (at least it wasn't my initial reaction) it is also possible to implement this without choice (e.g. quotient.out)

import data.sym.sym2

section

universe u
parameters {α : Type u} (f : α  α  Type u)
parameters (e : Π a b, f a b  f b a) (he :  a b, (e a b).symm = e b a) (he' :  a, e a a = equiv.refl _)

structure aux (s : sym2 α) :=
(a₁ a₂ : α)
(h : (a₁, a₂) = s)
(x : f a₁ a₂)

inductive aux_rel (s : sym2 α) : aux s  aux s  Prop
| sym (a₁ a₂ h x) : aux_rel a₁, a₂, h, x a₂, a₁, begin subst h, apply sym2.eq_swap end, e a₁ a₂ x

def lift_type : sym2 α  Type u := λ s, quot (aux_rel s)

end

Reid Barton (Dec 26 2021 at 00:04):

I didn't try to implement lift_sort_equiv so there may be more surprises there, but it seems like the right construction math-wise.

Bhavik Mehta (Dec 26 2021 at 00:05):

Woah I wasn't expecting it to be possible computably either, nice!

Reid Barton (Dec 26 2021 at 00:06):

Basically the h : ⟦(a₁, a₂)⟧ = s is a kind of strictification that produces an equality in Type where you wouldn't expect to obtain one

Reid Barton (Dec 26 2021 at 00:10):

I think the hypothesis he' that I added "just in case" probably isn't really necessary

Reid Barton (Dec 26 2021 at 00:13):

The way to arrive at this is rather than trying to build the type family lift_type : sym2 α → Type u, try to build the map X → sym2 α that it classifies

Kyle Miller (Dec 26 2021 at 03:18):

Here's a translation of @Reid Barton's construction into multigraph language. I wonder if there's a way to keep the universes for edges' from being bumped up?

import data.sym.sym2

universes u v

structure multigraph (α : Type u) :=
(edges : α  α  Sort v)
(flip : Π v w, edges v w  edges w v)
(inv :  v w, (flip v w).symm = flip w v)
(loops :  v, flip v v = equiv.refl _)

namespace multigraph
variables {α : Type u} (G : multigraph.{u v} α)

structure dart_at (s : sym2 α) :=
(v w : α)
(edge : G.edges v w)
(h : (v, w) = s)

inductive is_flipped_dart_at (s : sym2 α) : G.dart_at s  G.dart_at s  Prop
| is_flip (v w : α) (e : G.edges v w) (h : (v, w) = s) :
  is_flipped_dart_at v, w, e, h w, v, G.flip v w e, by { subst_vars, apply sym2.eq_swap }⟩

def edges' : sym2 α  Sort (max (u+1) v) := λ s, quot (G.is_flipped_dart_at s)

end multigraph

Kyle Miller (Dec 26 2021 at 03:36):

I find going through a map E -> sym2 V more natural on the way to the edges map, though (like what Reid mentioned):

import data.sym.sym2

universes u v

structure multigraph (α : Type u) :=
(edges : α  α  Sort v)
(flip : Π v w, edges v w  edges w v)
(inv :  v w, (flip v w).symm = flip w v)
(loops :  v, flip v v = equiv.refl _)

namespace multigraph
variables {α : Type u} (G : multigraph.{u v} α)

def dart := Σ' u v, G.edges u v

def dart.flip {G : multigraph α} : G.dart  G.dart
| u, v, e := v, u, G.flip u v e

inductive is_flipped_dart : G.dart  G.dart  Prop
| flip (d : G.dart) : is_flipped_dart d d.flip

def E := quot G.is_flipped_dart

def ends : G.E  sym2 α :=
quot.lift (λ (d : G.dart), (d.1, d.2.1))
begin
  rintros u,v,e u',v',e' _⟩,
  apply sym2.eq_swap,
end

def edges' (s : sym2 α) : Sort* := {e : G.E // G.ends e = s}

end multigraph

David Wärn (Dec 26 2021 at 11:42):

If you want to take this perspective seriously you will probably need to work with the transport from edges' ⟦(a, b)⟧ to edges' ⟦(b, a)⟧. I don't think this is any easier than having edges indexed by α × α and making flip explicit. I'm also sceptical of including this loops condition in the basic multigraph class (it means you can't view a groupoid as a multigraph). If you drop the loops condition then you can no longer think of a multigraph as a type family over some set, rather it would be a presheaf over a (non-discrete) groupoid analogue of sym2.


Last updated: Dec 20 2023 at 11:08 UTC