Zulip Chat Archive
Stream: mathlib4
Topic: Module.Dual and linear maps
Ruben Van de Velde (Aug 17 2023 at 13:24):
A fun issue for y'all: a linear map over a semiring can't be coerced to a function if Mathlib.LinearAlgebra.Dual
is imported; upgrading R
to a ring does work
import Mathlib.LinearAlgebra.Dual
import Mathlib.Algebra.Module.LinearMap
variable {R : Type*} [Ring R]
def foo {R : Type*} [Semiring R] : R →ₗ[R] R where
toFun := id
map_add' := sorry
map_smul' := sorry
def bar {R : Type*} [Ring R] : R →ₗ[R] R where
toFun := id
map_add' := sorry
map_smul' := sorry
example {R : Type*} [Semiring R] (p : R) : foo p = p := sorry -- fails
example {R : Type*} [Ring R] (p : R) : foo p = p := sorry -- fails
example {R : Type*} [Ring R] (p : R) : bar p = p := sorry -- works
function expected at
foo
term has type
?m.2379 →ₗ[?m.2379] ?m.2379
Removing the Mathlib.LinearAlgebra.Dual
import makes everything work, maybe because Module.Dual := M →ₗ[R] R
is reducible?
Eric Wieser (Aug 17 2023 at 14:09):
Making Module.Dual
not reducible had even more trouble
Ruben Van de Velde (Aug 17 2023 at 14:13):
Yeah, that didn't look like fun
Eric Wieser (Aug 17 2023 at 14:14):
This fixes it:
instance LinearMap.instCoeFun
{R : Type u_1} {S : Type u_6} {M : Type u_9} {M₃ : Type u_12} [inst : Semiring R] [inst : Semiring S] [inst : AddCommMonoid M] [inst : AddCommMonoid M₃]
[inst : Module R M] [inst : Module S M₃] {σ : R →+* S} :
CoeFun (M →ₛₗ[σ] M₃) fun x => M → M₃ := inferInstance -- or `⟨FunLike.coe⟩`
Eric Wieser (Aug 17 2023 at 14:14):
We had these shortcut instances in Lean 3, but they had the wrong implementation so we removed them
Eric Wieser (Aug 17 2023 at 14:14):
I guess the docs#LinearMap.instFunLike shortcut (that we replaced it with during porting) isn't enough
Matthew Ballard (Aug 17 2023 at 14:25):
How about
example {R : Type*} [Semiring R] (p : R) : foo (R := R) p = p := sorry
?
Ruben Van de Velde (Aug 17 2023 at 14:27):
That seems to work as well, though not so much fun in practice :)
Matthew Ballard (Aug 17 2023 at 14:31):
The trace is odd here
[Meta.synthInstance] [0.000107s] 💥 Semiring ?m.2810 ▼
[] [0.000051s] new goal Semiring ?m.2810 ▶
[] [0.000033s] 💥 apply inst✝ to Semiring ?m.2810 ▼
[tryResolve] [0.000023s] 💥 Semiring ?m.2810 ≟ Semiring R ▼
[isDefEq] [0.000020s] 💥 Semiring ?m.2810 =?= Semiring R ▼
[] [0.000003s] 💥 ?m.2810 =?= R ▼
[] ?m.2810 [nonassignable] =?= R [nonassignable]
Matthew Ballard (Aug 17 2023 at 14:32):
Where ?m.2810 : Type ?u.2808
Matthew Ballard (Aug 17 2023 at 14:33):
Universe issues?
Matthew Ballard (Aug 17 2023 at 14:35):
I also don't know what nonassignable
means...
Matthew Ballard (Aug 17 2023 at 14:35):
But it seems reasonable to expect success here right?
Matthew Ballard (Aug 17 2023 at 14:51):
For reference this still doesn't work after removing LinearAlgebra.Dual
from the imports. It just finds a CoeFun
where it couldn't before.
And that is because with LinearAlgebra.Dual
it ends up back at Semiring ?_
which it cannot solve
Jireh Loreaux (Aug 17 2023 at 14:58):
Kevin and I both witnessed this before. @Kevin Buzzard can you find the threads? I'm on mobile currently
Matthew Ballard (Aug 17 2023 at 15:03):
The message looks like it originates from Lean.Meta.isDefEqQuickOther
(private so no docs links but here is the link to the line)
Jireh Loreaux (Aug 17 2023 at 15:06):
Here is the thread (which itself links to the other one that has a lot of noise): https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/instance.20breaking.20FunLike
Jireh Loreaux (Aug 17 2023 at 15:07):
I think the problem is docs#Module.Dual.instFunLikeDual, but we haven't determined why.
Matthew Ballard (Aug 17 2023 at 15:09):
I am confused as to why R
is getting this nonassignable
tag. From reading the code, it seems like it should be a metavariable at that point in the logic
Matthew Ballard (Aug 17 2023 at 15:24):
Jireh Loreaux said:
I think the problem is docs#Module.Dual.instFunLikeDual, but we haven't determined why.
Someone should check me on this but it looks like trying that instance throws off side goals one of which is Semiring ?_
which fail regardless of importing LinearAlgebra.Dual
Matthew Ballard (Aug 17 2023 at 15:24):
Explicitly giving R
with (R := R)
makes things work in all cases.
Jireh Loreaux (Aug 17 2023 at 15:25):
Sorry, explicitly trying which instance? The one Eric suggested?
Kevin Buzzard (Aug 17 2023 at 15:25):
Sorry Jireh/Matt -- I'm in a field all week
Matthew Ballard (Aug 17 2023 at 15:25):
?
Jireh Loreaux (Aug 17 2023 at 15:25):
Nevermind Kevin, I found it, thanks!
Matthew Ballard (Aug 17 2023 at 15:27):
Import LinearAlgebra.Dual
and unification passes through Module.Dual.instFunLikeDual
and asks for which semiring we are using. It creates Semiring ?_
as a goal which it cannot solve
Matthew Ballard (Aug 17 2023 at 15:28):
Don't import it and it still tries to figure out Semiring ?_
but doesn't need it to find the coercion
Matthew Ballard (Aug 17 2023 at 15:28):
It gets to ?_ =?= R
and it fails...
Matthew Ballard (Aug 17 2023 at 15:29):
I think because both sides are marked nonassignable
Jireh Loreaux (Aug 17 2023 at 15:30):
Hmmm, is that because it's an outParam
? I don't know what nonassignable
is.
Matthew Ballard (Aug 17 2023 at 15:31):
From (rip)grepping, there is only one place where ?m.2810 [nonassignable] =?= R [nonassignable]
can be thrown
Matthew Ballard (Aug 17 2023 at 15:31):
Matthew Ballard (Aug 17 2023 at 15:33):
I don't know precisely what it is either but it seems like you want to assign ?_ := R
Sebastian Ullrich (Aug 17 2023 at 15:33):
Does it later repeat the TC synth with the metavariable instantiated?
Matthew Ballard (Aug 17 2023 at 15:33):
Not that I saw no
Matthew Ballard (Aug 17 2023 at 15:34):
Let me dump the full trace...
Sebastian Ullrich (Aug 17 2023 at 15:34):
Jireh Loreaux (Aug 17 2023 at 15:35):
Oh, I think assignable is about the mvar depth: docs#Lean.MVarId.isAssignable, but I'm sure Sebastian knows! :smiley:
Matthew Ballard (Aug 17 2023 at 15:35):
https://gist.github.com/mattrobball/15f8c763eaa169195367d2745e5a8e22
with code
import Mathlib.LinearAlgebra.Dual
import Mathlib.Algebra.Module.LinearMap
variable {R : Type*} [Ring R]
def foo {R : Type*} [Semiring R] : R →ₗ[R] R where
toFun := id
map_add' := sorry
map_smul' := sorry
def bar {R : Type*} [Ring R] : R →ₗ[R] R where
toFun := id
map_add' := sorry
map_smul' := sorry
set_option profiler true in
set_option trace.Meta.synthInstance true in
set_option trace.Meta.isDefEq true in
set_option synthInstance.maxHeartbeats 0 in
set_option maxHeartbeats 0 in
example {R : Type*} [Semiring R] (p : R) : foo p = p := sorry -- fails
-- example {R : Type*} [Ring R] (p : R) : foo p = p := sorry -- fails
-- example {R : Type*} [Ring R]
Matthew Ballard (Aug 17 2023 at 15:40):
Keyboard not cooperating with reformatting for readability... :sad:
Matthew Ballard (Aug 17 2023 at 15:53):
Sebastian Ullrich said:
Yeah this ones (eventually) ends up at α [nonassignable] =?= ?m.33 [assignable]
Sebastian Ullrich (Aug 17 2023 at 16:05):
Well this really is a vexing elaboration issue you're handing to Lean:
- When looking at
foo
, we don't knowR
yet, but Lean tries to find an instance ofSemiring
for it anyway; that's the trace you were looking at but ultimately not the source of the problem - We do know that we want to apply
foo : ?m.2142 →ₗ[?m.2142] ?m.2142
to an argument, so let's try to findCoeFun (?m.2142 →ₗ[?m.2142] ?m.2142) ?m.2177
(the latter mvar is from the outParam: we want TC synth to find the value of that parameter even if we expect it to beR
eventually) - For that let's try
FunLike (?m.2142 →ₗ[?m.2142] ?m.2142) ?m.2184 ?m.2185
; so far, so good - How about
Module.Dual.instFunLikeDual
? It fits, but only if we haveSemiring ?m.2142
- Now Lean is in a pickle: it can't apply this instance yet, but it also can't rule it out yet because
?m.2142
might eventually be a semiring, so it would be wrong to continue the search with the remaining, i.e. lower-priority, instances. So the only thing Lean can do is to wait and see whether it gets more information about that metavariable from another source in some later step, which here is not the case
Sebastian Ullrich (Aug 17 2023 at 16:07):
Basically by inserting a higher-priority (in this case, declared-later, I assume) instance than the desired one, you leave Lean unable to continue with the given amount of information
Matthew Ballard (Aug 17 2023 at 16:09):
What is problematic about using Semiring R
to start with? I ask in general more so than here.
Matthew Ballard (Aug 17 2023 at 16:22):
But one mathlib actionable thing I hear is to reduce the priority of Module.Dual.instFunLikeDual
Matthew Ballard (Aug 17 2023 at 16:38):
#6637 it goes through with low priority for instFunLikeDual
Sebastian Ullrich (Aug 17 2023 at 16:55):
Note that I don't necessarily recommend tweaking priorities for this reason, it might end up in a cat-and-mouse game. Ultimately CoeFun
simply needs more information than this to work robustly.
Eric Wieser (Aug 17 2023 at 17:01):
Eric Wieser said:
This fixes it:
instance LinearMap.instCoeFun {R : Type u_1} {S : Type u_6} {M : Type u_9} {M₃ : Type u_12} [inst : Semiring R] [inst : Semiring S] [inst : AddCommMonoid M] [inst : AddCommMonoid M₃] [inst : Module R M] [inst : Module S M₃] {σ : R →+* S} : CoeFun (M →ₛₗ[σ] M₃) fun x => M → M₃ := inferInstance -- or `⟨FunLike.coe⟩`
Do you think this sort of fix helps, or does this only work because it shuffles priorities again?
Matthew Ballard (Aug 17 2023 at 17:01):
Isn't that also tweaking priorities with declaration order?
Matthew Ballard (Aug 17 2023 at 17:06):
For reference, here is the trace without importing LinearAlgebra.Dual
https://gist.github.com/mattrobball/cd2c40f191a69b23241b7f913cc67555
Matthew Ballard (Aug 17 2023 at 17:08):
It seems to create an assignable metavariable for Semiring
itself and then succeeds in unifying it with the provided instance.
Matthew Ballard (Aug 17 2023 at 17:09):
As opposed to Semiring ?_
Matthew Ballard (Aug 17 2023 at 19:09):
I guess we could just delete instFunLikeDual
also lol
Jireh Loreaux (Aug 17 2023 at 19:21):
But it would be nice if we understood fully why we didn't have this problem in Lean 3, and because, as Mario indicated in the other thread, it seems like a bug. Moreover, I know that this isn't the only cause of this problem. I ran into another one with StarAlgHom
that de-instancing instFunLikeDual
didn't fix.
Matthew Ballard (Aug 17 2023 at 19:23):
It seems like assignability of the metavariables created is important. I think everything succeeds if one is assignable instead of unassignable.
I am sure there is a general reason for why they are marked as unassignable and I would love to understand it more.
Matthew Ballard (Aug 17 2023 at 19:24):
#6637 is updated to delete instFunLikeDual
.
Jireh Loreaux (Aug 17 2023 at 19:38):
I'm pretty sure the problem is that, for reasons I don't understand in relation to this specific issue, the metavariables don't occur at the same mvar depth. Mvars are only assignable when the current MVar depth matches the depth at which the MVar was created.
Jireh Loreaux (Aug 17 2023 at 19:41):
There's a discussion of this in the metaprogramming book, but I don't understand how it applies to this particular instance search.
Matthew Ballard (Aug 17 2023 at 19:43):
That is another thing I will need to learn.
One difference between LinearMap.instFunLike
and Module.Dual.instFunLikeDual
was that the first created metavariables to unify with Semiring
whereas the second only created a metavariable for the argument Semiring ?_
.
I don't understand why.
Matthew Ballard (Aug 18 2023 at 21:30):
Here is a basic example with similar behavior
variable (α : Type)
class SR (α : Type) where
def f {α : Type} : α → α := sorry
def foo {α : Type} [SR α] (_ : α → α) : Type _ := sorry
set_option trace.Meta.synthInstance true in
set_option trace.Meta.isDefEq true in
def bar {α : Type} [SR α] : foo f = foo f := sorry
It looks like it tries to unify ?1 → ?1 =?= ?2 → ?2
at context depth 0 and succeeds with ?1 := ?2
. Then it bumps the depth and tries to do Semiring ?1
which it cannot solve because the depth of ?1
is 0.
Matthew Ballard (Aug 18 2023 at 21:34):
I am still confused since reading the comments in the file makes me think that the context depth only gets bumped with the creation of new metavariables.
Notification Bot (Aug 22 2023 at 12:09):
This topic was moved here from #general > Module.Dual and linear maps by Kyle Miller.
Last updated: Dec 20 2023 at 11:08 UTC