New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(tactic/lint): check that left-hand side of all simp lemmas is in simp-normal form #2017
Conversation
This is a really great linter. I want to remark specifically about the case of subtraction though that I want to kill |
Is there a way to create a new attribute |
Then please submit a PR to our glorious Lean fork! We can also finally get rid of
Practical answer: you revert the "remove simp lemmas for sub" commit from this PR. Interesting answer: if the local confluence checker (#4 in the series) actually works (read: is fast enough and doesn't produce too many false positives), then you probably only need to add this lemma and fix all the subsequent linter issues: @[simp] lemma add_neg_eq_sub : a + -b = a - b := sorry |
Only very few of the lemmas I changed would be fixed by such an attribute. E.g. all of the Some of the changed lemmas are OK at the point where they are defined. They are only broken by later simp lemmas. A For the few lemmas where it would work, I believe it is clearer and more reliable to just write the correct left-hand side by hand. Furthermore, synthesizing the left-hand side automatically is fragile for the same reasons that non-terminal simp is fragile: 1) the simplifier is not fully deterministic (due to some bugs); 2) new simp lemmas may change the lhs, and even introduce non-termination. |
Should we just ignore |
BTW, why do we use a special |
it doesn't require a decidable instance, unlike the regular |
What's the status here? This PR works for both 3.5.1 and a future Lean including leanprover-community/lean#117 ? I think we should merge it fast before conflicts come up! @fpvandoorn @digama0 any thoughts? |
@gebner Could you add this to the list of default linters at the top of |
Yes, there's nothing that changes, really. At the moment I'm just manually removing
Done. |
@@ -46,8 +46,6 @@ def mk0 (a : α) (ha : a ≠ 0) : units α := | |||
|
|||
@[simp] theorem mk0_val (ha : a ≠ 0) : (mk0 a ha : α) = a := rfl | |||
|
|||
@[simp] theorem mk0_inv (ha : a ≠ 0) : ((mk0 a ha)⁻¹ : α) = a⁻¹ := rfl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was it deleted for a reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because it is exactly the same as mk0_val
, but with a ⁻¹
around (the coercion is inserted inside the inverse). It's not used anywhere, so I removed it.
There are merge conflicts already. @digama0 @fpvandoorn last chance to comment, I suggest we merge today! |
And the linter has caught three new broken simp lemmas (I've just fixed them): -- analysis/normed_space/multilinear.lean
#print continuous_multilinear_map.uncurry0_curry0 /- Argument #8 of left-hand side (continuous_multilinear_map.curry0 𝕜 G
(continuous_multilinear_map.uncurry0 f)) reduces from
continuous_multilinear_map.uncurry0 f
to
⇑f 0
using
[continuous_multilinear_map.uncurry0_apply] -/
#print continuous_multilinear_map.curry0_norm /- Argument #2 of left-hand side (∥continuous_multilinear_map.uncurry0 f∥) reduces from
continuous_multilinear_map.uncurry0 f
to
⇑f 0
using
[continuous_multilinear_map.uncurry0_apply] -/
-- algebraic_geometry/prime_spectrum.lean
#print prime_spectrum.zero_locus_bot /- Argument #2 of left-hand side (prime_spectrum.zero_locus ↑⊥) reduces from
↑⊥
to
{0}
using
[submodule.bot_coe] -/ |
This looks really useful! It seems good to merge this quickly indeed. Two questions:
|
Yes, indeed. You also get the list of simp lemmas causing this reduction.
You've got this right. I wanted the (first version of the) linter to only point out objectively broken simp lemmas. If one of the arguments is not in simp-normal form, then the simp lemma can never rewrite. You always need to fix the lemma indicated by the linter. Checking for reducibility of the whole left-hand side is also interesting and what I'm going to do real soon now. However such a check also subsumes a redundancy lint (i.e. it will complain whenever you have a simp lemma that can be proven by simp). I didn't know at first if it would be feasible remove all redundant simp lemmas or if there are performance issues when simplifying all left-hand sides. And there were performance issues: that's how I found the looping lemmas in #2026. But I think that linting and removing redundant simp lemmas is feasible now, there's not that many: https://gist.github.com/gebner/32577f90fafecde4db92b2efd4b49666 I'll probably merge the linter for redundant lemmas and the normal form linter. Practically speaking, it's easier to first fix the really broken lemmas and then fix the less broken lemmas in a second PR. |
… simp-normal form (leanprover-community#2017) * feat(tactic/lint): check that lhs of simp lemmas are in simp nf * fix(topology/metric_space/basic): remove @[simp] from lemmas with {x,y} on the lhs * chore(topology/local_homeomorph): remove redundant lemmas from the simp set * fix(topology/algebra/module): fix simp-nf lints * chore(ring_theory/localization): mark fewer things as simp * fix(set_theory/ordinal): put lhs into simp-normal form * chore(algebra/big_operators): fix simp lemmas * chore(data/set/lattice): remove redundant simp lemmas * chore(data/set/basic): remove redundant simp lemma * chore(data/zsqrtd/basic): make simp_nf lint happy * fix(order/complete_lattice): remove lemmas from simp set * chore(order/filter/filter_product): fix linting issues * feat(data/mv_polynomial): add simp lemmas about neg * fix(data/multiset): fix simp_nf linter issues * chore(data/list/sigma): fix simp_nf linter issues * fix(data/list/basic): remove redundant and unapplicable simp lemmas * fix(measure_theory/set_integral): remove redundant simp lemma * fix(measure_theory/l1_space): remove redundant simp lemmas * fix(algebra/group_power): remove simp lemmas that are not in nf * fix(algebra/field): remove redundant simp lemma * chore(data/list/alist): remove simp lemmas * fix(data/int/basic): simp-normal form for coercions... * fix(data/finset): formulate simp-lemmas for simp-nf * fix(data/int/parity): use simp-normal form * fix(data/equiv/denumerable): remove redundant simp lemma * fix(category_theory/**): fix simp-normal forms * fix(set_theory/zfc): put simp lemmas in simp-normal form * fix(tactlic/lint): ignore sub_eq_add_neg for simp_nf lint * doc(tactic/lint): add simp_nf linter to module doc * doc(docs/commands): add simp_nf linter * fix(*): put lemmas in simp-normal form
… simp-normal form (leanprover-community#2017) * feat(tactic/lint): check that lhs of simp lemmas are in simp nf * fix(topology/metric_space/basic): remove @[simp] from lemmas with {x,y} on the lhs * chore(topology/local_homeomorph): remove redundant lemmas from the simp set * fix(topology/algebra/module): fix simp-nf lints * chore(ring_theory/localization): mark fewer things as simp * fix(set_theory/ordinal): put lhs into simp-normal form * chore(algebra/big_operators): fix simp lemmas * chore(data/set/lattice): remove redundant simp lemmas * chore(data/set/basic): remove redundant simp lemma * chore(data/zsqrtd/basic): make simp_nf lint happy * fix(order/complete_lattice): remove lemmas from simp set * chore(order/filter/filter_product): fix linting issues * feat(data/mv_polynomial): add simp lemmas about neg * fix(data/multiset): fix simp_nf linter issues * chore(data/list/sigma): fix simp_nf linter issues * fix(data/list/basic): remove redundant and unapplicable simp lemmas * fix(measure_theory/set_integral): remove redundant simp lemma * fix(measure_theory/l1_space): remove redundant simp lemmas * fix(algebra/group_power): remove simp lemmas that are not in nf * fix(algebra/field): remove redundant simp lemma * chore(data/list/alist): remove simp lemmas * fix(data/int/basic): simp-normal form for coercions... * fix(data/finset): formulate simp-lemmas for simp-nf * fix(data/int/parity): use simp-normal form * fix(data/equiv/denumerable): remove redundant simp lemma * fix(category_theory/**): fix simp-normal forms * fix(set_theory/zfc): put simp lemmas in simp-normal form * fix(tactlic/lint): ignore sub_eq_add_neg for simp_nf lint * doc(tactic/lint): add simp_nf linter to module doc * doc(docs/commands): add simp_nf linter * fix(*): put lemmas in simp-normal form
Motivation: suppose you write a simp lemma
0 ≤ of_nat n
. You then try it out only to find out that it doesn't work. What happened? There is another simp lemma rewritingof_nat n
to↑n
, and your nice lemma never has a chance to apply.What was wrong with the lemma? The term
of_nat n
was not in simp-normal form, it is simplified to↑n
.This PR introduces a linter to detect such simp lemmas, concretely it checks that all arguments of the left-hand side of the simp lemma are in simp-normal form. It also fixes a large number of these issues across mathlib.
The error message from the linter is hopefully enlightening enough:
There is maybe an argument to be made that some of the simp-normal forms should be chosen differently. I tried to keep the existing simp-normal forms as far as possible, and only remove/fix lemmas that could never apply. If you want to change the simp NFs, I'd prefer to do this in follow-up PRs.
sub_eq_add_neg
rewritesa - b
toa + -b
. Hence no lemma with a-
on the left-hand side ever worked as a simp lemma.0
and+
instead of∅
and∪
. Therefore you can't use the built-in set notation on the lhs of simp lemmas.finset.singleton
, so you can't have{a}
on the lhs of a simp lemma.ℕ
toℤ
. And of course half of the lemmas used the wrong coercion on the lhs. To make it even worse, the error message you get from the linter is↑n reduces to ↑n
. 😠⋃ x ∈ A ∪ B, ...
on the lhs of a simp lemma, becausex ∈ A ∪ B
simplifies tox ∈ A ∨ x ∈ B
.∃ x ∈ A, ...
either. By now you can probably guess why.I have a few more linters for simp lemmas in the works: no local constants as head symbols, simp lemmas that can be proven by simp, and local confluence.