Zulip Chat Archive

Stream: mathlib4

Topic: Non-local behaviour in `abel`


Heather Macbeth (Jan 06 2023 at 06:19):

I am experiencing seemingly non-local behaviour in abel, and wondered if anyone else could reproduce it.

import Mathlib.Tactic.Abel

variable [Ring α]

lemma foo (a c : α) (f : α  α) :
    f a * c + f a - f (a * c + a) = f a * c - f (a * c) - (f (a * c + a) - f (a * c) - f a) := by
  abel

example (a : α) (c : ) (y z : ) (f : α  α)
    (hz : f a * c - f (a * c) = @Int.cast α Ring.toIntCast z)
    (hy : f (a * c + a) - f (a * c) - f a = y) :
     z : , f a * (Nat.succ c) - f (a * (Nat.succ c)) = z := by -- HERE
  use z - y
  rw [Nat.cast_succ, mul_add, mul_add, mul_one, mul_one]
  rw [Int.cast_sub,  hz,  hy]
  exact foo a c f

example (a : α) (c : ) (y z : ) (f : α  α)
    (hz : f a * c - f (a * c) = @Int.cast α Ring.toIntCast z)
    (hy : f (a * c + a) - f (a * c) - f a = y) :
     z : , f a * (Nat.succ c) - f (a * (Nat.succ c)) = z := by
  use z - y
  rw [Nat.cast_succ, mul_add, mul_add, mul_one, mul_one]
  rw [Int.cast_sub,  hz,  hy]
  abel -- fails with "Try this ..."
  done

Heather Macbeth (Jan 06 2023 at 06:20):

Where marked -- HERE, change ↑z to z. On my machine this makes the failure in the next example go away.

Heather Macbeth (Jan 06 2023 at 17:56):

:ping_pong: This behaviour persists for me today on fresh mathlib. Can anyone else reproduce it?

Kevin Buzzard (Jan 06 2023 at 18:38):

I can reproduce. Whatever is going on?

Heather Macbeth (Jan 06 2023 at 18:38):

@Mario Carneiro any ideas? This bug is pretty weird ...

Heather Macbeth (Jan 06 2023 at 18:41):

I tracked it down as a test case for something experienced by @Anatole Dedecker and me in mathlib4#1304.

Kevin Buzzard (Jan 06 2023 at 19:30):

import Mathlib.Tactic.Abel

variable [Ring α]

-- -- the evil example: uncomment me to break your definition!
-- example (a : α) (c : ℕ) (y z : ℤ) (f : α → α) :
--     f a * ↑c + f a - f (a * ↑c + a) = ↑(z - y) := by
--   sorry

def foo (a : α) (c : ) (y z : ) (f : α  α)
    (hz : f a * c - f (a * c) = @Int.cast α Ring.toIntCast z)
    (hy : f (a * c + a) - f (a * c) - f a = y) :
     z : , f a * (Nat.succ c) - f (a * (Nat.succ c)) = z := by
  use z - y
  rw [Nat.cast_succ, mul_add, mul_add, mul_one, mul_one]
  rw [Int.cast_sub,  hz,  hy]
  abel
  done

Live streaming on the discord

Kevin Buzzard (Jan 06 2023 at 19:37):

this can't happen, right?

import Mathlib.Tactic.Abel

variable [Ring α]

-- -- the evil example: uncomment me to break your definition!
-- example (a : α) (c : ℕ) (y z : ℤ) (f : α → α) :
--     f a * ↑c + f a - f (a * ↑c + a) = ↑(z - y) := by
--   sorry

-- -- I am the antidote -- uncomment me and your definition will work again!
-- def antidote (a : α) (c : ℕ) (y z : ℤ) (f : α → α)
--     (hy: f (a * ↑c + a) - f (a * ↑c) - f a = ↑y)
--     (hz: f a * ↑c - f (a * ↑c) = ↑z) :
--     f a * ↑c + f a - f (a * ↑c + a) = ↑(z - y) := by
--    rw [Int.cast_sub, ← hz, ← hy]
--    abel

def foo (a : α) (c : ) (y z : ) (f : α  α)
    (hz : f a * c - f (a * c) = @Int.cast α Ring.toIntCast z)
    (hy : f (a * c + a) - f (a * c) - f a = y) :
     z : , f a * (Nat.succ c) - f (a * (Nat.succ c)) = z := by
  use z - y
  rw [Nat.cast_succ, mul_add, mul_add, mul_one, mul_one]
  rw [Int.cast_sub,  hz,  hy]
  abel
  done

Kevin Buzzard (Jan 06 2023 at 19:38):

I'm assuming others can reproduce. I'm on Ubuntu 20.04.5 LTS

Kevin Buzzard (Jan 06 2023 at 19:38):

Lean (version 4.0.0-nightly-2023-01-04, commit 905d3204ae08, Release)

David Renshaw (Jan 06 2023 at 19:44):

I can reproduce the problem too.

David Renshaw (Jan 06 2023 at 19:46):

Same behavior with just able_nf, with narrows it down a bit I think.

David Renshaw (Jan 06 2023 at 20:03):

I'm trying looking at the output after doing

set_option trace.abel true
set_option trace.abel.detail true

Kevin Buzzard (Jan 06 2023 at 20:04):

import Mathlib.Tactic.Abel

variable [Ring α]

-- theorem uncommenting_me_breaks_foo (a : α) (c : ℕ) (f : α → α) : f a * ↑c + f a - f (a * ↑c + a)
--     = f a * ↑c - f (a * ↑c) - (f (a * ↑c + a) - f (a * ↑c) - f a) :=
-- Eq.trans
--   (sorry)
--   (Eq.symm
--     (Mathlib.Tactic.Abel.unfold_sub (f a * ↑c - f (a * ↑c)) (f (a * ↑c + a) - f (a * ↑c) - f a)
--       (Mathlib.Tactic.Abel.termg (-1) (f (a * ↑c + a))
--         (Mathlib.Tactic.Abel.termg 1 (f a) (Mathlib.Tactic.Abel.termg 1 (f a * ↑c) 0)))
--       (Mathlib.Tactic.Abel.subst_into_addg (f a * ↑c - f (a * ↑c)) (-(f (a * ↑c + a) - f (a * ↑c) - f a))
--         (Mathlib.Tactic.Abel.termg (-1) (f (a * ↑c)) (Mathlib.Tactic.Abel.termg 1 (f a * ↑c) 0))
--         (Mathlib.Tactic.Abel.termg (-1) (f (a * ↑c + a))
--           (Mathlib.Tactic.Abel.termg 1 (f (a * ↑c)) (Mathlib.Tactic.Abel.termg 1 (f a) 0)))
--         (Mathlib.Tactic.Abel.termg (-1) (f (a * ↑c + a))
--           (Mathlib.Tactic.Abel.termg 1 (f a) (Mathlib.Tactic.Abel.termg 1 (f a * ↑c) 0)))
--         (Mathlib.Tactic.Abel.unfold_sub (f a * ↑c) (f (a * ↑c))
--           (Mathlib.Tactic.Abel.termg (-1) (f (a * ↑c)) (Mathlib.Tactic.Abel.termg 1 (f a * ↑c) 0))
--           (Mathlib.Tactic.Abel.subst_into_addg (f a * ↑c) (-f (a * ↑c)) (Mathlib.Tactic.Abel.termg 1 (f a * ↑c) 0)
--             (Mathlib.Tactic.Abel.termg (-1) (f (a * ↑c)) 0)
--             (Mathlib.Tactic.Abel.termg (-1) (f (a * ↑c)) (Mathlib.Tactic.Abel.termg 1 (f a * ↑c) 0))
--             (Mathlib.Tactic.Abel.term_atomg (f a * ↑c))
--             (Mathlib.Tactic.Abel.subst_into_negg (f (a * ↑c)) (Mathlib.Tactic.Abel.termg 1 (f (a * ↑c)) 0)
--               (Mathlib.Tactic.Abel.termg (-1) (f (a * ↑c)) 0) (Mathlib.Tactic.Abel.term_atomg (f (a * ↑c)))
--               (Mathlib.Tactic.Abel.term_neg 1 (f (a * ↑c)) 0 (-1) 0 (Eq.refl (-1)) neg_zero))
--             (Mathlib.Tactic.Abel.const_add_termg (Mathlib.Tactic.Abel.termg 1 (f a * ↑c) 0) (-1) (f (a * ↑c)) 0
--               (Mathlib.Tactic.Abel.termg 1 (f a * ↑c) 0) (add_zero (Mathlib.Tactic.Abel.termg 1 (f a * ↑c) 0)))))
--         (sorry)
--         (sorry))))


def foo (a : α) (c : ) (y z : ) (f : α  α)
    (hz : f a * c - f (a * c) = @Int.cast α Ring.toIntCast z)
    (hy : f (a * c + a) - f (a * c) - f a = y) :
     z : , f a * (Nat.succ c) - f (a * (Nat.succ c)) = z := by
  use z - y
  rw [Nat.cast_succ, mul_add, mul_add, mul_one, mul_one]
  rw [Int.cast_sub,  hz,  hy]
  abel
  done

I need to go now. I took the other route and tried to see which part of the term it was generating was causing the problem. Maybe the above helps? I need to go and make dinner for 4 now though, so I'll be gone a while.

Kevin Buzzard (Jan 06 2023 at 20:06):

Last few things: when abel fails the goal becomes

f a * c + (f a + -1  f (a * c + a)) = f a + (f a * c + -1  f (a * c + a))

so some simp lemma might have kicked in or not kicked in? And even better, abel suggests abel_nf, which closes the goal ;-)

Kevin Buzzard (Jan 06 2023 at 21:47):

import Mathlib.Tactic.Abel

variable [Ring α]

-- theorem uncommenting_me_breaks_foo (x : α) :
--   -x = (-1 : ℤ) • (x) + (0 : α) := sorry

def foo (a : α) (c : ) (y z : ) (f : α  α)
    (hz : f a * c - f (a * c) = @Int.cast α Ring.toIntCast z)
    (hy : f (a * c + a) - f (a * c) - f a = y) :
     z : , f a * (Nat.succ c) - f (a * (Nat.succ c)) = z := by
  use z - y
  rw [Nat.cast_succ, mul_add, mul_add, mul_one, mul_one]
  rw [Int.cast_sub,  hz,  hy]
  abel
  done

Kevin Buzzard (Jan 06 2023 at 21:53):

So abel seems to be using the theorem uncommenting_me_breaks_foo. It turns the goal

f a * c + f a - f (a * c + a) = f a * c - f (a * c) - (f (a * c + a) - f (a * c) - f a)

into the goal

f a * c + (f a + -1  f (a * c + a)) = f a + (-1  f (a * c + a) + f a * c)

if uncommenting_me_breaks_foo : -x = (-1 : ℤ) • (x) + (0 : α) is declared, and then it gets lost. It would be interesting to check which tags uncommenting_me_breaks_foo has, I'm assuming none, but you never can tell with Lean 4. I think that now someone who knows something about linarith has to take over.

David Renshaw (Jan 06 2023 at 21:57):

what does this have to do with linarith?

Heather Macbeth (Jan 06 2023 at 21:58):

Probably a typo for abel? @Kevin Buzzard

Mario Carneiro (Jan 06 2023 at 23:31):

abel, unlike ring, does not use a list of atoms as state to deduplicate defeq terms, it uses Expr.quickLt which compares the hashes of the expressions. In particular, this makes it sensitive to changes in FVarId naming, which makes atom ordering nondeterministic. So this explains why a change in an unrelated example can cause the tactic to behave differently.

Mario Carneiro (Jan 06 2023 at 23:32):

What it doesn't explain is why it doesn't always find the proof, because even if atom ordering is nondeterministic it should still be consistent over a given run

Mario Carneiro (Jan 06 2023 at 23:34):

Here's the trace from the working invocation (edited for clarity):

[abel] running on an equality `f a * c + f a - f (a * c + a) = f a * c - f (a * c) - (f (a * c + a) - f (a * c) - f a)`.

[abel] found a proof that `f a * c + f a - f (a * c + a) =
    Mathlib.Tactic.Abel.termg (-1) (f (a * c + a))
      (Mathlib.Tactic.Abel.termg 1 (f a * c) (Mathlib.Tactic.Abel.termg 1 (f a) 0))`

[abel] found a proof that `f a * c - f (a * c) - (f (a * c + a) - f (a * c) - f a) =
    Mathlib.Tactic.Abel.termg (-1) (f (a * c + a))
      (Mathlib.Tactic.Abel.termg 1 (f a * c) (Mathlib.Tactic.Abel.termg 1 (f a) 0))`

[abel] verified that the simplified forms are identical

and the trace from the failing version:

[abel] running on an equality `f a * c + f a - f (a * c + a) = f a * c - f (a * c) - (f (a * c + a) - f (a * c) - f a)`.

[abel] found a proof that `f a * c + f a - f (a * c + a) =
    Mathlib.Tactic.Abel.termg 1 (f a * c)
      (Mathlib.Tactic.Abel.termg (-1) (f (a * c + a)) (Mathlib.Tactic.Abel.termg 1 (f a) 0))`

[abel] found a proof that `f a * c - f (a * c) - (f (a * c + a) - f (a * c) - f a) =
    Mathlib.Tactic.Abel.termg 1 (f a * c)
      (Mathlib.Tactic.Abel.termg 1 (f a) (Mathlib.Tactic.Abel.termg (-1) (f (a * c + a)) 0))`

As you can see, the atom ordering is different in the two cases, but the weird part is that the atom ordering is different even just for the two sides of the second equation.

Mario Carneiro (Jan 07 2023 at 00:24):

mathlib4#1394

Heather Macbeth (Jan 07 2023 at 01:00):

Thank you Mario.


Last updated: Dec 20 2023 at 11:08 UTC