Zulip Chat Archive

Stream: mathlib4

Topic: ring_nf returns ugly literals


Bhavik Mehta (Nov 08 2023 at 17:09):

import Mathlib.Data.Real.Basic

local macro_rules | `($x ^ $y) => `(HPow.hPow $x $y) -- Porting note: See issue lean4#2220

example {n : } : (n + 1 / 2) ^ 2 * (n + 1 + 1 / 3)  (n + 1 / 3) * (n + 1) ^ 2 := by
  ring_nf

After the ring_nf call, the goal looks like:

 (Int.ofNat 1) / 3 + n * ((Int.ofNat 19) / 12) + n ^ 2 * ((Int.ofNat 7) / 3) + n ^ 3 
  (Int.ofNat 1) / 3 + n * ((Int.ofNat 5) / 3) + n ^ 2 * ((Int.ofNat 7) / 3) + n ^ 3

which seems unnecessarily ugly. For comparison, ring_nf SOP in Lean 3 gives

n ^ 3 + n ^ 2 * (7 / 3) + n * (19 / 12) + 1 / 3  n ^ 3 + n ^ 2 * (7 / 3) + n * (5 / 3) + 1 / 3

which is clearer. This can be remedied in Lean 4 by using a bunch of simp lemmas:

simp only [Int.ofNat_eq_coe, Int.int_cast_ofNat, Nat.cast_ofNat, Int.cast_one, Nat.cast_one]

turns the goal into

1 / 3 + n * (19 / 12) + n ^ 2 * (7 / 3) + n ^ 3  1 / 3 + n * (5 / 3) + n ^ 2 * (7 / 3) + n ^ 3

which is something I would be satisfied with, but can we make ring_nf alone give something like this instead?

Bhavik Mehta (Nov 08 2023 at 17:10):

(This came up in porting the exponential ramsey project)

Patrick Massot (Nov 08 2023 at 18:46):

I also faced this in the rpow_simp tactic post-processor here.

Patrick Massot (Nov 08 2023 at 18:47):

I even created those lemmas for this purpose, but maybe they are equivalent to the lemmas you cite.

Bhavik Mehta (Nov 08 2023 at 18:59):

Ah yeah, I think those lemmas are implied by some subset of the ones I gave. But really, it seems like ring_nf shouldn't need this post-processing step at all (it didn't in Lean 3)

Patrick Massot (Nov 08 2023 at 19:01):

Sure, I was only agreeing with you here.

Mario Carneiro (Nov 09 2023 at 03:20):

yes this seems to be a bug, something is wrong with the simp lemmas

Bhavik Mehta (Nov 10 2023 at 18:14):

Is this something that's being worked on, or is it worth me making an issue on mathlib4 to track it?

Mario Carneiro (Nov 10 2023 at 19:18):

best make an issue

Mauricio Collares (Nov 15 2023 at 18:03):

Is it weird that ring_nf (config := {mode := .raw}) takes forever here?

Eric Wieser (Dec 05 2023 at 13:33):

A simpler mwe:

import Mathlib.Data.Real.Basic

example : 0  (1 / 2 : ) := by
  ring_nf
  sorry

Eric Wieser (Dec 06 2023 at 00:10):

Mauricio Collares said:

Is it weird that ring_nf (config := {mode := .raw}) takes forever here?

It seems like there's an infinite loop somewhere...

Eric Wieser (Dec 06 2023 at 00:30):

I think

/--
A "raw rat cast" is an expression of the form:

* `(Nat.rawCast lit : α)` where `lit` is a raw natural number literal
* `(Int.rawCast (Int.negOfNat lit) : α)` where `lit` is a nonzero raw natural number literal
* `(Rat.rawCast n d : α)` where `n` is a raw int cast, `d` is a raw nat cast, and `d` is not 1 or 0.

is being violated, as the Rat.rawCast does not have raw casts as arguments

Eric Wieser (Dec 06 2023 at 00:57):

The Int.ofNat seem to be coming from here. Should that be using Nat.rawCast instead? Or is there no strict convention here?

Eric Wieser (Dec 06 2023 at 00:58):

(cc @Mario Carneiro)

Mario Carneiro (Dec 06 2023 at 01:23):

there is a strict convention indeed, but there are some smart constructors that will remove those indirections in some cases

Mario Carneiro (Dec 06 2023 at 01:25):

And I believe this one is using the smart constructor (Result.isRat' calls Result.isInt which strips off the .ofNat)

Mario Carneiro (Dec 06 2023 at 01:28):

Oh wait, the doc string is wrong

Eric Wieser (Dec 06 2023 at 01:28):

The one I quote above?

Mario Carneiro (Dec 06 2023 at 01:28):

in the last case n and d should be raw int/nat numerals, not raw casts

Eric Wieser (Dec 06 2023 at 01:28):

The ofNat is definitely not being stripped off

Eric Wieser (Dec 06 2023 at 01:29):

What is a "raw int numeral"?

Mario Carneiro (Dec 06 2023 at 01:29):

that is, ofNat (nat_lit N) or negOfNat (nat_lit N)

Eric Wieser (Dec 06 2023 at 01:30):

Ah, so if the docstring is wrong then it really is just a missing simp lemma

Eric Wieser (Dec 06 2023 at 01:30):

Though maybe that doesn't explain why mode := .raw hangs

Mario Carneiro (Dec 06 2023 at 01:33):

the simp lemma rat_rawCast_2 looks suspicious / needs to be coupled with something else

Eric Wieser (Dec 06 2023 at 01:37):

I'll make a patch

Mario Carneiro (Dec 06 2023 at 01:38):

I'm testing these lemmas now (in place of the existing simp lemmas)

theorem int_rawCast_pos {R} [Ring R] : (Int.rawCast (.ofNat n) : R) = Nat.rawCast n := by simp
theorem int_rawCast_neg {R} [Ring R] : (Int.rawCast (.negOfNat n) : R) = -Nat.rawCast n := by simp
theorem rat_rawCast {R} [DivisionRing R] :
    (Rat.rawCast n d : R) = Int.rawCast n / Nat.rawCast d := by simp

Mario Carneiro (Dec 06 2023 at 01:40):

hm, it seems to work on the original problem but mode := .raw still hangs

Eric Wieser (Dec 06 2023 at 01:42):

#8836

Eric Wieser (Dec 06 2023 at 01:52):

(your message above only just arrived for me)

Eric Wieser (Dec 06 2023 at 01:53):

I wouldn't expect this to make any diference to .raw, because .raw skips out on using any of these lemmas anyway

Mario Carneiro (Dec 06 2023 at 02:11):

It seems that in .raw mode you have to set singlePass := true or else it will revisit raw expressions and expand 1 to Nat.rawCast 1 + 0 infinitely

Mario Carneiro (Dec 06 2023 at 02:12):

I pushed to your branch

Eric Wieser (Dec 07 2023 at 16:19):

I think this should be good to go now


Last updated: Dec 20 2023 at 11:08 UTC