Zulip Chat Archive
Stream: general
Topic: debugging `compute_degree_le`
Damiano Testa (Jul 23 2022 at 09:01):
Dear All,
now that compute_degree_le
is in mathlib, I have taken back looking at compute_degree
. I have found a bug though that I am not able to remove. In the code below, if you add and then remove a zero, compute_degree_le
works, but fails otherwise.
Does anyone have any idea of what might be going on?
import tactic.compute_degree
open polynomial
open_locale polynomial
variables {R : Type*} [ring R]
lemma repl {p q : R[X]} (hp : p.nat_degree ≤ 0) :
(p * q).nat_degree = 0 :=
sorry
example : nat_degree (- 1 * 1 : R[X]) = 0 :=
begin
apply repl _,
rw [← zero_add 0, zero_add], -- if you remove this line, then next one fails.
compute_degree_le,
end
As far as I can see, without adding and removing the zero, Lean does not realize that -1
is a negative. But this is where I can make no further progress.
Any help is greatly appreciated!
Thanks!
Damiano Testa (Jul 23 2022 at 09:08):
In order to "fix" compute_degree_le
, you can also use apply repl <no_underscore>
or use refine repl _
. This does not help me much in understanding how to make compute_degree_le
oblivious to the issue, though.
Floris van Doorn (Jul 23 2022 at 10:41):
Without looking into it much, maybe compute_degree_le
is not instantiating metavariables properly?
Damiano Testa (Jul 23 2022 at 10:44):
It is possible: where can I learn about what I should instantiate? I feel that I am running into this issue more and more as I get myself stuck deeper in meta-programs and never really understand how the instantiation works.
Damiano Testa (Jul 23 2022 at 10:45):
to give some context: I narrowed it down to here:
do `(nat_degree %%tl ≤ %%tr) ← target | fail!("Goal is not of the form `f.nat_degree ≤ d`"),
match tl with
| `(%%tl1 + %%tl2) := refine ``((nat_degree_add_le_iff_left _ _ _).mpr _)
| `(%%tl1 - %%tl2) := refine ``((nat_degree_sub_le_iff_left _ _ _).mpr _)
| `(%%tl1 * %%tl2) := do [d1, d2] ← [tl1, tl2].mmap guess_degree,
refine ``(nat_degree_mul_le.trans $ (add_le_add _ _).trans (_ : %%d1 + %%d2 ≤ %%tr))
| `(- %%f) := refine ``((nat_degree_neg _).le.trans _)
-- more similar lines
and Lean just ignores the last neg
match.
Damiano Testa (Jul 23 2022 at 10:47):
Floris, your suggestion is spot on! What is below fixes this issue:
do `(nat_degree %%tl1 ≤ %%tr) ← target | fail!("Goal is not of the form `f.nat_degree ≤ d`"),
tl ← instantiate_mvars tl1,
-- continue as before
Damiano Testa (Jul 23 2022 at 10:48):
How can I know if I should instantiate mvars or not?
Floris van Doorn (Jul 23 2022 at 10:56):
If you have an unknown expression (like target
), and you want to check whether it has a particular shape, you want to instantiate the metavariables first. You might also want to call whnf
in case you need to do some beta-reductions (but without unfolding the ≤
). Something like
do
t ← target >>= instantiate_mvars,
do `(nat_degree %%tl ≤ %%tr) ← whnf t reducible | fail!("Goal is not of the form `f.nat_degree ≤ d`"),
Floris van Doorn (Jul 23 2022 at 10:57):
In your example you can also double check that instantiating meta-variables is the problem, since this also succeeds:
example : nat_degree (- 1 * 1 : R[X]) = 0 :=
begin
apply repl _,
instantiate_mvars_in_target,
compute_degree_le,
end
Damiano Testa (Jul 23 2022 at 10:59):
So, whenever I do a match, Lean will infer nothing more than the bare minimum, unless I explicitly tell it to. Is this a good first approximation?
Floris van Doorn (Jul 23 2022 at 11:01):
Yeah basically. Lean is very lazy with instantiating metavariables (which is crucial for performance reasons), so it is possible your goal is something like nat_degree ?m ≤ 0
and Lean already knows exactly what ?m
is, but hasn't assigned ?m
yet in your goal.
Damiano Testa (Jul 23 2022 at 11:02):
I see. Is it reasonable to file this as "like the difference between apply and refine, except at a more fundamental level"?
Floris van Doorn (Jul 23 2022 at 11:03):
I don't understand your analogy, so maybe not :-)
Damiano Testa (Jul 23 2022 at 11:04):
This refers to simply matching (giving something like apply) or doing the mvars and whnf stuff (something like refine).
Damiano Testa (Jul 23 2022 at 11:05):
I'm saying this because I often find that apply
leaves goals that can be solved by apply_instance
whereas using refine
never seems to.
Damiano Testa (Jul 23 2022 at 11:05):
So, in my head, this is some unification that has not happened yet, but could have.
Damiano Testa (Jul 23 2022 at 11:06):
Anyway, this is more philosophical now: I will keep in mind that, whenever I match, I may want to give hints to Lean that it instantiate something.
Thanks a lot!
Floris van Doorn (Jul 23 2022 at 11:06):
I see what you mean. apply
indeed fails to do some post-processing (which it probably really should do), like doing some apply_instance
at the end and instantiating metavariables in the new goals.
Damiano Testa (Jul 23 2022 at 11:07):
Ok, I am happy that there is some analogy, even if vague. It helps to classify what is going on, by relating to something that I already know!
Damiano Testa (Jul 23 2022 at 19:11):
PR #15649 implements instantiate_mvars/whnf
, as well as using focus1
to avoid spillage of the tactic to neighboring goals.
Last updated: Dec 20 2023 at 11:08 UTC