Zulip Chat Archive
Stream: new members
Topic: Understanding assume
Daniel Keys (Jan 18 2020 at 22:47):
New to functional languages. Want to understand how assume
works in Lean. Why is it OK to have theorem ex1 : ¬(p ∧ ¬q) → (p → q) := begin assume h : ¬(p ∧ ¬q), assume hp : p
but not for example theorem ex2 : (p → r ∨ s) → ((p → r) ∨ (p → s)) := begin assume rs : r ∨ s
?
Moses Schönfinkel (Jan 18 2020 at 22:52):
Because -> is right associative. The first argument of theorem ex2
is a function from p
to r or s
.
Moses Schönfinkel (Jan 18 2020 at 22:53):
Also note that in theorem ex1
, your h
is of type (p and not q) -> false
, that is, a function type. You're then left with p -> s
, where associativity plays no part. You can therefore further assume p
. Note that the parentheses around (p -> q)
are redundant.
Kevin Buzzard (Jan 18 2020 at 23:03):
Surely the analogue of what works in ex1 is assume prs : (p → r ∨ s)
? That's the left hand side of the implication. Both goals are of the form P -> Q
and you want to start with assume hP : P
.
Daniel Keys (Jan 18 2020 at 23:04):
So is there any assumption that can be made to help in theorem ex2
? I wanted to get started like assume hp : p
, like @Kevin Buzzard suggests, but it just doesn't work. I get an error message.
Mario Carneiro (Jan 18 2020 at 23:08):
You can't prove that theorem in constructive logic, meaning that the straightforward "follow your nose" approach doesn't work
Mario Carneiro (Jan 18 2020 at 23:08):
You can prove it by cases on whether p
is true or false
Daniel Keys (Jan 18 2020 at 23:09):
How to get started in that case?
Mario Carneiro (Jan 18 2020 at 23:09):
begin by_cases p,
Mario Carneiro (Jan 18 2020 at 23:10):
if it complains about decidable something then write this at the top of your file:
local attribute [instance] classical.prop_decidable
Daniel Keys (Jan 18 2020 at 23:11):
Right, it does say by_cases tactic failed, type of given expression is not decidable
.
Kevin Buzzard (Jan 18 2020 at 23:15):
I said P
not p
. You have some super-complex goals with lots and lots of p's and q's and and's and r's, but ultimately it is of the form P -> Q with P and Q slightly less complicated expressions. Your job is to figure out what P and Q are, and then assume hP of type P.
Daniel Keys (Jan 18 2020 at 23:17):
@Kevin Buzzard Sorry, I noticed that too late. That is actually something I can already get from intro
, right?
Kevin Buzzard (Jan 18 2020 at 23:17):
oh sure
Kevin Buzzard (Jan 18 2020 at 23:25):
if it complains about decidable something then write this at the top of your file:
local attribute [instance] classical.prop_decidable
Isn't something like
local attribute [instance, priority 10] classical.prop_decidable
better? But isn't open_locale classical
even better?
Mario Carneiro (Jan 18 2020 at 23:30):
Yes, but I don't know if daniel is using mathlib
Daniel Keys (Jan 18 2020 at 23:41):
@Moses Schönfinkel Your response is too high-level for a newbie like me. Is there any way to elaborate a bit? For another example, I can do theorem T3L : ¬p ∧ ¬q → ¬(p ∨ q) := assume right: p ∨ q
but can't do assume right : ((p → r) ∨ (p → s))
in that ex2
.
Kevin Buzzard (Jan 18 2020 at 23:42):
Are you really sure you can do assume right: p ∨ q
?
Kevin Buzzard (Jan 18 2020 at 23:43):
¬p ∧ ¬q → ¬(p ∨ q)
is of the form X -> Y
with X=¬p ∧ ¬q
and Y=¬(p ∨ q)
. Do you understand that?
Kevin Buzzard (Jan 18 2020 at 23:43):
So the only possible thing you can assume is a proof of X
Kevin Buzzard (Jan 18 2020 at 23:44):
ex2 is also of the form X -> Y and you have to figure out what X and Y are, and then assume you have a proof of X, and your goal will be to prove Y. But first you need to figure out what X and Y are.
Daniel Keys (Jan 18 2020 at 23:45):
@Kevin Buzzard I sure can. I have that working.
theorem T3L : ¬p ∧ ¬q → ¬(p ∨ q) := begin intros notP_and_notQ, assume rhs : p ∨ q, { cases rhs with hp hq, { exact notP_and_notQ.left hp }, { exact notP_and_notQ.right hq } } end #check T3L p q
Kevin Buzzard (Jan 18 2020 at 23:55):
sure it works after the intros!
Kevin Buzzard (Jan 18 2020 at 23:56):
After the intros, the goal is (p ∨ q) -> false
Kevin Buzzard (Jan 18 2020 at 23:56):
so you can assume a proof of (p ∨ q)
Kevin Buzzard (Jan 18 2020 at 23:58):
If your goal is X -> Y then you can assume a proof of X. That's the rule.
Joe (Jan 18 2020 at 23:59):
@Daniel Keys
You want to prove ((p → r) ∨ (p → s))
in ex2
, so it just doesn't make any sense to assume it. Else there would be nothing left to prove.
Joe (Jan 18 2020 at 23:59):
I'm not sure why you find this confusing...
Daniel Keys (Jan 19 2020 at 00:20):
@Joe You're right, that part is not confusing. What I struggle with is something around these lines: to prove a statement, sometimes you need to go several routes. For example, you can have cases that split in "if p is true, this follows" and "if p is not true, this follows". So in my mind it seems like I should be able to "assume p" and reach a conclusion, then "assume not p" and reach the other. That is kind of where I struggle now.
Kevin Buzzard (Jan 19 2020 at 00:22):
Yes you can do that
Kevin Buzzard (Jan 19 2020 at 00:24):
Do you have mathlib installed? What happens if you type import tactic.linarith
at the beginning of your file?
Daniel Keys (Jan 19 2020 at 00:26):
What does that do? Why install mathlib?
Cerek Hillen (he) (W2'20) (Jan 19 2020 at 00:36):
fellow newbie so take this with a grain of salt: mathlib is the accompanying library that defines a bunch of common mathematical concepts for use in other proofs
Cerek Hillen (he) (W2'20) (Jan 19 2020 at 00:37):
e.g. i'm using it for data.set.basic
which just defines sets and their properties
Kevin Buzzard (Jan 19 2020 at 00:44):
Mathlib offers more tactic tools for you to be able to argue like a mathematician would, for example here's a proof of Q given that P -> Q
and ¬ P → Q
, but using a tactic from mathlib:
import tactic variables (P Q : Prop) open_locale classical example (hP : P → Q) (hnP : ¬ P → Q) : Q := begin by_cases h : P, { apply hP, assumption }, { apply hnP, assumption } end
Without mathlib you have to write some more intimidating stuff like Mario's local attribute [instance] classical.prop_decidable
above.
Kevin Buzzard (Jan 19 2020 at 00:46):
Your underlying problem with assume
is that you're assuming it means a vague all-purpose "assume" which we use in normal English. In Lean assume
has one, extremely precise, meaning -- it can only be used on goals of the form X -> Y
and it can only be used to assume that X
is true.
Kevin Buzzard (Jan 19 2020 at 00:48):
I proved Q
above by saying "Assume P
is true -- then use hP
; now assume it's false and use hnP
instead". But the Lean translation of that kind of "assume" is by_cases
, at least if you have mathlib. If you only have core Lean then it will look uglier.
Kevin Buzzard (Jan 19 2020 at 00:49):
variables (P Q : Prop) example (hP : P → Q) (hnP : ¬ P → Q) : Q := begin have H : P ∨ ¬ P := classical.em P, cases H, { apply hP, assumption }, { apply hnP, assumption } end
classical.em
is the classical law of the excluded middle.
Daniel Keys (Jan 19 2020 at 00:59):
@Kevin Buzzard OK then, so the way to introduce other assumptions (is it goals?) is by have
? But what was confusing was that I could still use assume hp:p
in the very first example I posted. It seems like an extra.
Kevin Buzzard (Jan 19 2020 at 01:01):
I can only repeat what I've said before about exactly what assume does
Daniel Keys (Jan 19 2020 at 01:01):
That's fine, thank you! I need more homework.
Kevin Buzzard (Jan 19 2020 at 01:01):
Try the exercises in Theorem Proving In Lean
Kevin Buzzard (Jan 19 2020 at 01:02):
Or the natural number game
Daniel Keys (Jan 19 2020 at 01:02):
Well, I did all of those in chapter 3 except for the classical stuff (7 problems) where I got totally stuck.
Kevin Buzzard (Jan 19 2020 at 01:03):
Well maybe you could ask some very precise questions about things you were stuck on
Kevin Buzzard (Jan 19 2020 at 01:04):
A precise question in the form of some working lean code which people can just cut and paste without having to figure out variables or whatever is usually what goes down best here
Daniel Keys (Jan 19 2020 at 01:04):
@Kevin Buzzard I can. Here is this, I need help! theorem T1 : (p → r ∨ s) → ((p → r) ∨ (p → s)) := sorry
. The first one in the classical problems in ch.3
Joe (Jan 19 2020 at 03:03):
@Daniel Keys
theorem T1 {p q r s : Prop} : (p → r ∨ s) → ((p → r) ∨ (p → s)) := λ h, classical.by_cases (λ hp : p, or.elim (h hp) (λ hr, or.inl $ λ hp, hr) $ λ hs, or.inr $ λ hp, hs) (λ hp : ¬p, or.inl $ λ hp', absurd hp' hp)
Daniel Keys (Jan 19 2020 at 08:11):
@Joe @Kevin Buzzard So that brings me exactly to what I fail to understand in these proofs. All of a sudden you have hr
and hs
, or the even more cryptic $ λ hp'
coming up in your lambda
terms. How can you produce these and work with them if the only hypothesis is (p → r ∨ s)
? Where from does LEAN know what hp'
is? Maybe it is my unwillingness to work with lambda
. While I'll be looking into it, can one get what you wrote in a framework like this:
theorem T1 : (p → r ∨ s) → ((p → r) ∨ (p → s)) := begin intros prs, cases (em p) with hp hnp, { ... }, { ... } end
which is easier to read, to help my understanding?
Mario Carneiro (Jan 19 2020 at 08:24):
lambda is a binder, meaning that it introduces a new name. So when you see λ hp'
, you should expect that the name hp'
has not been previously used
Mario Carneiro (Jan 19 2020 at 08:24):
The tactic version of lambda is intros
Mario Carneiro (Jan 19 2020 at 08:25):
The dollar sign is just a trick for reducing parentheses. f $ g x y
is the same as f (g x y)
Daniel Keys (Jan 19 2020 at 08:27):
So how do you write it with begin...end
? I probably just need to see that once.
Mario Carneiro (Jan 19 2020 at 08:28):
variables p q r s : Prop open classical theorem T1 : (p → r ∨ s) → ((p → r) ∨ (p → s)) := begin intros prs, cases (em p) with hp hnp, { cases prs hp with hr hs, { left, intro, exact hr }, { right, intro, exact hs } }, { left, intro, contradiction } end
Daniel Keys (Jan 19 2020 at 08:28):
Thanks a lot! This will get me going.
Mario Carneiro (Jan 19 2020 at 08:28):
protip: use ```lean ... ```
to fence lean code
Daniel Keys (Jan 19 2020 at 08:43):
I can see what the left
and right
terms do in the above, but I don't remember having seen that in the manual. Is it there somewhere?
Kevin Buzzard (Jan 19 2020 at 08:44):
They're explained in the natural number game
Patrick Massot (Jan 19 2020 at 09:01):
https://leanprover.github.io/theorem_proving_in_lean/tactics.html?highlight=left#more-tactics
Daniel Keys (Jan 19 2020 at 09:02):
OK, I see. I only got to the end of chapter 3.
Last updated: Dec 20 2023 at 11:08 UTC