Zulip Chat Archive
Stream: mathlib4
Topic: !4#3463 universe constraint issues
Kevin Buzzard (Apr 16 2023 at 12:37):
!4#3463 . Porting CategoryThjeory.Sites.Limits
and right now there are 40+ errors of the form stuck at solving universe constraint
which I don't know how to solve. The things Lean is getting stuck on are typically either of the form max v ?u.13688 =?= max u v
or max (max v w) ?u.16518 =?= max (max u v) w
. I've tagged the PR as help-wanted
. Any ideas?
Eric Wieser (Apr 16 2023 at 12:48):
Usually the fix is to tell Lean explicitly what you want to fill the universe metavariable with, by adding .{u}
somewhere
Eric Wieser (Apr 16 2023 at 12:49):
I think .{_,_,u}
might also be legal if u
isn't the first universe parameter, but I don't know
Jireh Loreaux (Apr 16 2023 at 13:09):
I've seen some universe issues like this arising from the ordering of implicit arguments changing (perhaps because of auto implicits?). So maybe compare those to the mathlib3 version.
Kevin Buzzard (Apr 16 2023 at 13:23):
Universe order changes in the following code.
-- lean3
import category_theory.category.basic
universes v u
open category_theory
variables {C : Type max v u} [i : category.{v} C]
set_option pp.universes true
#check @i -- i : category.{v (max v u)} C
vs
-- lean4
import Mathlib.CategoryTheory.Category.Basic
universe v u
open CategoryTheory
variable {C : Type max v u} [i : Category.{v} C]
set_option pp.universes true in
#check @i -- i : Category.{v, max u v} C
Reid Barton (Apr 16 2023 at 13:25):
Lean 4 seems to do some kind of universe level normalization that can make solving unification problems later more difficult
Reid Barton (Apr 16 2023 at 13:26):
We looked at this some in Karlsruhe with @Markus Himmel and others
Markus Himmel (Apr 16 2023 at 13:30):
Adam suggested at https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Universe.20issues.20with.20concrete.20categories/near/346361826 that the problem is related to typeclass inference, but I haven't made any progress on that file even with that knowledge.
Kevin Buzzard (Apr 16 2023 at 14:11):
Lean 4 is doing a better job of universes than lean 3 in CategoryTheory.Sheaf.multiforkEvaluationCone
: Lean 3 has stuff like (max v (max v u) w)
where Lean 4 has max (max u v) w
. One thing I find particularly surprising with Lean 4's normalisation is that it seems to be alphabetical: the "declare universes in a careful order" stuff we used to do in lean 3 category theory is now irrelevant?
I'm making progress with the PR again.
Joël Riou (Apr 16 2023 at 14:14):
I have just pushed this https://github.com/leanprover-community/mathlib4/pull/3463/commits/74211493db7923fe9ea0e7696f0a3f172b4888c2 which seems to make the situation less scary.
Kevin Buzzard (Apr 16 2023 at 14:23):
Yes, I'd also managed to find this fix! In fact you don't even need v
. Thanks for alerting me to the push!
Reid Barton (Apr 16 2023 at 14:36):
The order of declaring universe variables was for controlling the order that you would specify explicit universe level arguments in.
Kevin Buzzard (Apr 16 2023 at 16:19):
Ok so I've got it all compiling modulo a sorry -- an extra goal which appeared during an erw
and which is hopefully easy. But it's no good: the instances aren't firing because of the universe problems. See for example the bottom of the file:
-- porting note: I had to name this instance because I need to explicitly
-- use it in the next instance; in Lean 3 the typeclass inference
-- system could handle the universe problems.
instance instHasColimitsOfShapeSheaf [HasColimitsOfShape K D] : HasColimitsOfShape K (Sheaf J D) :=
⟨fun _ => HasColimit.mk
⟨sheafifyCocone.{_, _, u} (colimit.cocone _), isColimitSheafifyCocone _ (colimit.isColimit _)⟩⟩
-- porting note: typeclass inference used to do this and now it doesn't because of universe
-- issues.
instance [HasColimits D] : HasColimits (Sheaf J D) := ⟨by
intro K _
exact instHasColimitsOfShapeSheaf.{_, _, u}⟩
-- porting note: instance above won't fire because of universe issues.
-- example [HasColimits D] : HasColimits (Sheaf J D) := inferInstance -- doesn't actually work
Kevin Buzzard (Apr 17 2023 at 19:36):
Gabriel informs us in the porting meeting that Lean.Level.normalize
does indeed reorder universes into alphabetical order, which is presumably part of the reason that universes are being randomly permuted in the port.
import Lean
#eval Lean.Level.normalize (.max (.param `v) (.param `w))
-- Lean.Level.max (Lean.Level.param `v) (Lean.Level.param `w)
#eval Lean.Level.normalize (.max (.param `v) (.param `u))
-- Lean.Level.max (Lean.Level.param `u) (Lean.Level.param `v)
Mario Carneiro (Apr 18 2023 at 02:36):
Just catching up on the meeting now and seeing this issue, and it's not immediately clear to me why the observed reordering matters at all. The careful ordering of universe arguments in the category theory library is about the argument order to regular functions and definitions like Category.{v, u}
, not the built in level operation max u v
which is supposed to be commutative. Any occurrence of max u v
should be treated identically to max v u
, so the mentioned canonicalization doesn't seem to be a problem. @Kevin Buzzard mentions recalling that max u v = max u ?v
is unified to ?v := v
in lean 3 but I don't think this is the case, IIRC it was just as conservative as lean 4 in this regard.
Gabriel Ebner (Apr 18 2023 at 02:57):
From what I recall (and see in the source code), the order did matter in Lean 3. Level unification seems to be completely rewritten in Lean 4 though, and in a way that seems to intentionally ignore the order.
Gabriel Ebner (Apr 18 2023 at 03:10):
I couldn't find any design discussion on zulip or github, but my best guess is that this behavior is intentional since max u v = max u ?w
does not have a unique solution (e.g. we could assign ?w = v
or ?w = max u v
).
Mario Carneiro (Apr 18 2023 at 03:15):
Yes, the lean 4 behavior makes sense to me, but I recall having ambiguous unification issues of exactly that form in lean 3 as well, so perhaps that was a fallback behavior that triggered only in certain circumstances?
Mario Carneiro (Apr 18 2023 at 03:17):
Also this issue still needs a #mwe demonstrating a failing instance or something that worked in lean 3
Gabriel Ebner (Apr 18 2023 at 03:21):
universes u v
def foo : Type u × Type max u v := (punit, punit)
#check (foo : Type u × Type max u v) -- works in Lean 3
Gabriel Ebner (Apr 18 2023 at 03:22):
universe u v
def foo : Type u × Type max u v := (PUnit, PUnit)
#check (foo : Type u × Type max u v) -- fails in Lean 4
Mario Carneiro (Apr 18 2023 at 03:24):
I see. And #check (foo : Type u × Type max v u)
fails in lean 3
Mario Carneiro (Apr 18 2023 at 03:25):
and #check (foo : Type u × Type max u (max u v))
also yields foo.{u v}
which is... fun
Mario Carneiro (Apr 18 2023 at 03:29):
One possible way to improve the situation here would be if there was a way to declare universe inequalities, as an elaborator feature which desugars def foo.{u, v>=u}
to def foo.{u, v}
in the declaration site and an annotation to always pass max u v
instead of v
for the second universe argument
Gabriel Ebner (Apr 18 2023 at 03:32):
That would only change the unification problem from max u ?w = max u v
to max u (max u ?w) = max u v
.
Mario Carneiro (Apr 18 2023 at 03:34):
ex:
def foo.{u, v where v ≥ u} : Type u × Type v := (PUnit, PUnit)
-- sent to kernel: def foo.{u, v} : Type u × Type (max u v) := (PUnit, PUnit)
-- elaborator remembers that foo.{u, v where v ≥ u} : Type u × Type v
universe u v
#check (foo : Type u × Type (max u v)) -- infers foo.{u, max u v}
Mario Carneiro (Apr 18 2023 at 03:35):
the unification problem in this case would be foo.{?u, ?v} : Type ?u × Type ?v =?= Type u × Type (max u v)
because the elaborator remembers that foo
was declared with a universe inequality
Mario Carneiro (Apr 18 2023 at 03:39):
I think we don't have precedent for the "elaborator remembers" part, that would have to be a separate piece of data from the ConstInfo, maybe an environment extension which stores the type with its declared universes rather than the max encoding used for the kernel
Mario Carneiro (Apr 18 2023 at 03:41):
When creating the foo.{?u, ?v}
term we also get a pending defeq problem ?v =?= max ?u ?v
which needs to be resolved after ?v
is assigned
Mario Carneiro (Apr 18 2023 at 03:44):
Conceivably this could even be done without user annotations like where v ≥ u
, since you can look at the type to try to find candidate universes like v
here that only appear in the form max a v
for some fixed a
Gabriel Ebner (Apr 18 2023 at 03:52):
At that point it might be easier to just add the rule that max t s =?= max t r
reduces to s =?= r
.
Mario Carneiro (Apr 18 2023 at 05:02):
I assume you mean that it would be too much work to implement? I agree that it's quite a big divergence from the status quo but I think it would definitely lead to better outcomes than the lean 3 heuristic
Mario Carneiro (Apr 18 2023 at 05:06):
I'm just talking about what we could do to avoid dealing with unification problems of the form max u v = max u ?v
without changing the theory, in the long run
Reid Barton (Apr 18 2023 at 05:32):
Mario Carneiro said:
One possible way to improve the situation here would be if there was a way to declare universe inequalities, as an elaborator feature which desugars
def foo.{u, v>=u}
todef foo.{u, v}
in the declaration site and an annotation to always passmax u v
instead ofv
for the second universe argument
Yeah I mentioned the same idea to Sebastian in Karlsruhe--I only gave it a couple minutes' thought but it seems like it could be a translation managed by the elaborator, at least in ordinary use (e.g. ignoring metaprogramming)
Adam Topaz (Apr 21 2023 at 16:15):
I'm running into a similar universe issue on line 241 of !4#3487
Adam Topaz (Apr 21 2023 at 16:20):
instance topCat_hasLimitsOfSize : HasLimitsOfSize.{v} TopCat.{max v u}
where has_limits_of_shape _ :=
{ has_limit := fun F =>
HasLimit.mk
{ cone := limitCone.{v,u} F
isLimit := limitConeIsLimit F } }
#align Top.Top_has_limits_of_size TopCat.topCat_hasLimitsOfSize
example : HasLimitsOfSize.{v} TopCat.{max v u} := by infer_instance
/-
stuck at solving universe constraint
max (u+1) (v+1) =?= max (v+1) (?u.31052+1)
while trying to unify
HasLimitsOfSize TopCat
with
(HasLimitsOfSize TopCat) (HasLimitsOfSize TopCat) (HasLimitsOfSize TopCat)
-/
That can't be good.
Matthew Ballard (Apr 21 2023 at 16:22):
If you delete the universe annotations, it seems to work
Adam Topaz (Apr 21 2023 at 16:23):
but that's without general universes
Adam Topaz (Apr 21 2023 at 16:23):
I think
Matthew Ballard (Apr 21 2023 at 16:23):
The .{max v u}
annotation seems to make Lean 4 very unhappy
Adam Topaz (Apr 21 2023 at 16:24):
But I don't understand why.
Adam Topaz (Apr 21 2023 at 16:24):
Anyway, this is not sustainable.
Adam Topaz (Apr 21 2023 at 16:25):
I'm starting to think that we need to ungeneralize the universe parameters in the (co)limit library :-/
Matthew Ballard (Apr 21 2023 at 16:26):
That was my initial impression but it seems that stripping out the max’s generally makes things smoother than I first expected.
Matthew Ballard (Apr 21 2023 at 16:26):
From checking the resulting declaration, it seemed to me that Lean was doing the correct thing (or a reasonable thing).
Adam Topaz (Apr 21 2023 at 16:27):
I mean, this is ridiculous:
set_option pp.universes true
def foo : HasLimitsOfSize TopCat := inferInstance -- works
#check foo
/-
TopCat.foo.{u_1, u_2} : HasLimitsOfSize.{u_1, u_1, max u_1 u_2, (max u_1 u_2) + 1} TopCat.{max u_1 u_2}
-/
def bar : HasLimitsOfSize.{v, v, max v u, (max v u)+1} TopCat.{max v u} := inferInstance -- fails
/-
stuck at solving universe constraint
max (u+1) (v+1) =?= max (v+1) (?u.31092+1)
while trying to unify
HasLimitsOfSize.{v, v, max v u, (max v u) + 1} TopCat.{max v u}
with
(HasLimitsOfSize.{v, v, max ?u.31092 v, max (?u.31092 + 1) (v + 1)} TopCat.{max v ?u.31092})
(HasLimitsOfSize.{v, v, max ?u.31092 v, max (?u.31092 + 1) (v + 1)} TopCat.{max v ?u.31092})
(HasLimitsOfSize.{v, v, max ?u.31092 v, max (?u.31092 + 1) (v + 1)} TopCat.{max v ?u.31092})
-/
Matthew Ballard (Apr 21 2023 at 16:30):
Yes. Take my suggestion as a workaround and not a permanent solution.
Kevin Buzzard (Apr 21 2023 at 16:35):
@Adam Topaz does it work if you change u
to w
? (the reason I'm asking is that "u,v" is in alphabetical order whereas "w,v" isn't)
Adam Topaz (Apr 21 2023 at 16:36):
def bar : HasLimitsOfSize.{v, v, max v w, (max v w)+1} TopCat.{max v w} := inferInstance -- fails
nope, still fails.
Adam Topaz (Apr 21 2023 at 16:37):
@Gabriel Ebner @Mario Carneiro (or any other lean4 universe experts?) do you have any suggestions here?
Mario Carneiro (Apr 21 2023 at 16:40):
can you make a MWE? The types of relevant constants should suffice
Adam Topaz (Apr 21 2023 at 16:40):
I need to run in a few minutes, but I'll do my best.
Adam Topaz (Apr 21 2023 at 16:41):
Maybe Matt has time to make a MWE?
Mario Carneiro (Apr 21 2023 at 16:42):
pulling this stuff deep in mathlib always means getting the latest mathlib, lean, and cache which takes long enough for me to forget what I was trying to do in the first place
Kevin Buzzard (Apr 21 2023 at 16:42):
I'm about to get on the tube, I'll try minimising and report back in 50 minutes (if I don't get a seat then it won't happen)
Matthew Ballard (Apr 21 2023 at 16:42):
I’ve got to meet with a student in a few minutes
Kevin Buzzard (Apr 21 2023 at 16:46):
Meh do we not have the instance in master?
Kevin Buzzard (Apr 21 2023 at 16:50):
found it in !4#3487
Matthew Ballard (Apr 21 2023 at 16:54):
Sorry. I didn’t realize that was the question.
Adam Topaz (Apr 21 2023 at 17:02):
section
universe v u
class Foo (C : Type u) where
Bar : Type v
end
section
universe v' v u' u
class Bar (C : Type u) [Foo.{v} C] (D : Type u') [Foo.{v'} D] where
Baz : Type (max (max u' u) v)
end
universe v u
variable (C : Type ((max v u) + 1)) (D : Type v)
[Foo.{max v u} C] [Foo.{v} D]
instance : Bar.{v} C D := sorry
example : Bar.{v} C D := inferInstance
Adam Topaz (Apr 21 2023 at 17:03):
I think that should capture essentially the same error @Mario Carneiro with no mathlib4 dependency
Gabriel Ebner (Apr 21 2023 at 17:07):
Can you remind me what Foo/Bar/Baz are again?
Adam Topaz (Apr 21 2023 at 17:07):
Foo.{v} C
should correspond to Category.{v} C
and Bar C D
should correspond to HasLimitsOfShape C D
(approximately)
Mario Carneiro (Apr 21 2023 at 17:08):
This instance looks like it should be linted against
Mario Carneiro (Apr 21 2023 at 17:08):
because Bar
has four universe parameters and the second one is not constrained in a useful way
Adam Topaz (Apr 21 2023 at 17:08):
I did this in a rush, so I'm not 100% sure I got the universes right.
Eric Wieser (Apr 21 2023 at 17:08):
Would that linter forbid the docs4#Lean.ToLevel instances too Mario?
Adam Topaz (Apr 21 2023 at 17:08):
But the error at the end looks similar.
Mario Carneiro (Apr 21 2023 at 17:09):
no, since you can determine that universe from the output type
Eric Wieser (Apr 21 2023 at 17:10):
What do you mean "the output type"? The output type is Lean.ToLevel.toLevel.{u} : Nat
Mario Carneiro (Apr 21 2023 at 17:11):
I mean the typeclass type
Mario Carneiro (Apr 21 2023 at 17:11):
the thing that is being instance-searched
Mario Carneiro (Apr 21 2023 at 17:11):
ToLevel.{u}
in this case
Mario Carneiro (Apr 21 2023 at 17:13):
The error message here seems pretty borked though:
stuck at solving universe constraint
max (u+1) (v+1) =?= max (v+1) (?u.165+1)
while trying to unify
Bar C D
with
(Bar C D) C inst✝¹ D inst✝
Bar C D
is not a function, it looks like the error message put the type of the instance instead of the instance itself
Gabriel Ebner (Apr 21 2023 at 17:13):
(deleted)
Gabriel Ebner (Apr 21 2023 at 17:17):
because Bar has four universe parameters and the second one is not constrained in a useful way
It's constrained via the [Category.{v} C]
argument.
Mario Carneiro (Apr 21 2023 at 17:17):
also lean says the type of Bar.{v} C D
is
⊢ Type (max (max ((max (u + 1) (v + 1)) + 1) (v + 1)) ((max u v) + 1))
which seems like a failure of level normalization, although I doubt it is the actual issue
Mario Carneiro (Apr 21 2023 at 17:18):
sorry I meant v
u
in the anonymous instance
Gabriel Ebner (Apr 21 2023 at 17:20):
You mean u
, right? The v
is well constrained, but the only way to figure out the u
is by solving max ?u v = max u v
.
Mario Carneiro (Apr 21 2023 at 17:20):
The instance has type:
⊢ (C : Type ((max v u) + 1)) →
(D : Type v) →
[inst : Foo.{max v u, max (u + 1) (v + 1)} C] →
[inst_1 : Foo.{v, v} D] → Bar.{v, max u v, v, max (u + 1) (v + 1)} C D
u
never appears alone in this type, so the mathlib3 linter should fire on it
Mario Carneiro (Apr 21 2023 at 17:21):
it's possible it is fooled by the max (u + 1) (v + 1)
at the end, which seems to be the lean 4 preferred way to spell max u v + 1
Gabriel Ebner (Apr 21 2023 at 17:21):
From what I remember, the mathlib linter explicitly accepts this. It expects the unifier to solve max u v = max ?u v
.
Gabriel Ebner (Apr 21 2023 at 17:21):
The +1 is a red herring here.
Gabriel Ebner (Apr 21 2023 at 17:22):
Slightly cleanup up MWE:
universe v' v u' u -- specify order of universe parameters
class Category (C : Type u) where
Morphisms : Type v
class HasLimitsOfShape (C : Type u) [Category.{v} C] (D : Type u') [Category.{v'} D] where
Limits : Type max u' u v
variable (C : Type max v u) (D : Type v) [Category.{max v u} C] [Category.{v} D]
instance : HasLimitsOfShape.{v} C D := sorry
example : HasLimitsOfShape.{v} C D := inferInstance
/-
stuck at solving universe constraint
max u v =?= max v ?u.165
-/
Mario Carneiro (Apr 21 2023 at 17:22):
I mean it might be fooling our linter
Gabriel Ebner (Apr 21 2023 at 17:23):
To quote the linter doc:
This usually means that there is a
max u v
in the type where neitheru
norv
occur by themselves.
Here, the v
already appears by itself, so max u v
is kosher.
Mario Carneiro (Apr 21 2023 at 17:24):
I see. I maintain that this should be rejected by a linter though
Eric Wieser (Apr 21 2023 at 17:24):
Note that the example above still fails even if you hand-hold lean on the universe arguments of the desired type, and cut out typeclass search
def bar : Bar.{v, max u v, v, max (u + 1) (v + 1)} C D := sorry
example : Bar.{v, max u v, v, max (u + 1) (v + 1)} C D := bar _ _ -- fails
example : Bar.{v, max u v, v, max (u + 1) (v + 1)} C D := bar.{_,u} _ _ -- ok
Mario Carneiro (Apr 21 2023 at 17:25):
@Eric Wieser that's basically what I mean, from the input and output types alone you still can't solve the universe argument in bar.{_}
Mario Carneiro (Apr 21 2023 at 17:25):
this kind of instance will never work
Gabriel Ebner (Apr 21 2023 at 17:26):
It did work "just fine" in Lean 3 though.
Mario Carneiro (Apr 21 2023 at 17:27):
I don't like the idea of reintroducing the broken lean 3 normalization / level unification though
Gabriel Ebner (Apr 21 2023 at 17:27):
from the input and output types alone you still can't solve the universe argument
Of course you can solve it. Solving max ?u v = max u v
is not impossible, it's merely unclear whether we want or should do it.
Mario Carneiro (Apr 21 2023 at 17:28):
I am actually wondering whether we should try to prefer ?u := max u v
for that kind of problem
Eric Wieser (Apr 21 2023 at 17:28):
Do we have a scenario where solving it is harmful?
Gabriel Ebner (Apr 21 2023 at 17:30):
It is harmful if you later need to unify ?u = u
or ?u = max u v
. Right now, this kind of constraint gets postponed.
Mario Carneiro (Apr 21 2023 at 17:32):
Then again, if we get to the point that we are going to reject the solution entirely due to stuck universe constraints, we apparently never got to ?u = u
or ?u = max u v
Mario Carneiro (Apr 21 2023 at 17:32):
so maybe it's fine to just pick one
Mario Carneiro (Apr 21 2023 at 17:33):
and I think max u v
is the more predictable one, if we had to choose
Kevin Buzzard (Apr 21 2023 at 17:53):
Just catching up but here's the MWE I made:
-- set_option pp.universes true
class Quiver'.{v, u} (V : Type u) where
Hom : V → V → Sort v
class Category'.{v, u} (obj : Type u) extends Quiver'.{v + 1} obj : Type max u (v + 1) where
def TopCat'.{u} : Type (u + 1) := PUnit
instance moo.{u} : Category'.{u, u + 1} TopCat' := sorry
class HasLimitsOfSize'.{v₁, u₁, v, u} (C : Type u) [Category'.{v} C] : Prop where
has_limits_of_shape : ∀ (J : Type u₁) [Category'.{v₁} J], True
instance foo.{u_1, u_2} :
HasLimitsOfSize'.{u_1, u_1, max u_1 u_2, (max u_1 u_2) + 1} TopCat'.{max u_1 u_2} :=
sorry
def bar.{u_1, u_2} :
HasLimitsOfSize'.{u_1, u_1, max u_1 u_2, (max u_1 u_2) + 1} TopCat'.{max u_1 u_2} :=
inferInstance
/-
stuck at solving universe constraint
max u_1 u_2 =?= max u_1 ?u.98
while trying to unify
HasLimitsOfSize' TopCat'
with
(HasLimitsOfSize' TopCat') (HasLimitsOfSize' TopCat') (HasLimitsOfSize' TopCat')
-/
Kevin Buzzard (Apr 21 2023 at 17:54):
The error message here seems pretty borked though:
Yeah, that was already observed by Jeremy Tan in another thread. There's a lot of repetition.
Kevin Buzzard (Apr 21 2023 at 17:55):
My example shows that there's an issue even without the universe order switch.
Kevin Buzzard (Apr 21 2023 at 18:43):
Note also the incorrect repetitions in the error message.
Gabriel Ebner (Apr 21 2023 at 18:45):
I think we understand now pretty well what Lean code triggers this issue. It happens whenever we have two types and we want one of them to live in a bigger universe than the other. All of the examples in this thread are of this form:
class Something (A : Type u) (B : Type v)
instance whenUniversesLE (A : Type u) (B : Type max u v) : Something A B where
example (A : Type u) (B : Type max u v) : Something A B := inferInstance -- fails
Gabriel Ebner (Apr 21 2023 at 18:49):
What I still don't completely get is where these constraints come from in the first place, and how essential they are. Could we replace them by a Type u ↪ Type v
assumption?
Matthew Ballard (Apr 21 2023 at 18:51):
I’m curious. What do you have in mind?
Johan Commelin (Apr 21 2023 at 18:52):
@Gabriel Ebner They come from the fact that we want to support both small categories and large categories: https://en.wikipedia.org/wiki/Category_(mathematics)#Small_and_large_categories
Kevin Buzzard (Apr 21 2023 at 18:55):
Reid posted an example of why we care about universe inequalities: the category Type u
has v-small limits if v <= u and doesn't have them if v > u.
Johan Commelin (Apr 21 2023 at 18:55):
In pseudo-code:
GroupCat := Σ (G : Type u), GroupStructure G
#check GroupCat : Type (u+1) -- the large universe
variables (G₁ G₂ : GroupCat)
#check G₁ ⟶ G₂ : Type u -- the small universe
Johan Commelin (Apr 21 2023 at 18:57):
Here's a wild thought: we could have syntax for v ≤ u
, and the kernel could run a micro-version of omega
(probably omicron
?) to check that universe constraints are satisfied.
I have no idea how realistic this is performancewise....
Gabriel Ebner (Apr 21 2023 at 18:57):
Thanks Kevin for spelling this out to me.
Matthew Ballard (Apr 21 2023 at 18:57):
It guarantees you can quantify over some things without bumping universe levels for the objects.
Matthew Ballard (Apr 21 2023 at 18:58):
If universe inequalities are a feasible option, that would be great.
Adam Topaz (Apr 21 2023 at 19:55):
I'm just playing around with some ideas for now.
import Mathlib
class ULE.{u,v} : Prop where
cond : Nonempty (Cardinal.{u} ↪ Cardinal.{v})
instance [ULE.{u,v}] [ULE.{v,w}] : ULE.{u,w} where
cond := by
obtain ⟨a⟩ := ULE.cond.{u,v}
obtain ⟨b⟩ := ULE.cond.{v,w}
exact ⟨a.trans b⟩
instance : ULE.{u,u} where
cond := ⟨Function.Embedding.refl _⟩
instance : ULE.{u,u+1} where
cond := ⟨Cardinal.lift.{u+1}, Cardinal.lift_injective⟩
--instance : ULE.{u, max v u} where
-- cond := ⟨Cardinal.lift.{v}, Cardinal.lift_injective⟩
--instance : ULE.{u, max u v} where
-- cond := ⟨Cardinal.lift.{v}, Cardinal.lift_injective⟩
example [ULE.{u,v}] [ULE.{v,w}] [ULE.{w,v'}] : ULE.{u,v'} := inferInstance
If you uncomment one or both of the the two commented out instances, then the last one fails. Does TC search just stop when it can't unify universes? That seems strange.
Gabriel Ebner (Apr 21 2023 at 20:00):
I think this runs into the same issue as this thread. The two commented instances require unifying max u ?v = max u v
.
Adam Topaz (Apr 21 2023 at 20:01):
right, that's what I figured. But once this fails, why doesn't TC search just keep going?
Gabriel Ebner (Apr 21 2023 at 20:03):
Oh, it keeps going. But what happens is that it con't solve the unification constraint immediately, and postpones it. So it actually "successfully" returns an instance. It's only at the very end that it figures it can't solve max u ?v = max u v
and fails.
Adam Topaz (Apr 21 2023 at 20:08):
Ah I see.
Adam Topaz (Apr 21 2023 at 20:09):
I guess that's why reordering things works:
import Mathlib
class ULE.{u,v} : Prop where
cond : Nonempty (Cardinal.{u} ↪ Cardinal.{v})
instance : ULE.{u,u} where
cond := ⟨Function.Embedding.refl _⟩
instance : ULE.{u,u+1} where
cond := ⟨Cardinal.lift.{u+1}, Cardinal.lift_injective⟩
instance : ULE.{u, max v u} where
cond := ⟨Cardinal.lift.{v}, Cardinal.lift_injective⟩
instance : ULE.{u, max u v} where
cond := ⟨Cardinal.lift.{v}, Cardinal.lift_injective⟩
instance [ULE.{u,v}] [ULE.{v,w}] : ULE.{u,w} where
cond := by
obtain ⟨a⟩ := ULE.cond.{u,v}
obtain ⟨b⟩ := ULE.cond.{v,w}
exact ⟨a.trans b⟩
example [ULE.{u,v}] [ULE.{v,w}] [ULE.{w,v'}] : ULE.{u,v'} := inferInstance
Adam Topaz (Apr 21 2023 at 20:09):
Is this intended?
Gabriel Ebner (Apr 21 2023 at 20:13):
I mean, yeah. What instances are tried first depends among other things on the order they're declared in. (If the order is important, it's better to put a priority on the instance though.) In this case, one instance works out at the end while another one blows up.
Adam Topaz (Apr 21 2023 at 20:17):
Sure, that I understand. But I still find it strange that lean remembers the universe unification problem from a failed attempt, and then tries the same problem on a successful attempt later on.
Adam Topaz (Apr 21 2023 at 20:18):
But of course I know nothing about the internals of the typeclass system, and there's probably a good reason for this which I don't understand.
Gabriel Ebner (Apr 21 2023 at 20:20):
lean remembers the universe unification problem from a failed attempt
From Lean's POV, it was a successful attempt!
Adam Topaz (Apr 21 2023 at 20:24):
hmm... okay now I'm confused again :)
Adam Topaz (Apr 21 2023 at 20:25):
Ah okay I see. The TC trace is as follows:
import Mathlib
/-- foo -/
class ULE.{u,v} : Prop where
/-- bar -/
cond : Nonempty (Cardinal.{u} ↪ Cardinal.{v})
instance [ULE.{u,v}] [ULE.{v,w}] : ULE.{u,w} where
cond := by
obtain ⟨a⟩ := ULE.cond.{u,v}
obtain ⟨b⟩ := ULE.cond.{v,w}
exact ⟨a.trans b⟩
instance rfl_ULE : ULE.{u,u} where
cond := ⟨Function.Embedding.refl _⟩
instance succ_ULE : ULE.{u,u+1} where
cond := ⟨Cardinal.lift.{u+1}, Cardinal.lift_injective⟩
instance max_right_ULE : ULE.{u, max v u} where
cond := ⟨Cardinal.lift.{v}, Cardinal.lift_injective⟩
instance max_left_ULE : ULE.{u, max u v} where
cond := ⟨Cardinal.lift.{v}, Cardinal.lift_injective⟩
set_option pp.universes true in
set_option trace.Meta.synthInstance true in
example [ULE.{u,v}] [ULE.{v,w}] [ULE.{w,v'}] : ULE.{u,v'} := inferInstanc
[Meta.synthInstance] ✅ ULE.{u, v'} ▼
[] new goal ULE.{u, v'} ▶
[] ❌ apply inst✝ to ULE.{u, v'} ▶
[] ❌ apply inst✝¹ to ULE.{u, v'} ▶
[] ❌ apply inst✝² to ULE.{u, v'} ▶
[] ✅ apply max_left_ULE.{?u.238, u} to ULE.{u, v'} ▼
[tryResolve] ✅ ULE.{u, v'} ≟ ULE.{u, max u ?u.238}
[] result max_left_ULE.{?u.240, u}
so for some reason typeclass search stops thinking it succeeded, and only then tries to unify universes which causes a failure.
Gabriel Ebner (Apr 21 2023 at 20:28):
Okay, Lean tries to apply ULE.{?u, max ?u ?v}
to the ULE.{u,v'}
in the example. It can unify ?u = u
so it does that right away. But it can't solve max u ?v = v'
just yet, so it puts it on a todo list somewhere to figure out later. Maybe something down the line will give us a value for ?v
, maybe when we solve one of the subgoals, who knows? But there are no more subgoals, so Lean declares the instance a complete success. Does that make sense?
Adam Topaz (Apr 21 2023 at 20:28):
Yes, I think I understand. Thanks for the explanation!
Adam Topaz (Apr 22 2023 at 20:25):
Matthew Ballard said:
If you delete the universe annotations, it seems to work
Unfortunately, lean does not choose appropriately general universes in this case:
def piIsoPi {ι : Type v} (α : ι → TopCat) :
∏ α ≅ TopCat.of (∀ i, α i) :=
(limit.isLimit _).conePointUniqueUpToIso (piFanIsLimit α)
#align Top.pi_iso_pi TopCat.piIsoPi
set_option pp.universes true in #check piIsoPi
/-
TopCat.piIsoPi.{v} {ι : Type v} (α : ι → TopCat.{v}) :
Iso.{v, v + 1} (piObj.{v, v, v + 1} α) (of.{v} ((i : ι) → (α i).α))
-/
Replacing v
with _
gives this result:
{ι : Type (max u_1 u_2)} →
(α : ι → TopCat.{max u_1 u_2}) →
Iso.{max u_1 u_2, (max u_1 u_2) + 1} (piObj.{max u_1 u_2, max u_1 u_2, (max u_1 u_2) + 1} α)
(of.{max u_1 u_2} ((i : ι) → (α i).α))
I fiddled for a bit with specifying universes explicitly for this declaration, but I just couldn't get things to work out.
Mario Carneiro (Apr 25 2023 at 10:53):
At the porting meeting it was suggested that this problem could be addressed by using a constant with separate universe arguments to avoid trying to unify two max
expressions directly. Here is an example of using that technique to solve all the MWEs in this thread:
abbrev BigType.{u, v} := Type max u v
namespace X
universe u v
def foo : Type u × BigType.{u,v} := (PUnit, PUnit)
#check (foo : Type u × BigType.{u,v})
end X
section
universe v u
class Foo (C : Type u) where
Bar : Type v
end
section
universe v' v u' u
class Bar (C : Type u) [Foo.{v} C] (D : Type u') [Foo.{v'} D] where
Baz : Type (max (max u' u) v)
end
section
universe v u
variable (C : BigType.{u+1, v+1}) (D : Type v)
[Foo.{max v u} C] [Foo.{v} D]
instance : Bar.{v} C D := sorry
example : Bar.{v} C D := inferInstance
class Category (C : Type u) where
Morphisms : Type v
abbrev BigCategory (C : BigType.{u, v'}) := Category.{v} C
class HasLimitsOfShape (C : Type u) [Category.{v} C] (D : Type u') [Category.{v'} D] where
Limits : Type max u' u v
abbrev BigHasLimitsOfShape (C : BigType) [Category C] (D : Type u') [Category.{v'} D] :=
HasLimitsOfShape C D
variable (C : BigType.{u, v}) (D : Type v) [Category C] [Category.{v} D]
instance : BigHasLimitsOfShape.{v} C D := sorry
example : BigHasLimitsOfShape.{v} C D := inferInstance
end
section
-- set_option pp.universes true
class Quiver'.{v, u} (V : Type u) where
Hom : V → V → Sort v
class Category'.{v, u} (obj : Type u) extends Quiver'.{v + 1} obj : Type max u (v + 1) where
abbrev BigCategory'.{v, u, u'} (C : BigType.{u, u'}) := Category.{v} C
def TopCat'.{u} : Type (u + 1) := PUnit
abbrev BigTopCat'.{u, v} : BigType.{u+1,v+1} := TopCat'
instance moo.{u} : Category'.{u, u + 1} TopCat' := sorry
class HasLimitsOfSize'.{v₁, u₁, v, u} (C : Type u) [Category'.{v} C] : Prop where
has_limits_of_shape : ∀ (J : Type u₁) [Category'.{v₁} J], True
instance foo : HasLimitsOfSize' BigTopCat' := sorry
def bar : HasLimitsOfSize' BigTopCat' := inferInstance
end
class Something (A : Type u) (B : Type v)
instance whenUniversesLE (A : Type u) (B : BigType.{u, v}) : Something A B where
example (A : Type u) (B : BigType.{u, v}) : Something A B := inferInstance -- fails
Scott Morrison (Apr 25 2023 at 11:30):
Except you need to remove the -- fails
on the last line, as happily it doesn't fail! :-)
Kevin Buzzard (Apr 25 2023 at 12:09):
Interesting idea! Sorry I wasn't at the meeting yesterday, it coincided with family dinner. But this universe issue is "blocking Copenhagen" so thanks a lot for looking at it!
Adam Topaz (Apr 25 2023 at 12:25):
Nice! How could we use this in the TopCat
example? I suppose we could redefine it as TopCat.{u,v}
to cave carrier Type (max u v)
. Would that cause issues in the case where u=v
?
Mario Carneiro (Apr 25 2023 at 12:29):
I think I did the TopCat
example
Mario Carneiro (Apr 25 2023 at 12:31):
the basic strategy is to make a BigTopCat
wrapper when you want to be able to separately unify the u
and v
arguments of a max u v
universe somewhere
Adam Topaz (Apr 25 2023 at 12:33):
Ah I see.
Mario Carneiro (Apr 25 2023 at 12:34):
Since everything here is an abbrev
, it should not seriously block any unification problem when lean is in tryhard mode, but it gives a bit of extra hint in some cases. Notably, (rfl : BigType.{u, v} = BigType.{v, u})
fails, although using Eq.refl (Type _)
works as a proof
Mario Carneiro (Apr 25 2023 at 12:36):
my hope is that these tricks only need to be used in some implementation detail instances, so most theorems can still be stated "naturally"
Yaël Dillies (Apr 25 2023 at 14:23):
And if you want Type max u v w
you define BigBigType.{u, v, w}
?
Mario Carneiro (Apr 25 2023 at 14:26):
Note that the two universes in BigType
are not really interchangeable and I expect we will come up with some convention regarding which is the unbound universe and which is the bound one. For Type max u v w
I would expect only one unbound universe and hence BigType.{u, max v w}
should suffice
Adam Topaz (Apr 25 2023 at 14:27):
Yeah we will probably need to stick to the old "universe level of morphisms come before objects"
Matthew Ballard (Apr 25 2023 at 14:37):
Thanks Mario! Is this viewed as a workaround until something changes upstream or something more permanent?
Mario Carneiro (Apr 25 2023 at 14:42):
I have no idea what the prospects are for something better, as all the proposed solutions are at various levels of pie in the sky
Adam Topaz (Apr 25 2023 at 15:28):
I'm trying to make this trick work for the following decl:
def piIsoPi {ι : Type v} (α : ι → TopCat.{max v u}) :
∏ α ≅ TopCat.of (∀ i, α i) :=
(limit.isLimit _).conePointUniqueUpToIso (piFanIsLimit α)
Adam Topaz (Apr 25 2023 at 15:29):
But I'm still getting the error:
stuck at solving universe constraint
max u v =?= max v ?u.56877
while trying to unify
HasLimitsOfSize TopCat
with
(HasLimitsOfSize BigTopCat) (HasLimitsOfSize BigTopCat) (HasLimitsOfSize BigTopCat)
Adam Topaz (Apr 25 2023 at 15:32):
Even this
def piIsoPi {ι : Type v} (α : ι → BigTopCat.{v, u}) :
∏ α ≅ BigTopCat.of (∀ i, α i) :=
sorry
gives an error
stuck at solving universe constraint
max (u+1) (v+1) =?= max (?u.57707+1) (?u.57708+1)
while trying to unify
Type (max u v) : Type (max (u + 1) (v + 1))
with
Type (max ?u.57708 ?u.57707) : Type ((max ?u.57708 ?u.57707) + 1)
Adam Topaz (Apr 25 2023 at 15:34):
And besides we want the type of this def to not involve BigTopCat
, I suppose.
Mario Carneiro (Apr 25 2023 at 17:02):
you might need to define BigHasLimitsOfSize
Kevin Buzzard (Apr 25 2023 at 19:18):
I think you might want to avoid max v u
on the basis that Lean occasionally applies a universe normalisation procedure which changes this to the alphabetically-ordered max u v
.
Mario Carneiro (Apr 25 2023 at 21:42):
I don't think this will matter in practice since the sorting is relative to alphabetical order in the usage code, not the constant declaration
Mario Carneiro (Apr 25 2023 at 21:44):
also, exactly because lean 4 refuses to unify max
problems, the unification algorithm is independent of variable ordering, which is why the alphabetic canonicalization is fine and should not result in any observable differences
Adam Topaz (Apr 25 2023 at 22:46):
Mario Carneiro said:
you might need to define
BigHasLimitsOfSize
I'm not sure what you're suggesting with this.
Adam Topaz (Apr 25 2023 at 22:46):
I don't see how to get this BigTopCat
to work nicely with a declaration such as
def piIsoPi {ι : Type v} (α : ι → TopCat.{max v u}) :
∏ α ≅ TopCat.of (∀ i, α i) := ...
Adam Topaz (Apr 25 2023 at 22:48):
The issue is that lean needs some instance with problematic universes to even talk about ∏ α
. I could rewrite everything in terms of BigTopCat
as
def piIsoPi {ι : Type v} (α : ι → BigTopCat.{v, u}) :
∏ α ≅ BigTopCat.of.{v,u} (∀ i, α i) := ...
but that doesn't help us because we want this isomorphism for TopCat
and not for BigTopCat
.
Kevin Buzzard (Apr 25 2023 at 22:59):
Mario Carneiro said:
I don't think this will matter in practice since the sorting is relative to alphabetical order in the usage code, not the constant declaration
Does this example contradict your claim?
Matthew Ballard (Apr 25 2023 at 23:03):
Here is something that gets the correct signature with proper universe parameters but is unpleasant.
def piIsoPi.{a,b} {ι : Type b} (α : ι → TopCat.{max a b}) :
@limit (Discrete.{b} ι) _ TopCat.{max a b} _ (Discrete.functor α) (by
have I := topCat_hasLimitsOfSize.{a,b}; infer_instance) ≅ TopCat.of ((i:ι) → α i) := sorry
Kevin Buzzard (Apr 25 2023 at 23:16):
(deleted)
Scott Morrison (Apr 25 2023 at 23:24):
I hadn't realised until now how badly these universe constraints had borked https://github.com/leanprover-community/mathlib4/pull/2712. There's all these haveI := hasLimit.{v, v}
s that we probably shouldn't have merged.
Scott Morrison (Apr 25 2023 at 23:31):
Could I propose before we go further with experiments here that we rename Mario's BigType
to TypeMax
(and similarly for other uses of Big
)?
Matthew Ballard (Apr 25 2023 at 23:38):
Can we do something silly like
instance [HasLimitsOfMaxSize] : HasLimitsOfSize
?
Scott Morrison (Apr 25 2023 at 23:46):
Okay, I have used TypeMax
to fix CategoryTheory.Limits.Types
, and it is seamless.
Scott Morrison (Apr 25 2023 at 23:47):
I did not attempt to minimise the use of TypeMax
; I just put it everywhere we previously had Type max
.
Scott Morrison (Apr 25 2023 at 23:47):
We can drop every haveI
from that file as a result.
Scott Morrison (Apr 25 2023 at 23:47):
https://github.com/leanprover-community/mathlib4/pull/3653
Scott Morrison (Apr 25 2023 at 23:48):
Where should TypeMax
live?
Matthew Ballard (Apr 25 2023 at 23:50):
Mathlib.Data.TypeMax
?
Matthew Ballard (Apr 25 2023 at 23:54):
Do we still have ReflectedUniv
?
Scott Morrison (Apr 26 2023 at 00:34):
TopCatMax
seems to help in !4#3464, so I have pushed a merge with !4#3653 and made the "low-hanging fruit" changes. There is still a lot of work on this file, and it is marked as help-wanted
, so please jump in. :-)
Matthew Ballard (Apr 26 2023 at 00:42):
One of the hardest problems in CS ;) obtuse way to saying !4#3463
Adam Topaz (Apr 26 2023 at 01:24):
I'm not sure how I feel about this... for example, this still fails, even with the TypeMax
change:
import Mathlib.CategoryTheory.Limits.Types
import Mathlib.CategoryTheory.Limits.Shapes.Products
example {α : Type v} (f : α → Type (max v u)) : Type (max v u) := ∏ f
Mario Carneiro (Apr 26 2023 at 01:40):
Kevin Buzzard said:
Mario Carneiro said:
I don't think this will matter in practice since the sorting is relative to alphabetical order in the usage code, not the constant declaration
Does this example contradict your claim?
No, because that's not a defeq problem, you are just calling the level normalizer as a bare function. The meaning of that function depends on the context in which it is used. One reason why that kind of normalization is important (any consistent normalization, alphabetical or otherwise) is because lean wants to be able to use normalize l1 == normalize l2
as a way to prove that l1
and l2
are defeq, so this is exactly what you need to make max u v = max v u
be a defeq.
Mario Carneiro (Apr 26 2023 at 01:41):
(I am of course fine with the name change. I spent about half a second on the name choice)
Scott Morrison (Apr 26 2023 at 03:34):
Adam Topaz said:
I'm not sure how I feel about this... for example, this still fails, even with the
TypeMax
change:import Mathlib.CategoryTheory.Limits.Types import Mathlib.CategoryTheory.Limits.Shapes.Products example {α : Type v} (f : α → Type (max v u)) : Type (max v u) := ∏ f
Here
example {α : Type v} (f : α → Type (max v u)) : TypeMax.{v, u} := ∏ f
does work, but it's not quite up to Mario's "my hope is that these tricks only need to be used in some implementation detail instances".
Mario Carneiro (Apr 26 2023 at 03:40):
I think you rather want f : A -> TypeMax.{v, u}
here
Mario Carneiro (Apr 26 2023 at 03:40):
the output universe probably doesn't have to be a TypeMax
Scott Morrison (Apr 26 2023 at 03:41):
No, unfortunately that gives the same error message!
Scott Morrison (Apr 26 2023 at 03:41):
import Mathlib.CategoryTheory.Limits.Types
import Mathlib.CategoryTheory.Limits.Shapes.Products
example {α : Type v} (f : α → Type (max v u)) : Type (max v u) := ∏ f -- fails
example {α : Type v} (f : α → Type (max v u)) : TypeMax.{v, u} := ∏ f -- succeeds
example {α : Type v} (f : α → TypeMax.{v, u}) : Type (max v u) := ∏ f -- fails
example {α : Type v} (f : α → TypeMax.{v, u}) : TypeMax.{v, u} := ∏ f -- succeeds
Mario Carneiro (Apr 26 2023 at 03:42):
What is the type of pi?
Scott Morrison (Apr 26 2023 at 03:43):
abbrev piObj (f : β → C) [HasProduct f] : C :=
limit (Discrete.functor f)
notation "∏ " f:20 => piObj f
Mario Carneiro (Apr 26 2023 at 03:43):
I think this will work if pi is expecting a TypeMax
function
Mario Carneiro (Apr 26 2023 at 03:43):
what is the "source" of the max v u
here?
Scott Morrison (Apr 26 2023 at 03:46):
That the category Type u
has Type v
indexed products iff v <= u
?
Mario Carneiro (Apr 26 2023 at 03:46):
how about "the category TypeMax.{v, u}
has Type v
indexed products"
Scott Morrison (Apr 26 2023 at 03:47):
The actual instance is:
CategoryTheory.Limits.Types.hasLimit.{v, u} {J : Type v} [inst✝ : SmallCategory.{v} J]
(F : Functor.{v, max u v, v, max (u + 1) (v + 1)} J TypeMax.{v, u}) : HasLimit.{v, v, max u v, max (u + 1) (v + 1)} F
Mario Carneiro (Apr 26 2023 at 03:48):
So how did Type max v u
get involved?
Mario Carneiro (Apr 26 2023 at 03:49):
I suppose it's right in the example
Scott Morrison (Apr 26 2023 at 03:49):
Adam wanting it to work "for the user" without having to know about TypeMax
, I think.
Scott Morrison (Apr 26 2023 at 03:50):
Currently piObj
is excessively general:
CategoryTheory.Limits.piObj.{w, v, u} {β : Type w} {C : Type u} [inst✝ : Category.{v, u} C] (f : β → C)
[inst✝¹ : HasProduct.{w, v, u} f] : C
Scott Morrison (Apr 26 2023 at 03:51):
In practice HasProduct.{w, v, u}
instances with unbounded w
are never ever going to exist, so perhaps we should just reformulate this using TypeMax
CategoryMax
(which doesn't yet exist).
Mario Carneiro (Apr 26 2023 at 03:51):
I think it will push in the opposite direction, you want to try not to ever mention Type (max v u)
, TypeMax
is "a universe with v-morphisms at least as large as u"
Mario Carneiro (Apr 26 2023 at 03:52):
"for the user" they won't be using Type (max u v)
they will be using Type v
or Type (v + 1)
Mario Carneiro (Apr 26 2023 at 03:52):
As long as maxes (with unbound universes) are involved you want to stick with TypeMax
Scott Morrison (Apr 26 2023 at 03:53):
I'm pretty happy with that. We can put a "don't use max
in the category theory library" sticker somewhere. :-)
Scott Morrison (Apr 26 2023 at 12:37):
!4#3653 is hopefully almost ready to go for TypeMax
. Would someone (@Mario Carneiro? @Adam Topaz?) be willing to contribute a doc-string for TypeMax
, and hit merge? I can have a go tomorrow if no one has got to it.
After that, !4#3487 (Topology.Category.Top.Limits) should be ready to go! (In its new post #18871 chopped down form.)
Adam Topaz (Apr 26 2023 at 12:50):
Mario Carneiro said:
"for the user" they won't be using
Type (max u v)
they will be usingType v
orType (v + 1)
This doesn't quite work out, e.g. with the following:
import Mathlib.CategoryTheory.Limits.Shapes.Types
example {α : Type v} (f : α → Type v) : ∏ f ≅ (∀ i, f i) :=
CategoryTheory.Limits.Types.productIso f
Adam Topaz (Apr 26 2023 at 12:50):
stuck at solving universe constraint
max v ?u.293 =?= v
while trying to unify
α → α → TypeMax : Type (max (v + 1) (?u.293 + 1))
with
α → Type v : Type (v + 1)
Adam Topaz (Apr 26 2023 at 12:51):
well, in this case
noncomputable example {α : Type v} (f : α → Type v) : ∏ f ≅ (∀ i, f i) :=
CategoryTheory.Limits.Types.productIso.{v,v} f
works out, so maybe that's okay.
Adam Topaz (Apr 26 2023 at 12:51):
And yes, my main concern with TypeMax
TopCatMax
etc. is the user experience
Adam Topaz (Apr 26 2023 at 12:53):
It's funny, library_search
finds CategoryTheory.Limits.Types.productIso f
, but then results in the error above without the universe annotations.
Adam Topaz (Apr 26 2023 at 12:56):
Anyway, I think TypeMax
is a good solution to let us move forward with the port. But it means that we will have yet another confusing thing to explain to newcomers who want to interact with the category theory library.
Kevin Buzzard (Apr 26 2023 at 12:57):
Adam Topaz said:
And yes, my main concern with
TypeMax
TopCatMax
etc. is the user experience
We've had concerns with the user experience before in category theory (e.g. "please write universes v u
and not universes u v
", and "please write [\McC : category C]
instead of [category C]
"), and basically they were solved over time as the system got better.
Matthew Ballard (Apr 26 2023 at 14:16):
Are we waiting for #18871 to go through mathport before dealing with the other files? There are quite a few fixes in the other chunks that were made from the original mathport output.
Matthew Ballard (Apr 26 2023 at 14:25):
Scott Morrison said:
!4#3653 is hopefully almost ready to go for
TypeMax
. Would someone (Mario Carneiro? Adam Topaz?) be willing to contribute a doc-string forTypeMax
, and hit merge? I can have a go tomorrow if no one has got to it.
I wrote something for the documentation.
Scott Morrison (Apr 26 2023 at 20:28):
Yes, I think we can wait for mathport for the other files. Unfortunate my hasty approach here means we will need to retrieve the fixes from the other chunks from git history. :-(
Scott Morrison (Apr 26 2023 at 20:30):
Thanks Matthew for the docs. Can someone merge !4#3653 now?
Matthew Ballard (Apr 26 2023 at 20:53):
Scott Morrison said:
Yes, I think we can wait for mathport for the other files. Unfortunate my hasty approach here means we will need to retrieve the fixes from the other chunks from git history. :-(
I’ve got them on my local machine :)
Adam Topaz (Apr 27 2023 at 20:54):
Quick report re TypeMax
and friends: I just ported CompHaus.Basic
in !4#3688 and had to actually use TopCatMax
. With just a little hint for lean, I didn't have to introduce CompHausMax
! See https://github.com/leanprover-community/mathlib4/blob/76e8aeb932d9637fef67f8444bc8ae7c39c277cb/Mathlib/Topology/Category/CompHaus/Basic.lean#L252
Matthew Ballard (Apr 28 2023 at 14:13):
I’ve started the process of migrating the changes from !4#3487 to the new files in the Limits
folder with !4#3709. I probably won’t have much time for addressing the remaining errors until Monday. Please feel free to help rectifying it.
Joël Riou (Apr 30 2023 at 15:01):
If everything fails, another approach would be to implement universe inequalities like:
import Mathlib.Logic.Small.Basic
universe u₁ u₂
class UnivLE where
condition : ∀ (α : Type u₁), Small.{u₂} α
def ULiftOfLE [UnivLE.{u₁, u₂}] (α : Type u₁) : Type u₂ :=
@Shrink α (UnivLE.condition.{u₁, u₂} α)
noncomputable def equivULiftOfLE [UnivLE.{u₁, u₂}] (α : Type u₁) : α ≃ ULiftOfLE.{_, u₂} α :=
@equivShrink α (UnivLE.condition.{u₁, u₂} α)
Then, for example, under the assumption [Univ.Le.{u₁, u₂}]
, we could ensure that some limits/colimits in Type u₂
indexed by some J : Type u₁
exists by transporting the index set to Type u₂
. But I hope the TypeMax
approach will work...
Adam Topaz (Apr 30 2023 at 15:02):
I think this approach still has similar issues with max. See the code I posted way up in this thread with ULE
.
Joël Riou (Apr 30 2023 at 15:10):
What I would suggest is to make the definitions more universe polymorphic, by mostly getting rid of the max u v
universe parameters in the assumptions, replacing it with some w
and suitable assumptions UnivLE.{u, w}
.
Adam Topaz (Apr 30 2023 at 15:12):
But would you want an instance for UnivLE.{u, max u v}
? Maybe I’m misunderstanding the proposal
Joël Riou (Apr 30 2023 at 15:14):
In my proposal, there are no longer any max u v
we have to cope with!
Adam Topaz (Apr 30 2023 at 15:16):
What about Module.{u} R
where R : Type v
?
Adam Topaz (Apr 30 2023 at 15:29):
Oh maybe that’s just in Type (u+1)
, but I think you get my point. Categories living in some max
universe can arise naturally, so we would have to introduce instances for UnivLE
for max
, which would result in similar issues
Yaël Dillies (Apr 30 2023 at 15:30):
I think Joël's point is that we would never introduce max u v
but instead always work "in a big enough universe".
Yaël Dillies (Apr 30 2023 at 15:31):
And in particular your "category living in some max
universe" would instead be a "category living in any big enough universe".
Adam Topaz (Apr 30 2023 at 15:32):
Okay, here is an actual example: docs4#CategoryTheory.StructuredArrow
Adam Topaz (Apr 30 2023 at 15:33):
How do you propose to say that this category has a big enough universe without using max?
Adam Topaz (Apr 30 2023 at 15:34):
Another docs4#CategoryTheory.Over
Joël Riou (Apr 30 2023 at 15:35):
This Module.{u} R : Type (max v (u+1))
is a problem only if the categorical constructions you want to do with it are not enough universe polymorphic. This is why I suggest we could try to avoid assuming categories have special universe parameters: then, it would apply to any category, even Module.{u} R
.
Yaël Dillies (Apr 30 2023 at 15:35):
Replace
universe v₁ v₂ u₁ u₂
variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D]
def StructuredArrow (S : D) (T : C ⥤ D) : Type (max u₁ v₂) :=
Comma (Functor.fromPUnit S) T
with
universe v₁ v₂ u₁ u₂ w
variable [UnivLE.{u₁, w} [UnivLE.{v₂, w}]
{C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D]
def StructuredArrow (S : D) (T : C ⥤ D) : Type w :=
Comma (Functor.fromPUnit S) T
Joël Riou (Apr 30 2023 at 15:37):
@Yaël Dillies: this is not what I suggest. I suggest attempting at replacing variable (X : Type (max u v))
by variable (X : Type w)
, and if it is needed somewhere, we would add the assumption UnivLE.{u, w}
.
Yaël Dillies (Apr 30 2023 at 15:37):
Ah then I agree with Adam that it won't work!
Joël Riou (Apr 30 2023 at 15:50):
I am not saying it would solve all the universe issues: sometimes we may still have to remind Lean that UnivLE.{u, max u v}
holds because this cannot be an instance, but this is not my definition of "it won't work".
Scott Morrison (Jun 28 2023 at 04:55):
Some more news on TypeMax
.
First, if someone could review #5535, that would be great. It does a slight universe generalization, but mostly it documents some of the difficulties with instances involving TypeMax
.
Scott Morrison (Jun 28 2023 at 04:56):
I've been working on forward porting !3#19153, and have #5536, which fails due to max u v =?u max u ?v
errors, and #5534, which is the same except that it uses a patched version of Lean 4 and succeeds.
Scott Morrison (Jun 28 2023 at 04:59):
@Heather Macbeth, would you mind reviewing #5534 to check that it really did forward port the changes from !3#19153?
This can either be done "by hand" by comparing the diffs, or by going to #out-of-sync, clicking on each file affected by !3#19153, and then clicking "Overall diff" in the left pane (this shows the diff between the SHA in the header and mathlib3 master).
Scott Morrison (Jun 28 2023 at 05:00):
The motivation for the patch to Lean 4 is described at https://github.com/leanprover/lean4/issues/2297, and the patch itself is at https://github.com/leanprover/lean4/issues/2298. The verification that mathlib4 doesn't mind the patch is at #5416.
Last updated: Dec 20 2023 at 11:08 UTC