Zulip Chat Archive

Stream: mathlib4

Topic: Did norm_num just get weaker?


Bhavik Mehta (Nov 20 2023 at 01:49):

import Mathlib

example : 3  9 := by norm_num

I'm pretty sure this worked on mathlib head a week ago, but it fails today. Has something changed?

Bhavik Mehta (Nov 20 2023 at 01:56):

To be specific, this succeeds for me on mathlib4 commit aa0957f (from 13th Nov) and fails for me on 778f663 (from 19th Nov)

David Renshaw (Nov 20 2023 at 02:03):

Yes, see mathlib4#8366.

David Renshaw (Nov 20 2023 at 02:04):

My understanding is that the main difference is that simp no longer uses decide := true by default

Bhavik Mehta (Nov 20 2023 at 02:05):

Right I'm aware of this change, but that's not enough to justify this example breaking. For instance, simp in mathlib3 doesn't use decide either (and so it fails on this example) but norm_num in mathlib3 can do it

David Renshaw (Nov 20 2023 at 02:06):

Perhaps decide was masking other deficiencies in mathlib4 norm_num.

David Renshaw (Nov 20 2023 at 02:06):

fwiw, this works

example : 3  9 := by decide

Bhavik Mehta (Nov 20 2023 at 02:08):

Sure decide works but my actual case is a more complex expression where I'd like this to be normalised away! So perhaps to be more specific, the issue is that norm_num1 fails on this.

Bhavik Mehta (Nov 20 2023 at 02:10):

Ah, and all the tests for norm_num1 with divisibility are commented out...

David Renshaw (Nov 20 2023 at 02:10):

curiously, this fails, even though Mathlib.Tactic.NormNum.Prime exists and purports to be able to handle it

example : Prime 3 := by norm_num

David Renshaw (Nov 20 2023 at 02:11):

Ah, wait, no, it does work with Nat.Prime

Bhavik Mehta (Nov 20 2023 at 02:18):

It seems like the divisibility extension to norm_num was just never ported, and it wasn't noticed because decide was picking up the slack.

Thomas Murrills (Nov 20 2023 at 02:19):

Note issue #2136! (I’m not entirely sure it’s up to date)

Bhavik Mehta (Nov 20 2023 at 02:20):

Ah great to know, thank you!

Thomas Murrills (Nov 20 2023 at 02:24):

We should probably add the facts that an extension exists for Nat.Prime and that one doesn’t for the generic Prime; I’m on mobile at the moment, however.

David Renshaw (Nov 20 2023 at 02:39):

Note also that #7112 would allow you to re-enable decide in norm_num.

Patrick Massot (Nov 20 2023 at 02:49):

@Mario Carneiro is there any reason this wasn't labelled as awaiting review? I delegated it anyway since it looks fine to me.

Eric Rodriguez (Nov 20 2023 at 08:42):

For Prime it should be really easy to write an extension I guess? I can give it a crack to learn metaprogramming I guess

Eric Rodriguez (Nov 20 2023 at 08:42):

Where is the guide again?

Mario Carneiro (Nov 20 2023 at 16:13):

#8534 implements a norm_num extension for Nat.dvd, Int.dvd, Int.div

Gareth Ma (Nov 21 2023 at 08:58):

Hi, is the following example also related to the simp-decide change?

lemma works (n : ) : 2 * n + 1 + 1 = 2 * n + 2 := by norm_num
lemma fails (n : ) : (2 * n + 1 + 1) / 2 = (2 * n + 2) / 2 := by norm_num

Here's the trace:

 13:67-13:75: information:
[Tactic.norm_num] (2 * n + 1 + 1) / 2 failed: not a division ring
[Tactic.norm_num] Mathlib.Meta.NormNum.evalOfNat:
    2 ==> isNat 2 (Mathlib.Meta.NormNum.isNat_ofNat  (Eq.refl 2))
[Tactic.norm_num] 2 * n failed: n: no norm_nums apply
[Tactic.norm_num] 2 * n + 1 failed: 2 * n: no norm_nums apply
[Tactic.norm_num] 2 * n + 1 + 1 failed: 2 * n + 1: no norm_nums apply
[Tactic.norm_num] (2 * n + 1 + 1) / 2 failed: 2 * n + 1 + 1: no norm_nums apply
...

The final line is weird.

Anne Baanen (Nov 21 2023 at 09:14):

I don't think norm_num is supposed to work on either of these goals anyway, since it's supposed to work on concrete numerals, not variables. Does simp work on either goal? (What are you importing?)

Ruben Van de Velde (Nov 21 2023 at 09:15):

Wouldn't you expect norm_num to combine the +1 +1?

Gareth Ma (Nov 21 2023 at 09:16):

^

Ruben Van de Velde (Nov 21 2023 at 09:16):

Though I can see the argument about that being out of scope too

Gareth Ma (Nov 21 2023 at 09:16):

Anne Baanen said:

I don't think norm_num is supposed to work on either of these goals anyway, since it's supposed to work on concrete numerals, not variables. Does simp work on either goal? (What are you importing?)

I'm importing Mathlib.Tactic, I can switch to Mathlib and try. ring_nf normalises it to (2 + k * 2) / 2, simp does nothing.

Mauricio Collares (Nov 21 2023 at 09:16):

To confirm this is not related to the decide change, you can try norm_num (config := {decide := true}) on the norm_num_cfg branch (#7112). I just did and it fails there too.

Gareth Ma (Nov 21 2023 at 09:17):

uh
Screenshot-2023-11-21-at-09.17.01.png

Gareth Ma (Nov 21 2023 at 09:17):

Oh, I need to switch to the branch you mentioned, I see

Dan Velleman (Nov 30 2023 at 18:08):

The following example worked in v4.2.0, but doesn't work in v4.3.0-rc2:

import Mathlib.Tactic

def f (n : Nat) : Nat := n + 1

example : f 0 = 1 := by
  norm_num

Was this a deliberate change to norm_num, or a side effect of some other change?

Ruben Van de Velde (Nov 30 2023 at 18:14):

We had a change to make simp not run decide by default, that might be it

Patrick Massot (Nov 30 2023 at 18:21):

This is not about decide, this is about unfolding the definition of f.

Kyle Miller (Nov 30 2023 at 19:23):

@Patrick Massot I'm pretty sure this is about decide. The "decision procedure" for Nat equality is to do rfl. This succeeds:

example : f 0 = 1 := by
  decide

Kyle Miller (Nov 30 2023 at 19:23):

@Dan Velleman You can pass norm_num additional simp lemmas, including functions to unfold.

example : f 0 = 1 := by
  norm_num [f]

If you tag the function with @[simp] to make it auto-unfold, then norm_num succeeds.

@[simp]
def f (n : Nat) : Nat := n + 1

example : f 0 = 1 := by
  norm_num

Patrick Massot (Nov 30 2023 at 19:24):

I claims that

example : f 0 = 1 := by
  unfold f
  norm_num

should work

Patrick Massot (Nov 30 2023 at 19:24):

So this is about norm_num no longer unfolding f, right?

Patrick Massot (Nov 30 2023 at 19:25):

And by norm_num I really mean the simp called by norm_num

Kyle Miller (Nov 30 2023 at 19:25):

Yeah, that does work, but I think the specific change is that simp doesn't use decide by default anymore, and decide was incidentally unfolding f because it applies rfl.

Dan Velleman (Nov 30 2023 at 20:25):

If I make it f 0 < 2 rather than f 0 = 1, then rfl is no longer relevant, right? But decide still seems to work. So I think f is still getting unfolded, but not because of a call to rfl.

Kyle Miller (Nov 30 2023 at 20:30):

Sure, rfl wouldn't be relevant if you change the proposition to something that's not an equality. In the case of f 0 < 2, you can check the term that decide produces, and it uses Nat.decLt (f 0) 2. Inside of this is Nat.ble (f 0 + 1) 2, and the elaborator will unfold f 0 here while it computes whether this is true or false.

Kyle Miller (Nov 30 2023 at 20:32):

The short version is that decide can incidentally unfold functions because unification/whnf is eager to (efficiently) compute basic Nat functions including Nat.ble.

This is what decide is doing:

theorem foo : f 0 < 2 :=
  Nat.le_of_ble_eq_true (refl true : Nat.ble (f 0 + 1) 2 = true)

Kyle Miller (Nov 30 2023 at 20:36):

(Here's that list by the way: https://github.com/leanprover/lean4/blob/master/src/Lean/Meta/WHNF.lean#L858-L866)

Scott Morrison (Dec 02 2023 at 00:10):

I think turning decide back on inside norm_num may be reasonable! Someone should try it, and run !bench.

Mario Carneiro (Dec 02 2023 at 00:25):

yes, it's supposed to be enabled by default

Shreyas Srinivas (Dec 02 2023 at 11:36):

Stumbled into this issue with simp. Is there a shortcut to all simp using tactics that use the old configuration ? It breaks quite a few proofs for me (all fixed now, after some effort)

Scott Morrison (Dec 03 2023 at 02:19):

No, there is not. In future when making significant changes to tactic behaviour like this, we may add a set_option that gives a backwards compatibility mode. But we'll probably set it up to generate many warnings; it won't be an alternative to adapting to the new behaviour, just a helper.

Scott Morrison (Dec 03 2023 at 02:20):

I do hope someone looks at norm_num. It is probably just a one-liner fix.

Kyle Miller (Dec 03 2023 at 02:23):

One of the issues with norm_num back when simp was still doing decide was that this could cause norm_num to be slow because it was accidentally using a decide procedure rather than actually normalizing numbers. (And for something like equailty, that means it would be just applying rfl, which might be a heavy one.)

Maybe the fix is that norm_num should have a low-priority norm num extension for propositions that tries doing decide?

Kyle Miller (Dec 03 2023 at 02:28):

By the way, there's a declare_simp_like_tactic command to make your own simp with your own configuration. I've never used it, but I noticed it the other day.

Kyle Miller (Dec 03 2023 at 02:29):

That's how tactics like simp_arith are defined.

declare_simp_like_tactic simpArith "simp_arith " fun (c : Lean.Meta.Simp.Config) => { c with arith := true, decide := true }

Mario Carneiro (Dec 03 2023 at 05:40):

AFAIK norm_num should use its own algorithms by preference to decide when both are applicable. The only reason that situation should happen is if there is no norm_num extension for the function in question


Last updated: Dec 20 2023 at 11:08 UTC