Zulip Chat Archive

Stream: new members

Topic: proving things about functions defined by cases


Keefer Rowan (May 17 2020 at 19:58):

How do I complete the following?

noncomputable def f :    :=
begin
    intro x,
    have : decidable (x = 5),
        apply classical.prop_decidable,
    cases this,
        exact 1,
        exact 2
end

example : f 5 = 1 :=
begin
    sorry,
end

I don't know what tactic to use to try to split into the cases by which f was defined.

Also, is there a way to clean up my definition to get rid of the have : decidable (x=5)?

Note: I know that I don't need classical reasoning for decidability of = in nat, but this is just an example.

Bhavik Mehta (May 17 2020 at 20:03):

Here's how I'd write your example:

def f (n : ) :  :=
if n = 5
  then 1
  else 2

example : f 5 = 1 :=
rfl

Bhavik Mehta (May 17 2020 at 20:03):

You can use the split_ifs tactic in more complex examples to break up an if in general

Bhavik Mehta (May 17 2020 at 20:04):

You could alternatively do:

def f :   
| 5 := 1
| _ := 2

example : f 5 = 1 :=
rfl

Bhavik Mehta (May 17 2020 at 20:05):

Alternatively,

def f (n : ) :  :=
begin
  by_cases (n = 5),
  { exact 1 },
  { exact 2 }
end

example : f 5 = 1 :=
rfl

Keefer Rowan (May 17 2020 at 20:18):

@Bhavik Mehta Thanks for the info on cleaning up the definitions.

Lean isn't recognizing split_ifs; what should I import to make it work?

Mario Carneiro (May 17 2020 at 20:19):

import tactic gets you a bunch of things

Mario Carneiro (May 17 2020 at 20:19):

the precise import is import tactic.split_ifs

Keefer Rowan (May 17 2020 at 20:19):

I'm getting file 'tactic' not found in the LEAN_PATH

Keefer Rowan (May 17 2020 at 20:20):

I'm not using anything from mathlib right now, likely has something to do with that. Do I need to read about the mathlib projects thing to get this to work?

Bryan Gin-ge Chen (May 17 2020 at 20:20):

Yes, see the instructions here.

Jalex Stark (May 17 2020 at 20:21):

Keefer Rowan said:

I'm not using anything from mathlib right now, likely has something to do with that. Do I need to read about the mathlib projects thing to get this to work?

It may sound scary but actually should be pretty easy, if you follow instructions precisely you should be able to start using mathlib in just a few minutes without entering more than 10 terminal commands

Keefer Rowan (May 17 2020 at 20:22):

Ok, I'll start working on it

Keefer Rowan (May 17 2020 at 20:47):

split_ifs isn't working.

Here's where I am; I can't come up with a shorter example (and this is reasonably short and self-contained) so here it is:

import tactic

open classical function

attribute [instance] classical.prop_decidable

universes u v
variables {α : Type u} {β : Type v}

def injection (f : α  β) : Prop :=
     x y, f x = f y  x = y

def left_inv (f : α  β) (g : β  α) : Prop :=
    g  f  = id

def has_left_inv (f : α  β) : Prop :=
     g, left_inv f g


noncomputable def left_inv_func [h₁ : inhabited α] (f : α  β) : β  α :=
begin
    intro b,
    by_cases (b  set.image f set.univ),
        {unfold set.image has_mem.mem set.mem set_of at h,
        exact some h},
        {exact h₁.default}
end

theorem injection_left_inv_iff [inhabited α] {f : α  β} : injection f  has_left_inv f :=
begin
    split; intro h,
        {let g:= left_inv_func f,
        apply exists.intro g,
        unfold left_inv,
        unfold comp,
        apply funext,
        intro x,
        simp,
        split_ifs,}
end

I'm getting the error: no if-then-else expressions to split. How should I finish this proof?

Mario Carneiro (May 17 2020 at 20:50):

You should not use tactics to define data (the function left_inv_func)

Mario Carneiro (May 17 2020 at 20:51):

instead, use \lam b, if h : b ∈ set.image f set.univ then some h else h₁.default

Mario Carneiro (May 17 2020 at 20:51):

and then the theorem can use split_ifs profitably

Yury G. Kudryashov (May 17 2020 at 20:54):

I assumed that this tactic will generate the same definition.

Yury G. Kudryashov (May 17 2020 at 20:55):

@Keefer Rowan You can always look at the actual definition using #print left_inv_func

Keefer Rowan (May 17 2020 at 20:56):

Non-tactic definition:

noncomputable def function.left_inv_func : Π {α : Type u} {β : Type v} [h₁ : inhabited α], (α  β)  β  α :=
λ {α : Type u} {β : Type v} [h₁ : inhabited α] (f : α  β) (b : β),
  dite (b  f '' set.univ) (λ (h : b  f '' set.univ), some h) (λ (h : b  f '' set.univ), default α)

Tactic definition :

noncomputable def function.left_inv_func : Π {α : Type u} {β : Type v} [h₁ : inhabited α], (α  β)  β  α :=
λ {α : Type u} {β : Type v} [h₁ : inhabited α] (f : α  β) (b : β),
  dite (b  f '' set.univ) (λ (h : b  f '' set.univ), some _) (λ (h : b  f '' set.univ), default α)

They are indeed the same, and so I'm still stuck. Even with the non-tactic definition, split_ifs doesn't work.

Mario Carneiro (May 17 2020 at 20:57):

When you call split_ifs, dite should be visible in the goal

Reid Barton (May 17 2020 at 20:57):

It looks like you are not unfolding left_inv_func, so there is no if visible.

Yury G. Kudryashov (May 17 2020 at 20:59):

BTW, we already have this as inv_fun_on/inv_fun in logic/function/basic

Keefer Rowan (May 17 2020 at 21:00):

Ok, I assumed it would do the unfolding, but it is (mostly) working after unfolding, however, I can only get the unfold to work if if I have:

theorem injection_left_inv_iff [inhabited α] {f : α  β} : injection f  has_left_inv f :=
begin
    split; intro h,
        {let g := left_inv_func f,
        apply exists.intro g,
        unfold left_inv,
        unfold comp,
        apply funext,
        intro x,
        simp,
        unfold left_inv_func,}
end

If I introduce to the notation let g := left_inv_func f e.g. in

theorem injection_left_inv_iff [inhabited α] {f : α  β} : injection f  has_left_inv f :=
begin
    split; intro h,
        {
apply exists.intro (left_inv_func f),
        unfold left_inv,
        unfold comp,
        apply funext,
        intro x,
        simp,
        unfold left_inv_func,}
end

Mario Carneiro (May 17 2020 at 21:00):

you have to unfold g as well if you make a let

Mario Carneiro (May 17 2020 at 21:01):

unfortunately unfold doesn't work on let but dsimp only [g] should

Keefer Rowan (May 17 2020 at 21:02):

Sorry a bit confused by those two messages together. How do I unfold g? By dsimp only [g]?

Mario Carneiro (May 17 2020 at 21:02):

yes

Keefer Rowan (May 17 2020 at 21:02):

Ok thanks! It's all coming together now!

Scott Morrison (May 18 2020 at 06:57):

Arguably split_ifs should be more aggressive, so that if it fails to find an if statement it does some amount of unfolding. Where and how much to unfold, of course, is unclear.

Johan Commelin (May 18 2020 at 07:04):

Maybe it could take some arguments? So that

dsimp [foo, bar, quux], split_ifs

can be written as

split_ifs [foo, bar, quux]

Last updated: Dec 20 2023 at 11:08 UTC