Zulip Chat Archive

Stream: Is there code for X?

Topic: a "reflect" structure for when you don't want subtype


Kenny Lau (Jul 07 2025 at 12:14):

import Mathlib

/-- Morally, `A ≃ Subtype (α := B) p` -/
class HasReflect (A B : Type*) (p : B  Prop) extends Coe A B where
  reflect (x : B) (h : p x) : A
  satisfy (x : A) : p x := by simp
  left_inv {x : A} : reflect x (satisfy x) = x := by simp
  coe_reflect {x : B} {h : p x} : reflect x h = x := by simp

attribute [simp] HasReflect.satisfy HasReflect.left_inv HasReflect.coe_reflect

def HasReflect.addCommGroup (A B p) [HasReflect A B p] [AddCommGroup B]
    (hzero : p 0) (hadd :  {x y}, p x  p y  p (x + y)) : AddCommGroup A where
  add x y := reflect (x + y : B) (hadd (by simp) (by simp))
  zero := reflect (0 : B) hzero
  neg x := reflect (-x : B) (p := p) sorry
  nsmul := sorry
  zsmul := sorry
  add_assoc := sorry
  zero_add := sorry
  add_zero := sorry
  neg_add_cancel := sorry
  add_comm := sorry
  nsmul_zero := sorry
  nsmul_succ := sorry
  zsmul_zero' := sorry
  zsmul_succ' := sorry
  zsmul_neg' := sorry

structure Diagonal (M : Type*) where
  fst : M
  snd : M
  eq : fst = snd

attribute [simp] Diagonal.eq

@[ext] lemma Diagonal.ext {x y : Diagonal M} (h1 : x.1 = y.1) (h2 : x.2 = y.2) : x = y := by
  cases x; cases y; congr

attribute [simp] Diagonal.ext_iff

instance : HasReflect (Diagonal M) (M × M) (fun x  x.1 = x.2) where
  coe x := (x.fst, x.snd)
  reflect x p := x.1, x.2, p

instance [AddCommGroup M] : AddCommGroup (Diagonal M) :=
  HasReflect.addCommGroup _ (M × M) (fun x  x.1 = x.2) rfl (by simp)

Kenny Lau (Jul 07 2025 at 12:15):

I'm asking here to gauge if this is a good idea; basically this is useful for when something is morally a subtype, but you want to make it a separate definition rather than just to use subtype. Is there any usecases for that?

Kenny Lau (Jul 07 2025 at 12:15):

For example, the recently merged #26060 (Grassmannians) used structure rather than subtype:

Kenny Lau (Jul 07 2025 at 12:16):

@[stacks 089R] structure Grassmannian extends Submodule R M where
  finite_quotient : Module.Finite R (M  toSubmodule)
  projective_quotient : Projective R (M  toSubmodule)
  rankAtStalk_eq :  p, rankAtStalk (R := R) (M  toSubmodule) p = k

Kenny Lau (Jul 07 2025 at 12:17):

image.png

Kenny Lau (Jul 07 2025 at 12:17):

the justification was this comment (@Eric Wieser , do you remember why that was a good idea?)

Kenny Lau (Jul 07 2025 at 12:17):

maybe it's for better instances

Kenny Lau (Jul 07 2025 at 12:19):

or maybe I should have just used the equiv and transport the module structure... on hindsight maybe this code can be avoided

Kenny Lau (Jul 07 2025 at 12:19):

idk if there would be defeq problems tho if I use equiv...

Ruben Van de Velde (Jul 07 2025 at 12:31):

I'm thinking because the separate fields feel more ergonomic

Kenny Lau (Jul 07 2025 at 12:33):

Kenny Lau said:

or maybe I should have just used the equiv and transport the module structure... on hindsight maybe this code can be avoided

I'm mainly following the philosophy of IsLocalization here

Kenny Lau (Jul 07 2025 at 12:33):

that sometimes some explicit conditions is better than just an equiv

Andrew Yang (Jul 08 2025 at 03:00):

Why not just docs#Function.Injective.addCommGroup etc?

Kenny Lau (Jul 08 2025 at 03:30):

oh yeah I eventually discovered that instead


Last updated: Dec 20 2025 at 21:32 UTC