Zulip Chat Archive

Stream: new members

Topic: cumbersome typeclass in theorem statement


Daan van Gent (Nov 01 2022 at 15:45):

I am trying to prove a lemma of the following form.

import order.cover
import ring_theory.simple_module

variables {α : Type*} [lattice α] {x y : α}

open set

lemma covby_iff_simple_order_Icc : x  y   hxy : x  y, by {
  letI := Icc.bounded_order hxy, exact is_simple_order (Icc x y) } :=
begin
  rw covby_iff_lt_and_eq_or_eq,
  split;
  rintro hxy,h⟩, {
    use hxy.le,
    let x' : Icc x y := x, le_refl x, hxy.le⟩⟩,
    let y' : Icc x y := y, hxy.le, le_refl y⟩⟩,
    letI := Icc.bounded_order hxy.le,
    have hx' : x' =  := refl x',
    have hy' : y' =  := refl y',
    haveI : nontrivial (Icc x y) := ⟨⟨, , λ i, hxy.ne (subtype.mk_eq_mk.mp i)⟩⟩,
    exact λ z,hz⟩, begin
      apply (h z hz.1 hz.2).cases_on,
      exact λ h, or.inl begin rw [hx', subtype.mk_eq_mk, h] end,
      exact λ h, or.inr begin rw [hy', subtype.mk_eq_mk, h] end,
      end ⟩,
  }, {
    dsimp at h,
    letI := h,
    letI := Icc.bounded_order hxy,
    let x' : Icc x y := x, le_refl x, hxy⟩⟩,
    let y' : Icc x y := y, hxy, le_refl y⟩⟩,
    have hx' : x' =  := refl x',
    have hy' : y' =  := refl y',
    split, {
      apply lt_of_le_of_ne hxy,
      intro hxy,
      have i : x'  y' := bot_ne_top,
      apply i,
      rw [subtype.mk_eq_mk, hxy],
    }, {
      intros z hxz hzy,
      cases eq_bot_or_eq_top (⟨z,⟨hxz,hzy⟩⟩ : Icc x y) with h h, {
        left,
        exact subtype.mk.inj h,
      }, {
        right,
        exact subtype.mk.inj h,
      }
    }
  }
end

Besides the usual question of whether this is already in mathlib (#print instances is_simple_order gives no results), I wonder how to properly deal with the typeclasses in the theorem statement. It feels incorrect to go into tactics mode like this. Similarly, in the proof I need to construct the same typeclass instance. It forces me to duplicate the x' and hx' statements. Could you give me some style hints.

Alex J. Best (Nov 01 2022 at 16:18):

#print instances will only check the current environment, so unless you have import all (using leanproject mk-all) you won't find all of them.
Fortunately there is an easier way to find all instances: on the website: docs#is_simple_order you can click the arrow to show "instances of this typeclass"

Daan van Gent (Nov 01 2022 at 16:29):

It seems I was lucky, and my #print instances returned the same list as the docs. The question remains what the pythonic leanic way is to state this lemma.

Johan Commelin (Nov 01 2022 at 17:13):

One way to improve the statement would be if we refactor is_simple_order α to mean nat.card α = 2.

Jireh Loreaux (Nov 01 2022 at 17:14):

My short answer is: "don't". The reason it's a bit weird is that bounded_order is a data-carrying class (the data are ⊤ ⊥ : Icc x y), whereas x ⋖ y is a Prop. This is the reason you must have an existential.

But if you must you can make the statement without tactic mode by providing the terms directly.

lemma covby_iff_simple_order_Icc' : x  y   hxy : x  y,
  @is_simple_order (Icc x y) _ (Icc.bounded_order hxy) :=
sorry

However, I would instead suggest creating the following instance and lemma:

instance Icc.is_simple_order (h : x  y) :
  @is_simple_order (Icc x y) _ (Icc.bounded_order h.le) :=
sorry

lemma covby_of_Icc_is_simple_order [bounded_order (Icc x y)] [is_simple_order (Icc x y)] : x  y :=
sorry

Johan Commelin (Nov 01 2022 at 17:14):

Lemmas about simple orders can still assume that bounded_order is present, but the defn wouldn't need it.

Yaël Dillies (Nov 01 2022 at 18:38):

I know the context for this and my answer is: don't

Yaël Dillies (Nov 01 2022 at 18:39):

The blueprint I gave you carefully dodges trap statements like this one

Johan Commelin (Nov 01 2022 at 18:45):

@Yaël Dillies Nevertheless, what do you think of making is_simple_order a synonym for nat.card X = 2?

Eric Wieser (Nov 01 2022 at 19:03):

It seems a bit weird to use is_simple_order as the name if we define it without reference to orders

Yaël Dillies (Nov 01 2022 at 19:15):

@Johan Commelin, that's wrong. For example, bool with the discrete order (tt and ff are incomparable) is not a simple order.

Yaël Dillies (Nov 01 2022 at 19:16):

To be fair, the docstring of docs#is_simple_order is misleading.

Johan Commelin (Nov 01 2022 at 19:17):

I don't know much about order theory...

Adam Topaz (Nov 01 2022 at 19:17):

Using the word "simple" seems strange to me in this case.

Yaël Dillies (Nov 01 2022 at 19:18):

Technically, the current definition is wrong too...

Yaël Dillies (Nov 01 2022 at 19:19):

According to its definition, we could have a preorder where both and are less than each other (indistinguishable).

Adam Topaz (Nov 01 2022 at 19:20):

Does this notion agree with nlab#simple+object ?

Yaël Dillies (Nov 01 2022 at 19:21):

I would need to think it through. I think the correct interpretation for it would be in docs#Lattice

Adam Topaz (Nov 01 2022 at 19:22):

I guess if you have a simple object X then its lattice of quotients will be "simple" with this definition. But I don't know if that means the lattice itself is simple!

Adam Topaz (Nov 01 2022 at 19:22):

I'm confused.

Yaël Dillies (Nov 01 2022 at 19:25):

Hello confused, I'm confused too!

Junyan Xu (Nov 01 2022 at 19:44):

docs#is_simple_module unfolds to is_simple_order. docs#is_simple_group is definitionally the same as is_simple_order (subgroup G) except for the is_normal condition. I guess it could be defined to be is_simple_order {H : subgroup G // H.is_normal}.

Adam Topaz (Nov 01 2022 at 19:47):

yeah exactly.

Eric Wieser (Nov 01 2022 at 19:50):

According to its definition, we could have a preorder where both ⊥ and ⊤ are less than each other (indistinguishable).

Your comment amounts to

[preorder T] [bounded_order T] [is_simple_order T] is meaningless, only [partial_order T] [bounded_order T] [is_simple_order T] has mathematical content

right? I don't think redefining is_simple_order in terms of nat.card changes that

Pedro Sánchez Terraf (Nov 01 2022 at 20:45):

Adam Topaz said:

Does this notion agree with nlab#simple+object ?

I have not checked what the appropriate morphisms are. But in general (aka "universal") algebra, we treat categories that usually do not have a zero object, and still we call simple those objects with exactly two "congruences" (which is essentially, two quotients).

Adam Topaz (Nov 01 2022 at 20:47):

Yeah that's essentially what I was saying above. The congruences form a lattice (w.r.t. implication, say), and the lattice of congruences of a simple object is the a simple lattice w.r.t. docs#is_simple_order

Daan van Gent (Nov 01 2022 at 20:51):

Yaël Dillies said:

The blueprint I gave you carefully dodges trap statements like this one

You are right about what context I am using it, but it is actually for something else. I prove for modules that x ⋖ y iff the quotient is a simple module. However, I think that statement should go (1) x ⋖ y iff Icc x y is simple for lattices and then (2) Icc x y is order isomorphic to the quotient in the case of modules.

Daan van Gent (Nov 01 2022 at 20:56):

Yaël Dillies said:

Johan Commelin, that's wrong. For example, bool with the discrete order (tt and ff are incomparable) is not a simple order.

Isn't it? My bad I missed the discrete part.

Daan van Gent (Nov 01 2022 at 21:04):

Junyan Xu said:

docs#is_simple_module unfolds to is_simple_order. docs#is_simple_group is definitionally the same as is_simple_order (subgroup G) except for the is_normal condition. I guess it could be defined to be is_simple_order {H : subgroup G // H.is_normal}.

Working with the 'lattice of normal subgroups' feels unnatural, mostly because Icc x y is not order isomorphic with y / x.

Daan van Gent (Nov 01 2022 at 21:43):

At the risk of throwing oil at the fire: Is this better? I am also trying to improve my Lean. I have managed to eliminate code duplication.

Eric Wieser (Nov 01 2022 at 22:00):

Yael's comment above still applies; that lemma permits a more pleasant statement if you state the two directions separately (as this eliminates the exists). You can of course still prove the iff, but you can do so in terms of the separate directions.

Eric Wieser (Nov 01 2022 at 22:01):

Wrong thread @Yaël Dillies? (fixed)

Yaël Dillies (Nov 01 2022 at 22:01):

Uh yes :face_palm:

Daan van Gent (Nov 01 2022 at 22:31):

Eric Wieser said:

Yael's comment above still applies; that lemma permits a more pleasant statement if you state the two directions separately (as this eliminates the exists). You can of course still prove the iff, but you can do so in terms of the separate directions.

Fair point, I will do that.

Daan van Gent (Nov 01 2022 at 22:35):

Should a lemma like

def Icc_equiv_quot {R : Type*} [ring R] {M : Type*} [add_comm_group M] [module R M] {A B : submodule R M}
  (h : A  B) : (set.Icc A B) o submodule R (B  comap B.subtype A) := sorry

be added to mathlib? Does it exist? Or does anyone have a better idea for proving that A ⋖ B iff B/A is a simple module?

Daan van Gent (Nov 01 2022 at 23:36):

At least this one wasn't hard

import order.jordan_holder
import order.cover
import ring_theory.simple_module

open set
open submodule

@[simp]
lemma comap_map_subtype {R M : Type*} [ring R] [add_comm_group M] [module R M] (B : submodule R M)
(A : submodule R B) : comap B.subtype (map B.subtype A) = A :=
comap_map_eq_of_injective subtype.coe_injective A

@[simp]
lemma map_comap_subtype' {R M : Type*} [ring R] [add_comm_group M] [module R M] {B A : submodule R M}
(hab : A  B) : map B.subtype (comap B.subtype A) = A := by {
  rw [map_comap_subtype, inf_eq_right], exact hab }

def Iic_equiv_submodule (R M : Type*) [ring R] [add_comm_group M] [module R M]
  (C : submodule R M) : Iic C o submodule R C := {
  to_fun       := λ A, hA⟩, comap C.subtype A,
  inv_fun      := λ A, map C.subtype A, map_subtype_le C A⟩,
  left_inv     := λ A, hA⟩, subtype.mk_eq_mk.mpr (map_comap_subtype' hA),
  right_inv    := λ A, comap_map_subtype C A,
  map_rel_iff' := begin
    rintros A, hA B, hB⟩,
    change comap C.subtype A  comap C.subtype B  A  B,
    split; intro h,
    { rw [map_comap_subtype' hA, map_comap_subtype' hB],
      exact map_mono h },
    { exact comap_mono h }
  end }

Eric Wieser (Nov 02 2022 at 07:41):

It would be better to avoid the ⟨⟩ when defining to_fun

Kevin Buzzard (Nov 02 2022 at 07:42):

Because when defining data this trick can lead to some pretty nasty defeqs under the hood

Eric Wieser (Nov 02 2022 at 07:44):

I guess the statement above is also true as (C : set X) : Iic C ≃o set C

Daan van Gent (Nov 02 2022 at 11:06):

So I am trying to prove the Icc version, and I run into some very verbose goals in left_inv, right_inv and map_rel_iff'. Trying to change or dsimp them is very slow, to the point that it gives a deterministic timeout. Any suggestions?

Daan van Gent (Nov 02 2022 at 12:07):

Eric Wieser said:

I guess the statement above is also true as (C : set X) : Iic C ≃o set C

My statement does not follow from that one right? Certainly a submodule C is a set X, but set C is not equal to submodule R C. Or am I missing your point?

Kevin Buzzard (Nov 02 2022 at 20:17):

dsimp at h, does the change and it seems to do it much more quickly. Wait -- why are you changing C to C.val?

Kevin Buzzard (Nov 02 2022 at 20:19):

If you do dsimp at h first then the change might work more quickly?

Kevin Buzzard (Nov 02 2022 at 21:59):

lemma comap_map_mkq' {R M : Type*} [ring R] [add_comm_group M] [module R M] {A B : submodule R M}
  (hab : A  B) : comap A.mkq (map A.mkq B) = B := by rwa [comap_map_mkq, sup_eq_right]

rwa is rw, then assumption

Kevin Buzzard (Nov 02 2022 at 22:45):

  map_rel_iff' := begin
    rintro C, hAC, hCB D, hAD, hDB⟩,
    dsimp,
    simp only [map_le_iff_le_comap, comap_map_mkq],
    rw sup_eq_right.2 (comap_mono hAD : comap B.subtype A  comap B.subtype D),
    refine λ h x hxC, _, comap_mono⟩,
    specialize h (_ : B.subtype x, hCB hxC  C),
    exacts [hxC, h],
  end

Kevin Buzzard (Nov 02 2022 at 23:01):

left_inv := λ C, hAC, hCB⟩, by simp *,

Kevin Buzzard (Nov 02 2022 at 23:03):

Probably yours is faster though. Note that your h is defeq to A <= C \and C \le B.

Kevin Buzzard (Nov 02 2022 at 23:04):

Oh -- I changed your to_fun to to_fun := λ C, map (comap B.subtype A).mkq (comap B.subtype (C : submodule R M)), -- my guess is that the coercion is the simp normal form rather than C.val.

Kevin Buzzard (Nov 02 2022 at 23:23):

To avoid confusion let me just post my version of the full code. It's still slow though and I don't really know why.

def Icc_equiv_quot (R M : Type*) [ring R] [add_comm_group M] [module R M] (A B : submodule R M)
  (hAB : A  B) : (set.Icc A B) o submodule R (B  comap B.subtype A) := {
  to_fun := λ C, map (comap B.subtype A).mkq (comap B.subtype (C : submodule R M)),
  inv_fun := λ C, map B.subtype (comap (comap B.subtype A).mkq C), 
    le_trans (map_comap_subtype' hAB).symm.le (map_mono (le_comap_mkq _ C)),
    map_subtype_le B _ ⟩⟩,
  left_inv := λ C, hAC, hCB⟩, by simp *,
  right_inv := λ C, by simp,
  map_rel_iff' := begin
    rintro C, hAC, hCB D, hAD, hDB⟩,
    dsimp,
    simp only [map_le_iff_le_comap, comap_map_mkq],
    rw sup_eq_right.2 (comap_mono hAD : comap B.subtype A  comap B.subtype D),
    refine λ h x hxC, _, comap_mono⟩,
    specialize h (_ : B.subtype x, hCB hxC  C),
    exacts [hxC, h],
  end }

Daan van Gent (Nov 03 2022 at 09:46):

Thanks for your effort! I was really struggling with val/coe/etc. Do you mind if I pull request this to mathlib?

Daan van Gent (Nov 03 2022 at 09:49):

I did some experimenting by moving to_fun and inv_fun to separate definitions, and it becomes way faster. It seems like inv_fun is somewhat slow, and if we leave it inline as in your code it seems like it has to 'parse' (for lack of a better word) that multiple times.

Daan van Gent (Nov 03 2022 at 12:08):

I am now at the final stages of my proofs. I only require the following instance. However, I seem unable to tell Lean that beta is a bounded_order. Any hints?

import order.cover order.atoms

instance is_simple_order_of_equiv {α : Type*} [has_le α] [bounded_order α] [partial_order α]
  {β : Type*} [has_le β] [bounded_order β] [partial_order β] [h : is_simple_order α] (f : α o β) :
  is_simple_order β := {
  exists_pair_ne := begin
    rcases h.exists_pair_ne with x, y, h⟩,
    exact f x, f y, λ i, h ((order_iso.apply_eq_iff_eq f).mp i)⟩,
  end,
  eq_bot_or_eq_top := λ z, begin
    cases h.eq_bot_or_eq_top (f.symm z), {
      left,
      have := congr_arg f h_1,
      rw f.apply_symm_apply at this,
      --letI : order_bot β := bounded_order.to_order_bot β,
      have := @order_iso.map_bot α β _ _ _ _,
    }
  end }

Daan van Gent (Nov 03 2022 at 12:18):

Nevermind, I figured it out. has_le and partial_order conflict, so it should be {α : Type*} [partial_order α] [bounded_order α].

Eric Wieser (Nov 03 2022 at 12:34):

is_simple_order_of_equiv can't be an instance as lean can't find f, but it should be a @[reducible] def.

Eric Wieser (Nov 03 2022 at 12:35):

You should be able to golf that by using docs#function.injective.nontrivial


Last updated: Dec 20 2023 at 11:08 UTC