Zulip Chat Archive

Stream: general

Topic: unnecessarily big instances


Daniel Selsam (Jul 11 2021 at 00:33):

I traced a performance problem in binported mathlib to a surprising idiom in lean3: many instances are unnecessarily big. For example, many of the + occurrences in the fields of ring.mk actually involve instances such as

       (@has_add.add.{u} α
          (@add_zero_class.to_has_add.{u} α
             (@add_monoid.to_add_zero_class.{u} α
                (@sub_neg_monoid.to_add_monoid.{u} α
                   (@sub_neg_monoid.mk.{u} α add add_assoc zero zero_add add_zero nsmul nsmul_zero' nsmul_succ' neg sub
                      sub_eq_add_neg
                      gsmul
                      gsmul_zero'
                      gsmul_succ'
                      gsmul_neg'))))

and some of the + occurences in sub_neg_monoid.mk are actually

(@has_add.add.{u} G
            (@add_zero_class.to_has_add.{u} G
               (@add_monoid.to_add_zero_class.{u} G
                  (@add_monoid.mk.{u} G add add_assoc zero zero_add add_zero nsmul nsmul_zero' nsmul_succ')))

and so forth. Note that although the lean3 kernel knows not to try the self_opt with the to_* instances, type_context_old doesn't actually check this flag, and so is_def_eq will do a lot more work than necessary and is only saved from constantly doing exponential work thanks to its is_def_eq cache (which has been removed from MetaM in lean4). I can address this during binport, but you may find that it speeds up lean3 if you eagerly reduce these before sending them to the kernel.

Mario Carneiro (Jul 11 2021 at 01:45):

This is caused by the way the (old?) structure command handles notations coming from parent instances inside the structure definition. If you have something like:

class ring (A) extends add_group A :=
(bla : a + b = b + a)

then the constructor for ring.mk doesn't have an add_group instance available but needs one in order for the typeclass argument to has_add.add to be resolved. So there is some hackery to add what amounts to letI add_group A := { add := add, ... } where add is the local constant provided as a hypothesis to ring.mk, and so the type of the field becomes has_add.add (add_group.has_add { add := add, ... }) a b instead of just add a b. If we were to write add a b = add b a, using the name add which is an inherited field from add_group, directly, then this wouldn't happen, but then we won't be able to use notation which kind of sucks

Mario Carneiro (Jul 11 2021 at 01:47):

In short, it's not something that mathlib can easily do something about - this would have to be addressed in the C++ where the hackery is


Last updated: Dec 20 2023 at 11:08 UTC