import MyNat.Definition
import MultiplicationWorld.Level6 -- succ_mul
import MyNat.Multiplication -- mul_succ, mul_zero
import AdvancedMultiplicationWorld.Level2 -- eq_zero_or_eq_zero_of_mul_eq_zero
namespace MyNat
open MyNat

Advanced Multiplication World

Level 4: mul_left_cancel

This is the last of the bonus multiplication levels. mul_left_cancel will be useful in inequality world.

People find this level hard. I have probably had more questions about this level than all the other levels put together, in fact. Many levels in this game can just be solved by "running at it" -- do induction on one of the variables, keep your head, and you're done. In fact, if you like a challenge, it might be instructive if you stop reading after the end of this paragraph and try solving this level now by induction, seeing the trouble you run into, and reading the rest of these comments afterwards. This level has a sting in the tail. If you are a competent mathematician, try and figure out what is going on. Write down a maths proof of the theorem in this level. Exactly what statement do you want to prove by induction? It is subtle.

Ok so here are some spoilers. The problem with naively running at it, is that if you try induction on, say, c, then you are imagining a and b as fixed, and your inductive hypothesis P(c) is ab=ac ⟹ b=c. So for your inductive step you will be able to assume ab=ad ⟹ b=d and your goal will be to show ab=a(d+1) ⟹ b=d+1. When you also assume ab=a(d+1) you will realize that your inductive hypothesis is useless, because ab=ad is not true! The statement P(c) (with a and b regarded as constants) is not provable by induction.

What you can prove by induction is the following stronger statement. Imagine a ≠ 0 as fixed, and then prove "for all b, if ab=ac then b=c" by induction on c. This gives us the extra flexibility we require. Note that we are quantifying over all b in the inductive hypothesis -- it is essential that b is not fixed.

You can do this in two ways in Lean -- before you start the induction you can write revert b. The revert tactic is the opposite of the intro tactic; it replaces the b in the hypotheses with "for all b" in the goal.

Alternatively, you can write induction c generalizing b with as the first line of the proof.

If you do not modify your technique in this way, then this level seems to be impossible (judging by the comments I've had about it!)

Theorem

If a ≠ 0, b and c are natural numbers such that ab = ac, then b = c.

set_option trace.Meta.Tactic.simp true
theorem 
mul_left_cancel: ∀ (a b c : MyNat), a ≠ 0 → a * b = a * c → b = c
mul_left_cancel
(
a: MyNat
a
b: MyNat
b
c: MyNat
c
:
MyNat: Type
MyNat
) (
ha: a ≠ 0
ha
:
a: MyNat
a
0: MyNat
0
) :
a: MyNat
a
*
b: MyNat
b
=
a: MyNat
a
*
c: MyNat
c
b: MyNat
b
=
c: MyNat
c
:=
a, b, c: MyNat
ha: a 0

a * b = a * c b = c
a, b, c: MyNat
ha: a 0

a * b = a * c b = c
a: MyNat
ha: a 0
b: MyNat

zero
a * b = a * zero b = zero
a: MyNat
ha: a 0
b: MyNat

zero
a * b = a * zero b = zero
a: MyNat
ha: a 0
b: MyNat

zero
a * b = a * 0 b = 0
a: MyNat
ha: a 0
b: MyNat

zero
a * b = a * 0 b = 0
a: MyNat
ha: a 0
b: MyNat

zero
a * b = a * 0 b = 0
a: MyNat
ha: a 0
b: MyNat

zero
a * b = 0 b = 0
a: MyNat
ha: a 0
b: MyNat

zero
a * b = 0 b = 0
a: MyNat
ha: a 0
b: MyNat
h: a * b = 0

zero
b = 0
a: MyNat
ha: a 0
b: MyNat
h: a * b = 0
x✝: a = 0 b = 0

zero
b = 0
a: MyNat
ha: a 0
b: MyNat
h: a * b = 0
h1: a = 0

zero.inl
b = 0
a: MyNat
ha: a 0
b: MyNat
h: a * b = 0
h1: a = 0

zero.inl.h
False
a: MyNat
ha: a 0
b: MyNat
h: a * b = 0
h1: a = 0

zero.inl.h
a = 0

Goals accomplished! 🐙
a: MyNat
ha: a 0
b: MyNat
h: a * b = 0
h2: b = 0

zero.inr
b = 0

Goals accomplished! 🐙
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
b: MyNat

succ
a * b = a * succ d b = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
b: MyNat
hb: a * b = a * succ d

succ
b = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
b: MyNat
hb: a * b = a * succ d

succ
b = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: a * zero = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: a * zero = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: a * 0 = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: a * 0 = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: a * 0 = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: a * 0 = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: 0 = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: 0 = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: 0 = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: 0 = a * succ d

succ.zero
zero = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: 0 = a * succ d

succ.zero
0 = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: 0 = a * succ d

succ.zero
0 = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: 0 = a * succ d

succ.zero.h
False
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb: 0 = a * succ d

succ.zero.h
a = 0
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb✝: 0 = a * succ d
hb: a * succ d = 0

succ.zero.h
a = 0
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb✝: 0 = a * succ d
hb: a * succ d = 0
x✝: a = 0 succ d = 0

succ.zero.h
a = 0
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb✝: 0 = a * succ d
hb: a * succ d = 0
h: a = 0

succ.zero.h.inl
a = 0

Goals accomplished! 🐙
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb✝: 0 = a * succ d
hb: a * succ d = 0
h: succ d = 0

succ.zero.h.inr
a = 0
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
hb✝: 0 = a * succ d
hb: a * succ d = 0
h: succ d = 0

succ.zero.h.inr.h
False

Goals accomplished! 🐙
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
c: MyNat
hb: a * succ c = a * succ d

succ.succ
succ c = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
c: MyNat
hb: a * succ c = a * succ d
h: Prop

succ.succ
succ c = succ d
Error: tactic 'apply' failed, failed to unify ?b = d with succ c = succ d case succ.succ a : MyNat ha : a 0 d : MyNat hd : (b : MyNat), a * b = a * d b = d c : MyNat hb : a * succ c = a * succ d h : Prop succ c = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
c: MyNat
hb: a * succ c = a * succ d
h: Prop

succ.succ
succ c = succ d
a: MyNat
ha: a 0
d: MyNat
hd: (b : MyNat), a * b = a * d b = d
c: MyNat
hb: a * succ c = a * succ d
h: Prop

succ.succ
succ c = succ d

You should now be ready for Inequality World.