Zulip Chat Archive
Stream: general
Topic: eliminator for set based on whether it is empty or not
Bernd Losert (Dec 15 2021 at 22:55):
Say I have a set s
. Is there an eliminator on s
to deal with what happens when it is empty and when it isn't? Or do I have to useby_cases
on is_empty s
?
Eric Wieser (Dec 15 2021 at 22:56):
docs#set.eq_empty_or_nonempty might exist
Eric Wieser (Dec 15 2021 at 22:58):
Excellent, it does: so
obtain rfl | ⟨x, hx⟩ := s.eq_empty_or_nonempty
Will do all you need in tactic mode
Bernd Losert (Dec 15 2021 at 23:00):
So that will create two goals? One for the empty case and one for the nonempty case?
Bernd Losert (Dec 15 2021 at 23:01):
I would prefer an eliminator that I can use outside of tactic mode (if such a thing exists).
Adam Topaz (Dec 15 2021 at 23:06):
How do you propose to avoid cases?
Bernd Losert (Dec 15 2021 at 23:07):
I want cases, but in the form of an eliminator, like. set.empty_elim (empty_case_code) (non_empty_case_code)
.
Eric Wieser (Dec 15 2021 at 23:07):
In tactic mode you can use s.eq_empty_or_nonempty.elim _ _
Adam Topaz (Dec 15 2021 at 23:08):
Right, just combine what Eric said with the eliminator for or
Eric Wieser (Dec 15 2021 at 23:08):
You'll have to rewrite by s = ∅
manually in the first case though
Eric Wieser (Dec 15 2021 at 23:10):
Or use match s.empty_or_nonempty with | or.inl rfl := _ | or.inr r := _ end
, if that works
Bernd Losert (Dec 15 2021 at 23:10):
So (set.eq_empty_or_nonempty s).elim
? Let me try.
Eric Wieser (Dec 15 2021 at 23:10):
s.
should work fine
Adam Topaz (Dec 15 2021 at 23:11):
You can avoid those parens with the dot notation :) see Mario's comment
Bernd Losert (Dec 15 2021 at 23:12):
Ah, right.
Adam Topaz (Dec 15 2021 at 23:13):
Dot notation is really awesome when you get used to it
Bernd Losert (Dec 15 2021 at 23:15):
OK, it seems to work, but now I'm getting another error. Progress!
Bernd Losert (Dec 15 2021 at 23:31):
This doesn't work for me:
def f : set nat -> nat := fun (s : set nat),
match s.empty_or_nonempty with
| or.inl rfl := 0
| or.inr _ := 1
end
What am I doing wrong here?
Bernd Losert (Dec 15 2021 at 23:35):
Could it be that empty_or_nonempty only works in tactic mode?
Mario Carneiro (Dec 15 2021 at 23:38):
You can't eliminate an or
into a non-prop
Mario Carneiro (Dec 15 2021 at 23:39):
If you change the nat
for some proposition then it will work
Mario Carneiro (Dec 15 2021 at 23:39):
are you trying to construct data, or prove a theorem?
Mario Carneiro (Dec 15 2021 at 23:40):
for the former I would suggest using if s = ∅ then empty_case_code else non_empty_case_code
Mario Carneiro (Dec 15 2021 at 23:41):
which also requires open_locale classical
at the top of the file or by classical; exact
at the start of the function
Bernd Losert (Dec 15 2021 at 23:49):
Ah, I see. I didn't know about the restriction of or elimination. OK.
Bernd Losert (Dec 15 2021 at 23:51):
Is there a reason for this restriction?
Mario Carneiro (Dec 15 2021 at 23:54):
An or
does not contain information about which variant is true, there is provably at most one proof of a disjunction. So you can't use a proof of an or
to make a case disjunction unless the thing you are trying to prove is already a proposition (in which case it doesn't matter which one is actually true, in the case where both are true)
Yaël Dillies (Dec 15 2021 at 23:56):
Put simply, you know it's true, but you don't know which
Yaël Dillies (Dec 15 2021 at 23:56):
So you can't compute
Bernd Losert (Dec 15 2021 at 23:58):
That makes sense.
Bernd Losert (Dec 15 2021 at 23:59):
Although it's kind of weird - if you don't know which, how does the pattern matching work?
Adam Topaz (Dec 16 2021 at 00:00):
It should be mentioned that you can write if _ then _ else _
Yaël Dillies (Dec 16 2021 at 00:00):
Mario Carneiro said:
for the former I would suggest using
if s = ∅ then empty_case_code else non_empty_case_code
It has been :wink:
Mario Carneiro (Dec 16 2021 at 00:02):
Bernd Losert said:
Although it's kind of weird - if you don't know which, how does the pattern matching work?
The pattern matching only works in the case where it is in a computationally irrelevant position: it is never actually executed
Bernd Losert (Dec 16 2021 at 00:02):
So it's an illusion.
Mario Carneiro (Dec 16 2021 at 00:02):
In this case, it is simply nice syntax for the logical theorem or.cases_on
Bernd Losert (Dec 16 2021 at 00:03):
Thanks for clarifying.
Mario Carneiro (Dec 16 2021 at 00:03):
It's (ab)using the curry howard isomorphism to allow you to write proofs with some of the same syntax that you use to write programs
Bernd Losert (Dec 16 2021 at 00:15):
How do I get an element from the set in the nonempty_case_code?
Bernd Losert (Dec 16 2021 at 00:16):
I mean, when I do this if s = ∅ then empty_case_code else non_empty_case_code
.
Adam Topaz (Dec 16 2021 at 00:35):
We probably have docs#set.nonempty.some or something like that?
Adam Topaz (Dec 16 2021 at 00:36):
But you would have to show that s \neq \empty
implies s.nonempty
.
Adam Topaz (Dec 16 2021 at 00:37):
It might be better to use if s.nonempty then nonempty_case else empty_case
. It's very possible that you're trying to do something in a way that's not ideal.
Adam Topaz (Dec 16 2021 at 00:37):
Can you un- #xy ?
Bernd Losert (Dec 16 2021 at 00:39):
Well, I'm trying to define has_Inf
and I need to deal with the case when the set is empty and do something special in that case.
Bernd Losert (Dec 16 2021 at 00:40):
So far, Lean is not letting me do what I want. It keeps complaining about:
error: induction tactic failed, recursor 'or.dcases_on' can only eliminate into Prop
Bernd Losert (Dec 16 2021 at 00:43):
When I use if then else
, I run into invalid field notation
problems.
Adam Topaz (Dec 16 2021 at 00:44):
What are defining a has_Inf for? A #mwe would be helpful
Bernd Losert (Dec 16 2021 at 00:49):
import tactic
import order.filter.ultrafilter
import order.filter.partial
noncomputable theory
open set filter classical
open_locale classical filter
variable a : Type*
class convergence_space (a : Type*) :=
(conv : filter a -> a -> Prop)
def indiscrete : convergence_space a := {
conv := fun l x, l <= pure x,
}
instance : has_Inf (convergence_space a) := {
Inf := fun ps,
let ne := ps.nonempty in
if ne then { conv := @conv a (set.nonempty.some ne) }
else indiscrete
}
Adam Topaz (Dec 16 2021 at 00:58):
I don't know if this is the correct definition...
import tactic
import order.filter.ultrafilter
import order.filter.partial
noncomputable theory
open set filter classical
open_locale classical filter
variable (α : Type*)
class convergence_space (α : Type*) :=
(conv : filter α -> α -> Prop)
def indiscrete : convergence_space α := ⟨λ l x, l ≤ pure x⟩
instance {α} : has_Inf (convergence_space α) :=
{ Inf := λ S, ⟨λ F x, ∀ (t : convergence_space α) (ht : t ∈ S),
by letI : convergence_space α := t; exact convergence_space.conv F x⟩ }
Adam Topaz (Dec 16 2021 at 00:58):
This is saying that the convergence should hold true for every convergence space structure from the given set.
Bernd Losert (Dec 16 2021 at 00:59):
That would be has_Sup
. I had no problems with that one.
Mario Carneiro (Dec 16 2021 at 01:00):
If you have a sup, you can just skip the inf
Bernd Losert (Dec 16 2021 at 01:01):
True, but I wanted to define the instance just to check the theory.
Mario Carneiro (Dec 16 2021 at 01:01):
in a complete lattice one implies the other, although the expression you get out is ugly and it's good to supply one explicitly if it has a nice expresssion
Bernd Losert (Dec 16 2021 at 01:02):
In this Inf, it's supposed to be an existensial, but I have to deal with the empty case explicitly.
Mario Carneiro (Dec 16 2021 at 01:02):
Could you write the expression you want informally?
Adam Topaz (Dec 16 2021 at 01:03):
Are you looking for something like this?
import tactic
import order.filter.ultrafilter
import order.filter.partial
noncomputable theory
open set filter classical
open_locale classical filter
variable (α : Type*)
class convergence_space (α : Type*) :=
(conv : filter α -> α -> Prop)
def indiscrete : convergence_space α := ⟨λ l x, l ≤ pure x⟩
instance {α} : has_Inf (convergence_space α) :=
{ Inf := λ S, ⟨λ F x, ∃ (t : convergence_space α) (ht : t ∈ S),
by letI : convergence_space α := t; exact convergence_space.conv F x⟩ }
Bernd Losert (Dec 16 2021 at 01:04):
Basically, the Inf ps
of a set of convergence spaces ps
is suppose to defined as so that conv f x
in Inf ps
means there exists a p
in ps
such that conv f x
in p
. In the case the set is empty, use the indiscrete convergence space.
Mario Carneiro (Dec 16 2021 at 01:04):
btw you can use by exactI
instead of that letI
Bernd Losert (Dec 16 2021 at 01:05):
First time seeing letI and exactI. What do those do?
Mario Carneiro (Dec 16 2021 at 01:05):
how about F ≤ pure x \/ ∃ (t : convergence_space α) (ht : t ∈ S), by exactI convergence_space.conv F x
Bernd Losert (Dec 16 2021 at 01:05):
And why does the approach using if then else
fail?
Mario Carneiro (Dec 16 2021 at 01:06):
It can be made to work, but I think it is better to use propositional connectives in this case since you are defining a Prop
Bernd Losert (Dec 16 2021 at 01:06):
I tried to, but it still complained saying that I wasn't defining a Prop.
Mario Carneiro (Dec 16 2021 at 01:07):
But the code with { conv := @conv a (set.nonempty.some ne) }
is wrong, that is saying that some particular p in the set is converging, not that there exists one that converges
Bernd Losert (Dec 16 2021 at 01:08):
Ah, you're right. After giving up on the existensial version, I was trying this approach and I didn't realize it was not the same.
Bernd Losert (Dec 16 2021 at 01:10):
Again, thanks for clarifying. Thank goodness for zulip and the helpful people here. Without them, I would have given up formalizing this stuff.
Kevin Buzzard (Dec 16 2021 at 08:26):
Without the Zulip most of us would have given up. Without Mario I would never have made it through my first year example sheets, let alone schemes
Last updated: Dec 20 2023 at 11:08 UTC