Zulip Chat Archive
Stream: mathlib4
Topic: flexible vs rigid tactics
Yaël Dillies (Mar 19 2024 at 17:58):
I think all the tactic combinators like done
, skip
, try
, any_goals
, all_goals
should be allowed
Damiano Testa (Mar 19 2024 at 18:00):
Ok, I think that the way in which the "following tactic" is selected means that the tactic following the combinator will be flagged as well (unless it is whitelisted). This is the intended behaviour, right? I.e., the combinator should not be a stop-gag, just a see-through tactic that passes on the decision to the next one.
Do you agree?
Yaël Dillies (Mar 19 2024 at 18:03):
I don't really like the current logic of your linter. I think a more pertinent logic would be to mark locations (hypotheses/goals) as "non-squeezedly simped" and forbidding "rigid" tactics from using those assumptions
Yaël Dillies (Mar 19 2024 at 18:04):
Eg this should be allowed:
simp at h0
rw [h1] at h2
but neither of these should
simp at h0
rw [h1] at h0
simp at h0
rw [h0] at h1
Damiano Testa (Mar 19 2024 at 18:04):
Yaël, I do not really understand what you are proposing... what is a "non-squeezedly simped" location?
Damiano Testa (Mar 19 2024 at 18:05):
Maybe I should specify: currently, the "next tactic" is "the next tactic that acts on a goal that a simp
produced".
Damiano Testa (Mar 19 2024 at 18:05):
It is not the next tactic that you type.
Damiano Testa (Mar 19 2024 at 18:05):
(or rather, it need not be, although often it will be.)
Yaël Dillies (Mar 19 2024 at 18:06):
That sounds really brittle. That means that
simp
rw [h]
is forbidden but
simp
ring
rw [h]
is not
Yaël Dillies (Mar 19 2024 at 18:06):
Do you understand my proposition better now?
Damiano Testa (Mar 19 2024 at 18:08):
Yes, I think that I understand. You would like something like a cache of "after simp
locations" that are only allowed actions by "flexible" tactics, including simp, ring,...
, but, for instance, not rw
.
Damiano Testa (Mar 19 2024 at 18:08):
I wonder whether this should come after a first implementation of the linter, though...
Damiano Testa (Mar 19 2024 at 18:09):
This seems more like a "non-terminal flexible tactic
follower" linter to me.
Yaël Dillies (Mar 19 2024 at 18:09):
I think it's worth exploring! If we merge your linter now, we're at risk of teachings seas of beginners the wrong style
Damiano Testa (Mar 19 2024 at 18:09):
This is certainly a very good suggestion, but I think that focusing on simp
might already be productive.
Yaël Dillies (Mar 19 2024 at 18:10):
Damiano Testa said:
This seems more like a "non-terminal
flexible tactic
follower" linter to me.
Yes, that's exactly what it is, because simp is really no special here
Damiano Testa (Mar 19 2024 at 18:10):
Yaël Dillies said:
I think it's worth exploring! If we merge your linter now, we're at risk of teachings seas of beginners the wrong style
Ok, this is possible, but it is also possible that they can then learn a better style later on.
Yaël Dillies (Mar 19 2024 at 18:10):
Mathport experience would like to disagree...
Yaël Dillies (Mar 19 2024 at 18:11):
I claim that the correct implementation is so different to your current one that it's not worth trying to incrementally get to the correct one from yours
Damiano Testa (Mar 19 2024 at 18:11):
Ok, so maybe the tactics that I am placing in the whitelist should be all allowed and should never be followed by anything else.
This is probably not that hard to implement, although I have not really given this much thought.
Yaël Dillies (Mar 19 2024 at 18:12):
Also, you already ripped out most of the benefits from your linter by PRing fixes to the errors you found locally
Yaël Dillies (Mar 19 2024 at 18:12):
More errors will come, but only with a better logic
Damiano Testa (Mar 19 2024 at 18:12):
Yaël Dillies said:
I claim that the correct implementation is so different to your current one that it's not worth trying to incrementally get to the correct one from yours
The current suggestion is very far from v1 of the linter, not, I think, from v2 that I am testing right now.
Yaël Dillies (Mar 19 2024 at 18:12):
I think you should not allow specific tactics but instead disallow specific rigid tactics
Damiano Testa (Mar 19 2024 at 18:13):
Yaël Dillies said:
Also, you already ripped out most of the benefits from your linter by PRing fixes to the errors you found locally
Very few of those PRs have been merged and have conflicts now. I am planning to close them, if the newer version of the linter is definitely an improvement.
Damiano Testa (Mar 19 2024 at 18:14):
Yaël Dillies said:
I think you should not allow specific tactics but instead disallow them
As I am thinking of this right now, there are only two categories, right? The category of tactics that can only act on goals on which a flexible tactic has not yet acted, and the flexible tactics, right? You are saying that a tactic if automatically flexible, unless it is blacklisted?
Yaël Dillies (Mar 19 2024 at 18:15):
Nono, sorry I clarified
Damiano Testa (Mar 19 2024 at 18:15):
(the two perspective are easy to implement, it seems to be that we are simply deciding what the default category of each tactic is)
Yaël Dillies (Mar 19 2024 at 18:16):
The default should be rigid. This is what I'm claiming
Damiano Testa (Mar 19 2024 at 18:16):
Ok, I agree. By default, everything is like rw
(which I consider the default rigid tactic).
Damiano Testa (Mar 19 2024 at 18:17):
And if a goal/location has been produced/touched by a flexible tactic, then only flexible tactics are allowed to touch it.
Yaël Dillies (Mar 19 2024 at 18:17):
... or use it!
Damiano Testa (Mar 19 2024 at 18:18):
(the "location part" I am not too sure about -- the current linter is implemented thinking about goals, but the linting framework does have access to the context.)
Yaël Dillies (Mar 19 2024 at 18:18):
Actually, it's not merely "touched by a flexible tactic" that's bad but "potentially touched"
Damiano Testa (Mar 19 2024 at 18:19):
"potentially touched" might include everything, though? Do you mean that simp_all
makes everything flexible, even if it actually just modifies one hypothesis?
Yaël Dillies (Mar 19 2024 at 18:19):
So the correct rule is:
Only flexible tactics are allowed to target or use locations which have been previously been targeted by flexible tactics (regardless of whether said flexible tactics actually changed those locations)
Yaël Dillies (Mar 19 2024 at 18:21):
Yes, simp at *
means that no rigid tactic can target anything in that context anymore. If you then do have := something_not_from_context
, that can be touched by a rigid tactic however,
Damiano Testa (Mar 19 2024 at 18:21):
I understand your point, although I wonder whether this requires knowledge of what each tactic could do... E.g., when you see a simp
, you should figure out whether it is at
and what the at
locations are. I think that this would be very hard to maintain as a linter.
Yaël Dillies (Mar 19 2024 at 18:21):
Yes, but luckily there aren't many flexible tactics
Yaël Dillies (Mar 19 2024 at 18:22):
Regardless, information on targeted locations should be part of the tactic framework long term
Damiano Testa (Mar 19 2024 at 18:22):
To avoid scope-creep, what do you think of focusing on goals, rather than locations, to begin with?
Yaël Dillies (Mar 19 2024 at 18:23):
I don't see how that could give you anything sensible
Yaël Dillies (Mar 19 2024 at 18:23):
There are too many ways the goal-based heuristic could go wrong
Damiano Testa (Mar 19 2024 at 18:25):
Yaël Dillies said:
There are too many ways the goal-based heuristic could go wrong
While this is true, I also think that for most proofs, the goal heuristic is actually good.
Yaël Dillies (Mar 19 2024 at 18:26):
Yes, but I really really do not want false linter positives
Damiano Testa (Mar 19 2024 at 18:26):
(Also, I am aware of my abilities and, while I can see myself coding the linter with locations and all, I can also see the result as being unusably slow...)
Damiano Testa (Mar 19 2024 at 18:27):
Yaël Dillies said:
Yes, but I really really do not want false linter positives
You can view it as "Every silencing of the linter is a todo"...
Damiano Testa (Mar 19 2024 at 18:28):
I am going to move all this conversation to a separate topic, is that alright?
Damiano Testa (Mar 19 2024 at 18:29):
(assuming that I can...)
Notification Bot (Mar 19 2024 at 18:31):
49 messages were moved here from #mathlib4 > simp
followers by Damiano Testa.
Damiano Testa (Mar 19 2024 at 18:33):
Ok, to seriously implement this rigid vs flexible linter, I need to see what kind of information hides in the MetavarContext
that the linter offers.
Damiano Testa (Mar 19 2024 at 18:44):
Just to be clear, what you are suggesting is that, after a flexible tactic that potentially changes all locations, that metavariable can (almost) only be closed by flexible tactics: e.g. assumption, tauto, linarith,..., have+something else,...
and have
or something similar is the only way in which rigid tactics can play again there, and then only on the new hypotheses that have been introduced.
Damiano Testa (Mar 19 2024 at 18:46):
I agree that this would make proofs much less brittle. It may also be somewhat of an added burden to write proofs in this "flexible-vs-rigid" style.
Yaël Dillies (Mar 19 2024 at 19:56):
I don't think it will be much burden since this is already how we write most proofs
Damiano Testa (Mar 30 2024 at 13:02):
Some iteration of the "non-terminal simp
" linter produces the output below. Currently, the linter only looks at simp
and simp_all
, but this is easy to expand. What the linter is supposed to do is check if some tactics that are likely to break with small changes to the simp
output follow simp
.
The linter makes an effort to flag simp at h; rw [h]
as well as simp at h; rw at h
.
The lnter should not flag simp at h1; rw [h2] at h3
, assuming that h1
is different from h2, h3
.
Linted
Damiano Testa (Mar 30 2024 at 13:02):
Let me know if something from the output above looks like something that the linter should handle differently (i.e. should allow it).
[I gave one line of context before each flag, which sometimes may not be enough to reconstruct what the issue was.]
Yaël Dillies (Mar 30 2024 at 13:25):
I'm not sure about the induction as with simp
thing. Is simp
not an identifier there?
Yaël Dillies (Mar 30 2024 at 13:26):
I assume that in the RingTheory.Polynomial
Cyclotomic.Eval
example the above tactic is a simp operating on the goal that's focused?
Yaël Dillies (Mar 30 2024 at 13:27):
simp [q_zero]
by_cases p_zero : p = 0
should be legal since by_cases
doesn't operate on the goal.
Yaël Dillies (Mar 30 2024 at 13:28):
Similarly for the Probability.Kernel.Disintegration.Density
one
Ruben Van de Velde (Mar 30 2024 at 13:35):
No, induction as with simp
runs simp
on each of the new subgoals
Yaël Dillies (Mar 30 2024 at 13:50):
That's quite confusing given the induction'
syntax :thinking:
Damiano Testa (Mar 30 2024 at 15:42):
Yaël Dillies said:
simp [q_zero] by_cases p_zero : p = 0
should be legal since
by_cases
doesn't operate on the goal.
Yes, there are still some rough edges around flagging simp
when a new goal is created by the tactic.
However, what I pasted there is the first failure in each file with basically no extra filter, so this is promising!
Damiano Testa (Apr 01 2024 at 16:08):
The "flexible" linter is essentially ready: #11821
The PR above only defines the linter and adds a test file: the linter is not running on any file other than the test.
There is a separate PR where I added the linter to most of mathlib: you can find it here: #11822.
Here is a gist with the linter warnings from a separate run: there are approximately 230 files that the linter flags. I scanned quickly a few of them and the linter seems to be doing its job!
Damiano Testa (Apr 01 2024 at 16:10):
One situation that the linter does not handle correctly is the following:
example (h : 0 = 0) : True := by
simp at h -- h : True
assumption
Clearly, assumption
is using h
, but since h
is not part of the syntax of the tactic, the linter is unaware of that.
The linter does flag
example (h : 0 = 0) : True := by
simp at h -- h : True
exact h
Damiano Testa (Apr 01 2024 at 16:11):
Btw, if anyone feels like going through the gist above and knock down a few non-terminal simps, I would be more than thrilled!
Damiano Testa (Apr 01 2024 at 16:12):
(Also, while the whole setup would allow tactics other than simp
to be flexible, I am only linting simp
at the moment: already as it, it will be quite a lot of work to make mathlib
compliant.)
Damiano Testa (Apr 02 2024 at 09:02):
While going through some of the lints, this is the most controversial that I found so far: is the pattern
... <;> simp <;> split_ifs <;> simp
acceptable? What if the final simp
is exact
or rw
?
Damiano Testa (Apr 02 2024 at 09:04):
I personally am not a huge fan of the <;>
-combinator, because I usually value more clarity than saving space and I find that it more often obscures, rather than explain.
In some cases, my solution has been to unlint, in others to squeeze, in others still to split the <;>
combinators, depending on context.
Yaël Dillies (Apr 02 2024 at 09:05):
Damiano Testa said:
While going through some of the lints, this is the most controversial that I found so far: is the pattern
... <;> simp <;> split_ifs <;> simp
acceptable? What if the final
simp
isexact
orrw
?
Surely that's fine iff the final tactic is flexible?
Damiano Testa (Apr 02 2024 at 09:06):
Well, if
could in theory be resolved by a better simp
and then split_ifs
would fail.
Damiano Testa (Apr 02 2024 at 09:07):
I am not sure that I consider split_if
flexible. Are you saying that split_ifs
should simply be allowed as a simp
follower?
Yaël Dillies (Apr 02 2024 at 09:08):
I think split_ifs
is neither flexible nor rigid. It's just a combinator
Yaël Dillies (Apr 02 2024 at 09:08):
Damiano Testa said:
Well,
if
could in theory be resolved by a bettersimp
and thensplit_ifs
would fail.
In that case, you just remove the combinator, which should be a pretty obvious step to take
Mario Carneiro (Apr 02 2024 at 09:09):
Damiano Testa said:
Well,
if
could in theory be resolved by a bettersimp
and thensplit_ifs
would fail.
Most flexible tactics have this behavior
Mario Carneiro (Apr 02 2024 at 09:09):
simp can always produce something that the next tactic can't handle, flexible or otherwise
Mario Carneiro (Apr 02 2024 at 09:10):
but it's not dependent on the nitty gritty details of the goal, so it's flexible
Damiano Testa (Apr 02 2024 at 09:10):
Right, I agree that this is the behaviour of most flexible tactics, and the linter is trying to mitigate this by only allowing flexible tactics to follow flexible tactics. There are a lot of rigid tactics following flexible ones already as is, so I am trying to find some common ground...
Damiano Testa (Apr 02 2024 at 09:11):
Anyway, I'll add split_ifs
to the ignored list, which means that the linter would
- not complain on
simp <;> split_ifs <;> simp
but - would complain on
simp <;> split_ifs <;> rw
Damiano Testa (Apr 05 2024 at 15:12):
Another question: should this proof be allowed, or should simp
be squeezed?
by simp [multiplicity, rootMultiplicity, Part.Dom]; congr; funext; congr
Note that there is an underlying decision that congr
is allowed as a simp
follower, so really the question is whether the funext
jammed in there is acceptable or whether it is reason for preferring a simp only
instead.
Ruben Van de Velde (Apr 05 2024 at 15:42):
The last congr solves the goal? Too bad simp can't handle it on its own
Damiano Testa (Apr 05 2024 at 15:43):
Yes, this is the full declaration:
-- Mathlib/Algebra/Polynomial/Div.lean
theorem rootMultiplicity_eq_multiplicity [DecidableEq R] [@DecidableRel R[X] (· ∣ ·)]
(p : R[X]) (a : R) :
rootMultiplicity a p =
if h0 : p = 0 then 0 else (multiplicity (X - C a) p).get (multiplicity_X_sub_C_finite a h0) :=
by simp [multiplicity, rootMultiplicity, Part.Dom]; congr; funext; congr
#align polynomial.root_multiplicity_eq_multiplicity Polynomial.rootMultiplicity_eq_multiplicity
Damiano Testa (Apr 05 2024 at 15:44):
and this is the goal before the last congr
Nat.find ⋯ = Nat.find ⋯
:man_facepalming:
Damiano Testa (Apr 05 2024 at 15:58):
Is it expected that adding
set_option pp.deepTerms true/false in -- I tried both
before the declaration, I still see the ...
?
Yaël Dillies (Apr 05 2024 at 16:26):
Damiano Testa said:
and this is the goal before the last
congr
Nat.find ⋯ = Nat.find ⋯
:man_facepalming:
I feel like the predicate argument to docs#Nat.find should be explicit
Kevin Buzzard (Apr 05 2024 at 17:02):
Damiano Testa said:
Is it expected that adding
set_option pp.deepTerms true/false in -- I tried both
before the declaration, I still see the
...
?
I've been using set_option pp.proofs.threshold 37
to expand ...
.
Damiano Testa (Apr 05 2024 at 18:31):
Thanks Kevin! This is the goal:
⊢ Nat.find (multiplicity_X_sub_C_finite a (Eq.mpr_not (Eq.refl (p = 0)) x✝)) =
Nat.find
(id (Eq.refl (PartENat.find fun n ↦ ¬(X - C a) ^ (n + 1) ∣ p)) ▸
multiplicity_X_sub_C_finite a (Eq.mpr_not (Eq.refl (p = 0)) x✝))
Kevin Buzzard (Apr 05 2024 at 21:22):
(I tried 0 and it didn't work so I tried 37 and it worked great)
Yaël Dillies (May 23 2024 at 06:51):
I've just noticed that something we left out of the discussion is that tactics have different flexibility regarding their inputs and outputs eg in simp [ha] at hb
we have
ha
is a rigid inputhb
is a flexible inputhb
is a flexible output
Yaël Dillies (May 23 2024 at 06:52):
And, perhaps more subtly, ha
is a rigid output in have ha : Foo := by simpa using hb
but a flexible output in have ha := by simpa using hb
Yaël Dillies (May 23 2024 at 06:54):
I'm not quite sure how to classify ha
in intermediate situations like have ha : Foo _ := by simpa using hb
. I guess it should be considered rigid even if it allows have ha : _ := by simpa using hb
to leave ha
rigid
Damiano Testa (May 23 2024 at 07:38):
On the front of the flexible vs rigid, I was pretty happy with the linter output. However, I personally find that there is no uniformly good way of pleasing the linter: replacing simp [tacs]
with
- the output of
simp? [tacs]
hides whattacs
is and is often too verbose; simp? [tacs] says ...
is again very verbose and also means that you still have to update the list of tactics when the simp-set changes;suffices ...
can again be very verbose, when the goals are long.
Overall, while a non-terminal simp
(or rigid tactic following a flexible one more generally) is not great for stability, I am not sure that the alternatives that are currently available are really an net improvement.
Damiano Testa (May 23 2024 at 07:49):
I have been thinking about a possible alternative. Here is an initial idea.
If a simp
no longer works on a branch, but was present in master
, then squeezing it in master would tell you what to use. How about we write a tactic squeeze_me_earlier
that takes a tactic as input (initially just simp
) and
- checks out
master
, - downloads the cache,
- attempts to find the correct
simp
; - runs
simp?
recording the output; - checks out the branch in development;
- says
Try this: [recorded output of `simp?`]
.
This could also be something that runs in CI, possibly applying to simp
s that break downstream of your changes, maybe in an untouched file, to begin with.
Michael Rothgang (Jul 24 2024 at 12:58):
#15101 fixes about a hundred warnings from the "flexible tactic" linter, in a way that is hopefully non-controversial. #15102 was also found by the linter, and is a small performance improvement in itself.
Michael Rothgang (Jul 25 2024 at 14:42):
#15130 has a few more
Michael Rothgang (Aug 02 2024 at 10:47):
#15318 has a few more
Michael Rothgang (Aug 04 2024 at 18:21):
Update: I have finished going through all warnings on mathlib. #13812 either disables the linter with a comment, or fixes its warning. The fixes have been split into #15318.
For the manual suppressions, I can see a few trends
- a category theory pattern: simp followed by coherence (I have always allowed the linter)
- a number of errors are about simp followed by erw, with a comment pointing to lean4#2644: I've left those as is, as fixing the underlying issue will also fix this linter warning
<;> simp
(say, for two goals created byby_cases
orinduction
), followed by some further proof. The simp sets are usually different, and sometimes long enough be unreadable when spelled out- there are surely more, for which I'd need to look at the suppressions myself
Michael Rothgang (Aug 15 2024 at 19:10):
I just merged master and fixed CI again: compared to master
, enabling the flexible linter requires
- two minor fixes (three lines, will PR soon) and
- 187 individual linter suppressions (commented)
To be honest, this number does not seem absurdly high --- just from the churn perspective, one could even enable the linter by default (with a clear note that this may be disabled easily).
Michael Rothgang (Aug 15 2024 at 19:15):
Out of these 187 exceptions,
- 14 are because of lean4#2644/related to simp and erw
- 5 are about simp followed by coherence
- 4 exceptions are about simp followed by exact, which cannot be combined into
simpa
- most remaining exceptions are cases where either
- the set of simp lemmas is long enough that squeezing it is ugly
- simp is applied to several goals, often with different (and/or quite large) simp sets
David Ang (Oct 04 2024 at 10:33):
I'm not sure how flexible the flexible linter is, but do tactic patterns like field_simp; linear_combination
go through with no complaints? I believe field_simp
is just a juiced up version of simp
and linear_combination
is just a juiced up version of ring
. I'm asking this because I use this pattern quite a lot in my files.
David Ang (Oct 04 2024 at 10:35):
I know that simp; ring
is fine, but if field_simp
is tagged as a simp
but linear_combination
is not tagged as a ring
then it would complain, since linear_combination
is not in the list of flexible tactics.
Damiano Testa (Oct 04 2024 at 11:46):
Neither field_simp
, nor linear_combination
are "flexible: this means that, by default, they are rigid. Hence, simp; field_simp
counts as a non-terminal simp and the linter would flag it.
Damiano Testa (Oct 04 2024 at 11:47):
It is easy to add more tactics to the "flexible" list and maybe there is a case for field_simp
to be flexible. I am not sure that linear_combination
should count as flexible, though, since it is quite fixed to exact shapes, I think.
Yaël Dillies (Oct 04 2024 at 11:48):
I think of field_simp
and linear_combination
as flexible, FWIW
Damiano Testa (Oct 04 2024 at 11:52):
With linear_combination
, also if it uses a hypothesis that has been the target of simp
?
Yaël Dillies (Oct 04 2024 at 11:54):
Surely yes?
Damiano Testa (Oct 04 2024 at 11:55):
I view it as somewhat brittle, since that hypothesis could change with an increase/decrease in the simp-set and it is not clear that linear_combination
would be able to cope.
Damiano Testa (Oct 04 2024 at 11:55):
But it is almost no work to make linear_combination
and field_simp
flexible, and I am happy to add them!
David Ang (Oct 04 2024 at 12:21):
I'd argue that they are flexible, unless you change their default normalisation (and I'm very guilty of this)
Damiano Testa (Oct 04 2024 at 12:28):
Ok, here is an example which is maybe not too contrived of why I am not completely convinced that linear_combination
is flexible:
example (x y : ℤ) (h1 : x*y + 2*x = 1) (h2 : 2 * x = 2 * y) : x*y = -2*y + 1 := by
--simp at h2 -- uncomment to break `linear_combination`
linear_combination 1*h1 - h2
Ruben Van de Velde (Oct 04 2024 at 12:28):
Yeah, I don't think it is
Damiano Testa (Oct 04 2024 at 12:28):
Of course, any tactic could be broken by doing something different before it, so really everything is rigid.
Ruben Van de Velde (Oct 04 2024 at 12:29):
field_simp
is a difficult one, though
Damiano Testa (Oct 04 2024 at 12:29):
But my mental model is that simp
is "truly" flexible, while linear_combination
is "somewhat flexible", but not so much.
David Ang (Oct 04 2024 at 12:30):
If this is the case, then arguably field_simp; linear_combination
should be flagged, but it's not?
Damiano Testa (Oct 04 2024 at 12:32):
Something probably has to be done about field_simp
, but I view field_simp
as a "normalization" tactic: it should (in theory) produce a reliably equal result from a range of inputs, like norm_num
: this, to me, makes it look like a tactic that can follow a flexible one and can be followed by whatever.
Damiano Testa (Oct 04 2024 at 12:32):
(Right now, though, I think that field_simp
is purely rigid and cannot follow a flexible one.)
Damiano Testa (Oct 04 2024 at 12:34):
So, I think that field_simp; linear_combination
is ok, the linter correctly does not flag it, but for the wrong reason! :smile:
David Ang (Oct 04 2024 at 12:35):
But doesn't field_simp
do everything that simp
does, except for three lemmas that surely doesn't make it a lot more flexible than simp
? I'm now also confused about norm_num
because isn't it just norm_num1; simp
?
Damiano Testa (Oct 04 2024 at 12:35):
To give a little bit of extra context, the "flexible" linter started as a "non-terminal simp
linter". It evolved in splitting tactics into "flexible" and "rigid": a "rigid" tactic cannot follow a "flexible" one, since the output of a flexible one is unreliable and could break the rest of the proof.
Damiano Testa (Oct 04 2024 at 12:36):
In development, some tactics actually take a variety of inputs and convert them to normal form, like norm_num
: if you stray a little from the initial input, chances are that norm_num
will return the same result.
Damiano Testa (Oct 04 2024 at 12:36):
Such tactics can more reliably be followed by rigid ones, since it would be a big jump to make them normalize to something different.
Damiano Testa (Oct 04 2024 at 12:37):
These tactics are "stoppers": they can follow a flexible one, since they can adapt to multiple outputs, but have "fewer" outputs, so can be followed by rigid ones.
Damiano Testa (Oct 04 2024 at 12:37):
In this context, there is always some discretion of "how big of a change you expect the typical change to be".
Damiano Testa (Oct 04 2024 at 12:38):
Of course, a big enough change will break whatever.
David Ang (Oct 04 2024 at 12:38):
Here is my concern: take your example above and replace simp
with norm_num
or field_simp
, and they both break
Damiano Testa (Oct 04 2024 at 12:38):
But the kind of simp
inside norm_num
and field_simp
is not "all simp
lemmas", but "a curated list of lemmas, some that are simp
, some that make sense in this context.
Damiano Testa (Oct 04 2024 at 12:40):
David Ang said:
Here is my concern: take your example above and replace
simp
withnorm_num
orfield_simp
, and they both break
Right, so I view this as evidence that linear_combination
is "rigid". As for norm_num
and field_simp
, they of course can normalize to something different, but I view this as more rare.
Damiano Testa (Oct 04 2024 at 12:41):
If your point of view is "a change in the previous tactic may break the next", then nothing would be allowed.
Yaël Dillies (Oct 04 2024 at 12:41):
David Ang said:
If this is the case, then arguably
field_simp; linear_combination
should be flagged, but it's not?
Given that field_simp
is meant as a preprocessor to tactics like ring
and linear_combination
, it would be very damageable to forbid field_simp; linear_combination
!
Damiano Testa (Oct 04 2024 at 12:43):
Right, the example above with field_simp
instead of simp
breaks linear_combination
, but it is unlikely that a working pair field_simp; linear_combination
would break after a change in field_simp
.
Damiano Testa (Oct 04 2024 at 12:44):
Whereas a working pair simp; linear_combination
is less likely to continue working, as simp
evolves.
David Ang (Oct 04 2024 at 12:45):
Right, but your "change" in field_simp
(that is unlikely to break) refers exclusively to changes in field_simps
Damiano Testa (Oct 04 2024 at 12:46):
Yes, I expect field_simp
to converge to some normal form that is "highly unlikely" to change: an expression of the form 2 * x / 2
should be normalized to x
no matter how many times field_simp
is reimplemented.
Damiano Testa (Oct 04 2024 at 12:47):
Whereas whether that same expression is simplified or not by a simp
lemma depends more unreliably on the simp
set.
Damiano Testa (Oct 04 2024 at 12:49):
That's why I consider field_simp; something_else
"robust": the something_else
is using a "field normal form". Something unusual has to have happened for the notion of "field normal form" to have changed.
David Ang (Oct 04 2024 at 12:49):
Maybe my concern is better phrased like this: currently we have tactics (e.g. field_simp
or norm_num
) that are basically (do something); simp
, and you argue that we can put them before doing something rigid. On the other hand, I could may well do (do something); simp; (do something rigid)
, which should have identical behaviour but is flagged.
Damiano Testa (Oct 04 2024 at 12:49):
They are not a "free" simp
, they are a "controlled simp
".
Damiano Testa (Oct 04 2024 at 12:50):
You should view them more as simp only
s.
David Ang (Oct 04 2024 at 12:52):
How controlled are they? I don't know exactly how they're defined but the docs tell me e.g.: field_simp [hx, hy]
is a short form for simp (disch := field_simp_discharge) [-one_div, -one_divp, -mul_eq_zero, hx, hy, field_simps]
, which is quite far from being a simp only
?
Damiano Testa (Oct 04 2024 at 12:52):
From the doc-string of field_simp
:
The goal of `field_simp` is to reduce an expression in a field to an expression of the form `n / d`
where neither `n` nor `d` contains any division symbol, just using the simplifier (with a carefully
crafted simpset named `field_simps`)
Damiano Testa (Oct 04 2024 at 12:55):
There are about 40 field_simps
lemmas.
David Ang (Oct 04 2024 at 12:55):
Right, then shouldn't the implementation be closer to simp only [field_simps]
rather than simp [field_simps]
?
Mario Carneiro (Oct 04 2024 at 12:55):
I think David's point is that it does not use only
Mario Carneiro (Oct 04 2024 at 12:55):
likewise for norm_num
Sébastien Gouëzel (Oct 04 2024 at 12:55):
The field_simps
set of lemmas is indeed added to the simpset when applying field_simp
, but almost nothing is removed if I recall correctly, so adding new simp lemmas will definitely change the outcome of field_simp
. In terms of rigidity, simp
and field_simp
should definitely be on the same line.
Ruben Van de Velde (Oct 04 2024 at 12:56):
Or should we change that? I'm not sure I want field_simp
to go changing random things in my goal
Ruben Van de Velde (Oct 04 2024 at 12:56):
Or we could have both
Damiano Testa (Oct 04 2024 at 12:57):
Ok, so I can then make field_simp
flexible and then linear_combination
would not be allowed to follow it.
Mario Carneiro (Oct 04 2024 at 12:57):
field_simp only
?
Mario Carneiro (Oct 04 2024 at 12:57):
you can already do this for norm_num
Damiano Testa (Oct 04 2024 at 12:58):
So only
would mean "just field_simps
(plus whatever you explicitly add)"?
Damiano Testa (Oct 04 2024 at 12:58):
That would probably be clearly a stopper tactic! :smile:
David Ang (Oct 04 2024 at 13:00):
Mario Carneiro said:
you can already do this for
norm_num
You mean norm_num1
? Or can we do norm_num only
?
David Ang (Oct 04 2024 at 13:03):
I do think having field_simp only
would be very nice, but I don't know how well this works in practice because if I remember correctly the 40 lemmas in field_simps
doesn't actually do very much without calling all of simp
Mario Carneiro (Oct 04 2024 at 14:21):
David Ang said:
Mario Carneiro said:
you can already do this for
norm_num
You mean
norm_num1
? Or can we donorm_num only
?
Both. norm_num1
doesn't use the simplifier at all, and norm_num only
uses the simplifier with the usual meaning of simp only
Last updated: May 02 2025 at 03:31 UTC