Zulip Chat Archive

Stream: general

Topic: cases eliminating into type


Kevin Buzzard (Apr 25 2018 at 21:02):

I've just managed to internalise something Mario told me a couple of weeks ago.

Kevin Buzzard (Apr 25 2018 at 21:02):

Here's the cases tactic in action.

Kevin Buzzard (Apr 25 2018 at 21:02):

theorem T (γ : Type) (P : γ  Prop) (H :  g : γ, P g) : 2 + 2 = 4 :=
begin
cases H with g Pg,
/- context now has
g : γ,
Pg : P g
-/
admit,
end

Kevin Buzzard (Apr 25 2018 at 21:03):

Now here's an example of it failing because we need to use the axiom of choice.

Kevin Buzzard (Apr 25 2018 at 21:03):

definition D (γ : Type) (P : γ  Prop) (H :  g : γ, P g) : Type :=
begin
-- cases H with g Pg -- fails as we can only eliminate into Prop
admit
end

Kevin Buzzard (Apr 25 2018 at 21:04):

But of course us classical people want to run cases anyway.

Kevin Buzzard (Apr 25 2018 at 21:04):

definition D (γ : Type) (P : γ  Prop) (H :  g : γ, P g) : Type :=
begin
-- cases H with g Pg -- fails as we can only eliminate into Prop
let g := classical.some H,
have Pg : P g := classical.some_spec H,
/- ... but I made it anyway. Context now
g : γ := ...
Pg : P g
-/
admit
end

Kevin Buzzard (Apr 25 2018 at 21:06):

Using this trick (classical some and some_spec, plus the thing which I think Mario was trying to explain to me, which was that the moment you run classical.some you should make something _useful_ from classical.some_spec rather than just have Pg := classical.some_spec H which is a statement about classical.some _ and hence harder to work with.

Kevin Buzzard (Apr 25 2018 at 21:07):

I am going to use this idiom again and again

Kevin Buzzard (Apr 25 2018 at 21:07):

but surely this should just be a tactic

Kevin Buzzard (Apr 25 2018 at 21:07):

classical_cases H with g Pg

Kevin Buzzard (Apr 25 2018 at 21:09):

I have been fretting a bit over things like the fact that the "obvious in maths" statement that if there's a surjection X -> Y then there's an injection Y -> X looks so convoluted in Lean.

Kevin Buzzard (Apr 25 2018 at 21:09):

But this tactic is probably trivial to write and just looks like an extension of cases, which the students learn very early on when learning Lean anyway

Kevin Buzzard (Apr 25 2018 at 21:09):

Is this there already?

Kevin Buzzard (Apr 25 2018 at 21:10):

If not -- I _really_ think it should be! It is far more natural to write than all this classical.some_spec or indefinite_confusion or whatever it's called

Kevin Buzzard (Apr 25 2018 at 21:12):

Let me stress that the trick is that you force the type of Pg to be P g, the thing you want it to be, by explicitly making it of this type when you construct it. Just writing have Pg := classical.some_spec H doesn't work.

Reid Barton (Apr 25 2018 at 21:15):

Maybe choose for the tactic name?

Simon Hudon (Apr 25 2018 at 21:18):

Have a look at https://github.com/unitb/lean-lib/blob/master/test/tactic/classical.lean . It is not quite behaving like cases but it does make some and epsilon easier to work with. (I linked to the test case so that you see how I use it rather than how it works).

Kevin Buzzard (Apr 25 2018 at 21:33):

How do I use apply_some_spec Simon? I mean how do I get it running on my machine?

Simon Hudon (Apr 25 2018 at 21:35):

leanpkg add unitb/lean-lib

and don't forget:

import util.classical

Kevin Buzzard (Apr 25 2018 at 21:40):

open function
theorem inj_of_surj (X Y : Type) (f : X  Y) (Hf : surjective f) :  g : Y  X, f  g = id :=
begin
existsi _, --slightly weird first move
tactic.swap, -- ha ha, swap is now overloaded because I opened function!
{ intro y,
  --classical_cases (Hf y) with x Hx,
  let x := classical.some (Hf y),
  have Hx : f x = y := classical.some_spec (Hf y),
  exact x
},
{ funext y,
  --classical_cases (Hf y) with x Hx,
  let x := classical.some (Hf y),
  have Hx : f x = y := classical.some_spec (Hf y),
  exact Hx
}
end

Kevin Buzzard (Apr 25 2018 at 21:41):

I think my way looks a bit less intimidating for the newbie

Simon Hudon (Apr 25 2018 at 22:27):

You can do it like this:

namespace tactic
namespace interactive

open interactive interactive.types

meta def ccases (e : parse cases_arg_p) (ids : parse with_ident_list) :=
do cases (e.1,``(classical.indefinite_description _ %%(e.2))) ids

end interactive
end tactic

open function
theorem inj_of_surj (X Y : Type) (f : X  Y) (Hf : surjective f) :  g : Y  X, f  g = id :=
begin
split, --slightly weird first move
tactic.swap, -- ha ha, swap is now overloaded because I opened function!
{ intro y,
  ccases (Hf y) with x Hx,
  exact x
},
{ funext y,
  ccases (Hf y) with x Hx,
  -- let x := classical.some (Hf y),
  -- have Hx : f x = y := classical.some_spec (Hf y),
  simp,
  exact Hx
}
end

Mario Carneiro (Apr 25 2018 at 22:37):

Lol @ indefinite_confusion. But the right way to do this is to do cases on the pair some, some_spec, which is indeed classical.indefinite_description.

Mario Carneiro (Apr 25 2018 at 22:47):

Here's an idea that might help:

@[elab_as_eliminator]
noncomputable def classical.rec_on
  {α} {p : α → Prop} {C : Sort*}
  (h : ∃ a, p a) (H : ∀ a, p a → C) : C :=
H (classical.some h) (classical.some_spec h)

Mario Carneiro (Apr 25 2018 at 22:48):

You can apply that theorem to do cases on an exists without making cases complain

Kenny Lau (Apr 25 2018 at 22:49):

@Kevin Buzzard what if I told you “surjective functions have right inverse” is already in mathlib as inv_fun

Mario Carneiro (Apr 25 2018 at 22:50):

But in the case of inj_of_surj, this is the wrong approach (same for ccases or cases on indefinite description), because you are doing the case twice, once to define the function and again to give its properties. That means that you will have to unfold whatever proof term you constructed in the first half, i.e. classical.rec_on or subtype.rec_on or something

Mario Carneiro (Apr 25 2018 at 22:50):

The right solution here is to use axiom_of_choice

Mario Carneiro (Apr 25 2018 at 22:51):

theorem inj_of_surj (X Y : Type) (f : X → Y) (Hf : surjective f) : ∃ g : Y → X, f ∘ g = id :=
let ⟨g, h⟩ := classical.axiom_of_choice Hf in ⟨g, funext h⟩

Mario Carneiro (Apr 25 2018 at 22:51):

(Also this theorem already exists in core IIRC)

Mario Carneiro (Apr 25 2018 at 23:05):

For the golfers:

(classical.axiom_of_choice Hf).imp $ λ g, funext

Kevin Buzzard (Apr 26 2018 at 07:24):

The inj of surj example was pedagogical -- I know it's there, but I want to teach students how to write it without pain. There are other times this comes up too. I suspect a lot of undergraduate mathematicians will be very confused by constructive maths so I want to hide it from them. Many thanks for the tactic Simon and for the comments everyone.

Mario Carneiro (Apr 26 2018 at 07:25):

I think in particular that you should add axiom_of_choice to your toolkit

Kevin Buzzard (Apr 26 2018 at 07:27):

You are certainly right in that it's not currently in my toolkit.

Kevin Buzzard (Apr 26 2018 at 07:27):

I remember really struggling with all of this the first time around.

Kevin Buzzard (Apr 26 2018 at 07:28):

It's only revisiting it now I'm older and wiser that I understand it well enough to try and manipulate it into a form which I think beginners with no programming background might find more comprehensible.

Mario Carneiro (Apr 26 2018 at 07:29):

I would think that axiom_of_choice is the version of choice people are most used to

Mario Carneiro (Apr 26 2018 at 07:29):

classical.some is more like global choice, which ZFC doesn't usually admit so most proofs aren't framed that way

Kevin Buzzard (Apr 26 2018 at 07:30):

The problem is that most mathematicians apply the axiom of choice without noticing, and those that are aware of it believe that it says that an infinite product of non-empty sets is non-empty.

Kevin Buzzard (Apr 26 2018 at 07:30):

Mathematicians don't know the difference between the different kinds of non-empty

Mario Carneiro (Apr 26 2018 at 07:31):

I'm not talking about LEM here though

Kevin Buzzard (Apr 26 2018 at 07:31):

right

Mario Carneiro (Apr 26 2018 at 07:31):

all notions of nonempty are basically the same modulo LEM

Kevin Buzzard (Apr 26 2018 at 07:31):

they don't know what LEM is either

Mario Carneiro (Apr 26 2018 at 07:32):

I'm talking about how to use AC proper

Mario Carneiro (Apr 26 2018 at 07:32):

I think it is not a good thing that lean thinks LEM and AC are the same

Mario Carneiro (Apr 26 2018 at 07:33):

mathematicians certainly don't

Mario Carneiro (Apr 26 2018 at 07:33):

you can argue that mathematicians think both are true, but I think they admit LEM implicitly and don't see the need for AC until they reach a certain level

Kevin Buzzard (Apr 26 2018 at 07:33):

exactly

Kevin Buzzard (Apr 26 2018 at 07:34):

LEM is part of the logic

Kevin Buzzard (Apr 26 2018 at 07:34):

AC has some content

Mario Carneiro (Apr 26 2018 at 07:34):

Lean kind of gives you the ability to distinguish the two, since LEM is computable but AC is not


Last updated: Dec 20 2023 at 11:08 UTC