Zulip Chat Archive

Stream: Is there code for X?

Topic: Prop-valued "I have one term"


Kevin Buzzard (Nov 07 2021 at 18:06):

We have unique but it's Type-valued. I think I want to say "I have one element" in a Prop-valued way. I went for the definition of is_singleton below (and proved the lemmas I need for the application in LTE), but is this not the sort of thing I should be doing? Is this in the library already and I just missed it? If not, is there a reason it's not there?

import tactic

def is_singleton (X : Sort*) : Prop :=
nonempty (unique X)

noncomputable def is_singleton.default {X : Sort*} (hx : is_singleton X) :
  X := (nonempty.some hx).default

def punit.is_singleton : is_singleton (punit) :=
punit.unique

def is_singleton.to_subsingleton {X : Sort*} (hX : is_singleton X) :
  subsingleton X :=
begin
  unfreezingI {rcases hX with x, hx⟩},
  exact λ a b, (hx a).trans (hx b).symm⟩,
end


theorem is_singleton_iff_forall_bijective_to_punit (X : Sort*) :
  is_singleton X   f : X  punit, function.bijective f :=
begin
  split,
  { rintro ⟨⟨x⟩, hx f,
    exact λ a b h, (hx a).trans (hx b).symm, λ s, x, subsingleton.elim _ _⟩⟩ },
  { intro h,
    cases h (λ x, punit.star) with finj fsurj,
    choose g hg using fsurj,
    refine ⟨⟨⟨g punit.star⟩, λ x, finj rfl⟩⟩ }
end

theorem is_singleton_iff_forall_bijective_to_is_singleton (X : Sort*) :
  is_singleton X   (Y : Type*) (hY : is_singleton Y)
  (f : X  Y), function.bijective f :=
begin
  split,
  { rintro ⟨⟨x⟩, hx Y hY f,
    haveI := hY.to_subsingleton,
    exact λ a b h, (hx a).trans (hx b).symm, λ s, x, subsingleton.elim _ _⟩⟩ },
  { intro h,
    cases h punit punit.is_singleton (λ x, punit.star) with finj fsurj,
    choose g hg using fsurj,
    refine ⟨⟨⟨g punit.star⟩, λ x, finj rfl⟩⟩ }
end

theorem is_singleton_iff_exists_bijective_to_punit (X : Sort*) :
  is_singleton X   f : X  punit, function.bijective f :=
begin
  split,
  { rintro ⟨⟨x⟩, hx⟩,
    use (λ x, punit.star),
    refine λ a b _, (hx a).trans (hx b).symm,
      λ a, x, subsingleton.elim _ _⟩⟩ },
  { rintro f, finj, fsurj⟩,
    choose g hg using fsurj,
    refine ⟨⟨⟨g punit.star⟩, λ x, finj $ subsingleton.elim _ _⟩⟩ },
end

theorem is_singleton_iff_exists_bijective_to_is_singleton (X : Sort*) :
  is_singleton X   (Y : Sort*) (hY : is_singleton Y) (f : X  Y), function.bijective f :=
begin
  split,
  { rintro ⟨⟨x⟩, hx⟩,
    use [punit, punit.is_singleton, (λ x, punit.star)],
    refine λ a b _, (hx a).trans (hx b).symm,
      λ a, x, subsingleton.elim _ _⟩⟩ },
  { rintro Y, hY, f, finj, fsurj⟩,
    choose g hg using fsurj,
    haveI := hY.to_subsingleton,
    refine ⟨⟨⟨g hY.default⟩, λ x, finj $ subsingleton.elim _ _⟩⟩ },
end

Yakov Pechersky (Nov 07 2021 at 18:16):

Can't you just use [subsingleton X] [nonempty X]?

Kevin Buzzard (Nov 07 2021 at 18:17):

Oh that's maybe why it's not there.

Yakov Pechersky (Nov 07 2021 at 18:18):

The one thing I don't know how to do is conjure a term x : X, without doing cases on the nonempty hyp. Probably doing it on id h, to retain it in the TC cache.

Yakov Pechersky (Nov 07 2021 at 18:19):

Use "arbitrary", I guess

Eric Wieser (Nov 07 2021 at 18:20):

obtain ⟨x⟩ := id ‹nonempty α› is probably reasonable idiomatic

Eric Wieser (Nov 07 2021 at 18:22):

Do we have the lemma that conjures nonempty (unique X) from [subsingleton X] [nonempty X]?

Yakov Pechersky (Nov 07 2021 at 18:27):

We have the defn that makes a unique X from data and subsingleton X. Probably not yet what you're asking about.

Eric Wieser (Nov 07 2021 at 18:40):

What's that def?

Eric Wieser (Nov 07 2021 at 18:43):

Ah found it:

casesI nonempty X.map unique_of_subsingleton,  -- put `unique X` in the context

Johan Commelin (Nov 07 2021 at 18:57):

I think it would be nice to have a variant of tactic#inhabit that allows you to specify an alias for the default element.

Johan Commelin (Nov 07 2021 at 18:57):

inhabit X with x

Johan Commelin (Nov 07 2021 at 18:58):

This could be as simple as being a shortcut for

inhabit X,
let x := default X

Reid Barton (Nov 07 2021 at 19:28):

Why do you have all this unfreezingI/haveI/etc. stuff if is_singleton is not a class?

Kevin Buzzard (Nov 07 2021 at 20:39):

You mean in is_singleton.to_subsingleton? I have no idea. I tried doing cases and I got the *frozen local instance" error

Kevin Buzzard (Nov 07 2021 at 21:23):

MWE (note that nonempty is a class):

import tactic

def is_singleton (X : Sort*) : Prop :=
nonempty (unique X)

def is_singleton.to_subsingleton {X : Sort*} (hX : is_singleton X) :
  subsingleton X :=
begin
  -- cases hX, -- "failed to revert 'hX', it is a frozen local instance "
  unfreezingI {rcases hX with x, hx⟩},
  exact λ a b, (hx a).trans (hx b).symm⟩,
end

Eric Rodriguez (Nov 07 2021 at 21:40):

this does seem like a bug, right? as it shouldn't be in the instance cache at all

Eric Rodriguez (Nov 07 2021 at 21:42):

yeah, it's definitely a bug:

import tactic

def is_singleton (X : Sort*) : Prop :=
nonempty (unique X)

def is_singleton.to_subsingleton {X : Sort*} (hX : is_singleton X) :
  subsingleton X :=
begin
  --rw is_singleton at hX ; works if you do this!
  --have := classical.arbitrary (unique X) ; no instance error
  cases hX,
end

Eric Wieser (Nov 07 2021 at 22:33):

I think lean is seeing through is_singleton and finding the class attribute on nonempty

Eric Rodriguez (Nov 07 2021 at 22:49):

but if you rw it to the nonempty term you don't get the issue

Eric Rodriguez (Nov 07 2021 at 22:50):

I am confused how because the code seems pretty bulletproof


Last updated: Dec 20 2023 at 11:08 UTC