Zulip Chat Archive

Stream: mathlib4

Topic: Status of !4#2470 (SetTheory.Ordinal.Notation)


Arien Malec (Mar 16 2023 at 16:40):

I've been semi-adopting this file and fixing things on and off, but it's pretty heinous. In particular, the original Lean 3 (ab)uses _match_1 to prove certain invariants that are essential for proofs, and there's a thing that happens here where two match patterns generate three terms in a way that I don't understand (and neither does Lean 4).

theorem repr_inj {a b} [NF a] [NF b] : repr a = repr b  a = b :=
match cmp a b, cmp_compares a b with
 | ordering.lt, (h : repr a < repr b), e := (ne_of_lt h e).elim
 | ordering.gt, (h : repr a > repr b), e := (ne_of_gt h e).elim
 | ordering.eq, h, e := h
 end, congr_arg _

(cmp returns an ordering and cmp_compares returns (cmp a b).compares a b, and there's some magic that's happening there).

I wonder if the right thing here is for someone to refactor on the Lean 3 side then re-start the port. I've been inserting defs that recapitulate the _match_1 on the Lean 3 side (and yes, there's a match construct on Lean 4 but it returns different signatures), and generally cleaning stuff up, but someone's going to have a long review cycle....

Eric Wieser (Mar 16 2023 at 16:42):

_match_1 can probably be replaced with let rec?

Eric Wieser (Mar 16 2023 at 16:43):

Can you link to the offending use of _match_1 in mathlib3?

Arien Malec (Mar 16 2023 at 16:56):

Sure: docs#onote.opow_def docs#onote.oadd_add docs#onote.repr_sub, docs#onote.fast_growing_def

Eric Wieser (Mar 16 2023 at 17:14):

docs#opow_def is just the equation lemma for docs#opow

Arien Malec (Mar 16 2023 at 17:26):

Sort of.

Arien Malec (Mar 16 2023 at 17:30):

opow._match_1 is onote → onote × ℕ → onote and opow is onote → onote → onote, so it's a single step into opow

Arien Malec (Mar 18 2023 at 17:27):

I find this very confusing:

/-- The ordinal denoted by a notation -/
@[simp]
noncomputable def repr : Onote  Ordinal.{0}
  | 0 => 0
  | oadd e n a => ω ^ repr e * n + repr a
#align onote.repr Onote.repr

variable (e: Onote)
#check (repr e * (5: PNat)) -- OK: repr e * ↑↑5 : Ordinal
theorem oadd_repr: oadd e n a = ω ^ repr e * n + repr a := rfl -- fails
-- failed to synthesize instance
--  HMul Ordinal ℕ+ ?m.12533

This seemingly trivial proof is key to some shennanigans I'd like to try to unlock repr_inj.

Eric Wieser (Mar 18 2023 at 17:41):

Did you mean to write (oadd e n a).repr and not oadd e n a ?

Arien Malec (Mar 18 2023 at 17:42):

I just realized that...

Arien Malec (Mar 18 2023 at 18:45):

Sigh, now I'm in coercion hell.

theorem zere_ne_oadd_repr: (0: Ordinal)   ω ^ repr e * (n: +) + repr a := by
  have h: ω ^ repr e  0 := opow_ne_zero _ omega_ne_zero
  have h₂:  ω ^ repr e * (n : +)  0 := Ordinal.mul_ne_zero h (PNat.ne_zero n)

gives

argument
  PNat.ne_zero n
has type
  n  0 : Prop
but is expected to have type
  ↑↑n  0 : Prop

The plan here is that by cases, I can get repr_inj to a state where if I can prove the above, and can prove

@[simp]
theorem notation_ext_iff:
    ω ^ repr e * n + repr a = ω ^ repr e' * n' + repr a'  e = e'  n = n'  a = a' := sorry

then I'm done

Eric Wieser (Mar 18 2023 at 18:46):

How does it work in mathlib3?

Arien Malec (Mar 18 2023 at 18:47):

See above -- first post -- some weird thing where two matches generate three hypotheses.

(Sadly, my ext_iff relies on repr_inj so that's another corner).

Reid Barton (Mar 18 2023 at 18:50):

I don't understand why that syntax worked but it must have meant something like

fun e => match _, _ with
| _, _ => ...[e]
...

Reid Barton (Mar 18 2023 at 18:51):

In any case repr_inj should follow easily from cmp_compares

Reid Barton (Mar 18 2023 at 18:54):

Reid Barton said:

I don't understand why that syntax worked but it must have meant something like

fun e => match _, _ with
| _, _ => ...[e]
...

Because this match expression is appearing where we want a term of type
repr a = repr b -> a = b
and in the branch | ordering.lt, (h : repr a < repr b), e := (ne_of_lt h e).elim we see ne_of_lt h e with h : repr a < repr b, so e : repr a = repr b and there is a call to false.elim

Arien Malec (Mar 18 2023 at 18:55):

What's so very confusing here, is that we have h,e where h: repr a < repr b and e is a = b

Reid Barton (Mar 18 2023 at 18:55):

e should be of type repr a = repr b

Arien Malec (Mar 18 2023 at 18:56):

ne_of_lt

Reid Barton (Mar 18 2023 at 18:56):

Right, it is being passed h : repr a < repr b, so then the result is not (repr a = repr b), so if we pass e : repr a = repr b now, we get false

Reid Barton (Mar 18 2023 at 18:57):

This also makes sense, since we are proving the forwards direction so repr a = repr b is what we know.

Arien Malec (Mar 18 2023 at 18:57):

Sorry, e: repr a = repr b

Reid Barton (Mar 18 2023 at 18:58):

To be more precise what I mean is that you can rewrite the Lean 3 code equivalently by

  • inserting \lam e, between the \< and match
  • removing , e from the LHS of each branch

Reid Barton (Mar 18 2023 at 18:58):

I think whoever wrote this code the first time knows too much about how Lean works.

Arien Malec (Mar 18 2023 at 19:00):

Look at the copyright statement :rolling_on_the_floor_laughing:

Reid Barton (Mar 18 2023 at 19:01):

Yes, I was pretty sure I knew who it was without looking!

Reid Barton (Mar 18 2023 at 19:04):

Now I wonder if you could use match with with no expressions, but with multiple branches, as a lambda-case

Kevin Buzzard (Mar 18 2023 at 20:27):

Uber-compact/golfed code has turned out to be tricky to port on more than one occasion. For me this was an unexpected bad consequence of the mathlib3 golf-for-your-life policy.

Eric Wieser (Mar 18 2023 at 21:18):

On the flipside, I think long messy nonterminal-simp proofs would have been worse to port

Arien Malec (Mar 19 2023 at 01:47):

This is driving me crazy -- has to be an easy fix with a missing coercion somewhere.

import Mathlib.SetTheory.Ordinal.Principal

theorem mul_one' {o: Ordinal}: o * 1 = o := by
  rw [mul_one] -- good

theorem mul_one'' {o: Ordinal}: o * (1: +) = o := by
  rw [mul_one] -- fails

Eric Wieser (Mar 19 2023 at 01:59):

I would not expect the second one to work, look at the goal state

Arien Malec (Mar 19 2023 at 02:56):

Ah....

import Mathlib.SetTheory.Ordinal.Principal

theorem mul_one' {o: Ordinal}: o * 1 = o := by
  rw [mul_one] -- works

theorem mul_one'' {o: Ordinal}: o * (1 : Nat) = o := by
  rw [mul_one] -- doens't

theorem mul_one'''' {o: Ordinal}: o * (1: +) = o := by
  rw [mul_one] -- doesn't

Arien Malec (Mar 19 2023 at 02:59):

So in the first case, we use the One machinery, in the other two we use coercion machinery to cast a P/Nat as an Ordinal.

Arien Malec (Mar 19 2023 at 03:07):

Which, if the cast is to mean anything should be equal to Ordinal.one

Arien Malec (Mar 19 2023 at 17:08):

So, updating:

import Mathlib.SetTheory.Ordinal.Principal

theorem mul_one' {o: Ordinal}: o * 1 = o := by
  rw [mul_one]

theorem mul_one'' {o: Ordinal}: o * (1 : Nat) = o := by
  simp [mul_one] -- closes goal, below fails due to no goals to be solved
  have h: (1: ) = (1: Ordinal) := Nat.cast_one
  rw [h, mul_one]

theorem mul_one'''' {o: Ordinal}: o * (1: +) = o := by
  simp [mul_one] -- DOES NOT CLOSE GOAL but below closes goal
  have h: (↑↑(1: +) : Ordinal) = (1:) := rfl
  have h₂: (1: ) = (1: Ordinal) := Nat.cast_one
  rw [h, h₂, mul_one]

It seems like there's a simp lemma missing somewhere.

Eric Wieser (Mar 19 2023 at 17:09):

!4#2989 perhaps?

Arien Malec (Mar 19 2023 at 17:15):

I don't think that has the right signature, but maybe?

Arien Malec (Mar 19 2023 at 17:17):

One would like to express "if there's a coercion between and some time there's also a coercion between ℕ+ and that type"

Eric Wieser (Mar 19 2023 at 17:19):

Do the proofs above work in Lean 3?

Arien Malec (Mar 19 2023 at 17:20):

Lean 3 simps just fine

Eric Wieser (Mar 19 2023 at 17:20):

Then use simp? in Lean 3 vs Lean 4 and see what's different

Arien Malec (Mar 19 2023 at 17:26):

Ah, the missing bit is docs#coe_coe

Arien Malec (Mar 19 2023 at 17:27):

Not ported, and no align statement AFAICT?

Eric Wieser (Mar 19 2023 at 17:31):

coe_coe was a magic lemma in Lean3 which can't really exist in Lean4

Eric Wieser (Mar 19 2023 at 17:32):

At least, as I understand it; I think it exploited the fact that implicit typeclass arguments are found by unification, so it would apply to things that aren't actually the transitive coercion instance as long as they're defeq to it. There is no coe symbol to match on in Lean 4, so the lemma wouldn't work

Eric Wieser (Mar 19 2023 at 17:33):

If you add the coe_coe statement locally for the types you need, does it help?

Arien Malec (Mar 19 2023 at 17:36):

Let me try -- I see a bunch of local coe_coe lemmas that I can try from & obviously I have a hacky solution above that will work.

Arien Malec (Mar 19 2023 at 17:39):

I did confirm that

@[simp]
theorem PNat_Nat_coe: (↑↑(n: +) : Ordinal) = (n: ) := rfl

does not work where the local hypothesis does?

Eric Wieser (Mar 19 2023 at 17:40):

↑↑ is nonsense there

Eric Wieser (Mar 19 2023 at 17:40):

Lean has no way of knowing which coercion you meant

Arien Malec (Mar 19 2023 at 17:40):

Ah, because my local type is actually @Nat.cast Ordinal AddMonoidWithOne.toNatCast ↑1 : Ordinal

Eric Wieser (Mar 19 2023 at 17:41):

What statement are you trying to write? And what is n?

Arien Malec (Mar 19 2023 at 17:42):

Goal state is ω ^ repr x * ↑↑1 * repr o = ω ^ repr x * repr o

Arien Malec (Mar 19 2023 at 17:42):

and I want to close the goal with mul_one

Eric Wieser (Mar 19 2023 at 17:43):

Can you turn off coercion printing?

Eric Wieser (Mar 19 2023 at 17:44):

Eric Wieser said:

!4#2989 perhaps?

I'm pretty sure this PR will solve your problem

Arien Malec (Mar 19 2023 at 17:44):

ω ^ repr x * Nat.cast (PNat.val (OfNat.ofNat 1)) * repr o = ω ^ repr x * repr o

Eric Wieser (Mar 19 2023 at 17:47):

That's docs4#PNat.one_coe I think

Eric Wieser (Mar 19 2023 at 17:47):

Which like I said, is fixed in !4#2989

Eric Wieser (Mar 19 2023 at 17:48):

Eric Wieser said:

That's docs4#PNat.one_coe I think

@Henrik Böving, how hard would it be to make link to PNat.val in that lemma?

Arien Malec (Mar 19 2023 at 17:48):

OK, merged and building now...

Henrik Böving (Mar 19 2023 at 17:51):

Eric Wieser said:

Eric Wieser said:

That's docs4#PNat.one_coe I think

Henrik Böving, how hard would it be to make link to PNat.val in that lemma?

Hmmm, as I understand it the arrow is a Coe.coe call which has an implicit argument with theCoe instnace? And somewhere burried in that should be the call to PNat.val. So certainly not trivial :(

Eric Wieser (Mar 19 2023 at 17:54):

My understanding was that Coes got inlined, so the arrow is actually a direct call of PNat.val

Henrik Böving (Mar 19 2023 at 18:25):

Ah indeed it does desugar into PNat.val here I didn't know that cool...and I can directly go to definition on it as well so the InfoTree does seem to have the information even. In that case it should certainly be doable.

In fact I am rather surprise it doesnt just work :tm: out of the box :thinking:


Last updated: Dec 20 2023 at 11:08 UTC