l3lab/ntp-mathlib huggingface dataset:
/-- A version of `TensorProduct.ext` for `AlgHom`.

Using this as the `@[ext]` lemma instead of `Algebra.TensorProduct.ext'` allows `ext` to apply
lemmas specific to `A →ₐ[S] _` and `B →ₐ[R] _`; notably this allows recursion into nested tensor
products of algebras.

See note [partially-applied ext lemmas]. -/
@[ext high]
theorem ext ⦃f g : (A ⊗[R] B) →ₐ[S] C⦄
    (ha : f.comp includeLeft = g.comp includeLeft)
    (hb : (f.restrictScalars R).comp includeRight = (g.restrictScalars R).comp includeRight) :
    f = g := by
  

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹² : CommSemiring R
inst✝¹¹ : Semiring A
inst✝¹⁰ : Algebra R A
inst✝⁹ : Semiring B
inst✝⁸ : Algebra R B
inst✝⁷ : Semiring C
inst✝⁶ : Algebra R C
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S A
inst✝³ : Algebra R S
inst✝² : Algebra S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f g : A ⊗[R] B →ₐ[S] C
ha : AlgHom.comp f includeLeft = AlgHom.comp g includeLeft
hb : AlgHom.comp (AlgHom.restrictScalars R f) includeRight = AlgHom.comp (AlgHom.restrictScalars R g) includeRight
⊢ f = g

Next tactic:
apply AlgHom.toLinearMap_injective
/-- A version of `TensorProduct.ext` for `AlgHom`.

Using this as the `@[ext]` lemma instead of `Algebra.TensorProduct.ext'` allows `ext` to apply
lemmas specific to `A →ₐ[S] _` and `B →ₐ[R] _`; notably this allows recursion into nested tensor
products of algebras.

See note [partially-applied ext lemmas]. -/
@[ext high]
theorem ext ⦃f g : (A ⊗[R] B) →ₐ[S] C⦄
    (ha : f.comp includeLeft = g.comp includeLeft)
    (hb : (f.restrictScalars R).comp includeRight = (g.restrictScalars R).comp includeRight) :
    f = g := by
  apply AlgHom.toLinearMap_injective
  

Proof state:
case a
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹² : CommSemiring R
inst✝¹¹ : Semiring A
inst✝¹⁰ : Algebra R A
inst✝⁹ : Semiring B
inst✝⁸ : Algebra R B
inst✝⁷ : Semiring C
inst✝⁶ : Algebra R C
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S A
inst✝³ : Algebra R S
inst✝² : Algebra S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f g : A ⊗[R] B →ₐ[S] C
ha : AlgHom.comp f includeLeft = AlgHom.comp g includeLeft
hb : AlgHom.comp (AlgHom.restrictScalars R f) includeRight = AlgHom.comp (AlgHom.restrictScalars R g) includeRight
⊢ AlgHom.toLinearMap f = AlgHom.toLinearMap g

Next tactic:
ext a b
/-- A version of `TensorProduct.ext` for `AlgHom`.

Using this as the `@[ext]` lemma instead of `Algebra.TensorProduct.ext'` allows `ext` to apply
lemmas specific to `A →ₐ[S] _` and `B →ₐ[R] _`; notably this allows recursion into nested tensor
products of algebras.

See note [partially-applied ext lemmas]. -/
@[ext high]
theorem ext ⦃f g : (A ⊗[R] B) →ₐ[S] C⦄
    (ha : f.comp includeLeft = g.comp includeLeft)
    (hb : (f.restrictScalars R).comp includeRight = (g.restrictScalars R).comp includeRight) :
    f = g := by
  apply AlgHom.toLinearMap_injective
  ext a b
  

Proof state:
case a.a.h.h
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹² : CommSemiring R
inst✝¹¹ : Semiring A
inst✝¹⁰ : Algebra R A
inst✝⁹ : Semiring B
inst✝⁸ : Algebra R B
inst✝⁷ : Semiring C
inst✝⁶ : Algebra R C
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S A
inst✝³ : Algebra R S
inst✝² : Algebra S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f g : A ⊗[R] B →ₐ[S] C
ha : AlgHom.comp f includeLeft = AlgHom.comp g includeLeft
hb : AlgHom.comp (AlgHom.restrictScalars R f) includeRight = AlgHom.comp (AlgHom.restrictScalars R g) includeRight
a : A
b : B
⊢ ((AlgebraTensorModule.curry (AlgHom.toLinearMap f)) a) b = ((AlgebraTensorModule.curry (AlgHom.toLinearMap g)) a) b

Next tactic:
have := congr_arg₂ HMul.hMul (AlgHom.congr_fun ha a) (AlgHom.congr_fun hb b)
/-- A version of `TensorProduct.ext` for `AlgHom`.

Using this as the `@[ext]` lemma instead of `Algebra.TensorProduct.ext'` allows `ext` to apply
lemmas specific to `A →ₐ[S] _` and `B →ₐ[R] _`; notably this allows recursion into nested tensor
products of algebras.

See note [partially-applied ext lemmas]. -/
@[ext high]
theorem ext ⦃f g : (A ⊗[R] B) →ₐ[S] C⦄
    (ha : f.comp includeLeft = g.comp includeLeft)
    (hb : (f.restrictScalars R).comp includeRight = (g.restrictScalars R).comp includeRight) :
    f = g := by
  apply AlgHom.toLinearMap_injective
  ext a b
  have := congr_arg₂ HMul.hMul (AlgHom.congr_fun ha a) (AlgHom.congr_fun hb b)
  

Proof state:
case a.a.h.h
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹² : CommSemiring R
inst✝¹¹ : Semiring A
inst✝¹⁰ : Algebra R A
inst✝⁹ : Semiring B
inst✝⁸ : Algebra R B
inst✝⁷ : Semiring C
inst✝⁶ : Algebra R C
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S A
inst✝³ : Algebra R S
inst✝² : Algebra S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f g : A ⊗[R] B →ₐ[S] C
ha : AlgHom.comp f includeLeft = AlgHom.comp g includeLeft
hb : AlgHom.comp (AlgHom.restrictScalars R f) includeRight = AlgHom.comp (AlgHom.restrictScalars R g) includeRight
a : A
b : B
this :
  (AlgHom.comp f includeLeft) a * (AlgHom.comp (AlgHom.restrictScalars R f) includeRight) b =
    (AlgHom.comp g includeLeft) a * (AlgHom.comp (AlgHom.restrictScalars R g) includeRight) b
⊢ ((AlgebraTensorModule.curry (AlgHom.toLinearMap f)) a) b = ((AlgebraTensorModule.curry (AlgHom.toLinearMap g)) a) b

Next tactic:
dsimp at *
/-- A version of `TensorProduct.ext` for `AlgHom`.

Using this as the `@[ext]` lemma instead of `Algebra.TensorProduct.ext'` allows `ext` to apply
lemmas specific to `A →ₐ[S] _` and `B →ₐ[R] _`; notably this allows recursion into nested tensor
products of algebras.

See note [partially-applied ext lemmas]. -/
@[ext high]
theorem ext ⦃f g : (A ⊗[R] B) →ₐ[S] C⦄
    (ha : f.comp includeLeft = g.comp includeLeft)
    (hb : (f.restrictScalars R).comp includeRight = (g.restrictScalars R).comp includeRight) :
    f = g := by
  apply AlgHom.toLinearMap_injective
  ext a b
  have := congr_arg₂ HMul.hMul (AlgHom.congr_fun ha a) (AlgHom.congr_fun hb b)
  dsimp at *
  

Proof state:
case a.a.h.h
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹² : CommSemiring R
inst✝¹¹ : Semiring A
inst✝¹⁰ : Algebra R A
inst✝⁹ : Semiring B
inst✝⁸ : Algebra R B
inst✝⁷ : Semiring C
inst✝⁶ : Algebra R C
inst✝⁵ : CommSemiring S
inst✝⁴ : Algebra S A
inst✝³ : Algebra R S
inst✝² : Algebra S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f g : A ⊗[R] B →ₐ[S] C
ha : AlgHom.comp f includeLeft = AlgHom.comp g includeLeft
hb : AlgHom.comp (AlgHom.restrictScalars R f) includeRight = AlgHom.comp (AlgHom.restrictScalars R g) includeRight
a : A
b : B
this : f (a ⊗ₜ[R] 1) * f (1 ⊗ₜ[R] b) = g (a ⊗ₜ[R] 1) * g (1 ⊗ₜ[R] b)
⊢ f (a ⊗ₜ[R] b) = g (a ⊗ₜ[R] b)

Next tactic:
rwa [← f.map_mul, ← g.map_mul, tmul_mul_tmul, _root_.one_mul, _root_.mul_one] at this
instance instAddCommGroupWithOne : AddCommGroupWithOne (A ⊗[R] B) where
  toAddCommGroup := TensorProduct.addCommGroup
  __ := instAddCommMonoidWithOne
  intCast z := z ⊗ₜ (1 : B)
  intCast_ofNat n := by 

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommSemiring R
inst✝³ : AddCommGroupWithOne A
inst✝² : Module R A
inst✝¹ : AddCommGroupWithOne B
inst✝ : Module R B
src✝ : AddCommMonoidWithOne (A ⊗[R] B) := instAddCommMonoidWithOne
n : ℕ
⊢ IntCast.intCast ↑n = ↑n

Next tactic:
simp [natCast_def]
instance instAddCommGroupWithOne : AddCommGroupWithOne (A ⊗[R] B) where
  toAddCommGroup := TensorProduct.addCommGroup
  __ := instAddCommMonoidWithOne
  intCast z := z ⊗ₜ (1 : B)
  intCast_ofNat n := by simp [natCast_def]
  intCast_negSucc n := by 

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommSemiring R
inst✝³ : AddCommGroupWithOne A
inst✝² : Module R A
inst✝¹ : AddCommGroupWithOne B
inst✝ : Module R B
src✝ : AddCommMonoidWithOne (A ⊗[R] B) := instAddCommMonoidWithOne
n : ℕ
⊢ IntCast.intCast (Int.negSucc n) = -↑(n + 1)

Next tactic:
simp [natCast_def, add_tmul, neg_tmul, one_def]
theorem intCast_def' (z : ℤ) : (z : A ⊗[R] B) = (1 : A) ⊗ₜ (z : B) := by
  

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : Ring A
inst✝² : Algebra R A
inst✝¹ : Ring B
inst✝ : Algebra R B
z : ℤ
⊢ ↑z = 1 ⊗ₜ[R] ↑z

Next tactic:
rw [intCast_def, ← zsmul_one, smul_tmul, zsmul_one]
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
⊢ x * y = y * x

Next tactic:
refine TensorProduct.induction_on x ?_ ?_ ?_
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · 

Proof state:
case refine_1
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
⊢ 0 * y = y * 0

Next tactic:
simp
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · simp
      · 

Proof state:
case refine_2
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
⊢ ∀ (x : A) (y_1 : B), x ⊗ₜ[R] y_1 * y = y * x ⊗ₜ[R] y_1

Next tactic:
intro a₁ b₁
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · simp
      · intro a₁ b₁
        

Proof state:
case refine_2
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
a₁ : A
b₁ : B
⊢ a₁ ⊗ₜ[R] b₁ * y = y * a₁ ⊗ₜ[R] b₁

Next tactic:
refine TensorProduct.induction_on y ?_ ?_ ?_
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · simp
      · intro a₁ b₁
        refine TensorProduct.induction_on y ?_ ?_ ?_
        · 

Proof state:
case refine_2.refine_1
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
a₁ : A
b₁ : B
⊢ a₁ ⊗ₜ[R] b₁ * 0 = 0 * a₁ ⊗ₜ[R] b₁

Next tactic:
simp
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · simp
      · intro a₁ b₁
        refine TensorProduct.induction_on y ?_ ?_ ?_
        · simp
        · 

Proof state:
case refine_2.refine_2
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
a₁ : A
b₁ : B
⊢ ∀ (x : A) (y : B), a₁ ⊗ₜ[R] b₁ * x ⊗ₜ[R] y = x ⊗ₜ[R] y * a₁ ⊗ₜ[R] b₁

Next tactic:
intro a₂ b₂
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · simp
      · intro a₁ b₁
        refine TensorProduct.induction_on y ?_ ?_ ?_
        · simp
        · intro a₂ b₂
          

Proof state:
case refine_2.refine_2
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
a₁ : A
b₁ : B
a₂ : A
b₂ : B
⊢ a₁ ⊗ₜ[R] b₁ * a₂ ⊗ₜ[R] b₂ = a₂ ⊗ₜ[R] b₂ * a₁ ⊗ₜ[R] b₁

Next tactic:
simp [mul_comm]
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · simp
      · intro a₁ b₁
        refine TensorProduct.induction_on y ?_ ?_ ?_
        · simp
        · intro a₂ b₂
          simp [mul_comm]
        · 

Proof state:
case refine_2.refine_3
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
a₁ : A
b₁ : B
⊢ ∀ (x y : A ⊗[R] B),
    a₁ ⊗ₜ[R] b₁ * x = x * a₁ ⊗ₜ[R] b₁ →
      a₁ ⊗ₜ[R] b₁ * y = y * a₁ ⊗ₜ[R] b₁ → a₁ ⊗ₜ[R] b₁ * (x + y) = (x + y) * a₁ ⊗ₜ[R] b₁

Next tactic:
intro a₂ b₂ ha hb
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · simp
      · intro a₁ b₁
        refine TensorProduct.induction_on y ?_ ?_ ?_
        · simp
        · intro a₂ b₂
          simp [mul_comm]
        · intro a₂ b₂ ha hb
          -- porting note: was `simp` not `rw`
          

Proof state:
case refine_2.refine_3
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
a₁ : A
b₁ : B
a₂ b₂ : A ⊗[R] B
ha : a₁ ⊗ₜ[R] b₁ * a₂ = a₂ * a₁ ⊗ₜ[R] b₁
hb : a₁ ⊗ₜ[R] b₁ * b₂ = b₂ * a₁ ⊗ₜ[R] b₁
⊢ a₁ ⊗ₜ[R] b₁ * (a₂ + b₂) = (a₂ + b₂) * a₁ ⊗ₜ[R] b₁

Next tactic:
rw [mul_add, add_mul, ha, hb]
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · simp
      · intro a₁ b₁
        refine TensorProduct.induction_on y ?_ ?_ ?_
        · simp
        · intro a₂ b₂
          simp [mul_comm]
        · intro a₂ b₂ ha hb
          -- porting note: was `simp` not `rw`
          rw [mul_add, add_mul, ha, hb]
      · 

Proof state:
case refine_3
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y : A ⊗[R] B
⊢ ∀ (x y_1 : A ⊗[R] B), x * y = y * x → y_1 * y = y * y_1 → (x + y_1) * y = y * (x + y_1)

Next tactic:
intro x₁ x₂ h₁ h₂
instance instCommRing : CommRing (A ⊗[R] B) :=
  { toRing := inferInstance
    mul_comm := fun x y => by
      refine TensorProduct.induction_on x ?_ ?_ ?_
      · simp
      · intro a₁ b₁
        refine TensorProduct.induction_on y ?_ ?_ ?_
        · simp
        · intro a₂ b₂
          simp [mul_comm]
        · intro a₂ b₂ ha hb
          -- porting note: was `simp` not `rw`
          rw [mul_add, add_mul, ha, hb]
      · intro x₁ x₂ h₁ h₂
        -- porting note: was `simp` not `rw`
        

Proof state:
case refine_3
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝⁴ : CommRing R
inst✝³ : CommRing A
inst✝² : Algebra R A
inst✝¹ : CommRing B
inst✝ : Algebra R B
x y x₁ x₂ : A ⊗[R] B
h₁ : x₁ * y = y * x₁
h₂ : x₂ * y = y * x₂
⊢ (x₁ + x₂) * y = y * (x₁ + x₂)

Next tactic:
rw [mul_add, add_mul, h₁, h₂]
/-- Verify that typeclass search finds the ring structure on `A ⊗[ℤ] B`
when `A` and `B` are merely rings, by treating both as `ℤ`-algebras.
-/
example [Ring A] [Ring B] : Ring (A ⊗[ℤ] B) := by 

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹ : Ring A
inst✝ : Ring B
⊢ Ring (A ⊗[ℤ] B)

Next tactic:
infer_instance
/-- Verify that typeclass search finds the comm_ring structure on `A ⊗[ℤ] B`
when `A` and `B` are merely comm_rings, by treating both as `ℤ`-algebras.
-/
example [CommRing A] [CommRing B] : CommRing (A ⊗[ℤ] B) := by 

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹ : CommRing A
inst✝ : CommRing B
⊢ CommRing (A ⊗[ℤ] B)

Next tactic:
infer_instance
/-- Build an algebra morphism from a linear map out of a tensor product, and evidence that on pure
tensors, it preserves multiplication and the identity.

Note that we state `h_one` using `1 ⊗ₜ[R] 1` instead of `1` so that lemmas about `f` applied to pure
tensors can be directly applied by the caller (without needing `TensorProduct.one_def`).
-/
def algHomOfLinearMapTensorProduct (f : A ⊗[R] B →ₗ[S] C)
    (h_mul : ∀ (a₁ a₂ : A) (b₁ b₂ : B), f ((a₁ * a₂) ⊗ₜ (b₁ * b₂)) = f (a₁ ⊗ₜ b₁) * f (a₂ ⊗ₜ b₂))
    (h_one : f (1 ⊗ₜ[R] 1) = 1) : A ⊗[R] B →ₐ[S] C :=
  AlgHom.ofLinearMap f h_one <| f.map_mul_iff.2 <| by
    -- these instances are needed by the statement of `ext`, but not by the current definition.
    

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹³ : CommSemiring R
inst✝¹² : CommSemiring S
inst✝¹¹ : Algebra R S
inst✝¹⁰ : Semiring A
inst✝⁹ : Algebra R A
inst✝⁸ : Algebra S A
inst✝⁷ : IsScalarTower R S A
inst✝⁶ : Semiring B
inst✝⁵ : Algebra R B
inst✝⁴ : Semiring C
inst✝³ : Algebra R C
inst✝² : Algebra S C
inst✝¹ : Semiring D
inst✝ : Algebra R D
f : A ⊗[R] B →ₗ[S] C
h_mul : ∀ (a₁ a₂ : A) (b₁ b₂ : B), f ((a₁ * a₂) ⊗ₜ[R] (b₁ * b₂)) = f (a₁ ⊗ₜ[R] b₁) * f (a₂ ⊗ₜ[R] b₂)
h_one : f (1 ⊗ₜ[R] 1) = 1
⊢ LinearMap.compr₂ (LinearMap.mul S (A ⊗[R] B)) f = LinearMap.compl₂ (LinearMap.mul S C ∘ₗ f) f

Next tactic:
letI : Algebra R C := RestrictScalars.algebra R S C
/-- Build an algebra morphism from a linear map out of a tensor product, and evidence that on pure
tensors, it preserves multiplication and the identity.

Note that we state `h_one` using `1 ⊗ₜ[R] 1` instead of `1` so that lemmas about `f` applied to pure
tensors can be directly applied by the caller (without needing `TensorProduct.one_def`).
-/
def algHomOfLinearMapTensorProduct (f : A ⊗[R] B →ₗ[S] C)
    (h_mul : ∀ (a₁ a₂ : A) (b₁ b₂ : B), f ((a₁ * a₂) ⊗ₜ (b₁ * b₂)) = f (a₁ ⊗ₜ b₁) * f (a₂ ⊗ₜ b₂))
    (h_one : f (1 ⊗ₜ[R] 1) = 1) : A ⊗[R] B →ₐ[S] C :=
  AlgHom.ofLinearMap f h_one <| f.map_mul_iff.2 <| by
    -- these instances are needed by the statement of `ext`, but not by the current definition.
    letI : Algebra R C := RestrictScalars.algebra R S C
    

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹³ : CommSemiring R
inst✝¹² : CommSemiring S
inst✝¹¹ : Algebra R S
inst✝¹⁰ : Semiring A
inst✝⁹ : Algebra R A
inst✝⁸ : Algebra S A
inst✝⁷ : IsScalarTower R S A
inst✝⁶ : Semiring B
inst✝⁵ : Algebra R B
inst✝⁴ : Semiring C
inst✝³ : Algebra R C
inst✝² : Algebra S C
inst✝¹ : Semiring D
inst✝ : Algebra R D
f : A ⊗[R] B →ₗ[S] C
h_mul : ∀ (a₁ a₂ : A) (b₁ b₂ : B), f ((a₁ * a₂) ⊗ₜ[R] (b₁ * b₂)) = f (a₁ ⊗ₜ[R] b₁) * f (a₂ ⊗ₜ[R] b₂)
h_one : f (1 ⊗ₜ[R] 1) = 1
this : Algebra R C := RestrictScalars.algebra R S C
⊢ LinearMap.compr₂ (LinearMap.mul S (A ⊗[R] B)) f = LinearMap.compl₂ (LinearMap.mul S C ∘ₗ f) f

Next tactic:
letI : IsScalarTower R S C := RestrictScalars.isScalarTower R S C
/-- Build an algebra morphism from a linear map out of a tensor product, and evidence that on pure
tensors, it preserves multiplication and the identity.

Note that we state `h_one` using `1 ⊗ₜ[R] 1` instead of `1` so that lemmas about `f` applied to pure
tensors can be directly applied by the caller (without needing `TensorProduct.one_def`).
-/
def algHomOfLinearMapTensorProduct (f : A ⊗[R] B →ₗ[S] C)
    (h_mul : ∀ (a₁ a₂ : A) (b₁ b₂ : B), f ((a₁ * a₂) ⊗ₜ (b₁ * b₂)) = f (a₁ ⊗ₜ b₁) * f (a₂ ⊗ₜ b₂))
    (h_one : f (1 ⊗ₜ[R] 1) = 1) : A ⊗[R] B →ₐ[S] C :=
  AlgHom.ofLinearMap f h_one <| f.map_mul_iff.2 <| by
    -- these instances are needed by the statement of `ext`, but not by the current definition.
    letI : Algebra R C := RestrictScalars.algebra R S C
    letI : IsScalarTower R S C := RestrictScalars.isScalarTower R S C
    

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹³ : CommSemiring R
inst✝¹² : CommSemiring S
inst✝¹¹ : Algebra R S
inst✝¹⁰ : Semiring A
inst✝⁹ : Algebra R A
inst✝⁸ : Algebra S A
inst✝⁷ : IsScalarTower R S A
inst✝⁶ : Semiring B
inst✝⁵ : Algebra R B
inst✝⁴ : Semiring C
inst✝³ : Algebra R C
inst✝² : Algebra S C
inst✝¹ : Semiring D
inst✝ : Algebra R D
f : A ⊗[R] B →ₗ[S] C
h_mul : ∀ (a₁ a₂ : A) (b₁ b₂ : B), f ((a₁ * a₂) ⊗ₜ[R] (b₁ * b₂)) = f (a₁ ⊗ₜ[R] b₁) * f (a₂ ⊗ₜ[R] b₂)
h_one : f (1 ⊗ₜ[R] 1) = 1
this✝ : Algebra R C := RestrictScalars.algebra R S C
this : IsScalarTower R S C := RestrictScalars.isScalarTower R S C
⊢ LinearMap.compr₂ (LinearMap.mul S (A ⊗[R] B)) f = LinearMap.compl₂ (LinearMap.mul S C ∘ₗ f) f

Next tactic:
ext
/-- Build an algebra morphism from a linear map out of a tensor product, and evidence that on pure
tensors, it preserves multiplication and the identity.

Note that we state `h_one` using `1 ⊗ₜ[R] 1` instead of `1` so that lemmas about `f` applied to pure
tensors can be directly applied by the caller (without needing `TensorProduct.one_def`).
-/
def algHomOfLinearMapTensorProduct (f : A ⊗[R] B →ₗ[S] C)
    (h_mul : ∀ (a₁ a₂ : A) (b₁ b₂ : B), f ((a₁ * a₂) ⊗ₜ (b₁ * b₂)) = f (a₁ ⊗ₜ b₁) * f (a₂ ⊗ₜ b₂))
    (h_one : f (1 ⊗ₜ[R] 1) = 1) : A ⊗[R] B →ₐ[S] C :=
  AlgHom.ofLinearMap f h_one <| f.map_mul_iff.2 <| by
    -- these instances are needed by the statement of `ext`, but not by the current definition.
    letI : Algebra R C := RestrictScalars.algebra R S C
    letI : IsScalarTower R S C := RestrictScalars.isScalarTower R S C
    ext
    

Proof state:
case a.h.h.a.h.h
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹³ : CommSemiring R
inst✝¹² : CommSemiring S
inst✝¹¹ : Algebra R S
inst✝¹⁰ : Semiring A
inst✝⁹ : Algebra R A
inst✝⁸ : Algebra S A
inst✝⁷ : IsScalarTower R S A
inst✝⁶ : Semiring B
inst✝⁵ : Algebra R B
inst✝⁴ : Semiring C
inst✝³ : Algebra R C
inst✝² : Algebra S C
inst✝¹ : Semiring D
inst✝ : Algebra R D
f : A ⊗[R] B →ₗ[S] C
h_mul : ∀ (a₁ a₂ : A) (b₁ b₂ : B), f ((a₁ * a₂) ⊗ₜ[R] (b₁ * b₂)) = f (a₁ ⊗ₜ[R] b₁) * f (a₂ ⊗ₜ[R] b₂)
h_one : f (1 ⊗ₜ[R] 1) = 1
this✝ : Algebra R C := RestrictScalars.algebra R S C
this : IsScalarTower R S C := RestrictScalars.isScalarTower R S C
x✝³ : A
x✝² : B
x✝¹ : A
x✝ : B
⊢ ((AlgebraTensorModule.curry (((AlgebraTensorModule.curry (LinearMap.compr₂ (LinearMap.mul S (A ⊗[R] B)) f)) x✝³) x✝²))
        x✝¹)
      x✝ =
    ((AlgebraTensorModule.curry (((AlgebraTensorModule.curry (LinearMap.compl₂ (LinearMap.mul S C ∘ₗ f) f)) x✝³) x✝²))
        x✝¹)
      x✝

Next tactic:
exact h_mul _ _ _ _
/-- Build an algebra equivalence from a linear equivalence out of a triple tensor product,
and evidence of multiplicativity on pure tensors.
-/
def algEquivOfLinearEquivTripleTensorProduct (f : (A ⊗[R] B) ⊗[R] C ≃ₗ[R] D)
    (h_mul :
      ∀ (a₁ a₂ : A) (b₁ b₂ : B) (c₁ c₂ : C),
        f ((a₁ * a₂) ⊗ₜ (b₁ * b₂) ⊗ₜ (c₁ * c₂)) = f (a₁ ⊗ₜ b₁ ⊗ₜ c₁) * f (a₂ ⊗ₜ b₂ ⊗ₜ c₂))
    (h_one : f (((1 : A) ⊗ₜ[R] (1 : B)) ⊗ₜ[R] (1 : C)) = 1) :
    (A ⊗[R] B) ⊗[R] C ≃ₐ[R] D :=
  AlgEquiv.ofLinearEquiv f h_one <| f.map_mul_iff.2 <| by
    

Proof state:
R : Type uR
S : Type uS
A : Type uA
B : Type uB
C : Type uC
D : Type uD
E : Type uE
F : Type uF
inst✝¹³ : CommSemiring R
inst✝¹² : CommSemiring S
inst✝¹¹ : Algebra R S
inst✝¹⁰ : Semiring A
inst✝⁹ : Algebra R A
inst✝⁸ : Algebra S A
inst✝⁷ : IsScalarTower R S A
inst✝⁶ : Semiring B
inst✝⁵ : Algebra R B
inst✝⁴ : Semiring C
inst✝³ : Algebra R C
inst✝² : Algebra S C
inst✝¹ : Semiring D
inst✝ : Algebra R D
f : (A ⊗[R] B) ⊗[R] C ≃ₗ[R] D
h_mul :
  ∀ (a₁ a₂ : A) (b₁ b₂ : B) (c₁ c₂ : C),
    f (((a₁ * a₂) ⊗ₜ[R] (b₁ * b₂)) ⊗ₜ[R] (c₁ * c₂)) = f ((a₁ ⊗ₜ[R] b₁) ⊗ₜ[R] c₁) * f ((a₂ ⊗ₜ[R] b₂) ⊗ₜ[R] c₂)
h_one : f ((1 ⊗ₜ[R] 1) ⊗ₜ[R] 1) = 1
⊢ LinearMap.compr₂ (LinearMap.mul R ((A ⊗[R] B) ⊗[R] C)) ↑f = LinearMap.compl₂ (LinearMap.mul R D ∘ₗ ↑f) ↑f

Next tactic:
ext