Zulip Chat Archive
Stream: mathlib4
Topic: bug in ring?
Jireh Loreaux (Jul 07 2023 at 19:34):
@Mario Carneiro is this a bug in ring
, or am I misunderstanding something? The call to ring
succeeds and closes the goal, but it asks to try ring_nf
. So ring1
fails to close the goal, but ring_nf
does? I was under the impression that this shouldn't happen.
import Mathlib -- I'm lazy
example (x y : ℝ) : max x 0 + max y 0 + (-(y + x) + max (y + x) 0) -
(-x + max x 0 + (-y + max y 0) + max (x + y) 0) = 0 := by
ring -- Try this: ring_nf
-- also: no goals
Mario Carneiro (Jul 07 2023 at 22:40):
this can certainly happen, that's why it makes the suggestion
Mario Carneiro (Jul 07 2023 at 23:14):
in this case it's because you need to unify the x + y
and y + x
inside max
Kevin Buzzard (Aug 25 2023 at 12:16):
This is happening to a student of mine. At the end of the day I am very confused why ring
can ever both (a) close a goal and (b) tell the user they should be using another tactic instead. My student's work has 5 blue outputs telling them that they should be using ring_nf
for no obvious reason. Both ring
and ring_nf
close all 5 goals. Is this expected behaviour?
Ruben Van de Velde (Aug 25 2023 at 12:17):
Are they situation where ring
works on a subexpression of the goal, not the entire goal?
Alex J. Best (Aug 25 2023 at 12:21):
I think this is expected, it is maybe also a hint that you are using ring
which is a finishing tactic, in a potentially nonfinishing way.
Kevin Buzzard (Aug 25 2023 at 13:42):
But ring
is closing the goals. It's just moaning anyway.
Alex J. Best (Aug 25 2023 at 13:44):
That's why I said _potentially_ the difference is whether ring is being asked to prove an equality of rings (which it should finish on every time if the goal is a ring identity). Or just normalize all ring expressions it finds as subexpressions of the goal, which may happen to prove the goal but ring
has no guarentee of doing so
Mario Carneiro (Aug 25 2023 at 13:44):
when ring
moans about calling another tactic, it also calls that tactic itself
Mario Carneiro (Aug 25 2023 at 13:45):
it's just saying "you must have called me by mistake, here I'll call that tactic you meant to say but you may as well call that other tactic yourself"
Kevin Buzzard (Aug 25 2023 at 13:48):
I am very unclear about why ring
is telling me that I should not be using it when it is closing the goal.
Kevin Buzzard (Aug 25 2023 at 13:49):
Is this situation unique to ring
?
Mario Carneiro (Aug 25 2023 at 13:51):
simpa
does this too
Mario Carneiro (Aug 25 2023 at 13:52):
it's basically a lint
Mario Carneiro (Aug 25 2023 at 13:52):
polyrith
too
Kevin Buzzard (Aug 25 2023 at 13:58):
So I just tell the student to change to the "non-finishing tactic" ring_nf
and ignore the fact that it closes the goal despite the existence of this tactic being precisely because we want a non-finishing ring
?
Mario Carneiro (Aug 25 2023 at 13:58):
nf stands for normal form, not non-finishing
Mario Carneiro (Aug 25 2023 at 13:59):
it can close goals
Alex J. Best (Aug 25 2023 at 13:59):
Probably if they want to write a very maintainable proof it should be something like congr; ring
. Do you have examples you are thinking of?
Yaël Dillies (Aug 25 2023 at 13:59):
I thought the point of the normal form version of ring
was to use it in non-finishing contexts?
Mario Carneiro (Aug 25 2023 at 14:00):
it is not necessarily finishing
Kevin Buzzard (Aug 25 2023 at 14:00):
Right! I get the impression that we're told that ring_nf
has a second usage, namely to shut ring
up when it closes the goal but randomly complains.
Mario Carneiro (Aug 25 2023 at 14:01):
ring didn't close the goal, it failed and then called ring_nf
which closed the goal
Kevin Buzzard (Aug 25 2023 at 14:01):
ring
closed the goal in the sense that I ran ring
and the goal was closed.
Yaël Dillies (Aug 25 2023 at 14:01):
Okay, but then what is ring_nf
if not a subprocess of ring
?
Kevin Buzzard (Aug 25 2023 at 14:01):
I don't see the logic here. If you want ring
to fail then why not just let it fail?
Mario Carneiro (Aug 25 2023 at 14:02):
because otherwise you might not realize (1) that ring_nf
exists and (2) it closes your goal
Kevin Buzzard (Aug 25 2023 at 14:02):
By this logic why don't we have every tactic calling ring_nf
if it fails?
Yaël Dillies (Aug 25 2023 at 14:02):
In my mind, ring
is a big machine, calling several (sub)tactics, one of which is ring_nf
. Is my mental picture wrong?
Mario Carneiro (Aug 25 2023 at 14:02):
the version that fails and does not play games with ring_nf is called ring1
Kevin Buzzard (Aug 25 2023 at 14:03):
Great, so let's redefine rw
to be try rw; ring_nf
and have a new tactic rw1
which is the old rw
.
Mario Carneiro (Aug 25 2023 at 14:04):
This is just like tidy
, the simple to call tactic does a bunch of things, maybe more than you really ought to leave in a completed proof
Mario Carneiro (Aug 25 2023 at 14:05):
as an aside, rw
is already doing a similar thing
Mario Carneiro (Aug 25 2023 at 14:05):
it calls rfl
at the end, and you need rewrite
if you don't want the trailing rfl
Kyle Miller (Aug 25 2023 at 14:06):
That's a bit different though, since rw []
solving a goal by rfl
doesn't report any suggestion
Mario Carneiro (Aug 25 2023 at 14:06):
although it doesn't bug you about the difference since it's using a weak rfl
Eric Wieser (Aug 25 2023 at 14:06):
@Kevin Buzzard, I think the thing to realize is that ring
used to not complain at all, but they we decided "actually, it shouldn't be used on these goals at all". Instead of changing it to fail, which would be very annoying for new users, we changed it to complain and tell them to write something eles which is less annoying.
Alex J. Best (Aug 25 2023 at 14:06):
Kyle Miller said:
That's a bit different though, since
rw []
solving a goal byrfl
doesn't report any suggestion
it probably should imo
Kyle Miller (Aug 25 2023 at 14:06):
Maybe when ring
calls ring_nf
and it succeeds, it should fail with the helpful suggestion that ring_nf
would succeed?
Kevin Buzzard (Aug 25 2023 at 14:06):
If ring
is just like tidy
then are you suggesting that it should never occur in any mathlib code and should always be replaced by ring_nf
, like tidy
should be replaced with the output of tidy?
?
Mario Carneiro (Aug 25 2023 at 14:07):
ring
could certainly dress its suggestion up in the style of a linter warning
Kevin Buzzard (Aug 25 2023 at 14:08):
Right now the situation is that ring
sometimes happily closes goals with no complaints, and sometimes closes goals with complaints, and sometimes doesn't close goals and complains. I think this makes it unique: none of the other suggestions of "tactics which are like ring
" above have such a wide range of possibilities.
Mario Carneiro (Aug 25 2023 at 14:08):
when ring
succeeds, it is basically equivalent to ring1
(and it doesn't waste its time doing something else) so there isn't much value in suggesting ring1
there unless you are interested in using it for control flow
Eric Wieser (Aug 25 2023 at 14:09):
Mario, is my claim above that this was a backwards-compatibility feature correct?
Kyle Miller (Aug 25 2023 at 14:09):
Mario Carneiro said:
ring
could certainly dress its suggestion up in the style of a linter warning
Why a linter warning and not a full error? It seems like ring
's suggestion to use ring_nf
is more of a pointer to the user for what to try instead, and it's nice of it to try ring_nf
for you ahead of offering the suggestion.
Mario Carneiro (Aug 25 2023 at 14:09):
@Eric Wieser I believe so
Mario Carneiro (Aug 25 2023 at 14:10):
I suppose it could be an error, although that's an interesting combination of diagnostics
Mario Carneiro (Aug 25 2023 at 14:10):
since we have an error on top of an info message on top of an interesting final state
Mario Carneiro (Aug 25 2023 at 14:11):
(the final state is important because it shows the uncancelled terms)
Kevin Buzzard (Aug 25 2023 at 14:13):
Kevin Buzzard said:
Right now the situation is that
ring
sometimes happily closes goals with no complaints, and sometimes closes goals with complaints, and sometimes doesn't close goals and complains. I think this makes it unique: none of the other suggestions of "tactics which are likering
" above have such a wide range of possibilities.
Aah, this is false: simpa
also has this property (sometimes it will close the goal and tell the user to use simp
instead).
Kyle Miller (Aug 25 2023 at 14:23):
Yaël Dillies said:
In my mind,
ring
is a big machine, calling several (sub)tactics, one of which isring_nf
. Is my mental picture wrong?
Yes, that's not how it works. The ring1
tactic is monolithic, and all it does is take both sides of an equality, evaluate them into a normal form, and if both sides are the same, it generates a proof of the original equality. The ring_nf
tactic uses the internals of ring1
and simp
to evaluate subexpressions into a normal form, where it evaluates the expressions into a normal form to rewrite the expression.
Then this is the ring
tactic:
macro (name := ring) "ring" : tactic =>
`(tactic| first | ring1 | ring_nf; trace "Try this: ring_nf")
Kyle Miller (Aug 25 2023 at 14:25):
Both ring1
and ring_nf
share the ring expression normalizer, but ring_nf
has code supporting it that ring1
doesn't have.
Last updated: Dec 20 2023 at 11:08 UTC