Zulip Chat Archive
Stream: mathlib4
Topic: DecidableEq diamond
Joël Riou (Apr 10 2023 at 09:02):
The following should work
import Mathlib.Data.MvPolynomial.CommRing
import Mathlib.Data.Finset.Basic
open MvPolynomial Finset
lemma test (n : ℕ) (P : MvPolynomial ℕ ℚ)
(h : Disjoint (vars (X n : MvPolynomial ℕ ℚ)) (vars P)) : n ∈ (X n - P).vars := by
rw [vars_sub_of_disjoint _ h, vars_X, mem_union, Finset.mem_singleton]
exact Or.inl rfl
but rw [mem_union]
fails as
synthesized type class instance is not definitionally equal to expression inferred by typing rules, synthesized
fun a b => instDecidableEqNat a b
inferred
fun a b => Classical.propDecidable (a = b)
(This appeared in !4#3355 at https://github.com/leanprover-community/mathlib4/pull/3355/files#diff-f33593ea969bf958e5cb05e696cc502c949d9abfd4241a1f4be934e01466c818R259-R271 )
Eric Wieser (Apr 10 2023 at 09:31):
I would guess docs4#MvPolynomial.vars_sub_of_disjoint is to blame
Eric Wieser (Apr 10 2023 at 09:32):
It is missing a DecideableEq
argument
Eric Wieser (Apr 10 2023 at 09:33):
Removing open Classical
from that file should make the problem obvious
Joël Riou (Apr 10 2023 at 09:54):
Thanks, but then there is another DecidableEq
diamond on the set σ →₀ ℕ
of functions which are zero almost everywhere...
Joël Riou (Apr 10 2023 at 10:10):
(I will try to investigate this another day.)
Kevin Buzzard (Apr 10 2023 at 10:32):
Is open Classical
ever correct? Since I learnt the basic rule of thumb ("if the statement doesn't compile, add decidable instances; if the proof doesn't compile, use the classical tactic in the proof) I've never had this particular diamond issue (which used to plague my code before I understood the rule of thumb and was in fact the reason Jason KY and I wrote the basic finsum
API)
Eric Wieser (Apr 10 2023 at 11:00):
In lean 4 there's no reason to use it now the classical
tactic works properly and the variable inclusion rules have changed
Eric Wieser (Apr 10 2023 at 11:00):
(except obviously when porting)
Eric Wieser (Apr 10 2023 at 11:35):
That is to say, def foo := by classical; exact if p then x else y
didn't work well in Lean 3, and was the main reason that the locale was still useful
Joël Riou (Apr 10 2023 at 15:09):
After getting rid of open Classical
in 6 extra files, I could get RingTheory.WittVector.WittPolynomial
to compile, but it seems I have broken everything else :innocent:
Kyle Miller (Apr 10 2023 at 15:16):
There's also a difference between how instance arguments are handled between Lean 3 and Lean 4. Now there's a check that the instance argument is the "right" one, but in Lean 3 a theorem like docs4#Finset.mem_union would be happy to just use the instance argument that was already there in the expression.
@Joël Riou If you made a variant of Finset.mem_union
that takes the decidable instance as an implicit argument rather than an instance argument, I'd expect your original example to work.
Kyle Miller (Apr 10 2023 at 15:18):
Yeah, this works:
import Mathlib.Data.MvPolynomial.CommRing
import Mathlib.Data.Finset.Basic
open MvPolynomial Finset
theorem Finset.mem_union' {_ : DecidableEq α} {s t : Finset α} {a : α} :
a ∈ s ∪ t ↔ a ∈ s ∨ a ∈ t := Finset.mem_union
lemma test (n : ℕ) (P : MvPolynomial ℕ ℚ)
(h : Disjoint (vars (X n : MvPolynomial ℕ ℚ)) (vars P)) : n ∈ (X n - P).vars := by
rw [vars_sub_of_disjoint _ h, vars_X, mem_union', Finset.mem_singleton]
exact Or.inl rfl
Kyle Miller (Apr 10 2023 at 15:24):
I think we're going to have to figure out the new right way to handle instance arguments in rewrite theorems, since the rules of thumb that worked for Lean 3 don't apply perfectly to Lean 4.
I believe @Matthew Ballard had an example of Lean 3 style (where you have instance arguments rather than implicit arguments for everything that can be picked up from the LHS) causing timeouts for some algebraic structures in Lean 4, though I can't find the thread right now.
Matthew Ballard (Apr 10 2023 at 15:28):
There have been a few. One example RingTheory.Polynomial.Basic
- https://github.com/leanprover-community/mathlib4/blob/05186d6b6b04357326f679db65b90e45c6c8f8ed/Mathlib/RingTheory/Polynomial/Basic.lean#L864
- https://github.com/leanprover-community/mathlib4/blob/05186d6b6b04357326f679db65b90e45c6c8f8ed/Mathlib/RingTheory/Polynomial/Basic.lean#L1285 and below
Matthew Ballard (Apr 10 2023 at 15:29):
I think @Eric Wieser had some also. If you grep for (_)
you will find a good chunk of them (I would guess)
Kyle Miller (Apr 10 2023 at 15:33):
Oh right, I forgot about the (_)
solution to switch the argument from being elaborated as an instance argument. Here's how that looks here:
lemma test (n : ℕ) (P : MvPolynomial ℕ ℚ)
(h : Disjoint (vars (X n : MvPolynomial ℕ ℚ)) (vars P)) : n ∈ (X n - P).vars := by
rw [vars_sub_of_disjoint _ h, vars_X, @mem_union _ (_), Finset.mem_singleton]
exact Or.inl rfl
Matthew Ballard (Apr 10 2023 at 15:34):
You can force Lean to use unification in place of typeclass synthesis if you use (_)
in place of _
when filling in all parameters (or what Kyle said :)
Eric Wieser (Apr 10 2023 at 15:41):
In the long run it would be better to fix the classical issues, but I guess the above is a faithful port
Eric Wieser (Apr 10 2023 at 15:41):
It's a shame the instance arguments are all un-named so we can't use (inst12 := _)
instead
Eric Wieser (Apr 10 2023 at 15:42):
(Sure, it's unhygienic; but I'd rather see inst12
than count 12 underscores)
Matthew Ballard (Apr 10 2023 at 15:54):
I agree. Is there metaprogramming solution (or approximation)?
Kyle Miller (Apr 10 2023 at 15:59):
@Matthew Ballard I was just experimenting with something like that in the form of a no_inst%
term elaborator that turns every instance implicit into an implicit argument:
import Mathlib.Data.MvPolynomial.CommRing
import Mathlib.Data.Finset.Basic
import Lean
namespace NoInst
open Lean Elab Lean.Parser.Term
open Meta Command
syntax (name := no_inst) "no_inst% " ident : term
@[term_elab no_inst]
def no_inst_elab : Elab.Term.TermElab := fun stx _ =>
match stx with
| `(no_inst% $name) => do
if let some e ← Term.resolveId? name (withInfo := true) then
logInfo m!"no_inst% for type {← inferType e}"
let e' ← forallTelescope (← inferType e) fun args _ => do
let mut lctx ← getLCtx
for arg in args do
let decl := lctx.getFVar! arg
if decl.binderInfo.isInstImplicit then
lctx := lctx.setBinderInfo decl.fvarId .implicit
withLCtx lctx (← getLocalInstances) do
mkLambdaFVars args (mkAppN e args)
logInfo m!"no_inst% created type {← inferType e'}"
return e'
else
-- Generate error:
Term.elabTerm name none
| _ => throwUnsupportedSyntax
end NoInst
open MvPolynomial Finset
lemma test (n : ℕ) (P : MvPolynomial ℕ ℚ)
(h : Disjoint (vars (X n : MvPolynomial ℕ ℚ)) (vars P)) : n ∈ (X n - P).vars := by
rw [vars_sub_of_disjoint _ h, vars_X, no_inst% mem_union, Finset.mem_singleton]
exact Or.inl rfl
Matthew Ballard (Apr 10 2023 at 16:02):
Nice! I think turning all []
into {}
might not work so well in practice though. In my experience, I've had to mix and match.
Kyle Miller (Apr 10 2023 at 16:03):
For rewriting, it'd be better to keep track whether the instance argument is only for the RHS and leave those alone. Do you know if there are other heuristics?
Matthew Ballard (Apr 10 2023 at 16:03):
Would it make sense to try unification and fall back to synthesis if that fails?
Kyle Miller (Apr 10 2023 at 16:05):
I think you're getting into "changes to Lean 4 core" territory here. Anne Baanen I believe was the one who made that change to Lean 3, and it's been a nice feature.
Matthew Ballard (Apr 10 2023 at 16:05):
Yeah, it seems complicated to implement well
Matthew Ballard (Apr 10 2023 at 16:06):
Unfortunately, I don't have good rules for when to do which except if it times out, then switch to {}
Matthew Ballard (Apr 10 2023 at 16:08):
Is there any way to manually pick the instance argument(s) as Eric suggested?
Matthew Ballard (Apr 10 2023 at 16:13):
I guess: "earlier instance parameters in the signature tend to be less problematic than later ones" has been fairly true
Kyle Miller (Apr 10 2023 at 16:20):
@Matthew Ballard Here's another term elaborator. This time de_inst% mem_union 2
takes argument index 2, checks that it's an instance implicit, and then turns it into an implicit. You can give it as many argument indices as you want, like de_inst% f 3 5 7
.
import Mathlib.Data.MvPolynomial.CommRing
import Mathlib.Data.Finset.Basic
import Lean
namespace NoInst
open Lean Elab Lean.Parser.Term
open Meta Command
syntax (name := de_inst) "de_inst% " ident num* : term
@[term_elab de_inst]
def no_inst_elab : Elab.Term.TermElab := fun stx _ =>
match stx with
| `(de_inst% $name $nums*) => do
let nums := nums.map (·.getNat)
if let some e ← Term.resolveId? name (withInfo := true) then
let e' ← forallTelescope (← inferType e) fun args _ => do
let mut lctx ← getLCtx
for i in nums do
if i == 0 || i > args.size then
throwError "${name} does not have argument index {i}"
let arg := args[i - 1]!
let decl := lctx.getFVar! arg
if not decl.binderInfo.isInstImplicit then
throwError "argument index {i} (of type {← inferType arg}) is not an instance implicit"
lctx := lctx.setBinderInfo decl.fvarId .implicit
withLCtx lctx (← getLocalInstances) do
mkLambdaFVars args (mkAppN e args)
return e'
else
-- Generate error:
Term.elabTerm name none
| _ => throwUnsupportedSyntax
end NoInst
open MvPolynomial Finset
lemma test (n : ℕ) (P : MvPolynomial ℕ ℚ)
(h : Disjoint (vars (X n : MvPolynomial ℕ ℚ)) (vars P)) : n ∈ (X n - P).vars := by
rw [vars_sub_of_disjoint _ h, vars_X, de_inst% mem_union 2, Finset.mem_singleton]
exact Or.inl rfl
Kyle Miller (Apr 10 2023 at 16:22):
The indexing could also be with respect to the instance implicit arguments themselves, but this a little easier.
Matthew Ballard (Apr 10 2023 at 16:25):
Great! Yeah, I think either specifying the index or type manually probably has the widest use without getting seriously into the guts of the synthesis algorithm
Eric Wieser (Apr 10 2023 at 16:37):
I think the big win here would be specifying the type of the target argument
Eric Wieser (Apr 10 2023 at 16:42):
Perhaps foo (_ : Bar := val)
would be a reasonable syntax request for core?
Kyle Miller (Apr 10 2023 at 16:58):
That syntax at least seems unambiguous, and it might not be that crazy of a feature since something like foo (x : Bar := val)
could still be valid and be helpful for elaboration of both val
and foo
. I guess you still have to decide how this works when there are multiple matches, either if there are two Bar
s or if you allow Bar
to have placeholders.
Kyle Miller (Apr 10 2023 at 16:58):
In the meantime, it's not so hard to implement this as a term elaborator, with syntax like with_args% foo (_ : Bar := val)
.
Joël Riou (Apr 11 2023 at 10:13):
Now !4#3355 changes 29 files, but it compiles!
Eric Wieser (Apr 11 2023 at 10:51):
It sounds to me like it would be worth backporting some of these changes just to check they don't cause trouble elsewhere
Scott Morrison (Apr 21 2023 at 06:50):
Gah, what's going on here? I thought we decided long ago not to have any decidability instances in the polynomial library?
Eric Wieser (Apr 21 2023 at 07:42):
I think we decided to not have them in definitions
Eric Wieser (Apr 21 2023 at 07:43):
Lemmas without them are harder to use than lemmas with them
Eric Wieser (Apr 21 2023 at 07:43):
Because they introduce non-canonical decidability instances into the goal
Joël Riou (Apr 21 2023 at 09:22):
The problem arose while porting WittVector.WittPolynomial
. In the proof of xInTermsOfW_vars_aux
, there are some manipulations on Finset ℕ
. Some lemmas used in the proof involve the DecidableEq
instance coming from the integers and some involve the one obtained by classical
. Lean3 rw
was able to deal with that; but it is not so in Lean4
. By adding DecidableEq
in many places as I eventually did in !4#3355 I could have this PR compile. However, I think that either we can make rw
work following Kyle suggestion or we should just completely get rid of any global DecidableEq
instance that is not classical.decEq
...
Eric Wieser (Apr 21 2023 at 09:26):
!4#3355 changes a lot more than it needs to, as discussed in the backport
Joël Riou (Apr 21 2023 at 09:39):
I have made other attempts, and it eventually reduces to the problem I have mentionned just above.
Eric Wieser (Apr 21 2023 at 09:41):
@Joël Riou, my point is that #18791 (+621 −426, the backport) adds decidable_eq
arguments to both def
s (which Scott is rightly opposed to) and lemmas
(which I think we recently agreed was a good thing)
Eric Wieser (Apr 21 2023 at 09:46):
I have created a smaller PR at #18848 (+154 −90) which should hopefully be less controversial. Getting I've added the changes to this file too.mv_polynomial.vars
right will need more care so as to not break everything downstream like it seem to in #18791
Eric Wieser (Apr 24 2023 at 11:51):
@Scott Morrison, are you happy with #18848? (other than the 10 files of forward-porting burden it creates)
Scott Morrison (Apr 24 2023 at 11:53):
I better sleep before attempting to read the changes, but at least the PR description I'm happy with. :-)
Eric Wieser (May 09 2023 at 23:18):
:ping_pong: on the above. I probably won't have time to respond to any review feedback this week, but it would be good not to forget about it
Anne Baanen (May 10 2023 at 09:37):
:ping_pong: answered!
Eric Wieser (May 17 2023 at 10:52):
The forward-port, !4#4007, is ready for (careful) review. This uses up 10 spots on #out-of-sync.
Eric Wieser (May 22 2023 at 09:45):
The DecidableEq
problems in this PR are all gone
Eric Wieser (May 22 2023 at 09:45):
I got the whole thing building, but some of the porting had introduced some mistakes, so after fixing them there are some things to cleanup
Eric Wieser (May 22 2023 at 09:46):
Annoyingly rw [Finset.sum_congr rfl]
no longer seems to work
Mauricio Collares (May 22 2023 at 10:26):
!4#3355 for reference
Joël Riou (May 22 2023 at 14:34):
!4#3355 compiles now. Thanks very much @Eric Wieser for your efforts!
Eric Wieser (May 22 2023 at 14:35):
Looking over the diff against the mathport output, it looks like there are a few places that are missing porting note (at least one of them is one I introduced!)
Eric Wieser (May 22 2023 at 14:36):
The sum_eq_zero
thing you mention is particularly strange; is it still a problem with all the other fixes?
Last updated: Dec 20 2023 at 11:08 UTC