Zulip Chat Archive

Stream: general

Topic: Nat.unaryCast and one


Sebastien Gouezel (Aug 04 2023 at 09:41):

In current mathlib, we have:

example : (0 : Cardinal) = ((0 : ) : Cardinal) := rfl -- works
example : (1 : Cardinal) = ((1 : ) : Cardinal) := rfl -- fails
example : (2 : Cardinal) = ((2 : ) : Cardinal) := rfl -- works
example : (3 : Cardinal) = ((3 : ) : Cardinal) := rfl -- works
example : (4 : Cardinal) = ((4 : ) : Cardinal) := rfl -- works
...

which is a little bit unpleasant -- I've been bitten by this in #6348.

This is due to the inductive definition of the cast, which is

protected def Nat.unaryCast {R : Type u} [One R] [Zero R] [Add R] :   R
  | 0 => 0
  | n + 1 => Nat.unaryCast n + 1

(so 1 is mapped to 0 + 1, not 1, which is why the rfl above breaks for n = 1).

We could fix this by changing the definition to

protected def Nat.unaryCast' {R : Type u} [One R] [Zero R] [Add R] :   R
  | 0 => 0
  | 1 => 1
  | n + 2 => (Nat.unaryCast' (n + 1)) + 1

but at the expense of the loss of the defeq

example (n : ) : ((n + 1 : ) : Cardinal) = (n : Cardinal) + 1 := rfl

(which works currently, but would be broken with the new definition).

For me, good defeqs for 1 are more important than coincidental defeqs in arithmetic equations, so I would be ready to refactor mathlib (not only in cardinals) by changing the definition of Nat.unaryCast to Nat.unaryCast'. But since it's a pretty fundamental change (and probably quite painful), I'd be happy to read your thoughts about that before I start.

Eric Wieser (Aug 04 2023 at 09:58):

Should we instead set Cardinal.natCast n := Quotient.mk (Fin n)?

Eric Wieser (Aug 04 2023 at 09:59):

That gives us nice defeqs for toNat

Eric Wieser (Aug 04 2023 at 10:09):

I think there might have been an abandoned Lean3 PR that did that

Sebastien Gouezel (Aug 04 2023 at 11:45):

It's not just for cardinals: in any type using the default Nat.unaryCast for natCast, defeqs for 1 are currently broken (while defeqs for all other natural numbers work just fine).

Anne Baanen (Aug 04 2023 at 12:02):

I assume the alternative would be to redefine the One instance to be 0 + 1?

Sebastien Gouezel (Aug 04 2023 at 12:05):

No, because then the cast of 1 would be 0 + (0 + 1)...

Sebastien Gouezel (Aug 04 2023 at 12:05):

It uses the One instance in the inductive definition.

Eric Wieser (Aug 04 2023 at 12:59):

My understanding is that unaryCast is just a compatibility shim for code that existing before natCast was introduced

Eric Wieser (Aug 04 2023 at 13:02):

Note that there are many other types where ($n : X) = (($n : ℕ) : X) is not defeq; two that come to mind are Fin k with n = 0 and Polynomial (due to irreducible_def)

Sebastien Gouezel (Aug 05 2023 at 14:02):

Eric Wieser said:

Should we instead set Cardinal.natCast n := Quotient.mk (Fin n)?

Done in #6384.


Last updated: Dec 20 2023 at 11:08 UTC