Zulip Chat Archive

Stream: new members

Topic: Fastest proof of a trivial statement


Ioannis Konstantoulas (Aug 17 2023 at 20:21):

I have code of the following form all around my code base (pure Lean 4, no mathlib):

if pred_n_eq_one  : n - 1 = 1 then
      have : n = 2 := sorry

The fastest way to prove that for me is calc:

  if n_eq_2 : n - 1 = 1 then
      have : n = 2 := Eq.symm <| calc
        2 = 1 + 1 := by simp
        _ = n - 1 + 1 := by rw [n_eq_2]
        _ = n := Nat.sub_add_cancel <| calc
          1 = n - 1 := n_eq_2.symm
          _  n := Nat.pred_le n

There has to be a simpler (and shorter, but chiefly simpler) way to prove this. What am I missing? Simple simp and simp_arith invocations do not work.

Vincent Beffara (Aug 17 2023 at 22:10):

Something starting with cases n?

Alex J. Best (Aug 17 2023 at 22:10):

theorem a (_h : n - 1 = 1) :
   n = 2 :=
   match n with
   | 2 => rfl

#print a

Ioannis Konstantoulas (Aug 17 2023 at 22:26):

Where can I find some explanation of how this works? I have not encountered this use for match in TPIL so far, and it simplifies things so much that I cannot help but feel extremely frustrated.

Alex J. Best (Aug 17 2023 at 22:33):

I should say this proof is a bit of a trick, and while its good to understand how it works its not a proof style I use myself that often. Match is explained in https://leanprover.github.io/theorem_proving_in_lean4/induction_and_recursion.html, the key point is that from the hypotheses the pattern matcher is smart enough to work out that the other possible ways of constructing a natural dont work, by definition of sub.

Ioannis Konstantoulas (Aug 17 2023 at 22:34):

Alex J. Best said:

I should say this proof is a bit of a trick, and while its good to understand how it works its not a proof style I use myself that often. Match is explained in https://leanprover.github.io/theorem_proving_in_lean4/induction_and_recursion.html, the key point is that from the hypotheses the pattern matcher is smart enough to work out that the other possible ways of constructing a natural dont work, by definition of sub.

Thank you very much for your feedback.

Alex J. Best (Aug 17 2023 at 22:34):

And please don't feel frustrated, that wasn't my intention. But a big part of learning any programming langauge (or indeed anything) is to get a good handle on the fundamentals, before moving on to more advanced / esoteric features

Ioannis Konstantoulas (Aug 17 2023 at 22:38):

Alex J. Best said:

And please don't feel frustrated, that wasn't my intention. But a big part of learning any programming langauge (or indeed anything) is to get a good handle on the fundamentals, before moving on to more advanced / esoteric features

Following that thought, is my code above about the shortest/simplest "elementary" proof of the theorem that doesn't use such tricks?

Vincent Beffara (Aug 17 2023 at 22:41):

My suggestion of using cases is kind of in between: either n is 0 and then the assumption fails, or it is a successor and then the assumption simplifies and you can conclude using subst or something.

Arend Mellendijk (Aug 17 2023 at 22:50):

Scratch this - missed the 'no mathilb' part

Here's a much shorter proof that doesn't use any tricks

import Mathlib.Data.Nat.Basic

example (n : ) (hn : n-1 = 1) : n = 2 :=
  Nat.eq_add_of_sub_eq (le_of_lt (Nat.lt_of_sub_eq_succ hn)) hn

Alex J. Best (Aug 17 2023 at 22:54):

Ioannis Konstantoulas said:

Alex J. Best said:

And please don't feel frustrated, that wasn't my intention. But a big part of learning any programming langauge (or indeed anything) is to get a good handle on the fundamentals, before moving on to more advanced / esoteric features

Following that thought, is my code above about the shortest/simplest "elementary" proof of the theorem that doesn't use such tricks?

Well its a bit hard to measure shortest / simplest, and by not using any of std or mathlib you place a lot of restrictions on what you can use, the material built in to lean is mostly just what is required to build lean itself and some very fundamental tactics.
Maybe a clearer version of my proof above is osmething like

theorem a (h : n - 1 = 1) :
   n = 2 := by
match n with
| 0 => simp at h
| 1 => simp at h
| 2 => rfl
| n + 3 =>
  simp [Nat.add_sub_assoc] at h
  injection h

Ioannis Konstantoulas (Aug 18 2023 at 09:01):

Thank you very much for your responses, everyone; I learned a lot!

Mario Carneiro (Aug 18 2023 at 19:12):

Alex J. Best said:

theorem a (_h : n - 1 = 1) :
   n = 2 :=
   match n with
   | 2 => rfl

#print a

By the way there is an even more amusing way to write that:

theorem a (_h : n - 1 = 1) : n = 2 :=
   let 2 := n; rfl

#print a

Eric Rodriguez (Aug 18 2023 at 19:17):

what language feature is this!?

Mario Carneiro (Aug 18 2023 at 19:48):

it's the same language feature as the one already demonstrated, because let pat := e1; e2 macro expands to match e1 with | pat => e2


Last updated: Dec 20 2023 at 11:08 UTC