Zulip Chat Archive
Stream: new members
Topic: Primes and modular arithmetic.
Wrenna Robson (Nov 13 2020 at 21:57):
Hi. I'm working on a kata and I'm doing some actual number theory in Lean for the first time.
theorem solution
{p q : ℕ}
(hp : nat.prime p)
(hq : nat.prime q)
(p_lt_q : p < q)
(p_ne_two : p ≠ 2)
(q_ne_two : q ≠ 2)
(consecutive : ∀ k, p < k → k < q → ¬ nat.prime k) :
∃ a b c, p + q = a * b * c
∧ a > 1 ∧ b > 1 ∧ c > 1 :=
begin
sorry,
end
This is my MWE, although it's really just a sorry right now. I did one attempt but it got in such a tangle...
Here is my sketch proof:
p odd as non-two prime, q same. So p + q even, so there's a natural k such that 2*k = p + q. p < k < q, so by hypothesis k is not prime. So there's some a, 1 < a < k, such that a | k. Let b = (k/a). Use a, b, 2 as the a, b, c needed.
Now, I'd like to avoid too much unnecessary work here. To show that p and q are odd, it makes sense that I'd use nat.prime.eq_two_or_odd. But this has the "odd" condition as p % 2 = 1. This doesn't seem very useful - in particular, I can't see how you make it compatible with the MOD N definition, or the definition of oddness - so while there surely must be a way to get to where I want, it isn't clear to me.
To find k, I think I might want to use nat.exists_dvd_of_not_prime or nat.not_prime_iff_min_fac_lt - the former seems better. These are the only two "number theoretic" theorems I want - everything else seems like it ought to just be algebra. But I can't see how to run at it neat#ly.
Jalex Stark (Nov 13 2020 at 22:00):
Wrenna Robson said:
Now, I'd like to avoid too much unnecessary work here. To show that p and q are odd, it makes sense that I'd use nat.prime.eq_two_or_odd. But this has the "odd" condition as p % 2 = 1. This doesn't seem very useful - in particular, I can't see how you make it compatible with the MOD N definition, or the definition of oddness - so while there surely must be a way to get to where I want, it isn't clear to me.
It sounds like you're asking for a lemma relating oddness and % 2 = 1
relation. You could write this lemma out explicitly and then see if library_search
finds it.
Wrenna Robson (Nov 13 2020 at 22:00):
Yes. I have had a good look before asking! But I haven't found one.
Jalex Stark (Nov 13 2020 at 22:00):
finding existing lemmas is hard, for sure
Jalex Stark (Nov 13 2020 at 22:01):
Jalex Stark (Nov 13 2020 at 22:01):
one surprisingly useful strategy is to literally guess the name of the lemma
Wrenna Robson (Nov 13 2020 at 22:01):
Yes I've got very far with that!
Jalex Stark (Nov 13 2020 at 22:01):
another strategy is using tactic#library_search
Jalex Stark (Nov 13 2020 at 22:02):
for the latter you have to actually write a statement of the lemma you want, for this you might find tactic#extract_goal useful
Wrenna Robson (Nov 13 2020 at 22:02):
How embarassing!
Wrenna Robson (Nov 13 2020 at 22:02):
Here it is: https://leanprover-community.github.io/mathlib_docs/data/nat/parity.html#nat.odd_iff
Wrenna Robson (Nov 13 2020 at 22:03):
lemma odd_iff_one_mod_2 {a : ℕ} : odd a ↔ a % 2 = 1 :=
begin
library_search,
end
This worked :)
Jalex Stark (Nov 13 2020 at 22:03):
I don't think it's embarrassing at all!
Wrenna Robson (Nov 13 2020 at 22:04):
So using nat.prime.eq_two_or_odd I can get p = 2 \\/ p % 2 = 1.
Jalex Stark (Nov 13 2020 at 22:04):
I think I wrote the kata you're working on, and I think I found and forgot the name of this lemma literally three times during the process of writing it
Ruben Van de Velde (Nov 13 2020 at 22:04):
or.resolve_left
?
Wrenna Robson (Nov 13 2020 at 22:05):
Thanks :)
Wrenna Robson (Nov 13 2020 at 22:05):
That was my next question.
Wrenna Robson (Nov 13 2020 at 22:05):
It's a really nice kata, Jalex! Because it is not very hard number theory but it's just hard enough to stretch me in Lean.
Ruben Van de Velde (Nov 13 2020 at 22:06):
(I went looking for that with library_search
as well just now, so I guessed :))
Kevin Buzzard (Nov 13 2020 at 22:08):
Proving stuff like this is a kerfuffle. I can do the maths, and then I just muddle through the proofs. I think the only difference between you (Wrenna) and me is that I know a couple more tricks. I've always had a "grind it out" policy in maths (as you saw with my L<0 proof earlier). I think people with more dignity try to write cleaner code but all I want is "goals accomplished".
Wrenna Robson (Nov 13 2020 at 22:08):
I like beauty in my code, for my sins.
Ruben Van de Velde (Nov 13 2020 at 22:10):
Not sure if you knew this trick yet:
have := hp.eq_two_or_odd.resolve_left p_ne_two,
(given hp : nat.prime p
, nat.prime.foo hp
can be abbreviated hp.foo
)
Wrenna Robson (Nov 13 2020 at 22:16):
Why does it look like there are two functions with the same name here?
Wrenna Robson (Nov 13 2020 at 22:16):
https://leanprover-community.github.io/mathlib_docs/data/nat/parity.html#nat.even_add
Wrenna Robson (Nov 13 2020 at 22:16):
theorems, even, not functions
Jalex Stark (Nov 13 2020 at 22:17):
do you mean nat.even_add
and nat.even.add
?
Wrenna Robson (Nov 13 2020 at 22:18):
Oh I see. Ha, a punctuation mark off.
Kevin Buzzard (Nov 13 2020 at 22:20):
you were nat even wrong
Wrenna Robson (Nov 13 2020 at 22:20):
Alright, next question - this is more of a logic one.
begin
have op : ¬ even p,
{
rw nat.not_even_iff,
exact hp.eq_two_or_odd.resolve_left p_ne_two,
},
have oq : ¬ even q,
{
rw nat.not_even_iff,
exact hq.eq_two_or_odd.resolve_left q_ne_two,
},
have epq : even (p + q),
{
rw nat.even_add,
sorry,
},
sorry,
end
Here, I have even p ↔ even q as a goal, and ¬even p and ¬even q as hypotheses. So, uh, this is "just true", right? I tried simp (didn't work) - clearly I guess I could split the iff and so on but it seems like a lot...
Kevin Buzzard (Nov 13 2020 at 22:22):
I would envisage simp
proving it by changing even p
and even q
to false
, but it won't do that unless you explicitly tell it to use the hypotheses not even p
and not even q
Kevin Buzzard (Nov 13 2020 at 22:22):
(simp
doesn't use any of the hypotheses in your local context by default)
Wrenna Robson (Nov 13 2020 at 22:22):
So something like simp [op, oq]
?
Wrenna Robson (Nov 13 2020 at 22:23):
Yes!
Kevin Buzzard (Nov 13 2020 at 22:23):
that's what I'd try
Kevin Buzzard (Nov 13 2020 at 22:24):
when I was a beginner I'd try simp
on anything. Now I know a bit more about term rewriting I kind of get how to use it much better.
Wrenna Robson (Nov 13 2020 at 22:36):
Suppose I have something like p + q = 2*d and p < q, and I want to show p < d and d < q. It feels a bit like I want to do something like p = p /2 + p/2 < p/2 + q/2 = (p+q)/2 = d and so forth. However everything here is in the naturals (where I would prefer to stay I think?), even though I want to briefly soujourn into the rationals.
Kevin Buzzard (Nov 13 2020 at 22:37):
I agree that staying in the naturals is a PITA for this one. The moment you divide by 2 you have trouble. I would be tempted to use norm_cast
.
Wrenna Robson (Nov 13 2020 at 22:37):
This really reminds me of some of the first stuff of yours I read, Kevin - the way mathematicians hop between the naturals, the reals, the integers, the rationals, without ever thinking of them as different objects, and how that sort of thing is uncovered by formalising like this.
Wrenna Robson (Nov 13 2020 at 22:37):
Ah, I haven't encountered norm_cast before.
Kevin Buzzard (Nov 13 2020 at 22:37):
Lemme see if I can knock something up. I would prove it for the rationals first.
Ruben Van de Velde (Nov 13 2020 at 22:38):
I used
have : ¬nat.prime k,
{ apply consecutive; linarith },
Wrenna Robson (Nov 13 2020 at 22:39):
Ha! Yes, indeed, linarith just does it...
Kevin Buzzard (Nov 13 2020 at 22:39):
oh that's great! That's better than my suggestion. I had assumed linarith would only work over Q
Kevin Buzzard (Nov 13 2020 at 22:42):
This was what I was thinking; change the entire question to one about rationals and then use linarith.
example (p q d : ℕ) (h : p < q) (hd : p + q = 2 * d) : p < d ∧ d < q :=
begin
suffices : (p : ℚ) < d ∧ (d : ℚ) < q,
cases this, split; assumption_mod_cast,
have hd' : (p : ℚ) + q = 2 * d,
assumption_mod_cast,
have h' : (p : ℚ) < q,
assumption_mod_cast,
split; linarith,
end
Kevin Buzzard (Nov 13 2020 at 22:42):
it didn't occur to me that split; linarith
would do it over N
Ruben Van de Velde (Nov 13 2020 at 22:42):
I have no intuition about when linarith
works on N, but sometimes it does
Kevin Buzzard (Nov 13 2020 at 22:43):
example (p q d : ℕ) (h : p < q) (hd : p + q = 2 * d) : p < d ∧ d < q :=
begin
split; omega
end
This is the correct proof.
Wrenna Robson (Nov 13 2020 at 22:43):
...
Kevin Buzzard (Nov 13 2020 at 22:43):
omega
is a tactic designed to work on naturals, it's complete for Presburger arithmetic, he said, only barely understanding what this means
Kevin Buzzard (Nov 13 2020 at 22:44):
I think it means "as long as you don't have two variables multiplied together, you're in good shape with omega
"
Wrenna Robson (Nov 13 2020 at 22:44):
I have put it in. Next I need 2 ≤ d...
Wrenna Robson (Nov 13 2020 at 22:44):
Again this is obviously true as p < d by omega or linarith or whatever
Wrenna Robson (Nov 13 2020 at 22:45):
and p is not 2 and is prime. However...
Kevin Buzzard (Nov 13 2020 at 22:45):
you want p prime -> p >=2, that will be in the library. Then omega or linarith can take it from there.
Wrenna Robson (Nov 13 2020 at 22:45):
Aye.
Wrenna Robson (Nov 13 2020 at 22:46):
nat.prime.one_lt is the one I think.
Kevin Buzzard (Nov 13 2020 at 22:46):
But you need it in the local context, it's not good enough to just have it somewhere in mathlib
Wrenna Robson (Nov 13 2020 at 22:46):
Aye.
Wrenna Robson (Nov 13 2020 at 22:48):
I think it doesn't like the ≠...
Kevin Buzzard (Nov 13 2020 at 22:48):
rotten luck. Not even omega?
Ruben Van de Velde (Nov 13 2020 at 22:48):
Try two_le
?
Wrenna Robson (Nov 13 2020 at 22:48):
?
Wrenna Robson (Nov 13 2020 at 22:49):
do you mean one_le_two?
Ruben Van de Velde (Nov 13 2020 at 22:49):
No, nat.prime.two_le
rather than nat.prime.one_lt
Kevin Buzzard (Nov 13 2020 at 22:50):
omega
works for me.
Wrenna Robson (Nov 13 2020 at 22:50):
hmm, maybe I'm using it wrong.
Kevin Buzzard (Nov 13 2020 at 22:51):
example (p : ℕ) (h : nat.prime p) (h2 : p ≠ 2) : 2 < p :=
begin
have h := nat.prime.one_lt h,
omega,
end
Wrenna Robson (Nov 13 2020 at 22:52):
Ah I was trying omega [nat.prime.two_le hp],
Kevin Buzzard (Nov 13 2020 at 22:52):
oh omega _does_ look at your local context
Wrenna Robson (Nov 13 2020 at 22:53):
bother said pooh
Kevin Buzzard (Nov 13 2020 at 22:53):
and I don't know if it takes arguments
Kevin Buzzard (Nov 13 2020 at 22:53):
yeah we make it random to keep beginners on their toes
Wrenna Robson (Nov 13 2020 at 22:54):
The have k := syntax I either hadn't seen or had forgotton.
Kevin Buzzard (Nov 13 2020 at 22:54):
there is some code I don't really understand that you can see when you hover over a tactic. It's something to do with parsers. If I hover over omega
it says omega id*
Wrenna Robson (Nov 13 2020 at 22:54):
That's quite useful for "I want to instantiate a theorem in some particular way."
Kevin Buzzard (Nov 13 2020 at 22:54):
but if I hover over simp
it says simp !? only? (* | [(* | (- id | (<- expr | expr))), ...]?) (with id*)? (at (* | (⊢ | id)*))? tactic.simp_config_ext?
Kevin Buzzard (Nov 13 2020 at 22:54):
which I think means "simp can take some extra arguments"
Kevin Buzzard (Nov 13 2020 at 22:56):
I genuinely don't know what you can put after omega
, I only use it as a standalone tactic and I don't understand parsers well enough to know what id*
means
Wrenna Robson (Nov 13 2020 at 22:57):
Alright, home stretch...
Wrenna Robson (Nov 13 2020 at 22:57):
begin
have op : ¬ even p,
{
rw nat.not_even_iff,
exact hp.eq_two_or_odd.resolve_left p_ne_two,
},
have oq : ¬ even q,
{
rw nat.not_even_iff,
exact hq.eq_two_or_odd.resolve_left q_ne_two,
},
have epq : even (p + q),
{
rw nat.even_add,
simp [op, oq],
},
rw even_iff_two_dvd at epq,
cases (exists_eq_mul_right_of_dvd epq) with d hd,
have compd : ¬ nat.prime d,
{
apply consecutive;
omega,
},
have d2 : 2 ≤ d,
{
have k := nat.prime.two_le hp,
omega,
},
cases (nat.exists_dvd_of_not_prime d2 compd) with n hn,
use [2, n, d/n],
sorry,
end
Kevin Buzzard (Nov 13 2020 at 22:57):
What's the local context at the sorry
?
Kevin Buzzard (Nov 13 2020 at 22:57):
(either that or post a #mwe)
Wrenna Robson (Nov 13 2020 at 22:57):
pq: ℕ
hp: nat.prime p
hq: nat.prime q
p_lt_q: p < q
p_ne_two: p ≠ 2
q_ne_two: q ≠ 2
consecutive: ∀ (k : ℕ), p < k → k < q → ¬nat.prime k
op: ¬even p
oq: ¬even q
epq: 2 ∣ p + q
d: ℕ
hd: p + q = 2 * d
compd: ¬nat.prime d
d2: 2 ≤ d
n: ℕ
hn: n ∣ d ∧ n ≠ 1 ∧ n ≠ d
⊢ p + q = 2 * n * (d / n) ∧ 2 > 1 ∧ n > 1 ∧ d / n > 1
Kevin Buzzard (Nov 13 2020 at 22:58):
still loving the cut and paste from the infoview eats random spaces bug
Kevin Buzzard (Nov 13 2020 at 22:59):
a style point: you're not supposed to ever see >
in Lean code or goals.
Wrenna Robson (Nov 13 2020 at 22:59):
So if from hn I can get 1 < n and n < d then technically I should be done...
Kevin Buzzard (Nov 13 2020 at 22:59):
a > b
desugars to b < a
but it still manages to fool some tactics, so we just decided to ban it
Kevin Buzzard (Nov 13 2020 at 23:00):
yeah this is looking good
Wrenna Robson (Nov 13 2020 at 23:00):
I am a bit suspicious that, mmm, I haven't necessarily shown that d/n is an integer - it just seemed to accept me using it.
Kevin Buzzard (Nov 13 2020 at 23:00):
it's natural division, so 3/2=1 and 1/0=37
Wrenna Robson (Nov 13 2020 at 23:00):
Like it is an integer becasuse n | d but I'm not used to Lean letting me be lazy.
Wrenna Robson (Nov 13 2020 at 23:00):
Ah lovely.
Kevin Buzzard (Nov 13 2020 at 23:01):
right -- it's divided and then rounded
Wrenna Robson (Nov 13 2020 at 23:01):
So possibly I don't want to use the division.
Kevin Buzzard (Nov 13 2020 at 23:02):
it should be OK, there will probably be a lemma saying that if n | d then (n / d) * d = n
Wrenna Robson (Nov 13 2020 at 23:02):
Really I want to use n | d to find some m so that n*m = d. There should be some lemma for that.
Wrenna Robson (Nov 13 2020 at 23:02):
Or that, yes.
Kevin Buzzard (Nov 13 2020 at 23:02):
in fact you can just do cases on n | d
Kevin Buzzard (Nov 13 2020 at 23:02):
n | d
is by definition "exists m, d = n * m`
Wrenna Robson (Nov 13 2020 at 23:02):
Now, for some chunk series of ands, it's split, right?
Wrenna Robson (Nov 13 2020 at 23:02):
Repeated multiple times.
Kevin Buzzard (Nov 13 2020 at 23:02):
yes, split if they're in the goal and cases if they're hypotheses
Kevin Buzzard (Nov 13 2020 at 23:03):
the introduction and elimination tactics for and.
Wrenna Robson (Nov 13 2020 at 23:06):
Now, can I use rcases instead of cases, in order to get hn as three separate hypotheses originally?
Wrenna Robson (Nov 13 2020 at 23:06):
I'm not sure if I'll need to but...
Wrenna Robson (Nov 13 2020 at 23:06):
Hmm, it didn't work like I expected.
Kevin Buzzard (Nov 13 2020 at 23:07):
I like the way that you're kind of mathsy and computer-sciency at the same time. Are you that Royal Holloway PhD student or am I confusing you with someone else?
Wrenna Robson (Nov 13 2020 at 23:07):
That's me :)
Kevin Buzzard (Nov 13 2020 at 23:07):
mathsy beginners have more trouble with the CS stuff and CS beginners with the maths stuff
Wrenna Robson (Nov 13 2020 at 23:07):
And I have trouble with everything! ;P
Kevin Buzzard (Nov 13 2020 at 23:07):
You're doing great!
Wrenna Robson (Nov 13 2020 at 23:07):
Thanks!
Kevin Buzzard (Nov 13 2020 at 23:08):
example (P Q R : Prop) (h : P ∧ Q ∧ R) : false :=
begin
rcases h with ⟨hP, hQ, hR⟩,
sorry
end
Wrenna Robson (Nov 13 2020 at 23:08):
I can even claim that Lean is actual research work... though the paper I'm currently trying to figure out uses Isabelle for what it does (and I don't get Isabelle and it's much less user-friendly, alas).
Kevin Buzzard (Nov 13 2020 at 23:09):
I think the 24/7 helpline we have here is massively important
Wrenna Robson (Nov 13 2020 at 23:09):
Yes.
Kevin Buzzard (Nov 13 2020 at 23:09):
It was just over 3 years ago that I was spamming the chat asking questions and other people were helping me out.
Wrenna Robson (Nov 13 2020 at 23:10):
Circle of life!
Kevin Buzzard (Nov 13 2020 at 23:10):
I could do the maths no problem but I had no clue about the CS stuff.
Wrenna Robson (Nov 13 2020 at 23:11):
Hmm, the rcases format I wanted to use hasn't worked. Before I had cases (nat.exists_dvd_of_not_prime d2 compd) with n hn
. Now I thought rcases (nat.exists_dvd_of_not_prime d2 compd) with n ⟨hn1, hn2, hn3⟩
might work... but it does not
Kevin Buzzard (Nov 13 2020 at 23:11):
Try rcases?
Wrenna Robson (Nov 13 2020 at 23:12):
No joy.
Kevin Buzzard (Nov 13 2020 at 23:12):
you probably want \<n, hn1, hn2, hn3\>
Wrenna Robson (Nov 13 2020 at 23:12):
Hmm! Yes. In my head the n was on a different level of hypothesis.
Kevin Buzzard (Nov 13 2020 at 23:12):
rcases? (nat.exists_dvd_of_not_prime d2 compd)
should tell you what you want though
Wrenna Robson (Nov 13 2020 at 23:13):
It actually gave me something not very helpful!
Kevin Buzzard (Nov 13 2020 at 23:13):
rcases ('?' expr (: n)?) | ((h :)? expr (with patt)?)
should answer all your questions
Wrenna Robson (Nov 13 2020 at 23:13):
oh well that clears that up
Wrenna Robson (Nov 13 2020 at 23:14):
how could i have been so blind
Kevin Buzzard (Nov 13 2020 at 23:14):
parsers are cool. I wish I understood them a bit better.
Kevin Buzzard (Nov 13 2020 at 23:14):
The moment you start learning how to write interactive tactics you need to know this stuff, but I have never written a line of meta
code in my life
Wrenna Robson (Nov 13 2020 at 23:14):
the deep magic
Wrenna Robson (Nov 13 2020 at 23:15):
Now, I am going to want to extract 1<= n <= d from n|d and let omega do its work.
Wrenna Robson (Nov 13 2020 at 23:15):
Must be a lemma for that.
Kevin Buzzard (Nov 13 2020 at 23:16):
I'm guessing le_of_dvd
or something
Kevin Buzzard (Nov 13 2020 at 23:16):
for n<=d
Kevin Buzzard (Nov 13 2020 at 23:16):
the naming convention is really cool
Wrenna Robson (Nov 13 2020 at 23:16):
What does "of" mean?
Wrenna Robson (Nov 13 2020 at 23:16):
Hmm, I have it but for ints. I hope that isn't an issue...
Kevin Buzzard (Nov 13 2020 at 23:16):
X_of_Y
means Y -> X
Kevin Buzzard (Nov 13 2020 at 23:16):
is it really not there for nats?
Wrenna Robson (Nov 13 2020 at 23:17):
Oh it is, the search just didn't give it the first time.
Kevin Buzzard (Nov 13 2020 at 23:17):
oh yeah, sometimes I hit esc and then ctrl-space and get more options
Kevin Buzzard (Nov 13 2020 at 23:17):
I've never understood what's going on with that
Kevin Buzzard (Nov 13 2020 at 23:17):
X_of_Y_of_Z
means Y -> Z -> X
Kevin Buzzard (Nov 13 2020 at 23:18):
e.g. lt_of_le_of_lt
, something we used a lot before linarith
was discovered
Kevin Buzzard (Nov 13 2020 at 23:18):
Ruben Van de Velde (Nov 13 2020 at 23:29):
I got there in the end, but the 1 < a and 1 < k/a were somewhat tedious - I hope there's a better solution
theorem solution
{p q : ℕ}
(hp : nat.prime p)
(hq : nat.prime q)
(p_lt_q : p < q)
(p_ne_two : p ≠ 2)
(q_ne_two : q ≠ 2)
(consecutive : ∀ k, p < k → k < q → ¬ nat.prime k) :
∃ a b c, p + q = a * b * c
∧ a > 1 ∧ b > 1 ∧ c > 1 :=
begin
have hp1 := hp.eq_two_or_odd.resolve_left p_ne_two,
have hq1 := hq.eq_two_or_odd.resolve_left q_ne_two,
rw ←nat.odd_iff at hp1 hq1,
obtain ⟨k, hk⟩ : even (p + q),
{ simp at hp1 hq1,
simp [hp1, hq1] with parity_simps },
have : ¬nat.prime k,
{ apply consecutive; linarith },
obtain ⟨a, hadvd, hane1, hanek⟩ := nat.exists_dvd_of_not_prime (by linarith [hp.two_le, hq.two_le]) this,
use [a, k / a, 2],
have hapos : 0 < a,
{ rw [nat.pos_iff_ne_zero],
rintro rfl,
rw [zero_dvd_iff] at hadvd,
exact hanek hadvd.symm },
refine ⟨_, _, _, _⟩,
{ rw [hk, nat.mul_div_cancel' hadvd, mul_comm] },
{ apply lt_of_le_of_ne _ hane1.symm,
rwa [nat.succ_le_iff] },
{ obtain ⟨b, rfl⟩ := hadvd,
have : b ≠ 0,
{ rintro rfl,
linarith [hp.two_le, hq.two_le, hk] },
rw mul_comm,
rw nat.mul_div_cancel _ hapos,
apply lt_of_le_of_ne,
{ rwa [nat.succ_le_iff, nat.pos_iff_ne_zero] },
{ contrapose! hanek, rw [←hanek, mul_one] } },
{ dec_trivial }
end
Wrenna Robson (Nov 13 2020 at 23:32):
Hmm my lean server crashed...
Kevin Buzzard (Nov 13 2020 at 23:32):
Where's the 1 < a proof?
Kevin Buzzard (Nov 13 2020 at 23:33):
it's difficult to follow the spoiler solution because no indents. Style point: the question should say 1 < a \and ...
, not a > 1
.
Wrenna Robson (Nov 13 2020 at 23:34):
I'm done!
Wrenna Robson (Nov 13 2020 at 23:34):
theorem solution
{p q : ℕ}
(hp : nat.prime p)
(hq : nat.prime q)
(p_lt_q : p < q)
(p_ne_two : p ≠ 2)
(q_ne_two : q ≠ 2)
(consecutive : ∀ k, p < k → k < q → ¬ nat.prime k) :
∃ a b c, p + q = a * b * c
∧ a > 1 ∧ b > 1 ∧ c > 1 :=
begin
have op : ¬ even p,
{
rw nat.not_even_iff,
exact hp.eq_two_or_odd.resolve_left p_ne_two,
},
have oq : ¬ even q,
{
rw nat.not_even_iff,
exact hq.eq_two_or_odd.resolve_left q_ne_two,
},
have epq : even (p + q),
{
rw nat.even_add,
simp [op, oq],
},
rw even_iff_two_dvd at epq,
cases (exists_eq_mul_right_of_dvd epq) with d hd,
have compd : ¬ nat.prime d,
{
apply consecutive;
omega,
},
have d2 : 2 ≤ d,
{
have k := nat.prime.two_le hp,
omega,
},
have d0 : d > 0,
{
omega,
},
rcases (nat.exists_dvd_of_not_prime d2 compd) with ⟨n, hn1, hn2, hn3⟩,
have npos := nat.pos_of_dvd_of_pos hn1 d0,
have nltd := nat.le_of_dvd d0 hn1,
use [2, n, d/n],
split,
{
rw mul_assoc,
rw nat.mul_div_cancel';
assumption,
},
split,
{
omega,
},
split,
{
omega,
},
{
apply (mul_lt_mul_left npos).mp,
rw nat.mul_div_cancel',
omega,
assumption,
},
end
Kevin Buzzard (Nov 13 2020 at 23:34):
ctrl-shift-p and type "Lean : restart" to restart lean after a crash
Kevin Buzzard (Nov 13 2020 at 23:34):
(in VS Code, if you're using emacs you're on your own)
Wrenna Robson (Nov 13 2020 at 23:34):
Would very much appreciate feedback on how making this less sprawling, although happily I do have indents.
Mario Carneiro (Nov 13 2020 at 23:35):
Kevin Buzzard said:
I genuinely don't know what you can put after
omega
, I only use it as a standalone tactic and I don't understand parsers well enough to know whatid*
means
It means it takes 0 or more identifiers. For example, omega h1 h2
Wrenna Robson (Nov 13 2020 at 23:35):
I'm using VS Code, because emacs scares me.
Mario Carneiro (Nov 13 2020 at 23:35):
I don't know from that what the identifiers mean, though
Kevin Buzzard (Nov 13 2020 at 23:35):
but I couldn't get omega (f h)
to work -- should I have been able to?
Mario Carneiro (Nov 13 2020 at 23:35):
no
Mario Carneiro (Nov 13 2020 at 23:35):
id
means an identifier or name, not an expression
Kevin Buzzard (Nov 13 2020 at 23:35):
oh, f h is not an identifier?
Kevin Buzzard (Nov 13 2020 at 23:36):
but f and h are?
Mario Carneiro (Nov 13 2020 at 23:36):
f h
is two identifiers, (f h)
is an expression
Mario Carneiro (Nov 13 2020 at 23:36):
f h
is also an expression
Ruben Van de Velde (Nov 13 2020 at 23:36):
Hmm, can't nest code in the spoiler tag, but since you're done as well, I just opened it up
Kevin Buzzard (Nov 13 2020 at 23:36):
that was what was confusing me.
Mario Carneiro (Nov 13 2020 at 23:36):
an identifier is a sequence of letters and underscores
Mario Carneiro (Nov 13 2020 at 23:36):
and dots
Kevin Buzzard (Nov 13 2020 at 23:37):
Can you quote code in the spoiler tag? I think spoilers are new to Zulip
Mario Carneiro (Nov 13 2020 at 23:37):
pretty sure
Kevin Buzzard (Nov 13 2020 at 23:39):
I think my code would look pretty much the same as Ruben's or Wrenna's, except Wrenna I'd indent 2 spaces not 4.
Wrenna Robson (Nov 13 2020 at 23:39):
Yes that is that I haven't changed the setting in VS code.
Mario Carneiro (Nov 13 2020 at 23:40):
Kevin Buzzard said:
rcases ('?' expr (: n)?) | ((h :)? expr (with patt)?)
should answer all your questions
This says that rcases
takes either a ?
followed by an expression, followed by optionally a colon and a number, i.e. rcases? (f x)
or rcases? f x : 5
, or an optional variable and a colon, followed by an expression, optionally followed by with
and a pattern, like rcases h : e with <>
or rcases e with <a, b, c>
Kevin Buzzard (Nov 13 2020 at 23:40):
these things are fiddly. Did you say it was a kata? You should both post your solutions and see if any of the CS whizzes had a go at it.
Wrenna Robson (Nov 13 2020 at 23:40):
Presumably there is some way to tell it to do two spaces for Lean files.
Wrenna Robson (Nov 13 2020 at 23:40):
Yeah it was. I'm just doing some basic tidying up.
Mario Carneiro (Nov 13 2020 at 23:40):
the syntax of patterns is not specified there because it is recursive and the notation kind of breaks down
Kevin Buzzard (Nov 13 2020 at 23:40):
That was going to be my next question :-)
Wrenna Robson (Nov 13 2020 at 23:41):
For a pattern like this:
have op : ¬ even p,
{
rw nat.not_even_iff,
exact hp.eq_two_or_odd.resolve_left p_ne_two,
},
Is there a one-liner way of doing it? "have some goal, by re-writing the goal and then having it exactly"
Kevin Buzzard (Nov 13 2020 at 23:41):
instead of rw h
you might well be able to just use the function h.1
directly.
Mario Carneiro (Nov 13 2020 at 23:41):
you can find it in the docs for docs#tactic.rcases_patt_parse though, in pseudo BNF style
patt ::= patt_med (":" expr)?
patt_med ::= (patt_hi "|")* patt_hi
patt_hi ::= id | "rfl" | "_" | "⟨" (patt ",")* patt "⟩" | "(" patt ")"
Kevin Buzzard (Nov 13 2020 at 23:42):
have op : ¬ even p := nat.not_even_iff.1 (hp.eq_two_or_odd.resolve_left p_ne_two),
or something like that should work
Wrenna Robson (Nov 13 2020 at 23:43):
Sadly not.
Wrenna Robson (Nov 13 2020 at 23:43):
type mismatch at application
nat.not_even_iff.mp (hp.eq_two_or_odd.resolve_left p_ne_two)
term
hp.eq_two_or_odd.resolve_left p_ne_two
has type
p % 2 = 1
but is expected to have type
¬even ?m_1
Ruben Van de Velde (Nov 13 2020 at 23:43):
mpr
?
Ruben Van de Velde (Nov 13 2020 at 23:43):
Looks like I should've tried throwing omega at more subgoals
Kevin Buzzard (Nov 13 2020 at 23:43):
then it would be rw \l
Kevin Buzzard (Nov 13 2020 at 23:44):
no you're right
Wrenna Robson (Nov 13 2020 at 23:44):
mpr?
Kevin Buzzard (Nov 13 2020 at 23:44):
try .2
Kevin Buzzard (Nov 13 2020 at 23:44):
or .mpr
. If h : a <-> b
then internally h is a pair of proofs, h.1 : a -> b
and h.2 : b -> a
Wrenna Robson (Nov 13 2020 at 23:45):
Right.
Wrenna Robson (Nov 13 2020 at 23:45):
.mpr is a mnemonic of some kind?
Kevin Buzzard (Nov 13 2020 at 23:45):
and h.mp
is the same as h.1
and h.mpr
is the same as h.2
. I think Ruben's suggestion should work.
Mario Carneiro (Nov 13 2020 at 23:45):
have op : ¬ even p := nat.not_even_iff.2 (hp.eq_two_or_odd.resolve_left p_ne_two),
Ruben Van de Velde (Nov 13 2020 at 23:45):
Modus ponens reverse
Kevin Buzzard (Nov 13 2020 at 23:45):
"modus ponens reversed" or something?
Wrenna Robson (Nov 13 2020 at 23:45):
Right.
Kevin Buzzard (Nov 13 2020 at 23:46):
omega
is great for nat goals because some stuff is so fiddly with nat. There are so many stupid things like a + b - a = b
which are more painful than you think because of natural subtraction.
Kevin Buzzard (Nov 13 2020 at 23:47):
After a while the naming convention can't handle it all so you have to rely more on memory or search skillz
Kevin Buzzard (Nov 13 2020 at 23:47):
is that add_sub_self or what?
Kevin Lacker (Nov 13 2020 at 23:47):
naming is going to become even harder as we get more and more lemmas. i think we are going to need a better library_search
& i hope lean 4 enables that
Wrenna Robson (Nov 13 2020 at 23:47):
Can we do a similar one-liner trick for
have compd : ¬ nat.prime d,
{
apply consecutive;
omega,
},
Wrenna Robson (Nov 13 2020 at 23:48):
:= consecutive (by omega)
?
Wrenna Robson (Nov 13 2020 at 23:48):
No.
Kevin Buzzard (Nov 13 2020 at 23:48):
something like that could well work
Kevin Buzzard (Nov 13 2020 at 23:48):
you should be able to get it to work somehow
Ruben Van de Velde (Nov 13 2020 at 23:48):
It needs two (by omega)
s
Kevin Buzzard (Nov 13 2020 at 23:48):
got it
Kevin Buzzard (Nov 13 2020 at 23:48):
hence the semicolon
Wrenna Robson (Nov 13 2020 at 23:49):
So with have compd : ¬ nat.prime d := consecutive (by omega) (by omega),
I get Cannot reify expr : ℕ
Wrenna Robson (Nov 13 2020 at 23:49):
Which is a bit mysterious.
Kevin Buzzard (Nov 13 2020 at 23:49):
what is the type of consecutive
? apply
is quite clever.
Kevin Buzzard (Nov 13 2020 at 23:49):
you might need to add some _
s in
Wrenna Robson (Nov 13 2020 at 23:49):
∀ (k : ℕ), p < k → k < q → ¬nat.prime k
Kevin Buzzard (Nov 13 2020 at 23:49):
so try consecutive _ (by omega) (by omega)
Wrenna Robson (Nov 13 2020 at 23:49):
Yep
Kevin Buzzard (Nov 13 2020 at 23:50):
apply
figured out the natural input by itself.
Wrenna Robson (Nov 13 2020 at 23:50):
Magic.
Wrenna Robson (Nov 13 2020 at 23:50):
begin
have op : ¬ even p := nat.not_even_iff.mpr (hp.eq_two_or_odd.resolve_left p_ne_two),
have oq : ¬ even q := nat.not_even_iff.mpr (hq.eq_two_or_odd.resolve_left q_ne_two),
have epq : even (p + q) := nat.even_add.mpr (by simp [op, oq]),
cases (exists_eq_mul_right_of_dvd (even_iff_two_dvd.mpr epq)) with d hd,
have compd : ¬ nat.prime d := consecutive _ (by omega) (by omega),
have d2 : 2 ≤ d, by linarith [nat.prime.two_le hp],
have d0 : d > 0, by omega,
rcases (nat.exists_dvd_of_not_prime d2 compd) with ⟨n, hn1, hn2, hn3⟩,
have npos := nat.pos_of_dvd_of_pos hn1 d0,
have nltd := nat.le_of_dvd d0 hn1,
use [2, n, d/n],
split,
{
rw mul_assoc,
rw nat.mul_div_cancel';
assumption,
},
split, omega,
split, omega,
{
apply (mul_lt_mul_left npos).mp,
rw nat.mul_div_cancel',
omega,
assumption,
},
end
Wrenna Robson (Nov 13 2020 at 23:50):
This is looking very respectable.
Wrenna Robson (Nov 13 2020 at 23:51):
Oh bother. It looks like the version of Lean on Codewars doesn't like it.
Wrenna Robson (Nov 13 2020 at 23:51):
Something to do with the even.
Wrenna Robson (Nov 13 2020 at 23:52):
Here's my full #mwe.
import tactic
import data.nat.basic
import data.nat.prime
import data.nat.modeq
import data.int.basic
import data.int.parity
universe u
open_locale classical
theorem solution
{p q : ℕ}
(hp : nat.prime p)
(hq : nat.prime q)
(p_lt_q : p < q)
(p_ne_two : p ≠ 2)
(q_ne_two : q ≠ 2)
(consecutive : ∀ k, p < k → k < q → ¬ nat.prime k) :
∃ a b c, p + q = a * b * c
∧ a > 1 ∧ b > 1 ∧ c > 1 :=
begin
have op : ¬ even p := nat.not_even_iff.mpr (hp.eq_two_or_odd.resolve_left p_ne_two),
have oq : ¬ even q := nat.not_even_iff.mpr (hq.eq_two_or_odd.resolve_left q_ne_two),
have epq : even (p + q) := nat.even_add.mpr (by simp [op, oq]),
cases (exists_eq_mul_right_of_dvd (even_iff_two_dvd.mpr epq)) with d hd,
have compd : ¬ nat.prime d := consecutive _ (by omega) (by omega),
have d2 : 2 ≤ d, by linarith [nat.prime.two_le hp],
have d0 : d > 0, by omega,
rcases (nat.exists_dvd_of_not_prime d2 compd) with ⟨n, hn1, hn2, hn3⟩,
have npos := nat.pos_of_dvd_of_pos hn1 d0,
have nltd := nat.le_of_dvd d0 hn1,
use [2, n, d/n],
split,
{
rw mul_assoc,
rw nat.mul_div_cancel';
assumption,
},
split, omega,
split, omega,
{
apply (mul_lt_mul_left npos).mp,
rw nat.mul_div_cancel',
omega,
assumption,
},
end
Kevin Buzzard (Nov 13 2020 at 23:52):
When i do codewars I use a custom repo with precisely the version of lean and mathlib supported by codewars at that time
Ruben Van de Velde (Nov 13 2020 at 23:53):
Try nat.even
Ruben Van de Velde (Nov 13 2020 at 23:53):
There was some refactoring there recently
Wrenna Robson (Nov 13 2020 at 23:54):
"unknown identifier 'nat.even'" on my local copy.
Kevin Buzzard (Nov 13 2020 at 23:54):
If you're using a version of lean/mathlib which is not the same as the codewars one then you can't expect to get a piece of code which compiles both locally and on codewars.
Wrenna Robson (Nov 13 2020 at 23:54):
Yes.
Kevin Buzzard (Nov 13 2020 at 23:55):
Lean is not backwards compatible
Wrenna Robson (Nov 13 2020 at 23:56):
Aye. Some progress on CodeWars using that, but even_iff_two_dvd (or nat.even_iff_two_dvd) is unrecognised - I don't know if the name of it changed.
Mario Carneiro (Nov 13 2020 at 23:57):
Here's my version of the compression pass:
theorem solution
{p q : ℕ}
(hp : nat.prime p)
(hq : nat.prime q)
(p_lt_q : p < q)
(p_ne_two : p ≠ 2)
(q_ne_two : q ≠ 2)
(consecutive : ∀ k, p < k → k < q → ¬ nat.prime k) :
∃ a b c, p + q = a * b * c
∧ a > 1 ∧ b > 1 ∧ c > 1 :=
begin
have op : ¬ even p := nat.not_even_iff.2 (hp.eq_two_or_odd.resolve_left p_ne_two),
have oq : ¬ even q := nat.not_even_iff.2 (hq.eq_two_or_odd.resolve_left q_ne_two),
have epq : even (p + q) := nat.even_add.2 (by simpa [op]),
rw even_iff_two_dvd at epq,
cases exists_eq_mul_right_of_dvd epq with d hd,
have compd : ¬ nat.prime d := consecutive d (by linarith) (by linarith),
have d2 : 2 ≤ d := by linarith [hp.two_le],
have d0 : d > 0 := by linarith [d2],
rcases nat.exists_dvd_of_not_prime d2 compd with ⟨n, hn1, hn2, hn3⟩,
have npos := nat.pos_of_dvd_of_pos hn1 d0,
have nltd := nat.le_of_dvd d0 hn1,
refine ⟨2, n, d/n, _, _, _, _⟩,
{ rwa [mul_assoc, nat.mul_div_cancel' hn1] },
{ norm_num },
{ exact lt_of_le_of_ne npos hn2.symm },
{ apply (mul_lt_mul_left npos).mp,
rw nat.mul_div_cancel' hn1,
simp [lt_of_le_of_ne nltd hn3] },
end
Kevin Buzzard (Nov 13 2020 at 23:57):
honestly the way to fix this is to make a project with the same version of lean and mathlib as codewars. They say explicitly what version they're running. It's impossible to second-guess what has changed in the interim.
Wrenna Robson (Nov 13 2020 at 23:57):
Right.
Mario Carneiro (Nov 13 2020 at 23:57):
I also removed all the omega
calls because omega
is slow
Ruben Van de Velde (Nov 13 2020 at 23:58):
Try replacing (even_iff_two_dvd.mpr epq)
by epq
, I think it'll be fine definitionally
Mario Carneiro (Nov 13 2020 at 23:58):
and you don't need omega
to prove 1 < 2
Kevin Buzzard (Nov 13 2020 at 23:58):
linarith
Kevin Buzzard (Nov 13 2020 at 23:58):
lt_add_one
Ruben Van de Velde (Nov 13 2020 at 23:58):
one_lt_two
Kevin Buzzard (Nov 13 2020 at 23:58):
lol does that work for 3 < 37?
Kevin Buzzard (Nov 13 2020 at 23:58):
dec_trivial
Mario Carneiro (Nov 13 2020 at 23:59):
:(
Kevin Buzzard (Nov 13 2020 at 23:59):
Maybe le_refl _
works?
Mario Carneiro (Nov 13 2020 at 23:59):
no one loves my baby
Ruben Van de Velde (Nov 13 2020 at 23:59):
Or nat.le.intro or something like that? suggest
tends to come up with that
Kevin Buzzard (Nov 13 2020 at 23:59):
:-)
Wrenna Robson (Nov 13 2020 at 23:59):
Replacing epq worked with some prodding. Lesson learned about setting up a project right...
Kevin Buzzard (Nov 14 2020 at 00:00):
Mario wrote norm_num
precisely to solve goals like this (3 < 37 etc)
Kevin Buzzard (Nov 14 2020 at 00:00):
linarith
is good for inequalities with variables but when there's only numbers, norm_num
works.
Kevin Buzzard (Nov 14 2020 at 00:01):
Your baby was what convinced me not to give up! Remember in 2017 when i couldn't do anything?
Ruben Van de Velde (Nov 14 2020 at 00:01):
Plenty of options in any case
Kevin Buzzard (Nov 14 2020 at 00:01):
Q1 on my first example sheet needed a proof that (1 : real) != 2 and there was no way of doing it :-)
Wrenna Robson (Nov 14 2020 at 00:02):
Not quite sure I understand simpa
.
Kevin Buzzard (Nov 14 2020 at 00:02):
Mario can tell you what that does too.
Kevin Buzzard (Nov 14 2020 at 00:02):
It does something like: simplify all goals and assumptions, and then try closing the goal with assumption
Mario Carneiro (Nov 14 2020 at 00:02):
simpa using h
= simp at h |-; exact h
Kevin Buzzard (Nov 14 2020 at 00:02):
so it works if an assumption and a goal simplify to the same thing
Wrenna Robson (Nov 14 2020 at 00:03):
Right!
Wrenna Robson (Nov 14 2020 at 00:05):
refine
is nice.
Wrenna Robson (Nov 14 2020 at 00:09):
In { exact lt_of_le_of_ne npos hn2.symm }
, npos is of type n > 0, and lt_of_le_of_ne is expecting 1 <= n in that spot. So 1 <= n is definitionally equal to n > 0?
Wrenna Robson (Nov 14 2020 at 00:13):
Wew! Alright. Thank you all - this has been a really great learning experience.
Wrenna Robson (Nov 14 2020 at 00:14):
Also how is it 00:14... I guess when the focus hole hits.
Kevin Buzzard (Nov 14 2020 at 00:18):
what better way to spend a Friday night in lockdown.
Kevin Buzzard (Nov 14 2020 at 00:19):
Well done to both of you!
Wrenna Robson (Nov 14 2020 at 00:29):
Ha, yes, of course, I certainly wouldn't spend a Friday night in normal times on my computer doing compuscimaths <_<
Kevin Buzzard (Nov 14 2020 at 00:31):
By the way I have a discord server which currently has 3 Imperial UGs and a Cambridge UG solving basic analysis questions in Lean, live streaming and chatting, right now.
Wrenna Robson (Nov 14 2020 at 00:31):
Ooh.
Kevin Buzzard (Nov 14 2020 at 00:31):
voice chat -- the one thing zulip doesn't offer
Wrenna Robson (Nov 14 2020 at 00:32):
Yes! I really like zulip o/w.
Wrenna Robson (Nov 14 2020 at 00:32):
We used it for our first year project vivas - topic per talk, could field questions during other talks.
Wrenna Robson (Nov 14 2020 at 00:32):
It works like my mind works - that is, multi-stranded.
Wrenna Robson (Nov 14 2020 at 00:33):
(...I would be super interested in listening in...)
Kevin Buzzard (Nov 14 2020 at 00:34):
I DM'ed you a link
Kevin Buzzard (Nov 14 2020 at 00:35):
anyone is welcome, but I don't advertise the links publically any more
Wrenna Robson (Nov 14 2020 at 00:36):
So you did! Thank you.
Last updated: Dec 20 2023 at 11:08 UTC