Zulip Chat Archive

Stream: new members

Topic: Why does omega fail on this simple lemma?


Dylan Ede (Jun 13 2025 at 18:26):

import Mathlib

-- this works fine
lemma foo (a b : ) (h : 0 < a) : a * b = a * b - b + b := by
  rw [Nat.sub_add_cancel]
  apply Nat.le_mul_of_pos_left
  exact h

-- this does not
lemma foo' (a b : ) (h : 0 < a) : a * b = a * b - b + b := by
  omega

-- nor does this
lemma foo'' (a b : ) (h : 0 < a) : a * b = a * b - b + b := by
  linarith

Luigi Massacci (Jun 13 2025 at 18:37):

That goal is arguably out of scope for linarith (it is not really about linear arithmetic, and the naturals are already borderline for linarith).

Bjørn Kjos-Hanssen (Jun 13 2025 at 18:56):

ring helps a bit:

import Mathlib

lemma foo' (a b : ) (h : 0 < a) : a * b = a * b - b + b := by
  cases a <;> (ring_nf;omega) -- works

Dylan Ede (Jun 13 2025 at 19:32):

@Bjørn Kjos-Hanssen thanks. What's interesting is that that technique fails on an ever so slightly more complicated version and instead ring! does the trick:

import Mathlib

-- this works fine
lemma bar (a b : ) (h : 0 < a) : a * b = (a - 1) * b + b := by
  rw [Nat.sub_one_mul, Nat.sub_add_cancel]
  apply Nat.le_mul_of_pos_left
  exact h

-- this does not
lemma bar' (a b : ) (h : 0 < a) : a * b = (a - 1) * b + b := by
  cases a
  . contradiction
  . ring_nf
    omega -- FAILED

-- but this does
lemma bar'' (a b : ) (h : 0 < a) : a * b = (a - 1) * b + b := by
  cases a
  . contradiction
  . ring!

But ring! doesn't work on the original example.

Kenny Lau (Jun 13 2025 at 19:58):

The theory of (N, +, -, *) would seem to me to be completely equivalent to the usual theory of (N, +, *) (which I assume omega is based on), but maybe nobody has actually studied the decision algorithms for the first one yet? Especially since it's not a very "standard" system

Kenny Lau (Jun 13 2025 at 20:00):

I would assume that b + c = a -> a - b = c and a - b = 0 iff exists c, a + c = b would be the translations... oh but now it would increase the arithmetic complexity of the formula...

Kenny Lau (Jun 13 2025 at 20:00):

ok maybe they're not completely equivalent once you bring arithmetic complexity into the picture

Kenny Lau (Jun 13 2025 at 20:00):

maybe someone who knows more about proof theory can offer some pointers

Bjørn Kjos-Hanssen (Jun 13 2025 at 20:09):

That quantifier over c is bounded though (c is at most b), so it shouldn't really increase the complexity.

Robin Arnez (Jun 13 2025 at 20:13):

omega treats natural number subtraction like

b  a  (a - b) = a - b  a < b  (a - b) = 0

so basically ↑(a - b) = if b ≤ a then ↑a - ↑b else 0
(for reference: docs#Lean.Omega.Int.ofNat_sub_dichotomy).
grind does almost literally this, it uses:

if b + (-1) * x  0 then
  x + (-1) * y
else
  0

(docs#Int.Linear.natCast_sub)

Robin Arnez (Jun 13 2025 at 20:14):

so... case split

Kenny Lau (Jun 13 2025 at 20:23):

@Robin Arnez if omega has a correct translation of -, then why would it fail?

Markus Himmel (Jun 13 2025 at 20:25):

omega is a decision procedure for linear arithmetic, i.e., it can only reason about multiplication by constants.

Robin Arnez (Jun 13 2025 at 20:26):

Yes, it's not quite right to say omega supports +, - and * and it's better to say it supports +, - and * (constant)

Kenny Lau (Jun 13 2025 at 20:27):

I see, now I understand

Dylan Ede (Jun 13 2025 at 20:27):

Is this kind of problem within scope for grind?

Robin Arnez (Jun 13 2025 at 20:31):

No, as far as I know, grind only supports +, - and * (constant) (like omega) fully. Solving equations with variable by variable multiplication is a much harder problem

Robin Arnez (Jun 13 2025 at 20:34):

To be fair though, grind does support basic simplification similar to ring (in commutative rings, not e.g. Nat) like (a + b) ^ 2 = a^2 + 2*a*b + b^2


Last updated: Dec 20 2025 at 21:32 UTC