-- Mathlib/LinearAlgebra/Trace.lean
theorem trace_prodMap :
    trace R (M × N) ∘ₗ prodMapLinear R M N M N R =
      (coprod id id : R × R →ₗ[R] R) ∘ₗ prodMap (trace R M) (trace R N)

Proof state:
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
h : Function.Surjective ⇑↑e
⊢ (trace R (M × N) ∘ₗ prodMapLinear R M N M N R) ∘ₗ ↑e = (id.coprod id ∘ₗ (trace R M).prodMap (trace R N)) ∘ₗ ↑e

Tactic:
ext

Result:
case hl.a.h.h
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
h : Function.Surjective ⇑↑e
x✝¹ : Dual R M
x✝ : M
⊢ ((AlgebraTensorModule.curry
          (((trace R (M × N) ∘ₗ prodMapLinear R M N M N R) ∘ₗ ↑e) ∘ₗ inl R (Dual R M ⊗[R] M) (Dual R N ⊗[R] N)))
        x✝¹)
      x✝ =
    ((AlgebraTensorModule.curry
          (((id.coprod id ∘ₗ (trace R M).prodMap (trace R N)) ∘ₗ ↑e) ∘ₗ inl R (Dual R M ⊗[R] M) (Dual R N ⊗[R] N)))
        x✝¹)
      x✝

case hr.a.h.h
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
h : Function.Surjective ⇑↑e
x✝¹ : Dual R N
x✝ : N
⊢ ((AlgebraTensorModule.curry
          (((trace R (M × N) ∘ₗ prodMapLinear R M N M N R) ∘ₗ ↑e) ∘ₗ inr R (Dual R M ⊗[R] M) (Dual R N ⊗[R] N)))
        x✝¹)
      x✝ =
    ((AlgebraTensorModule.curry
          (((id.coprod id ∘ₗ (trace R M).prodMap (trace R N)) ∘ₗ ↑e) ∘ₗ inr R (Dual R M ⊗[R] M) (Dual R N ⊗[R] N)))
        x✝¹)
      x✝

Proof state:
case hr.a.h.h
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
h : Function.Surjective ⇑↑e
x✝¹ : Dual R N
x✝ : N
⊢ ((AlgebraTensorModule.curry
          (((trace R (M × N) ∘ₗ prodMapLinear R M N M N R) ∘ₗ ↑e) ∘ₗ inr R (Dual R M ⊗[R] M) (Dual R N ⊗[R] N)))
        x✝¹)
      x✝ =
    ((AlgebraTensorModule.curry
          (((id.coprod id ∘ₗ (trace R M).prodMap (trace R N)) ∘ₗ ↑e) ∘ₗ inr R (Dual R M ⊗[R] M) (Dual R N ⊗[R] N)))
        x✝¹)
      x✝

Tactic:
simp only [e, dualTensorHomEquiv, LinearEquiv.coe_prod, dualTensorHomEquivOfBasis_toLinearMap,
  AlgebraTensorModule.curry_apply, curry_apply, coe_restrictScalars, coe_comp, coe_inr,
  Function.comp_apply, prodMap_apply, map_zero, prodMapLinear_apply, zero_prodMap_dualTensorHom,
  trace_eq_contract_apply, contractLeft_apply, snd_apply, coprod_apply, id_coe, id_eq, zero_add]

Result:
no goals

Proof state:
case hl.a.h.h
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
h : Function.Surjective ⇑↑e
x✝¹ : Dual R M
x✝ : M
⊢ ((AlgebraTensorModule.curry
          (((trace R (M × N) ∘ₗ prodMapLinear R M N M N R) ∘ₗ ↑e) ∘ₗ inl R (Dual R M ⊗[R] M) (Dual R N ⊗[R] N)))
        x✝¹)
      x✝ =
    ((AlgebraTensorModule.curry
          (((id.coprod id ∘ₗ (trace R M).prodMap (trace R N)) ∘ₗ ↑e) ∘ₗ inl R (Dual R M ⊗[R] M) (Dual R N ⊗[R] N)))
        x✝¹)
      x✝

Tactic:
simp only [e, dualTensorHomEquiv, LinearEquiv.coe_prod, dualTensorHomEquivOfBasis_toLinearMap,
  AlgebraTensorModule.curry_apply, curry_apply, coe_restrictScalars, coe_comp, coe_inl,
  Function.comp_apply, prodMap_apply, map_zero, prodMapLinear_apply, dualTensorHom_prodMap_zero,
  trace_eq_contract_apply, contractLeft_apply, fst_apply, coprod_apply, id_coe, id_eq, add_zero]

Result:
no goals

Proof state:
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
h : Function.Surjective ⇑↑e
⊢ trace R (M × N) ∘ₗ prodMapLinear R M N M N R = id.coprod id ∘ₗ (trace R M).prodMap (trace R N)

Tactic:
refine (cancel_right h).1 ?_

Result:
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
h : Function.Surjective ⇑↑e
⊢ (trace R (M × N) ∘ₗ prodMapLinear R M N M N R) ∘ₗ ↑e = (id.coprod id ∘ₗ (trace R M).prodMap (trace R N)) ∘ₗ ↑e

Proof state:
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
⊢ trace R (M × N) ∘ₗ prodMapLinear R M N M N R = id.coprod id ∘ₗ (trace R M).prodMap (trace R N)

Tactic:
have h : Function.Surjective e.toLinearMap := e.surjective

Result:
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
h : Function.Surjective ⇑↑e
⊢ trace R (M × N) ∘ₗ prodMapLinear R M N M N R = id.coprod id ∘ₗ (trace R M).prodMap (trace R N)

Proof state:
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
⊢ trace R (M × N) ∘ₗ prodMapLinear R M N M N R = id.coprod id ∘ₗ (trace R M).prodMap (trace R N)

Tactic:
let e := (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)

Result:
R : Type u_1
inst✝⁸ : CommRing R
M : Type u_2
inst✝⁷ : AddCommGroup M
inst✝⁶ : Module R M
N : Type u_3
inst✝⁵ : AddCommGroup N
inst✝⁴ : Module R N
inst✝³ : Free R M
inst✝² : Module.Finite R M
inst✝¹ : Free R N
inst✝ : Module.Finite R N
e : (Dual R M ⊗[R] M × Dual R N ⊗[R] N) ≃ₗ[R] (M →ₗ[R] M) × (N →ₗ[R] N) :=
  (dualTensorHomEquiv R M M).prod (dualTensorHomEquiv R N N)
⊢ trace R (M × N) ∘ₗ prodMapLinear R M N M N R = id.coprod id ∘ₗ (trace R M).prodMap (trace R N)