Zulip Chat Archive

Stream: lean4

Topic: proof 1 ≠ 2 the hard way


James Sully (Jun 01 2023 at 07:16):

How do I prove 1 ≠ 2? I can always use by simp, but what about without it?

I know this is the same as 1 = 2 → False, so presumably I want something along these lines?

example : 1  2 :=
  fun h1eq2 : 1 = 2 =>
    show False from _

Ruben Van de Velde (Jun 01 2023 at 07:17):

What type are your numbers?

James Sully (Jun 01 2023 at 07:17):

Nat

James Sully (Jun 01 2023 at 07:18):

let's say

Mario Carneiro (Jun 01 2023 at 07:19):

fun.

Mario Carneiro (Jun 01 2023 at 07:19):

or fun h => nomatch h

Mario Carneiro (Jun 01 2023 at 07:22):

one more step lower in abstraction is

example : 1  2 :=
  fun (h : 1 = 2) =>
    Nat.noConfusion h fun (h : 0 = 1) =>
      Nat.noConfusion h

James Sully (Jun 01 2023 at 07:25):

Thanks! ok, the nomatch one works (I'll have to look up nomatch)

theorem oneNeqTwo : (1 : Nat)  2 :=
  fun h => nomatch h

But i'm not sure where to put that fun. syntax. This is a syntax error:

theorem oneNeqTwo : (1 : Nat)  2 :=
  fun.

Mario Carneiro (Jun 01 2023 at 07:25):

import Std.Tactic.NoMatch

Mario Carneiro (Jun 01 2023 at 07:26):

it's just syntax over nomatch , to allow empty pattern matches in match and fun

James Sully (Jun 01 2023 at 07:26):

unknown package 'Std'

Mario Carneiro (Jun 01 2023 at 07:28):

put this in your lakefile:

require std from git "https://github.com/leanprover/std4" @ "main"

Mario Carneiro (Jun 01 2023 at 07:29):

the lean core distribution basically only contains the compiler and facilities needed to write the compiler

James Sully (Jun 01 2023 at 07:29):

Ah, I see. I'm just working through Theorem Proving, so I'm not in a project, I'm just using the vscode extension on a standalone file.

Mario Carneiro (Jun 01 2023 at 07:30):

You will hit on limitations of that mode pretty quickly

Mario Carneiro (Jun 01 2023 at 07:30):

not being able to import anything being the main one

Mario Carneiro (Jun 01 2023 at 07:31):

You can start a lake project depending on mathlib using lake new myproj math, you will want to do that to play with more advanced library stuff

James Sully (Jun 01 2023 at 07:32):

makes sense.
I'm also not seeing Nat.noConfusion when I search the docs?
https://leanprover-community.github.io/mathlib4_docs/search.html?sitesearch=https%3A%2F%2Fleanprover-community.github.io%2Fmathlib4_docs&q=Nat.noConfusion

Mario Carneiro (Jun 01 2023 at 07:32):

It's an automatically generated definition created for every inductive type

Mario Carneiro (Jun 01 2023 at 07:33):

recommended reading: https://xenaproject.wordpress.com/2018/03/24/no-confusion-over-no_confusion/

Mario Carneiro (Jun 01 2023 at 07:33):

you can use #print Nat.noConfusion and #print Nat.noConfusionType to see the definitions

James Sully (Jun 01 2023 at 07:34):

Ok, cheers! Doing a quick search, it looks like it comes up in chapter 8 of Theorem Proving as well

Kyle Miller (Jun 01 2023 at 07:54):

Here's another alternative:

example : 1  2 :=
  fun h1eq2 : 1 = 2 => by cases h1eq2

cases on an equality means it tries to unify the LHS and RHS since rfl is the only constructor, and cases knows how to peel off constructors and that different constructors can't be equal, so it sees 1 = 2, turns it into 0 = 1, and then knows 0 can't equal Nat.succ so recognizes the contradiction.

Kyle Miller (Jun 01 2023 at 07:58):

match/nomatch can do the same kinds of calculations

Kyle Miller (Jun 01 2023 at 07:59):

A term proof is

example : 1  2 :=
  fun h1eq2 : 1 = 2 =>
    Nat.zero_ne_one (Nat.succ_inj'.mp h1eq2)

though these are probably proved using match or Nat.noConfusion

Mario Carneiro (Jun 01 2023 at 08:01):

It is worth noting that the actual proof that simp comes up with is actually a bit closer to

example : 1  2 := Nat.ne_of_beq_eq_false rfl

taking advantage of the fact that natural number equality has a primitive implementation in the kernel. This is especially important if the proof is not about 1 ≠ 2 but rather 1000000000 ≠ 2000000000, because the methods involving noConfusion involve peeling one constructor off at a time, which would mean a billion steps to prove this

Kevin Buzzard (Jun 01 2023 at 08:11):

It's all very well explaining these cute hacky methods/tricks but by norm_num is really the correct answer because this is the technique which generalises. norm_num is the tactic which proves equalities and inequalities between numerals.

James Sully (Jun 01 2023 at 08:17):

how do I look at the term proof a tactic produces?

Henrik Böving (Jun 01 2023 at 08:18):

#print mytheorem

James Sully (Jun 01 2023 at 08:19):

ah, of course lol

Kevin Buzzard (Jun 01 2023 at 08:20):

You don't want to look at the term proof that norm_num produces though :-)

Mario Carneiro (Jun 01 2023 at 08:21):

you know, saying that is just going to make people want to look at it

James Sully (Jun 01 2023 at 08:22):

I'm staying away from std for the duration of this book. The book hasn't told me to use it and I assume there are pedagogical reasons not to yet

James Sully (Jun 01 2023 at 08:22):

or mathlib rather

Kevin Buzzard (Jun 01 2023 at 08:22):

Now I've found that James is a "let me look at the proof term" kind of person (ie not a mathematician) I wish I'd not opened my mouth :-)

James Sully (Jun 01 2023 at 08:23):

hahaha

James Sully (Jun 01 2023 at 08:23):

my cover's blown

Kevin Buzzard (Jun 01 2023 at 08:24):

Re pedagogical reasons -- it depends what you're trying to teach. "Mathematics in Lean" uses mathlib from page 1

James Sully (Jun 01 2023 at 08:24):

I actually started on Functional Programming in lean and then switched halfway through out of curiosity

Kevin Buzzard (Jun 01 2023 at 08:24):

I teach maths undergraduates lean from scratch using mathlib, but I don't teach them anything about term mode at all, or proof terms etc

Kevin Buzzard (Jun 01 2023 at 08:25):

It all depends on the level of abstraction you're interested in

Mario Carneiro (Jun 01 2023 at 08:25):

lol, I tried it and got:

example : 1  2 := show_term by norm_num
-- Try this: of_eq_true (eq_true_of_decide (Eq.refl true))

James Sully (Jun 01 2023 at 08:25):

yeah, I'm more interested in the FP side and potentially bringing insights back with me to other languages

Mario Carneiro (Jun 01 2023 at 08:25):

which is not a norm_num proof at all

Mario Carneiro (Jun 01 2023 at 08:26):

using norm_num1 produces the expected horror:

example : 1  2 := show_term by norm_num1
-- Try this: of_eq_true
--   (eq_true
--     (Mathlib.Meta.NormNum.isNat_eq_false (Mathlib.Meta.NormNum.isNat_ofNat ℕ (Eq.refl 1))
--       (Mathlib.Meta.NormNum.isNat_ofNat ℕ (Eq.refl 2)) (Eq.refl false)))

Mario Carneiro (Jun 01 2023 at 08:27):

(which BTW is just an obfuscated version of the same proof)

Kevin Buzzard (Jun 01 2023 at 08:27):

James can take that insight back with them to other languages


Last updated: Dec 20 2023 at 11:08 UTC