Zulip Chat Archive
Stream: general
Topic: Typeclass search is affected by other subexpressions
Eric Wieser (Sep 08 2023 at 08:20):
Two very confusing typeclass failures:
import Mathlib.Analysis.NormedSpace.OperatorNorm
variable (π : Type*) [NontriviallyNormedField π]
variable (E : Type*) [SeminormedAddCommGroup E] [NormedSpace π E]
abbrev Dual : Type _ := E βL[π] π
def inclusionInDoubleDual : E βL[π] Dual π (Dual π E) := sorry
#check _ = βContinuousLinearMap.id π (Dual π E)β
-- ok
example : (by exact βinclusionInDoubleDual π Eβ) = βContinuousLinearMap.id π (Dual π E)β := sorry
-- fail
example : βinclusionInDoubleDual π Eβ = βContinuousLinearMap.id π (Dual π E)β := sorry
--ok
example := @ContinuousLinearMap.norm_id_le π (Dual π E) _ _ _
-- fail
example : βinclusionInDoubleDual π Eβ β€ 1 := by
have := @ContinuousLinearMap.norm_id_le π (Dual π E) _ _ _
Β· sorry
Β· sorry -- where did these goals come from?
Β· sorry
Eric Wieser (Sep 08 2023 at 08:20):
In the first example, the βinclusionInDoubleDual π Eβ
on the LHS is breaking typeclass search on the RHS (unless we use by exact
to isolate it)
Eric Wieser (Sep 08 2023 at 08:21):
In the second example, the type of the goal is somehow changing the elaboration of a have
statement
Eric Wieser (Sep 08 2023 at 08:21):
(cc @Sebastian Ullrich, whom I discussed this with this morning)
Eric Wieser (Sep 08 2023 at 08:24):
Replacing Dual π E
with E βL[π] π
in any of the broken examples seems to fix the issue, suggesting this is a bug in abbrev
+ TC search.
Eric Wieser (Sep 08 2023 at 08:39):
The problem seems to be a bad search cache: on the first example, I get
[Meta.synthInstance] β Norm (Dual π E βL[π] Dual π E) βΌ
[] new goal Norm (Dual π E βL[π] Dual π E) βΌ
[instances] #[@SeminormedAddGroup.toNorm, @SeminormedGroup.toNorm, @NormedAddGroup.toNorm, @NormedGroup.toNorm, @SeminormedAddCommGroup.toNorm, @SeminormedCommGroup.toNorm, @NormedAddCommGroup.toNorm, @NormedCommGroup.toNorm, @NonUnitalSeminormedRing.toNorm, @SeminormedRing.toNorm, @NonUnitalNormedRing.toNorm, @NormedRing.toNorm, @NormedDivisionRing.toNorm, @NormedField.toNorm, @ContinuousLinearMap.hasOpNorm]
[] β apply @ContinuousLinearMap.hasOpNorm to Norm (Dual π E βL[π] Dual π E) βΌ
[tryResolve] β Norm (Dual π E βL[π] Dual π E) β Norm (?m.16472 βSL[?m.16480] ?m.16473) βΌ
[] β
NontriviallyNormedField π βΌ
[] result instβΒ² (cached)
[] β
NontriviallyNormedField π βΆ
[] β SeminormedAddCommGroup (Dual π E) βΌ
[] result <not-available> (cached)
<snip>
where on the last line, lean didn't even bother to look for the instance that it couldn't find and just falsely claimed it already knew it was missing
Eric Wieser (Sep 08 2023 at 08:52):
Another MWE, where a rw
affects TC search withina have
that follows it; even though the have
does not ever see the main goal!
import Mathlib.Analysis.NormedSpace.OperatorNorm
variable (π : Type) [NontriviallyNormedField π]
variable (E : Type) [SeminormedAddCommGroup E] [NormedSpace π E]
abbrev Dual : Type _ := E βL[π] π
def inclusionInDoubleDual : E βL[π] Dual π (Dual π E) := sorry
example : βinclusionInDoubleDual π Eβ = 0 := by
-- this `rw` is needed to make the `have` below work
-- rw [inclusionInDoubleDual]
haveI : Norm (Dual π E βL[π] Dual π E) := inferInstance
sorry
Sebastian Ullrich (Sep 08 2023 at 10:36):
Underlying bug is lean4#2522. More data on impact and a non-Mathlib MWE would be greatly appreciated!
Eric Wieser (Sep 08 2023 at 11:47):
Thanks, your explanation is already helpful!
Kevin Buzzard (Sep 08 2023 at 12:48):
Making a non-Mathlib MWE will be hours of work, however it would not surprise me if someone could be persuaded to do that work if someone explained to them more details about why non-Mathlib MWEs are so important. All I know from experience is that they are very much appreciated by the lean dev community, but I don't really understand why. Is it because you don't know about lake exe cache get
and think that you have to spend hours compiling mathlib? ;-) If the answer is "mathlib just makes traces much more cluttered in general" then my first reaction to this is "are you absolutely sure that mathlib is making traces much more cluttered in this particular case?". But maybe the answer is something else which I haven't internalised yet.
Eric Wieser (Sep 08 2023 at 12:49):
Is it because you don't know about lake exe cache get and think that you have to spend hours compiling mathlib?
If you make a fix to Lean, the cache is (probably?) invalidated and you have to rebuild it all again
Sebastian Ullrich (Sep 08 2023 at 12:54):
@Kevin Buzzard Also, we can't add code with dependencies to the Lean 4 test suite (whose tests' runtimes should be measured in seconds, not hours)
Sebastian Ullrich (Sep 08 2023 at 12:56):
But note that doing minimization the usual way starting from the full code really isn't the optimal way here I believe. Instead one should start at the traces I posted and recreate only the components mentioned there, which hopefully should be much faster.
Kevin Buzzard (Sep 08 2023 at 13:26):
I think that it's not unreasonable to suggest that a general tool which produces mathlib-free MWEs would be very useful for this sort of thing; of course I don't have the ability to make it. I've heard that there is one in Coq but I don't know how well it works in practice. Thanks for the responses Sebastian and Eric.
Kevin Buzzard (Sep 08 2023 at 13:28):
@Eric Wieser and @Patrick Massot I might well take on mathlib-free minimisation of an example this evening; just to let you know in case you've started on one as well. What is the best target? Is it this post?
Kevin Buzzard (Sep 08 2023 at 13:28):
Sebastian -- do you have a preference?
Eric Wieser (Sep 08 2023 at 13:29):
I was not planning to take this on in the immediate future, so please do so!
Eric Wieser (Sep 08 2023 at 13:29):
I would guess all three examples will reproduce the same way
Kevin Buzzard (Sep 08 2023 at 20:28):
Here is a preliminary reduction, although there is still a long way to go:
import Mathlib.Analysis.Normed.Field.Basic
variable (π : Type) [NonUnitalSeminormedRing π]
variable (E : Type) [SeminormedAddCommGroup E]
structure ContinuousLinearMap' (M : Type) [TopologicalSpace M] (Mβ : Type) [TopologicalSpace Mβ] where
notation:25 M " βz " Mβ => ContinuousLinearMap' M Mβ
abbrev Dual : Type := E βz π
instance ContinuousLinearMap'.toSeminormedAddCommGroup {E : Type} {F : Type}
[SeminormedAddCommGroup E] [SeminormedAddCommGroup F] :
SeminormedAddCommGroup (E βz F) := sorry
def foo : E βz Dual π (Dual π E) := 0
example : βfoo π Eβ = 0 := by
-- this `rw` is needed to make the `have` below work
--rw [foo]
have : SeminormedAddCommGroup (Dual π E) := inferInstance
sorry
But now I need to properly understand what is going on, because further attempts by me to minimise just result in the problem going away. I have two questions about the summary at lean4#2522 :
1) what is a nested TC problem?
2) If I add set_option trace.Meta.synthInstance true
then I can see the failure
[Meta.synthInstance] β SeminormedAddCommGroup (Dual π E) βΌ
[] result <not-available> (cached)
at the end of the example above. My understanding is that the current belief is that the cache has been tricked to return this because of some earlier failure (when things were "nested"). But I can't find that earlier failure in the trace and am not entirely sure where I should be looking.
Kevin Buzzard (Sep 08 2023 at 20:52):
Aah, I've solved (2), it's deep within [Meta.synthInstance] β
Norm (E βz Dual π (Dual π E))
Kevin Buzzard (Sep 08 2023 at 20:59):
Aah and in my search I suspect I've also figured out what a nested typeclass search is; indeed the reason it was hard to find was because it was...erm...a typeclass search within a typeclass search.
Kevin Buzzard (Sep 08 2023 at 22:10):
class Norm' (E : Type) where
norm : E β Nat
export Norm' (norm)
class TopologicalSpace' (Ξ± : Type) where
random : Ξ± -- need something here for some reason
class SeminormedAddCommGroup' (Ξ± : Type) extends Norm' Ξ±, TopologicalSpace' Ξ± where
-- need to extend Norm' again for some reason; note that this doesn't seem to cause a diamond
class NonUnitalSeminormedRing' (Ξ± : Type) extends Norm' Ξ±, SeminormedAddCommGroup' Ξ± where
variable (π : Type) [NonUnitalSeminormedRing' π]
variable (E : Type) [SeminormedAddCommGroup' E]
structure ContinuousLinearMap' (M : Type) [TopologicalSpace' M] (Mβ : Type) [TopologicalSpace' Mβ] where
notation:25 M " βz " Mβ => ContinuousLinearMap' M Mβ
abbrev Dual : Type := E βz π
instance ContinuousLinearMap'.toSeminormedAddCommGroup' {E : Type} {F : Type}
[SeminormedAddCommGroup' E] [SeminormedAddCommGroup' F] :
SeminormedAddCommGroup' (E βz F) := sorry
def foo : E βz Dual π (Dual π E) := sorry
#synth SeminormedAddCommGroup' (Dual π E) -- works fine
-- set_option trace.Meta.synthInstance true
example : norm (foo π E) = 0 := by
-- this `rw` is needed to make the `have` below work
--rw [foo]
have : SeminormedAddCommGroup' (Dual π E) := inferInstance -- now fails!
sorry
/-
Relevant traces in the example:
1) On `norm (foo π E)`:
[Meta.synthInstance] β
Norm' (E βz Dual π (Dual π E)) βΌ
[] new goal Norm' (E βz Dual π (Dual π E)) βΆ
[] β
apply @NonUnitalSeminormedRing'.toNorm' to Norm' (E βz Dual π (Dual π E)) βΆ
[] β apply instβΒΉ to NonUnitalSeminormedRing' (E βz Dual π (Dual π E)) βΆ
[] β
apply @SeminormedAddCommGroup'.toNorm' to Norm' (E βz Dual π (Dual π E)) βΆ
[] β apply instβ to SeminormedAddCommGroup' (E βz Dual π (Dual π E)) βΆ
[] β
apply @ContinuousLinearMap'.toSeminormedAddCommGroup' to SeminormedAddCommGroup' (E βz Dual π (Dual π E)) βΌ
[tryResolve] β
SeminormedAddCommGroup' (E βz Dual π (Dual π E)) β SeminormedAddCommGroup' (E βz Dual π (Dual π E)) βΌ
[] β
SeminormedAddCommGroup' E βΆ
[] β
SeminormedAddCommGroup' (Dual π (Dual π E)) βΌ
[] new goal SeminormedAddCommGroup' (Dual π (Dual π E)) βΆ
[] β apply instβ to SeminormedAddCommGroup' (Dual π (Dual π E)) βΆ
[] β
apply @ContinuousLinearMap'.toSeminormedAddCommGroup' to SeminormedAddCommGroup' (Dual π (Dual π E)) βΌ
[tryResolve] β
SeminormedAddCommGroup' (Dual π (Dual π E)) β SeminormedAddCommGroup' (Dual π E βz π) βΌ
[] β SeminormedAddCommGroup' (Dual π E) βΌ
[] new goal SeminormedAddCommGroup' (Dual π E) βΆ
[] β apply instβ to SeminormedAddCommGroup' (Dual π E) βΆ
[] β apply @ContinuousLinearMap'.toSeminormedAddCommGroup' to SeminormedAddCommGroup' (Dual π E) βΌ
[tryResolve] β SeminormedAddCommGroup' (Dual π E) β SeminormedAddCommGroup' (?m.8308 βz ?m.8309)
2) Later, on `inferInstance`
[Meta.synthInstance] β SeminormedAddCommGroup' (Dual π E) βΌ
[] result <not-available> (cached)
-/
Mathlib-free! Should I post this on the github issue or are the names distasteful and I should replace them with proper computer science name like foo
and bar
?
Patrick Massot (Sep 08 2023 at 22:12):
I think those names are allowed.
Kevin Buzzard (Sep 08 2023 at 22:15):
The example is extremely fragile (this was one reason that minimisation was hard). If you tinker with random things then all of a sudden the failing [tryResolve] β SeminormedAddCommGroup' (Dual π E) β SeminormedAddCommGroup' (?m.8308 βz ?m.8309)
magically turns into a succeeding SeminormedAddCommGroup' (Dual π E) β SeminormedAddCommGroup' (E βz π)
. I have no understanding of what is going on here. Similarly the topological space structure has to have a field or else the problem goes away, and you have to extend Norm'
twice or the problem goes away.
Kevin Buzzard (Sep 08 2023 at 22:20):
class Norm' (E : Type) where
norm : E β Nat
export Norm' (norm)
class TopologicalSpace' (Ξ± : Type) where
random : Ξ± -- need something here for some reason
class SeminormedAddCommGroup' (Ξ± : Type) extends Norm' Ξ±, TopologicalSpace' Ξ± where
-- need to extend Norm' again for some reason; note that this doesn't seem to cause a diamond
class NonUnitalSeminormedRing' (Ξ± : Type) extends Norm' Ξ±, SeminormedAddCommGroup' Ξ± where
variable (π : Type) [NonUnitalSeminormedRing' π]
-- no diamond
example : (NonUnitalSeminormedRing'.toNorm' : Norm' π) =
@SeminormedAddCommGroup'.toNorm' π (@NonUnitalSeminormedRing'.toSeminormedAddCommGroup' π _) := rfl
Last updated: Dec 20 2023 at 11:08 UTC