Skip to content

Commit

Permalink
fix(RingTheory/TensorProduct): fix instance diamonds (#6162)
Browse files Browse the repository at this point in the history
The optional fields to the algebra typeclasses are a trap; if you forget to provide them then you get diamonds.

This change includes `example`s to verify that the issues are gone.

It looks like this was contributing to the very poor performance of `RingTheory.Kahler`; while the `intAlgebra` and `natAlgebra` diamonds were probably irrelevant, the `Ring.toAddCommGroup` diamond likely caused havoc during unification.
  • Loading branch information
eric-wieser committed Jul 27, 2023
1 parent 0bcfc2d commit 758b7d6
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 17 deletions.
4 changes: 2 additions & 2 deletions Mathlib/RingTheory/Kaehler.lean
Expand Up @@ -388,12 +388,12 @@ theorem KaehlerDifferential.End_equiv_aux (f : S →ₐ[R] S ⊗ S ⧸ KaehlerDi
exact e₁.symm.trans (e.trans e₂)
#align kaehler_differential.End_equiv_aux KaehlerDifferential.End_equiv_aux

set_option maxHeartbeats 4400000 in
set_option maxHeartbeats 600000 in
-- Porting note: extra heartbeats are needed to infer the instance
-- Module S { x // x ∈ Ideal.cotangentIdeal (ideal R S) }
set_option synthInstance.maxHeartbeats 1500000 in
-- This has type
-- `Derivation R S Ω[S⁄R] ≃ₗ[R] Derivation R S (KaehlerDifferential.ideal R S).cotangentIdeal`
-- `Derivation R S (Ω[S⁄R]) ≃ₗ[R] Derivation R S (KaehlerDifferential.ideal R S).cotangentIdeal`
-- But lean times-out if this is given explicitly.
/-- Derivations into `Ω[S⁄R]` is equivalent to derivations
into `(KaehlerDifferential.ideal R S).cotangentIdeal`. -/
Expand Down
50 changes: 35 additions & 15 deletions Mathlib/RingTheory/TensorProduct.lean
Expand Up @@ -431,15 +431,29 @@ theorem mul_one (x : A ⊗[R] B) : mul x (1 ⊗ₜ 1) = x := by

instance : One (A ⊗[R] B) where one := 1 ⊗ₜ 1

instance : AddMonoidWithOne (A ⊗[R] B) :=
AddMonoidWithOne.unary
theorem one_def : (1 : A ⊗[R] B) = (1 : A) ⊗ₜ (1 : B) :=
rfl
#align algebra.tensor_product.one_def Algebra.TensorProduct.one_def

instance : AddMonoidWithOne (A ⊗[R] B) where
natCast n := n ⊗ₜ 1
natCast_zero := by simp
natCast_succ n := by simp [add_tmul, one_def]

theorem natCast_def (n : ℕ) : (n : A ⊗[R] B) = (n : A) ⊗ₜ (1 : B) := rfl

instance : AddCommMonoid (A ⊗[R] B) := by infer_instance

-- providing this instance separately makes some downstream code substantially faster
instance instMul : Mul (A ⊗[R] B) where
mul a b := mul a b

@[simp]
theorem tmul_mul_tmul (a₁ a₂ : A) (b₁ b₂ : B) :
a₁ ⊗ₜ[R] b₁ * a₂ ⊗ₜ[R] b₂ = (a₁ * a₂) ⊗ₜ[R] (b₁ * b₂) :=
rfl
#align algebra.tensor_product.tmul_mul_tmul Algebra.TensorProduct.tmul_mul_tmul

-- note: we deliberately do not provide any fields that overlap with `AddMonoidWithOne` as this
-- appears to help performance.
instance instSemiring : Semiring (A ⊗[R] B) where
Expand All @@ -450,16 +464,8 @@ instance instSemiring : Semiring (A ⊗[R] B) where
mul_assoc := mul_assoc
one_mul := one_mul
mul_one := mul_one

theorem one_def : (1 : A ⊗[R] B) = (1 : A) ⊗ₜ (1 : B) :=
rfl
#align algebra.tensor_product.one_def Algebra.TensorProduct.one_def

@[simp]
theorem tmul_mul_tmul (a₁ a₂ : A) (b₁ b₂ : B) :
a₁ ⊗ₜ[R] b₁ * a₂ ⊗ₜ[R] b₂ = (a₁ * a₂) ⊗ₜ[R] (b₁ * b₂) :=
rfl
#align algebra.tensor_product.tmul_mul_tmul Algebra.TensorProduct.tmul_mul_tmul
natCast_zero := AddMonoidWithOne.natCast_zero
natCast_succ := AddMonoidWithOne.natCast_succ

@[simp]
theorem tmul_pow (a : A) (b : B) (k : ℕ) : a ⊗ₜ[R] b ^ k = (a ^ k) ⊗ₜ[R] (b ^ k) := by
Expand Down Expand Up @@ -505,6 +511,8 @@ instance leftAlgebra [SMulCommClass R S A] : Algebra S (A ⊗[R] B) :=
simp [*] }
#align algebra.tensor_product.left_algebra Algebra.TensorProduct.leftAlgebra

example : (algebraNat : Algebra ℕ (ℕ ⊗[ℕ] B)) = leftAlgebra := rfl

-- This is for the `undergrad.yaml` list.
/-- The tensor product of two `R`-algebras is an `R`-algebra. -/
instance instAlgebra : Algebra R (A ⊗[R] B) :=
Expand Down Expand Up @@ -574,9 +582,21 @@ variable {A : Type v₁} [Ring A] [Algebra R A]

variable {B : Type v₂} [Ring B] [Algebra R B]

instance instRing : Ring (A ⊗[R] B) :=
{ toSemiring := inferInstance
add_left_neg := add_left_neg }
instance instRing : Ring (A ⊗[R] B) where
zsmul := SubNegMonoid.zsmul
zsmul_zero' := SubNegMonoid.zsmul_zero'
zsmul_succ' := SubNegMonoid.zsmul_succ'
zsmul_neg' := SubNegMonoid.zsmul_neg'
intCast z := z ⊗ₜ (1 : B)
intCast_ofNat n := by simp [natCast_def]
intCast_negSucc n := by simp [natCast_def, add_tmul, neg_tmul, one_def]
add_left_neg := add_left_neg

theorem intCast_def (z : ℤ) : (z : A ⊗[R] B) = (z : A) ⊗ₜ (1 : B) := rfl

-- verify there are no diamonds
example : (instRing : Ring (A ⊗[R] B)).toAddCommGroup = addCommGroup := rfl
example : (algebraInt _ : Algebra ℤ (ℤ ⊗[ℤ] B)) = leftAlgebra := rfl

end Ring

Expand Down

1 comment on commit 758b7d6

@eric-wieser
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!bench

Please sign in to comment.