Zulip Chat Archive

Stream: new members

Topic: Choosing, classically


Cody Roux (Nov 28 2020 at 19:21):

Ok, I'll ask something I could probably figure out on my own but seems to be eluding me: how does one classically, given a finset A, case over whether it is empty or not, and get some arbitrary element if it isn't?

Cody Roux (Nov 28 2020 at 19:22):

Basically, if I can switch over s.nonempty I'm good, but I don't know how to switch!

Marc Huisinga (Nov 28 2020 at 19:26):

is this what you're looking for? docs#finset.eq_empty_or_nonempty

Cody Roux (Nov 28 2020 at 19:27):

Sure, along with a way to switch on either possibility...

Rob Lewis (Nov 28 2020 at 19:27):

Are you in term mode or tactic mode? In general you have many options for classical case splits, all boiling down to classical.prop_decidable.

import data.finset

open_locale classical

example {α} (s : finset α) : true :=
if hs : s.nonempty then trivial else trivial

example {α} (s : finset α) : true :=
begin
  by_cases hs : s.nonempty,
  { trivial },
  { trivial }
end

Rob Lewis (Nov 28 2020 at 19:28):

The open_locale line gives you a local instance that says "every proposition is decidable."

Cody Roux (Nov 28 2020 at 19:29):

term mode

Rob Lewis (Nov 28 2020 at 19:29):

Marc Huisinga said:

is this what you're looking for? docs#finset.eq_empty_or_nonempty

Or, if you get the disjunction from here, you can use or.elim (term mode) or cases (tactic mode)

Cody Roux (Nov 28 2020 at 19:29):

oh can you use that hs in the if statement?

Cody Roux (Nov 28 2020 at 19:30):

brilliant! Here's what I have so far:

noncomputable def finset_take :  (n : ) (s : finset α), finset α
| 0 := λ _, 
| (nat.succ n) := λ s,
   if hs : s.nonempty then
     let a := classical.choice hs s in
     cons a (finset_take n (s.erase a))
  else 

Cody Roux (Nov 28 2020 at 19:31):

classical.choice doesn't seem to be in love with this particular version of nonempty. Should I use inhabited?

Cody Roux (Nov 28 2020 at 19:32):

Can or.elim eliminate to Type?

Cody Roux (Nov 28 2020 at 19:32):

(sorry for the question rapid fire)

Rob Lewis (Nov 28 2020 at 19:40):

Sorry, or.by_cases, not or.elim

Rob Lewis (Nov 28 2020 at 19:42):

Not quite sure what the issue is there with classical.choice, mathlib favors classical.some

Rob Lewis (Nov 28 2020 at 19:43):

But it should be basically the same

Rob Lewis (Nov 28 2020 at 19:43):

I have to run, maybe someone else can figure out what's wrong there

Cody Roux (Nov 28 2020 at 19:43):

Thanks a bunch Rob!

Cody Roux (Nov 28 2020 at 19:43):

Hope things are good!

Bryan Gin-ge Chen (Nov 28 2020 at 19:52):

This is progress, I think:

import tactic
open_locale classical
variables (α : Type*)

noncomputable def finset_take :   finset α  finset α
| 0 _ := 
| (nat.succ n) s :=
   if hs : s.nonempty then
     let a := classical.some hs in
     finset.cons a (finset_take n (s.erase a)) sorry
  else 

Not quite sure how to fill in the sorry, which is asking for a proof that a ∉ finset_take n (s.erase a).

Bryan Gin-ge Chen (Nov 28 2020 at 19:53):

Oh, I guess you could also use insert instead of finset.cons:

import tactic
open_locale classical
variables (α : Type*)

noncomputable def finset_take :   finset α  finset α
| 0 _ := 
| (nat.succ n) s :=
   if hs : s.nonempty then
     let a := classical.some hs in
     insert a (finset_take n (s.erase a))
  else 

Kenny Lau (Nov 28 2020 at 19:55):

why not just choose a list representative

Cody Roux (Nov 29 2020 at 03:54):

I'm avoiding going down to lists, since it makes proofs a bit harder, it seems.

Mario Carneiro (Nov 29 2020 at 05:09):

what properties do you want this take function to have?

Kenny Lau (Nov 29 2020 at 05:11):

yeah, what's the defining properties (aka API) of your take

Cody Roux (Nov 30 2020 at 02:47):

I just want take n s to return exactly n distinct arbitrary members of s, if n < card s. This is actually a first step, just to get a taste of classical reasoning. Second step is building all possible such sets, and then building some well-founded induction principles, if the existing one on <+ proves insufficient.

This seems like a pretty common thing to do in additive combinatorics, along the lines of "pick an arbitrary n element set from an n+1 element set. Either this set has the k property or it doesn't in which case it has the k-1 property by IH, and we'll carefully add a new element in it, by cases".

Mario Carneiro (Nov 30 2020 at 03:21):

I would suggest proving the theorem first, and then using choice to extract it as a function after:

import tactic
open_locale classical
variables {α : Type*}

theorem exists_finset_take (n) (s: finset α) (h : n  s.card) :  t : finset α, t.card = n  t  s :=
begin
  have :  n (s: finset α), n = s.card   t : finset α, t.card = n  t  s,
  { rintro _ s rfl, refine s, rfl, _⟩, refl },
  refine finset.induction (λ h, _) (λ a s ha IH h, _) s h,
  { exact this n  (le_zero_iff_eq.1 h) },
  rw [finset.card_insert_of_not_mem ha] at h,
  obtain h | h := lt_or_eq_of_le h,
  { obtain t, te, st := IH (nat.lt_succ_iff.1 h),
    refine t, te, finset.subset.trans st (finset.subset_insert _ _)⟩ },
  { apply this, rwa [finset.card_insert_of_not_mem ha] }
end

noncomputable def finset_take (n) (s: finset α) : finset α :=
if h : n  s.card then classical.some (exists_finset_take n s h) else 

theorem card_finset_take (n) (s : finset α) (h : n  s.card) : (finset_take n s).card = n :=
by rw [finset_take, dif_pos h]; exact (classical.some_spec (exists_finset_take n s h)).1

theorem finset_take_subset (n) (s : finset α) : finset_take n s  s :=
begin
  rw finset_take, split_ifs,
  { exact (classical.some_spec (exists_finset_take n s h)).2 },
  { apply finset.empty_subset }
end

Cody Roux (Nov 30 2020 at 03:32):

Thanks a bunch @Mario Carneiro ! I have to meditate on this a bit, and figure out what finset induction is, what rintro is, etc.

Mario Carneiro (Nov 30 2020 at 03:32):

tactic#rintro is like intro but you can do pattern matching while introducing variables, like the equation compiler

Cody Roux (Nov 30 2020 at 03:33):

Cool! Well this is all very fun. I'm sure I'll be back around when I try my next baby proof.

Mario Carneiro (Nov 30 2020 at 03:33):

docs#finset.induction is a convenient way to do induction on finsets by adding elements disjoint from everything so far, which seems relevant for your additive combinatorics example

Bhavik Mehta (Nov 30 2020 at 04:00):

You could alternatively use https://leanprover-community.github.io/mathlib_docs/data/finset/basic.html#finset.exists_intermediate_set or the lemma after that :)

Bhavik Mehta (Nov 30 2020 at 04:01):

which, unsurprisingly, I needed for doing combinatorics in Lean as well!

Floris van Doorn (Nov 30 2020 at 04:02):

Ah nice! I was already surprised that Mario's lemma exists_finset_take apparently didn't exist yet.

Cody Roux (Nov 30 2020 at 18:23):

Oh dang, I thought I had looked! Sheesh, these libs are quite detailed. I'm actually a little surprised no-one's tried Ramsey's theorem.

Johan Commelin (Nov 30 2020 at 18:32):

@Cody Roux I don't know anything about Ramsey, but it has been tried afaik

Johan Commelin (Nov 30 2020 at 18:32):

https://github.com/b-mehta/combinatorics/blob/extras/src/inf_ramsey.lean

Alex J. Best (Nov 30 2020 at 18:34):

(deleted)


Last updated: Dec 20 2023 at 11:08 UTC