Zulip Chat Archive
Stream: mathlib4
Topic: RingTheory.Adjoin.Field is slow
Kevin Buzzard (Jun 07 2023 at 17:35):
I was trying to get to the bottom of
set_option maxHeartbeats 950000 in
set_option synthInstance.maxHeartbeats 140000 in
...
in RingTheory.Adjoin.Field
. One of the (several) problems in this file is some kind of typeclass unification issue. On this (quite fast) machine I see (in the exact
at the end):
[] [7.158198s] ✅ CommSemiring.toSemiring =?= CommSemiring.toSemiring
in the traces. This is taking 7 seconds and the pattern is the following. First it unfolds a bit, then it explodes:
[] [7.158198s] ✅ CommSemiring.toSemiring =?= CommSemiring.toSemiring ▼
[] [7.158189s] ✅ CommRing.toCommSemiring.1 =?= CommRing.toCommSemiring.1 ▼
[] [7.158163s] ✅ Ring.toSemiring =?= Ring.toSemiring ▼
[] [7.158157s] ✅ CommRing.toRing.1 =?= CommRing.toRing.1 ▼
[] [7.157881s] ✅ Ring.toSemiring =?= Ring.toSemiring ▼
[] [7.157873s] ✅ (Function.Surjective.ring Quotient.mk'' (_ : Function.Surjective Quotient.mk'')
(_ : Quotient.mk'' 0 = Quotient.mk'' 0) (_ : Quotient.mk'' 1 = Quotient.mk'' 1)
(_ :
∀ (x x_1 : { x // x ∈ Algebra.adjoin F ↑s }[X]),
Quotient.mk'' (x + x_1) = Quotient.mk'' (x + x_1))
(_ :
∀ (x x_1 : { x // x ∈ Algebra.adjoin F ↑s }[X]),
Quotient.mk'' (x * x_1) = Quotient.mk'' (x * x_1))
(_ :
∀ (x : { x // x ∈ Algebra.adjoin F ↑s }[X]),
Quotient.mk'' (-x) = Quotient.mk'' (-x))
(_ :
∀ (x x_1 : { x // x ∈ Algebra.adjoin F ↑s }[X]),
Quotient.mk'' (x - x_1) = Quotient.mk'' (x - x_1))
(_ :
∀ (x : { x // x ∈ Algebra.adjoin F ↑s }[X]) (x_1 : ℕ),
Quotient.mk'' (x_1 • x) = Quotient.mk'' (x_1 • x))
(_ :
∀ (x : { x // x ∈ Algebra.adjoin F ↑s }[X]) (x_1 : ℤ),
Quotient.mk'' (x_1 • x) = Quotient.mk'' (x_1 • x))
(_ :
∀ (x : { x // x ∈ Algebra.adjoin F ↑s }[X]) (x_1 : ℕ),
Quotient.mk'' (x ^ x_1) = Quotient.mk'' (x ^ x_1))
(_ : ∀ (x : ℕ), Quotient.mk'' ↑x = Quotient.mk'' ↑x)
(_ :
∀ (x : ℤ),
Quotient.mk'' ↑x =
Quotient.mk''
↑x)).1 =?= (Function.Surjective.ring Quotient.mk''
(_ : Function.Surjective Quotient.mk'') (_ : Quotient.mk'' 0 = Quotient.mk'' 0)
(_ : Quotient.mk'' 1 = Quotient.mk'' 1)
(_ :
∀ (x x_1 : { x // x ∈ Algebra.adjoin F ↑s }[X]),
Quotient.mk'' (x + x_1) = Quotient.mk'' (x + x_1))
(_ :
∀ (x x_1 : { x // x ∈ Algebra.adjoin F ↑s }[X]),
Quotient.mk'' (x * x_1) = Quotient.mk'' (x * x_1))
(_ :
∀ (x : { x // x ∈ Algebra.adjoin F ↑s }[X]),
Quotient.mk'' (-x) = Quotient.mk'' (-x))
(_ :
∀ (x x_1 : { x // x ∈ Algebra.adjoin F ↑s }[X]),
Quotient.mk'' (x - x_1) = Quotient.mk'' (x - x_1))
(_ :
∀ (x : { x // x ∈ Algebra.adjoin F ↑s }[X]) (x_1 : ℕ),
Quotient.mk'' (x_1 • x) = Quotient.mk'' (x_1 • x))
(_ :
∀ (x : { x // x ∈ Algebra.adjoin F ↑s }[X]) (x_1 : ℤ),
Quotient.mk'' (x_1 • x) = Quotient.mk'' (x_1 • x))
(_ :
∀ (x : { x // x ∈ Algebra.adjoin F ↑s }[X]) (x_1 : ℕ),
Quotient.mk'' (x ^ x_1) = Quotient.mk'' (x ^ x_1))
(_ : ∀ (x : ℕ), Quotient.mk'' ↑x = Quotient.mk'' ↑x)
(_ : ∀ (x : ℤ), Quotient.mk'' ↑x = Quotient.mk'' ↑x)).1 ▶
And then things calm down a bit and you run into things like
[] [1.024850s] ✅ Monoid.npow =?= Monoid.npow
and
[] [3.193706s] ✅ AddMonoidWithOne.toAddMonoid =?= AddMonoidWithOne.toAddMonoid
and
[] [1.133736s] ✅ MulZeroClass.toMul =?= MulZeroClass.toMul
and all of them follow the same pattern -- they unfold a bit and then explode and then calm down and basically it's taking forever.
Is there a trick where something could be made irreducible, or something, to stop this happening?
Mario Carneiro (Jun 07 2023 at 17:38):
My reading is that there are two ways to prove that whatever type this is is a Ring
and they are not obviously defeq
Mario Carneiro (Jun 07 2023 at 17:39):
probably this is the same issue that came up before, the field structure does not extend the ring structure and so you have to work it down to individual pieces
Riccardo Brasca (Jun 07 2023 at 17:42):
This instances are about AdjoinRoot
, right?
Kevin Buzzard (Jun 07 2023 at 17:58):
Yes, CommSemiring.toSemiring
is actually @CommSemiring.toSemiring (AdjoinRoot (minpoly { x // x ∈ Algebra.adjoin F ↑s } a)) CommRing.toCommSemiring : Semiring (AdjoinRoot (minpoly { x // x ∈ Algebra.adjoin F ↑s } a))
(both of them look like this but presumably they're not syntactically equal with pp.all on, unfortunately pp.all is a bit hectic).
Yes, the issue is that these things are defeq but it takes a fast machine 7 seconds to prove this. What do we do about this? That's what I don't understand.
Reid Barton (Jun 07 2023 at 18:01):
I guess there is some defeq diamond way at the bottom and then Lean has to unfold some fully massive construction applied to this to see that the results are still defeq
Kevin Buzzard (Jun 07 2023 at 18:02):
So you think there _is_ a diamond?
Mathematically the issue is that is always a ring, and it's a field if is irreducible, but the field structure doesn't extend the ring structure. Maybe this can be fixed?
Reid Barton (Jun 07 2023 at 18:03):
Well otherwise I suppose Lean would see that the terms are syntactically equal which would not take 7 seconds
Kevin Buzzard (Jun 07 2023 at 18:04):
Wait -- I thought I had fixed this last week:
noncomputable instance field [Fact (Irreducible f)] : Field (AdjoinRoot f) :=
{ AdjoinRoot.instCommRing f,
Quotient.groupWithZero (span {f} : Ideal K[X]) with
ratCast := fun a => of f (a : K)
ratCast_mk := fun a b h1 h2 => by
letI : GroupWithZero (AdjoinRoot f) := Ideal.Quotient.groupWithZero _
-- porting note: was
-- `rw [Rat.cast_mk' (K := ℚ), _root_.map_mul, _root_.map_intCast, map_inv₀, map_natCast]`
convert_to ((Rat.mk' a b h1 h2 : K) : AdjoinRoot f) = ((↑a * (↑b)⁻¹ : K) : AdjoinRoot f)
. simp only [_root_.map_mul, map_intCast, map_inv₀, map_natCast]
. simp only [Rat.cast_mk', _root_.map_mul, map_intCast, map_inv₀, map_natCast]
qsmul := (· • ·)
qsmul_eq_mul' := fun a x =>
-- porting note: I gave the explicit motive and changed `rw` to `simp`.
AdjoinRoot.induction_on (C := fun y => a • y = (of f) a * y) x fun p => by
simp only [smul_mk, of, RingHom.comp_apply, ← (mk f).map_mul, Polynomial.rat_smul_eq_C_mul]
}
Mario Carneiro (Jun 07 2023 at 18:05):
did it get reverted?
Mario Carneiro (Jun 07 2023 at 18:05):
IIRC the result of our live debugging session was to use toCommRing := AdjoinRoot.instCommRing f
Kevin Buzzard (Jun 07 2023 at 18:40):
I think that you still get the same term. I just changed the definition of field
locally to
noncomputable instance field [Fact (Irreducible f)] : Field (AdjoinRoot f) :=
{ Quotient.groupWithZero (span {f} : Ideal K[X]) with
toCommRing := AdjoinRoot.instCommRing f
ratCast := fun a => of f (a : K)
...
and we still take forever to solve [] [11.496132s] ✅ CommSemiring.toSemiring =?= CommSemiring.toSemiring
. I will try braving pp.all
.
Eric Rodriguez (Jun 07 2023 at 18:42):
it seems that that is taking a different path than through the toCommRing
projection :/
Eric Wieser (Jun 07 2023 at 18:49):
You made the change in !4#4507, and src4#AdjoinRoot.field says it wasn't reverted. You must be looking at old code.
Eric Wieser (Jun 07 2023 at 18:50):
I suspect that the toCommRing
fix you made is the tip of the iceberg; we'll have the same problem in things like docs4#Function.surjective.field too.
Eric Wieser (Jun 07 2023 at 18:51):
Speculatively, the new-style structures give us a mild performance boost if we use them perfectly, but are a foot-gun in the presence of with
notation that pretty much means they get used "incorrectly" every time
Eric Wieser (Jun 07 2023 at 18:52):
(and are arguably therefore not worth the trouble for algebra, if they're so easy to use incorrectly)
Jireh Loreaux (Jun 07 2023 at 18:53):
Eric, can you write something up (if you know, I suppose) about how to avoid the foot-gun with with
? I understand it's about things being unpackaged and repackaged, but I'm not sure what the correct syntax is to avoid problems.
Eric Wieser (Jun 07 2023 at 18:56):
The "correct" syntax is to write toBaseOne := _, toBaseTwo := _
for every "preferred" base class that the current structure has
Eric Wieser (Jun 07 2023 at 18:57):
Of course, the fact that toCommRing
is a "preferred" base class but toDivisionRing
isn't is silly and non-mathematical
Eric Wieser (Jun 07 2023 at 18:57):
So to know what the base class is, you can't appear to any mathematical insight and you instead have to #print Field.mk
and look at the constructor arguments
Kevin Buzzard (Jun 07 2023 at 19:04):
So I was indeed looking at old code (failure to understand how git works) but current mathlib master still exhibits the same problem. And pp.all takes my VS code down. Is there an option for just showing instance names explicitly?
Jireh Loreaux (Jun 07 2023 at 19:14):
Isn't that set_option pp.explicit true
?
Riccardo Brasca (Jun 07 2023 at 20:55):
Kevin Buzzard said:
So you think there _is_ a diamond?
Mathematically the issue is that is always a ring, and it's a field if is irreducible, but the field structure doesn't extend the ring structure. Maybe this can be fixed?
I think the "original sin" is something else. AdjoinRoot
is slow even without irreducible f
, so without the Field
instance.
Kevin Buzzard (Jun 07 2023 at 21:14):
@Riccardo Brasca I was just looking at the RingTheory.Adjoin.Field
file because the
terrifying
set_option maxHeartbeats 950000 in
set_option synthInstance.maxHeartbeats 140000 in
caught my eye and I thought I'd try and understand it. Can you give me an example where something is slow and fields aren't involved?
Riccardo Brasca (Jun 07 2023 at 21:19):
I don't have access to Lean for about 1 hour, but IIRC declarations around docs4#AdjoinRoot.modByMonicHom are already quite slow. You can maybe have a look at the whole file (the declarations at the end are already slow in Lean3, but less slow).
Eric Wieser (Jun 07 2023 at 22:00):
I reckon pp.proofs false
would make the trace a lot shorter, even with pp.explicit true
Last updated: Dec 20 2023 at 11:08 UTC