Zulip Chat Archive
Stream: mathlib4
Topic: nat fighting
James Gallicchio (Jul 06 2024 at 02:06):
Kim recently used the term "nat-fighting" and I really like the phrase :) I'm gonna use this thread to document any goals over nat that IMO should be within the scope of automation (let me know if there's a similar thread I should be sending these instead!)
James Gallicchio (Jul 06 2024 at 02:08):
first MWE:
import Mathlib
example (i j k l : Nat)
: i * j + k + l - k = i * j + l
:= by
try omega
try linarith
try aesop
sorry
My manual proof would be something like
rw [Nat.add_assoc, Nat.add_comm k, ← Nat.add_assoc]
simp
James Gallicchio (Jul 06 2024 at 02:29):
MWE 2 (I am trying the same tactics for all of these)
example (i j k : Nat) : i ≤ j * i + i + k := by
sorry
manual proof something like
rw [Nat.add_comm _ i, Nat.add_assoc]; simp
James Gallicchio (Jul 06 2024 at 02:35):
MWE 3
example (i j k : Nat) : i ≤ i + j * j + k := by sorry
manually
apply Nat.le_add_right_of_le
simp
James Gallicchio (Jul 06 2024 at 02:36):
My experience with omega has been very positive but I also have no idea how it works internally, so I'm surprised omega
does not work but only because it works on so many problems :big_smile:
Damiano Testa (Jul 06 2024 at 02:40):
James Gallicchio said:
first MWE:
import Mathlib example (i j k l : Nat) : i * j + k + l - k = i * j + l := by try omega try linarith try aesop sorry
My manual proof would be something like
rw [Nat.add_assoc, Nat.add_comm k, ← Nat.add_assoc] simp
You can also do
import Mathlib
example (i j k l : Nat)
: i * j + k + l - k = i * j + l
:= by
move_add [k]
exact? says exact Nat.add_sub_self_right (i * j + l) k
Damiano Testa (Jul 06 2024 at 02:44):
The others can also follow a similar pattern:
import Mathlib
example (i j k : Nat) : i ≤ j * i + i + k := by
move_add [i]
exact? says exact Nat.le_add_left i (j * i + k)
example (i j k : Nat) : i ≤ i + j * j + k := by
move_add [i]
exact? says exact Nat.le_add_left i (j * j + k)
Damiano Testa (Jul 06 2024 at 02:45):
In case this is not clear: I would love for these to be further automated! Automating proofs with this kind of rearranging was one of my motivations for writing move_add
!
James Gallicchio (Jul 06 2024 at 02:46):
move_add
is a life-saver for doing these manually, thanks for the heads up
James Gallicchio (Jul 06 2024 at 02:49):
oh wait, maybe this is why omega
isn't working here?
example (i : Nat) : i * i ≥ 0 := by
omega -- fails
If I add such lemmas then the proof proceeds fine.
example (i j k : Nat) : i ≤ i + j * j + k := by
have : j * j ≥ 0 := Nat.zero_le (j * j)
omega
Damiano Testa (Jul 06 2024 at 02:53):
I do not know the internals of omega
, but I am a little surprised that it helps to mention that a Nat is non-negative!
Damiano Testa (Jul 06 2024 at 02:57):
Judging from the error message, it seems to convert to Int before doing something. Maybe there is an option to add the Nat.zero_le
inequalities for the various Int
-coerced Nat
s.
James Gallicchio (Jul 06 2024 at 02:58):
It's to do with the multiplication:
example (i : Nat) : i ≥ 0 := by
omega -- works
example (i : Nat) : i * i ≥ 0 := by
omega -- fails
example (i : Int) : i ≥ 0 → i * i ≥ 0 := by
intro; omega -- fails
I think omega
might be able to add constraints to characterize multiplication sufficiently appropriately here though?
Damiano Testa (Jul 06 2024 at 03:02):
The doc-string does say that it is for linear problems (and without some constraints the general problem is undecidable). I also know that omega
makes an effort to work with constant multiples (e.g. try replacing one of the factors to a constant). However, maybe omega
could consider products of variables as atoms.
James Gallicchio (Jul 06 2024 at 03:04):
Yeah, all three MWEs I listed are linear if you choose the right expressions to fix as constants
James Gallicchio (Jul 06 2024 at 03:05):
:shrug: and maybe I'm expecting omega to do too much. I watched an isabelle user live-code last week and have been feeling greedy ever since.
Damiano Testa (Jul 06 2024 at 03:06):
I do not know if this is indeed in scope for omega
, but I definitely feel that it should be in scope for something!
James Gallicchio (Jul 06 2024 at 03:07):
I think it would be good to compile lots of these nat-fighting examples to build up a little test suite for more automation. So if anyone has more examples please do share!!
Damiano Testa (Jul 06 2024 at 03:15):
Maybe you can find examples looking for uses of docs#Nat.add_sub_assoc. Whenever I had to use that lemma I wished for more automation.
Peter Nelson (Jul 06 2024 at 03:50):
This is probably (definitely) scope creep, but I think it would also be nice to have the potential automation being discussed also work for ENat
, which is still pretty rough around the edges in its API.
Kim Morrison (Jul 06 2024 at 21:40):
The examples above definitely represent a bug in omega
(presumably in the preprocessor rather than the actual elimination algorithm) that I will try to fix asap!
We have to do some processing of terms with multiplications, just to identify scalar multiplications, but omega should certainly understand that i * j
is nonnegative!
Kim Morrison (Jul 08 2024 at 21:45):
Well, I'm not sure it is a bug after all, but I've slightly tweaked the handling of products so these examples work: lean#4695.
Note that there is a lot that omega
could be doing with atoms-that-are-products that it does not do. For example
example (i j : Nat) : i * j = j * i := by omega -- fails
is out of scope for omega
.
Kevin Buzzard (Jul 08 2024 at 21:58):
Somehow this doesn't surprise me. My mental model is addition, subtraction and multiplication by numerical constants. Isn't that what the spec is?
Kim Morrison (Jul 08 2024 at 22:01):
Yes. The change I've made is that when it tries pushing the Nat->Int coercion over multiplication, it now checks if the result is an atom, and if it is, it cancels the push.
This means that i * i
stays as an atom (which is then manifestly non-negative) rather than being converted into (i : Int) * (i : Int)
(which is not).
Last updated: May 02 2025 at 03:31 UTC