Zulip Chat Archive

Stream: general

Topic: natural number hell


Patrick Massot (May 15 2018 at 07:56):

I want to use big.map once I have the map

Patrick Massot (May 15 2018 at 07:57):

I should push something so that you can see the context

Mario Carneiro (May 15 2018 at 07:57):

and then the f will be applied to the functions P and F... then what?

Patrick Massot (May 15 2018 at 07:58):

https://github.com/PatrickMassot/bigop/blob/master/src/bigop.lean#L343

Mario Carneiro (May 15 2018 at 07:59):

wait, so you want the function f to be i |-> a+b-i?

Mario Carneiro (May 15 2018 at 07:59):

then why are you mapping with something else in the lemma?

Patrick Massot (May 15 2018 at 08:01):

The problem is reverse_range' is about your range', with start and length, and my goal is to have the maths range', with start and end

Mario Carneiro (May 15 2018 at 08:03):

Think of the problem in reverse. You want the theorem to say a+b-i at the end, so you want f to be \lam i, a+b-i when you apply big.map; the reverse theorem just adds a list.reverse on the set. So you should be proving reverse (range' a b) = map (λ i, a+b-i) (range' a b)

Mario Carneiro (May 15 2018 at 08:04):

that is, without any algebraic rearrangement this is exactly what you need to fill the gap in the proof. Right?

Patrick Massot (May 15 2018 at 08:05):

Maybe I did so many detours I forgot the goal on the road

Patrick Massot (May 15 2018 at 08:08):

It seems I still need a + (b + 1 - a) - i = a + b - i (still assuming i ∈ range' a (b + 1 - a))

Mario Carneiro (May 15 2018 at 08:09):

that's easy though, it is one of the add_sub theorems

Patrick Massot (May 15 2018 at 08:09):

I think we already saw that one

Mario Carneiro (May 15 2018 at 08:10):

nat.add_sub_cancel', which requires a <= b + 1

Mario Carneiro (May 15 2018 at 08:11):

Note that your assumption is sufficient to prove this, but only in a circuitous fashion, do you have any more direct evidence that a <= b+1?

Patrick Massot (May 15 2018 at 08:12):

wait

Mario Carneiro (May 15 2018 at 08:12):

wait

Mario Carneiro (May 15 2018 at 08:13):

your theorem is nonsense

Patrick Massot (May 15 2018 at 08:13):

your theorem is nonsense

Patrick Massot (May 15 2018 at 08:13):

reverse (range' a b) = map (λ i, a+b-i) (range' a b) is not true

Patrick Massot (May 15 2018 at 08:13):

I changed all statements so many times...

Mario Carneiro (May 15 2018 at 08:14):

I'm rather confused by the dual use of range' btw, could you give it another name? range'' maybe?

Patrick Massot (May 15 2018 at 08:14):

You mean in the name of reverse_range'?

Mario Carneiro (May 15 2018 at 08:15):

I mean range' a b = [a, ..., b] vs range' a b = [a, ..., a+b]

Mario Carneiro (May 15 2018 at 08:15):

pretty sure both functions are being called range'

Patrick Massot (May 15 2018 at 08:15):

I don't redefine range'

Mario Carneiro (May 15 2018 at 08:15):

What is your definition?

Patrick Massot (May 15 2018 at 08:16):

I use your range'

Mario Carneiro (May 15 2018 at 08:16):

oh I see

Patrick Massot (May 15 2018 at 08:16):

But always in range' a (b+1-a)

Mario Carneiro (May 15 2018 at 08:16):

In that case I need to state the theorem above with your bounds

Mario Carneiro (May 15 2018 at 08:16):

reverse (range' a (b+1-a)) = map (λ i, a+b-i) (range' a (b+1-a))

Patrick Massot (May 15 2018 at 08:17):

yes, this is correct

Patrick Massot (May 15 2018 at 08:17):

(not that I can prove it, but I can check it on examples)

Patrick Massot (May 15 2018 at 08:19):

But I wanted to deduce it from a version involving only range' a b in LHS

Patrick Massot (May 15 2018 at 08:19):

hence the "arithmetic" trouble

Patrick Massot (May 15 2018 at 08:20):

But indeed this is the statement which makes big.range_anti_mph trivial to prove from the previous results

Mario Carneiro (May 15 2018 at 08:20):

Well, there are a lot of free endpoints in the reverse theorem, maybe you need to generalize it?

Patrick Massot (May 15 2018 at 08:21):

what reverse theorem?

Mario Carneiro (May 15 2018 at 08:24):

I'm thinking:

reverse (range' a (n + 1)) = map (λ i, c-i) (range' b (n + 1))

subject to an equation relating a,b,c

Mario Carneiro (May 15 2018 at 08:25):

Actually I think we need another generalization of range' that varies the step too

Mario Carneiro (May 15 2018 at 08:26):

that would make this easy

Patrick Massot (May 15 2018 at 08:28):

I need to go to my office, but the situation improved a lot: https://github.com/PatrickMassot/bigop/blob/master/src/bigop.lean#L335-L341 Thank you very much

Patrick Massot (May 15 2018 at 08:29):

I hope I'll be able to prove that last missing lemma later if you don't have time to do it properly

Mario Carneiro (May 15 2018 at 09:07):

I did it properly. Here are the lemmas I added:

theorem map_add_range' (a) : ∀ s n : ℕ, map ((+) a) (range' s n) = range' (a + s) n
| s 0     := rfl
| s (n+1) := congr_arg (cons _) (map_add_range' (s+1) n)

theorem range_succ_eq_map (n : ℕ) : range (n + 1) = 0 :: map succ (range n) :=
by rw [range_eq_range', range_eq_range', range',
       add_comm, ← map_add_range'];
   congr; exact funext one_add

theorem reverse_range' : ∀ s n : ℕ,
  reverse (range' s n) = map (λ i, s + n - 1 - i) (range n)
| s 0     := rfl
| s (n+1) := by rw [range'_concat, reverse_append, range_succ_eq_map];
  simpa [show s + (n + 1) - 1 = s + n, from rfl, (∘),
    λ a i, show a - 1 - i = a - succ i,
    by rw [nat.sub_sub, add_comm]; refl]
  using reverse_range' s n

Patrick Massot (May 15 2018 at 09:58):

Thank you Mario! I already had the first one at https://github.com/PatrickMassot/bigop/blob/master/src/bigop.lean#L126

Patrick Massot (May 15 2018 at 09:58):

Maybe I should learn to do induction using pattern matching

Patrick Massot (May 15 2018 at 17:42):

I read too quickly, I thought you proved the lemma I needed

Patrick Massot (May 15 2018 at 17:43):

But your RHS doesn't even contains range'

Patrick Massot (May 15 2018 at 17:44):

Proving the lemma I stated from what you proved seems to be as much work as a direct proof, no?

Mario Carneiro (May 15 2018 at 20:20):

You still have some algebra before you get to the exact version you need, but you can put reverse_range', range_eq_range', map_add_range' and map_map together and then do some algebra

Mario Carneiro (May 15 2018 at 20:34):

theorem range'_eq_map_range (s n : ℕ) : range' s n = map ((+) s) (range n) :=
by rw [range_eq_range', map_add_range']; refl

example (a b : ℕ) : reverse (range' a (b+1-a)) = map (λ i, a+b-i) (range' a (b+1-a)) :=
begin
  rw [reverse_range', range'_eq_map_range, map_map],
  apply map_congr, intros i H,
  simp at *,
  rw [nat.add_sub_add_left, nat.add_sub_cancel'], {refl},
  refine (le_total _ _).resolve_left (λ h, _),
  rw sub_eq_zero_of_le h at H,
  exact not_lt_zero _ H
end

Patrick Massot (May 15 2018 at 21:22):

Thank you very much Mario! I'm still not convinced this is simpler than a direct attack on this lemma, but I very much relieved to have it.

Patrick Massot (May 15 2018 at 21:22):

What is this resolve_left thing?

Patrick Massot (May 15 2018 at 21:24):

The state at the point where you write this, a b i : ℕ, H : i < b + 1 - a ⊢ b + 1 ≥ a is typically something that could have led me to harm my computer.

Patrick Massot (May 15 2018 at 21:25):

I also note that you used simp at * in the middle of a proof. Isn't this frowned upon according to mathlib's docs?

Mario Carneiro (May 15 2018 at 21:25):

That's actually a really subtle thing, it wouldn't work if it was i <= b+1-a

Patrick Massot (May 15 2018 at 21:26):

What do you mean it wouldn't work? The statement would still be true, right?

Mario Carneiro (May 15 2018 at 21:26):

no

Patrick Massot (May 15 2018 at 21:27):

This is crazy

Mario Carneiro (May 15 2018 at 21:27):

if i is zero then b+1 could be less than a

Patrick Massot (May 15 2018 at 21:28):

Did I mentioned I hate this substraction?

Mario Carneiro (May 15 2018 at 21:28):

the argument is basically that when you subtract small minus large you get 0, so since i is less than the subtraction it isn't zero so it is in the proper domain

Mario Carneiro (May 15 2018 at 21:30):

You could also have taken a <= b+1 as an assumption to the theorem if you like

Patrick Massot (May 15 2018 at 21:31):

I still don't know what resolve_left stands for

Mario Carneiro (May 15 2018 at 21:31):

or.resolve_left

Kenny Lau (May 15 2018 at 21:32):

@Patrick Massot The type of le_total _ _ is or _ _

Kenny Lau (May 15 2018 at 21:32):

So (le_total _ _).resolve_left means or.resolve_left (le_total _ _)

Patrick Massot (May 15 2018 at 21:32):

Thanks

Patrick Massot (May 15 2018 at 21:32):

to both of you

Patrick Massot (May 15 2018 at 21:33):

So the strategy here is some variation on a case disjunction, right?

Patrick Massot (May 15 2018 at 21:34):

Is it possible to use by_cases instead? (I only try to understand, I don't really want to use by_cases)

Kenny Lau (May 15 2018 at 21:34):

by_cases uses p or not p instead of any arbitrary p or q

Patrick Massot (May 15 2018 at 21:35):

It's true that le_total is almost but not quite like this

Kenny Lau (May 15 2018 at 21:37):

however I don't see the difference between or.resolve_left (le_total _ _) and le_of_not_le

Patrick Massot (May 15 2018 at 21:38):

I still don't understand why the goal after this refine is false

Kenny Lau (May 15 2018 at 21:38):

refine (le_total _ _).resolve_left (λ h, _)

Kenny Lau (May 15 2018 at 21:39):

the expected type of (λ h, _) is not (le _ _)

Kenny Lau (May 15 2018 at 21:39):

so h has type le _ _

Kenny Lau (May 15 2018 at 21:39):

so _ has type false

Patrick Massot (May 15 2018 at 21:40):

Indeed the mysterious line has the same effect as apply le_of_not_le, by_contradiction h,

Kenny Lau (May 15 2018 at 21:41):

try refine le_of_not_le (λ h, _)

Mario Carneiro (May 15 2018 at 21:41):

le_of_not_le would also have worked

Kenny Lau (May 15 2018 at 21:41):

@Mario Carneiro entao eu ganho?

Mario Carneiro (May 15 2018 at 21:41):

vc ganhou

Kenny Lau (May 15 2018 at 21:42):

:D

Patrick Massot (May 15 2018 at 21:43):

The proof of le_of_not_le is exactly this or.resolve_left le_total

Patrick Massot (May 15 2018 at 21:44):

But indeed Kenny's solution will probably be easier to remember for me

Patrick Massot (May 15 2018 at 21:47):

So, what should we do with all those lemmas we discussed in the last few days. Do you want me to prepare a PR? Are you doing it yourself?

Mario Carneiro (May 15 2018 at 21:49):

I've got a pot brewing, you can hold onto them locally until then

Patrick Massot (May 15 2018 at 21:49):

No problem

Patrick Massot (May 15 2018 at 21:56):

I extracted everything from my bigop file. It's now all in https://github.com/PatrickMassot/bigop/blob/master/src/pending_lemmas.lean if you want to make sure you have everything that was discussed here

Patrick Massot (May 15 2018 at 21:57):

It's bedtime now. Thank you very much again!

Patrick Massot (May 16 2018 at 09:05):

I have three substractions now :fearful: H : N ≥ 1, hyp : 0 ≤ i ∧ i < N ⊢ N - (N - 1 - i) = i + 1

Patrick Massot (May 16 2018 at 09:06):

Isn't it a way to first prove that we would get the same result in Z, because each substraction comes with its relevant inequality, and then ring?

Mario Carneiro (May 16 2018 at 09:12):

yes, of course

Mario Carneiro (May 16 2018 at 09:13):

just use int.cast_sub

Patrick Massot (May 16 2018 at 09:14):

how does that work?

Mario Carneiro (May 16 2018 at 09:14):

that is, use int.cast_inj to convert the natural number equality to a Z equality, and then use int.cast_add, int.cast_sub etc lemmas to move the arrows down to the bottom

Patrick Massot (May 16 2018 at 09:14):

Looking at the statement is pretty puzzling

Mario Carneiro (May 16 2018 at 09:15):

simp will do the latter part

Chris Hughes (May 16 2018 at 09:15):

example {i N : } (H : N  1) (hyp : 0  i  i < N) : N - (N - 1 - i) = i + 1 :=
have 1 + i  N, by rw add_comm; exact hyp.2,
by rw [nat.sub_sub, nat.sub_sub_self this, add_comm]

Kenny Lau (May 16 2018 at 09:15):

and the winner is...

Mario Carneiro (May 16 2018 at 09:15):

^ or just prove it directly

Patrick Massot (May 16 2018 at 09:16):

Thanks Chris, but I'm really tired of those direct proofs

Patrick Massot (May 16 2018 at 09:16):

I want a systematic method

Mario Carneiro (May 16 2018 at 09:17):

example {i N : ℕ} (H : N ≥ 1) (hyp : 0 ≤ i ∧ i < N) : N - (N - 1 - i) = i + 1 :=
by rw [nat.sub_sub, add_comm, nat.sub_sub_self hyp.2]

Kenny Lau (May 16 2018 at 09:17):

and the winner is...

Chris Hughes (May 16 2018 at 09:17):

Is it poor form to use exact hyp.2 instead of exact nat.succ_le_of_lt hyp.2?

Mario Carneiro (May 16 2018 at 09:17):

meh

Kenny Lau (May 16 2018 at 09:17):

maybe you should replace exact hyp.2 with cc

Kenny Lau (May 16 2018 at 09:18):

I mean, it isn't like you can't prove H from hyp...

Mario Carneiro (May 16 2018 at 09:18):

in general you should minimize your implicit definitional unfolding, but some things are too foundational to change at this point and I assume it will stay that way

Patrick Massot (May 16 2018 at 09:19):

I don't know how to use int.cast_inj

Mario Carneiro (May 16 2018 at 09:20):

oops, I mean int.coe_nat_inj'

Mario Carneiro (May 16 2018 at 09:23):

example {i N : ℕ} (H : N ≥ 1) (hyp : 0 ≤ i ∧ i < N) : N - (N - 1 - i) = i + 1 :=
by rw [← int.coe_nat_inj', int.coe_nat_sub, int.coe_nat_sub, int.coe_nat_sub]

produces a bunch of side conditions about less equal stuff

Mario Carneiro (May 16 2018 at 09:24):

actually it's a bit messy since the side conditions themselves involve natural number subtraction, so you need to rewrite them too or else prove them directly

Mario Carneiro (May 16 2018 at 09:26):

If you want to take this route I would suggest not writing natural number subtraction at all when you can help it, so that you don't need to deal with nested subtractions and the like

Mario Carneiro (May 16 2018 at 09:27):

that is, just use integer subtraction and convert back to natural numbers at the end with int.to_nat if necessary

Patrick Massot (May 16 2018 at 09:29):

"not writing natural number subtraction at all" is my greatest Lean dream

Mario Carneiro (May 16 2018 at 09:30):

A simple way to actually do that is to replace m - n everywhere with int.to_nat (m - n) (where the subtraction there is actually integer subtraction now)

Patrick Massot (May 16 2018 at 09:30):

I need to go, I'll try tonight. Thanks you!

Mario Carneiro (May 16 2018 at 09:30):

That way the funky zero saturation operator is explicit

Kevin Buzzard (May 16 2018 at 12:48):

I want a systematic method

How about this: replace every occurrence of X <= Y with Y = X + c and replace every occurrence of X < Y with Y = X + c + 1, and then just use add_sub_cancel or whatever it's called -- a + b - b = a. It would not surprise me if this algorithm worked every time.

Kevin Buzzard (May 16 2018 at 12:50):

Example: you know i < N and you want to prove N - (N - 1 - i) = i + 1, well, write N = i + 1 + j and -- oh -- you also need X - (Y + Z) = X- Y - Z -- you get N - (j + 1 + i - (1 + i)) which is N - j which is i + 1 + j - j which is i + 1

Kevin Buzzard (May 16 2018 at 12:51):

I am assuming that your mathematician's goals never actually rely on the fact that a - b = 0 if b>a

Kevin Buzzard (May 16 2018 at 12:56):

This should reduce everything to nat.sub_sub (if memory serves -- is it called that?) and add_sub_cancel or whatever it's called (not in front of Lean right now).

Kevin Buzzard (May 16 2018 at 12:56):

oh and associativity and commutativity of course

Kevin Buzzard (May 16 2018 at 12:56):

Make them simp lemmas and see if simp can do it after you make the substitutions

Kevin Buzzard (May 16 2018 at 12:57):

(if they're not simp lemmas already)

Kevin Buzzard (May 16 2018 at 12:57):

Might not be the optimal approach but it looks pretty systematic to me

Chris Hughes (May 16 2018 at 12:59):

replace every occurrence of X <= Y with `Y = X + c

This bit sounds hard to do with simp, since it involves casing on exists.

Kevin Buzzard (May 16 2018 at 12:59):

you just introduce another variable

Kevin Buzzard (May 16 2018 at 12:59):

you do all that before you start the simp


Last updated: Dec 20 2023 at 11:08 UTC