l3lab/ntp-mathlib huggingface dataset:
/-- 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
    ext
    

Proof state:
case a.a.h.h.h.a.a.h.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) ⊗[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
x✝⁵ : A
x✝⁴ : B
x✝³ : C
x✝² : A
x✝¹ : B
x✝ : C
⊢ (((AlgebraTensorModule.curry
            (AlgebraTensorModule.curry
              ((((AlgebraTensorModule.curry
                      (AlgebraTensorModule.curry (LinearMap.compr₂ (LinearMap.mul R ((A ⊗[R] B) ⊗[R] C)) ↑f)))
                    x✝⁵)
                  x✝⁴)
                x✝³)))
          x✝²)
        x✝¹)
      x✝ =
    (((AlgebraTensorModule.curry
            (AlgebraTensorModule.curry
              ((((AlgebraTensorModule.curry (AlgebraTensorModule.curry (LinearMap.compl₂ (LinearMap.mul R D ∘ₗ ↑f) ↑f)))
                    x✝⁵)
                  x✝⁴)
                x✝³)))
          x✝²)
        x✝¹)
      x✝

Next tactic:
exact h_mul _ _ _ _ _ _
/-- The forward direction of the universal property of tensor products of algebras; any algebra
morphism from the tensor product can be factored as the product of two algebra morphisms that
commute.

See `Algebra.TensorProduct.liftEquiv` for the fact that every morphism factors this way. -/
def lift (f : A →ₐ[S] C) (g : B →ₐ[R] C) (hfg : ∀ x y, Commute (f x) (g y)) : (A ⊗[R] B) →ₐ[S] C :=
  algHomOfLinearMapTensorProduct
    (AlgebraTensorModule.lift <|
      letI restr : (C →ₗ[S] C) →ₗ[S] _ :=
        { toFun := (·.restrictScalars R)
          map_add' := fun f g => LinearMap.ext fun x => rfl
          map_smul' := fun c g => LinearMap.ext fun x => rfl }
      LinearMap.flip <| (restr ∘ₗ LinearMap.mul S C ∘ₗ f.toLinearMap).flip ∘ₗ g)
    (fun a₁ a₂ b₁ b₂ => show f (a₁ * a₂) * g (b₁ * b₂) = f a₁ * g b₁ * (f a₂ * g 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✝¹⁵ : 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
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f : A →ₐ[S] C
g : B →ₐ[R] C
hfg : ∀ (x : A) (y : B), Commute (f x) (g y)
a₁ a₂ : A
b₁ b₂ : B
⊢ f (a₁ * a₂) * g (b₁ * b₂) = f a₁ * g b₁ * (f a₂ * g b₂)

Next tactic:
rw [f.map_mul, g.map_mul, (hfg a₂ b₁).mul_mul_mul_comm]
/-- The forward direction of the universal property of tensor products of algebras; any algebra
morphism from the tensor product can be factored as the product of two algebra morphisms that
commute.

See `Algebra.TensorProduct.liftEquiv` for the fact that every morphism factors this way. -/
def lift (f : A →ₐ[S] C) (g : B →ₐ[R] C) (hfg : ∀ x y, Commute (f x) (g y)) : (A ⊗[R] B) →ₐ[S] C :=
  algHomOfLinearMapTensorProduct
    (AlgebraTensorModule.lift <|
      letI restr : (C →ₗ[S] C) →ₗ[S] _ :=
        { toFun := (·.restrictScalars R)
          map_add' := fun f g => LinearMap.ext fun x => rfl
          map_smul' := fun c g => LinearMap.ext fun x => rfl }
      LinearMap.flip <| (restr ∘ₗ LinearMap.mul S C ∘ₗ f.toLinearMap).flip ∘ₗ g)
    (fun a₁ a₂ b₁ b₂ => show f (a₁ * a₂) * g (b₁ * b₂) = f a₁ * g b₁ * (f a₂ * g b₂) by
      rw [f.map_mul, g.map_mul, (hfg a₂ b₁).mul_mul_mul_comm])
    (show f 1 * g 1 = 1 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
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f : A →ₐ[S] C
g : B →ₐ[R] C
hfg : ∀ (x : A) (y : B), Commute (f x) (g y)
⊢ f 1 * g 1 = 1

Next tactic:
rw [f.map_one, g.map_one, one_mul]
@[simp]
theorem lift_includeLeft_includeRight :
    lift includeLeft includeRight (fun a b => (Commute.one_right _).tmul (Commute.one_left _)) =
      .id S (A ⊗[R] 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✝¹⁵ : 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
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
⊢ lift includeLeft includeRight (_ : ∀ (a : A) (b : B), Commute (a ⊗ₜ[R] 1) (1 ⊗ₜ[R] b)) = AlgHom.id S (A ⊗[R] B)

Next tactic:
ext
@[simp]
theorem lift_includeLeft_includeRight :
    lift includeLeft includeRight (fun a b => (Commute.one_right _).tmul (Commute.one_left _)) =
      .id S (A ⊗[R] B) := by
  ext <;> 

Proof state:
case ha.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
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
x✝ : A
⊢ (AlgHom.comp (lift includeLeft includeRight (_ : ∀ (a : A) (b : B), Commute (a ⊗ₜ[R] 1) (1 ⊗ₜ[R] b))) includeLeft)
      x✝ =
    (AlgHom.comp (AlgHom.id S (A ⊗[R] B)) includeLeft) x✝

Next tactic:
simp
@[simp]
theorem lift_includeLeft_includeRight :
    lift includeLeft includeRight (fun a b => (Commute.one_right _).tmul (Commute.one_left _)) =
      .id S (A ⊗[R] B) := by
  ext <;> 

Proof state:
case hb.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
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
x✝ : B
⊢ (AlgHom.comp
        (AlgHom.restrictScalars R
          (lift includeLeft includeRight (_ : ∀ (a : A) (b : B), Commute (a ⊗ₜ[R] 1) (1 ⊗ₜ[R] b))))
        includeRight)
      x✝ =
    (AlgHom.comp (AlgHom.restrictScalars R (AlgHom.id S (A ⊗[R] B))) includeRight) x✝

Next tactic:
simp
@[simp]
theorem lift_comp_includeLeft (f : A →ₐ[S] C) (g : B →ₐ[R] C) (hfg : ∀ x y, Commute (f x) (g y)) :
    (lift f g hfg).comp includeLeft = f :=
  AlgHom.ext <| 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
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f : A →ₐ[S] C
g : B →ₐ[R] C
hfg : ∀ (x : A) (y : B), Commute (f x) (g y)
⊢ ∀ (x : A), (AlgHom.comp (lift f g hfg) includeLeft) x = f x

Next tactic:
simp
@[simp]
theorem lift_comp_includeRight (f : A →ₐ[S] C) (g : B →ₐ[R] C) (hfg : ∀ x y, Commute (f x) (g y)) :
    ((lift f g hfg).restrictScalars R).comp includeRight = g :=
  AlgHom.ext <| 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
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f : A →ₐ[S] C
g : B →ₐ[R] C
hfg : ∀ (x : A) (y : B), Commute (f x) (g y)
⊢ ∀ (x : B), (AlgHom.comp (AlgHom.restrictScalars R (lift f g hfg)) includeRight) x = g x

Next tactic:
simp
/-- The universal property of the tensor product of algebras.

Pairs of algebra morphisms that commute are equivalent to algebra morphisms from the tensor product.

This is `Algebra.TensorProduct.lift` as an equivalence.

See also `GradedTensorProduct.liftEquiv` for an alternative commutativity requirement for graded
algebra. -/
@[simps]
def liftEquiv [IsScalarTower R S A] [IsScalarTower R S C] :
    {fg : (A →ₐ[S] C) × (B →ₐ[R] C) // ∀ x y, Commute (fg.1 x) (fg.2 y)}
      ≃ ((A ⊗[R] B) →ₐ[S] C) where
  toFun fg := lift fg.val.1 fg.val.2 fg.prop
  invFun f' := ⟨(f'.comp includeLeft, (f'.restrictScalars R).comp includeRight), fun x y =>
    ((Commute.one_right _).tmul (Commute.one_left _)).map f'⟩
  left_inv fg := 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
inst✝³ : IsScalarTower R S A
inst✝² : IsScalarTower R S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
fg : { fg // ∀ (x : A) (y : B), Commute (fg.1 x) (fg.2 y) }
⊢ (fun f' =>
        { val := (AlgHom.comp f' includeLeft, AlgHom.comp (AlgHom.restrictScalars R f') includeRight),
          property := (_ : ∀ (x : A) (y : B), Commute (f' (x ⊗ₜ[R] 1)) (f' (1 ⊗ₜ[R] y))) })
      ((fun fg => lift (↑fg).1 (↑fg).2 (_ : ∀ (x : A) (y : B), Commute ((↑fg).1 x) ((↑fg).2 y))) fg) =
    fg

Next tactic:
ext
/-- The universal property of the tensor product of algebras.

Pairs of algebra morphisms that commute are equivalent to algebra morphisms from the tensor product.

This is `Algebra.TensorProduct.lift` as an equivalence.

See also `GradedTensorProduct.liftEquiv` for an alternative commutativity requirement for graded
algebra. -/
@[simps]
def liftEquiv [IsScalarTower R S A] [IsScalarTower R S C] :
    {fg : (A →ₐ[S] C) × (B →ₐ[R] C) // ∀ x y, Commute (fg.1 x) (fg.2 y)}
      ≃ ((A ⊗[R] B) →ₐ[S] C) where
  toFun fg := lift fg.val.1 fg.val.2 fg.prop
  invFun f' := ⟨(f'.comp includeLeft, (f'.restrictScalars R).comp includeRight), fun x y =>
    ((Commute.one_right _).tmul (Commute.one_left _)).map f'⟩
  left_inv fg := by ext <;> 

Proof state:
case a.a.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
inst✝³ : IsScalarTower R S A
inst✝² : IsScalarTower R S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
fg : { fg // ∀ (x : A) (y : B), Commute (fg.1 x) (fg.2 y) }
x✝ : A
⊢ (↑((fun f' =>
              { val := (AlgHom.comp f' includeLeft, AlgHom.comp (AlgHom.restrictScalars R f') includeRight),
                property := (_ : ∀ (x : A) (y : B), Commute (f' (x ⊗ₜ[R] 1)) (f' (1 ⊗ₜ[R] y))) })
            ((fun fg => lift (↑fg).1 (↑fg).2 (_ : ∀ (x : A) (y : B), Commute ((↑fg).1 x) ((↑fg).2 y))) fg))).1
      x✝ =
    (↑fg).1 x✝

Next tactic:
simp
/-- The universal property of the tensor product of algebras.

Pairs of algebra morphisms that commute are equivalent to algebra morphisms from the tensor product.

This is `Algebra.TensorProduct.lift` as an equivalence.

See also `GradedTensorProduct.liftEquiv` for an alternative commutativity requirement for graded
algebra. -/
@[simps]
def liftEquiv [IsScalarTower R S A] [IsScalarTower R S C] :
    {fg : (A →ₐ[S] C) × (B →ₐ[R] C) // ∀ x y, Commute (fg.1 x) (fg.2 y)}
      ≃ ((A ⊗[R] B) →ₐ[S] C) where
  toFun fg := lift fg.val.1 fg.val.2 fg.prop
  invFun f' := ⟨(f'.comp includeLeft, (f'.restrictScalars R).comp includeRight), fun x y =>
    ((Commute.one_right _).tmul (Commute.one_left _)).map f'⟩
  left_inv fg := by ext <;> 

Proof state:
case a.a.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
inst✝³ : IsScalarTower R S A
inst✝² : IsScalarTower R S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
fg : { fg // ∀ (x : A) (y : B), Commute (fg.1 x) (fg.2 y) }
x✝ : B
⊢ (↑((fun f' =>
              { val := (AlgHom.comp f' includeLeft, AlgHom.comp (AlgHom.restrictScalars R f') includeRight),
                property := (_ : ∀ (x : A) (y : B), Commute (f' (x ⊗ₜ[R] 1)) (f' (1 ⊗ₜ[R] y))) })
            ((fun fg => lift (↑fg).1 (↑fg).2 (_ : ∀ (x : A) (y : B), Commute ((↑fg).1 x) ((↑fg).2 y))) fg))).2
      x✝ =
    (↑fg).2 x✝

Next tactic:
simp
/-- The universal property of the tensor product of algebras.

Pairs of algebra morphisms that commute are equivalent to algebra morphisms from the tensor product.

This is `Algebra.TensorProduct.lift` as an equivalence.

See also `GradedTensorProduct.liftEquiv` for an alternative commutativity requirement for graded
algebra. -/
@[simps]
def liftEquiv [IsScalarTower R S A] [IsScalarTower R S C] :
    {fg : (A →ₐ[S] C) × (B →ₐ[R] C) // ∀ x y, Commute (fg.1 x) (fg.2 y)}
      ≃ ((A ⊗[R] B) →ₐ[S] C) where
  toFun fg := lift fg.val.1 fg.val.2 fg.prop
  invFun f' := ⟨(f'.comp includeLeft, (f'.restrictScalars R).comp includeRight), fun x y =>
    ((Commute.one_right _).tmul (Commute.one_left _)).map f'⟩
  left_inv fg := by ext <;> simp
  right_inv f' := 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
inst✝³ : IsScalarTower R S A
inst✝² : IsScalarTower R S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f' : A ⊗[R] B →ₐ[S] C
⊢ (fun fg => lift (↑fg).1 (↑fg).2 (_ : ∀ (x : A) (y : B), Commute ((↑fg).1 x) ((↑fg).2 y)))
      ((fun f' =>
          { val := (AlgHom.comp f' includeLeft, AlgHom.comp (AlgHom.restrictScalars R f') includeRight),
            property := (_ : ∀ (x : A) (y : B), Commute (f' (x ⊗ₜ[R] 1)) (f' (1 ⊗ₜ[R] y))) })
        f') =
    f'

Next tactic:
ext
/-- The universal property of the tensor product of algebras.

Pairs of algebra morphisms that commute are equivalent to algebra morphisms from the tensor product.

This is `Algebra.TensorProduct.lift` as an equivalence.

See also `GradedTensorProduct.liftEquiv` for an alternative commutativity requirement for graded
algebra. -/
@[simps]
def liftEquiv [IsScalarTower R S A] [IsScalarTower R S C] :
    {fg : (A →ₐ[S] C) × (B →ₐ[R] C) // ∀ x y, Commute (fg.1 x) (fg.2 y)}
      ≃ ((A ⊗[R] B) →ₐ[S] C) where
  toFun fg := lift fg.val.1 fg.val.2 fg.prop
  invFun f' := ⟨(f'.comp includeLeft, (f'.restrictScalars R).comp includeRight), fun x y =>
    ((Commute.one_right _).tmul (Commute.one_left _)).map f'⟩
  left_inv fg := by ext <;> simp
  right_inv f' := by ext <;> 

Proof state:
case ha.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
inst✝³ : IsScalarTower R S A
inst✝² : IsScalarTower R S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f' : A ⊗[R] B →ₐ[S] C
x✝ : A
⊢ (AlgHom.comp
        ((fun fg => lift (↑fg).1 (↑fg).2 (_ : ∀ (x : A) (y : B), Commute ((↑fg).1 x) ((↑fg).2 y)))
          ((fun f' =>
              { val := (AlgHom.comp f' includeLeft, AlgHom.comp (AlgHom.restrictScalars R f') includeRight),
                property := (_ : ∀ (x : A) (y : B), Commute (f' (x ⊗ₜ[R] 1)) (f' (1 ⊗ₜ[R] y))) })
            f'))
        includeLeft)
      x✝ =
    (AlgHom.comp f' includeLeft) x✝

Next tactic:
simp
/-- The universal property of the tensor product of algebras.

Pairs of algebra morphisms that commute are equivalent to algebra morphisms from the tensor product.

This is `Algebra.TensorProduct.lift` as an equivalence.

See also `GradedTensorProduct.liftEquiv` for an alternative commutativity requirement for graded
algebra. -/
@[simps]
def liftEquiv [IsScalarTower R S A] [IsScalarTower R S C] :
    {fg : (A →ₐ[S] C) × (B →ₐ[R] C) // ∀ x y, Commute (fg.1 x) (fg.2 y)}
      ≃ ((A ⊗[R] B) →ₐ[S] C) where
  toFun fg := lift fg.val.1 fg.val.2 fg.prop
  invFun f' := ⟨(f'.comp includeLeft, (f'.restrictScalars R).comp includeRight), fun x y =>
    ((Commute.one_right _).tmul (Commute.one_left _)).map f'⟩
  left_inv fg := by ext <;> simp
  right_inv f' := by ext <;> 

Proof state:
case hb.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
inst✝³ : IsScalarTower R S A
inst✝² : IsScalarTower R S C
inst✝¹ : IsScalarTower R S A
inst✝ : IsScalarTower R S C
f' : A ⊗[R] B →ₐ[S] C
x✝ : B
⊢ (AlgHom.comp
        (AlgHom.restrictScalars R
          ((fun fg => lift (↑fg).1 (↑fg).2 (_ : ∀ (x : A) (y : B), Commute ((↑fg).1 x) ((↑fg).2 y)))
            ((fun f' =>
                { val := (AlgHom.comp f' includeLeft, AlgHom.comp (AlgHom.restrictScalars R f') includeRight),
                  property := (_ : ∀ (x : A) (y : B), Commute (f' (x ⊗ₜ[R] 1)) (f' (1 ⊗ₜ[R] y))) })
              f')))
        includeRight)
      x✝ =
    (AlgHom.comp (AlgHom.restrictScalars R f') includeRight) x✝

Next tactic:
simp
/-- The base ring is a left identity for the tensor product of algebra, up to algebra isomorphism.
-/
protected nonrec def lid : R ⊗[R] A ≃ₐ[R] A :=
  algEquivOfLinearEquivTensorProduct (TensorProduct.lid R A) (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✝¹¹ : Algebra S B
inst✝¹⁰ : IsScalarTower R S B
inst✝⁹ : Semiring C
inst✝⁸ : Algebra R C
inst✝⁷ : Algebra S C
inst✝⁶ : IsScalarTower R S C
inst✝⁵ : Semiring D
inst✝⁴ : Algebra R D
inst✝³ : Semiring E
inst✝² : Algebra R E
inst✝¹ : Semiring F
inst✝ : Algebra R F
⊢ ∀ (a₁ a₂ : R) (b₁ b₂ : A),
    (_root_.TensorProduct.lid R A) ((a₁ * a₂) ⊗ₜ[R] (b₁ * b₂)) =
      (_root_.TensorProduct.lid R A) (a₁ ⊗ₜ[R] b₁) * (_root_.TensorProduct.lid R A) (a₂ ⊗ₜ[R] b₂)

Next tactic:
simp only [mul_smul, lid_tmul, Algebra.smul_mul_assoc, Algebra.mul_smul_comm]
/-- The base ring is a left identity for the tensor product of algebra, up to algebra isomorphism.
-/
protected nonrec def lid : R ⊗[R] A ≃ₐ[R] A :=
  algEquivOfLinearEquivTensorProduct (TensorProduct.lid R A) (by
    simp only [mul_smul, lid_tmul, Algebra.smul_mul_assoc, Algebra.mul_smul_comm]
    

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✝¹¹ : Algebra S B
inst✝¹⁰ : IsScalarTower R S B
inst✝⁹ : Semiring C
inst✝⁸ : Algebra R C
inst✝⁷ : Algebra S C
inst✝⁶ : IsScalarTower R S C
inst✝⁵ : Semiring D
inst✝⁴ : Algebra R D
inst✝³ : Semiring E
inst✝² : Algebra R E
inst✝¹ : Semiring F
inst✝ : Algebra R F
⊢ ∀ (a₁ a₂ : R) (b₁ b₂ : A), a₁ • a₂ • (b₁ * b₂) = a₂ • a₁ • (b₁ * b₂)

Next tactic:
simp_rw [← mul_smul, mul_comm]
/-- The base ring is a left identity for the tensor product of algebra, up to algebra isomorphism.
-/
protected nonrec def lid : R ⊗[R] A ≃ₐ[R] A :=
  algEquivOfLinearEquivTensorProduct (TensorProduct.lid R A) (by
    simp only [mul_smul, lid_tmul, Algebra.smul_mul_assoc, Algebra.mul_smul_comm]
    simp_rw [← mul_smul, mul_comm]
    

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✝¹¹ : Algebra S B
inst✝¹⁰ : IsScalarTower R S B
inst✝⁹ : Semiring C
inst✝⁸ : Algebra R C
inst✝⁷ : Algebra S C
inst✝⁶ : IsScalarTower R S C
inst✝⁵ : Semiring D
inst✝⁴ : Algebra R D
inst✝³ : Semiring E
inst✝² : Algebra R E
inst✝¹ : Semiring F
inst✝ : Algebra R F
⊢ R → R → A → A → True

Next tactic:
simp
/-- The base ring is a left identity for the tensor product of algebra, up to algebra isomorphism.
-/
protected nonrec def lid : R ⊗[R] A ≃ₐ[R] A :=
  algEquivOfLinearEquivTensorProduct (TensorProduct.lid R A) (by
    simp only [mul_smul, lid_tmul, Algebra.smul_mul_assoc, Algebra.mul_smul_comm]
    simp_rw [← mul_smul, mul_comm]
    simp)
    (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✝¹¹ : Algebra S B
inst✝¹⁰ : IsScalarTower R S B
inst✝⁹ : Semiring C
inst✝⁸ : Algebra R C
inst✝⁷ : Algebra S C
inst✝⁶ : IsScalarTower R S C
inst✝⁵ : Semiring D
inst✝⁴ : Algebra R D
inst✝³ : Semiring E
inst✝² : Algebra R E
inst✝¹ : Semiring F
inst✝ : Algebra R F
⊢ (_root_.TensorProduct.lid R A) (1 ⊗ₜ[R] 1) = 1

Next tactic:
simp [Algebra.smul_def]