l3lab/ntp-mathlib huggingface dataset:
theorem eval_ker : LinearMap.ker (eval K V) = ⊥ := by
  

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ ker (eval K V) = ⊥

Next tactic:
classical exact (Module.Free.chooseBasis K V).eval_ker
theorem eval_ker : LinearMap.ker (eval K V) = ⊥ := by
  classical 

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ ker (eval K V) = ⊥

Next tactic:
exact (Module.Free.chooseBasis K V).eval_ker
theorem map_eval_injective : (Submodule.map (eval K V)).Injective := by
  

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ Function.Injective (Submodule.map (eval K V))

Next tactic:
apply Submodule.map_injective_of_injective
theorem map_eval_injective : (Submodule.map (eval K V)).Injective := by
  apply Submodule.map_injective_of_injective
  

Proof state:
case hf
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ Function.Injective ⇑(eval K V)

Next tactic:
rw [← LinearMap.ker_eq_bot]
theorem map_eval_injective : (Submodule.map (eval K V)).Injective := by
  apply Submodule.map_injective_of_injective
  rw [← LinearMap.ker_eq_bot]
  

Proof state:
case hf
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ ker (eval K V) = ⊥

Next tactic:
exact eval_ker K V
theorem comap_eval_surjective : (Submodule.comap (eval K V)).Surjective := by
  

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ Function.Surjective (Submodule.comap (eval K V))

Next tactic:
apply Submodule.comap_surjective_of_injective
theorem comap_eval_surjective : (Submodule.comap (eval K V)).Surjective := by
  apply Submodule.comap_surjective_of_injective
  

Proof state:
case hf
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ Function.Injective ⇑(eval K V)

Next tactic:
rw [← LinearMap.ker_eq_bot]
theorem comap_eval_surjective : (Submodule.comap (eval K V)).Surjective := by
  apply Submodule.comap_surjective_of_injective
  rw [← LinearMap.ker_eq_bot]
  

Proof state:
case hf
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ ker (eval K V) = ⊥

Next tactic:
exact eval_ker K V
theorem eval_apply_eq_zero_iff (v : V) : (eval K V) v = 0 ↔ v = 0 := by
  

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
v : V
⊢ (eval K V) v = 0 ↔ v = 0

Next tactic:
simpa only using SetLike.ext_iff.mp (eval_ker K V) v
theorem forall_dual_apply_eq_zero_iff (v : V) : (∀ φ : Module.Dual K V, φ v = 0) ↔ v = 0 := by
  

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
v : V
⊢ (∀ (φ : Dual K V), φ v = 0) ↔ v = 0

Next tactic:
rw [← eval_apply_eq_zero_iff K v, LinearMap.ext_iff]
theorem forall_dual_apply_eq_zero_iff (v : V) : (∀ φ : Module.Dual K V, φ v = 0) ↔ v = 0 := by
  rw [← eval_apply_eq_zero_iff K v, LinearMap.ext_iff]
  

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
v : V
⊢ (∀ (φ : Dual K V), φ v = 0) ↔ ∀ (x : Dual K V), ((eval K V) v) x = 0 x

Next tactic:
rfl
@[simp]
theorem subsingleton_dual_iff :
    Subsingleton (Dual K V) ↔ Subsingleton V := by
  

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ Subsingleton (Dual K V) ↔ Subsingleton V

Next tactic:
refine ⟨fun h ↦ ⟨fun v w ↦ ?_⟩, fun h ↦ ⟨fun f g ↦ ?_⟩⟩
@[simp]
theorem subsingleton_dual_iff :
    Subsingleton (Dual K V) ↔ Subsingleton V := by
  refine ⟨fun h ↦ ⟨fun v w ↦ ?_⟩, fun h ↦ ⟨fun f g ↦ ?_⟩⟩
  · 

Proof state:
case refine_1
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
h : Subsingleton (Dual K V)
v w : V
⊢ v = w

Next tactic:
rw [← sub_eq_zero, ← forall_dual_apply_eq_zero_iff K (v - w)]
@[simp]
theorem subsingleton_dual_iff :
    Subsingleton (Dual K V) ↔ Subsingleton V := by
  refine ⟨fun h ↦ ⟨fun v w ↦ ?_⟩, fun h ↦ ⟨fun f g ↦ ?_⟩⟩
  · rw [← sub_eq_zero, ← forall_dual_apply_eq_zero_iff K (v - w)]
    

Proof state:
case refine_1
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
h : Subsingleton (Dual K V)
v w : V
⊢ ∀ (φ : Dual K V), φ (v - w) = 0

Next tactic:
intros f
@[simp]
theorem subsingleton_dual_iff :
    Subsingleton (Dual K V) ↔ Subsingleton V := by
  refine ⟨fun h ↦ ⟨fun v w ↦ ?_⟩, fun h ↦ ⟨fun f g ↦ ?_⟩⟩
  · rw [← sub_eq_zero, ← forall_dual_apply_eq_zero_iff K (v - w)]
    intros f
    

Proof state:
case refine_1
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
h : Subsingleton (Dual K V)
v w : V
f : Dual K V
⊢ f (v - w) = 0

Next tactic:
simp [Subsingleton.elim f 0]
@[simp]
theorem subsingleton_dual_iff :
    Subsingleton (Dual K V) ↔ Subsingleton V := by
  refine ⟨fun h ↦ ⟨fun v w ↦ ?_⟩, fun h ↦ ⟨fun f g ↦ ?_⟩⟩
  · rw [← sub_eq_zero, ← forall_dual_apply_eq_zero_iff K (v - w)]
    intros f
    simp [Subsingleton.elim f 0]
  · 

Proof state:
case refine_2
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
h : Subsingleton V
f g : Dual K V
⊢ f = g

Next tactic:
ext v
@[simp]
theorem subsingleton_dual_iff :
    Subsingleton (Dual K V) ↔ Subsingleton V := by
  refine ⟨fun h ↦ ⟨fun v w ↦ ?_⟩, fun h ↦ ⟨fun f g ↦ ?_⟩⟩
  · rw [← sub_eq_zero, ← forall_dual_apply_eq_zero_iff K (v - w)]
    intros f
    simp [Subsingleton.elim f 0]
  · ext v
    

Proof state:
case refine_2.h
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
h : Subsingleton V
f g : Dual K V
v : V
⊢ f v = g v

Next tactic:
simp [Subsingleton.elim v 0]
@[simp]
theorem nontrivial_dual_iff :
    Nontrivial (Dual K V) ↔ Nontrivial V := by
  

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ Nontrivial (Dual K V) ↔ Nontrivial V

Next tactic:
rw [← not_iff_not, not_nontrivial_iff_subsingleton, not_nontrivial_iff_subsingleton,
    subsingleton_dual_iff]
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ Finite K (Dual K V) ↔ Finite K V

Next tactic:
constructor
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> 

Proof state:
case mp
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ Finite K (Dual K V) → Finite K V

Next tactic:
intro h
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> 

Proof state:
case mpr
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
⊢ Finite K V → Finite K (Dual K V)

Next tactic:
intro h
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> intro h
  · 

Proof state:
case mp
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
h : Finite K (Dual K V)
⊢ Finite K V

Next tactic:
obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> intro h
  · obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
    

Proof state:
case mp.intro.mk
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
h : Finite K (Dual K V)
ι : Type uV
b : Basis ι K V
⊢ Finite K V

Next tactic:
nontriviality K
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> intro h
  · obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
    nontriviality K
    

Proof state:
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
h : Finite K (Dual K V)
ι : Type uV
b : Basis ι K V
✝ : Nontrivial K
⊢ Finite K V

Next tactic:
obtain ⟨⟨s, span_s⟩⟩ := h
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> intro h
  · obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
    nontriviality K
    obtain ⟨⟨s, span_s⟩⟩ := h
    

Proof state:
case mk.intro
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
ι : Type uV
b : Basis ι K V
✝ : Nontrivial K
s : Finset (Dual K V)
span_s : Submodule.span K ↑s = ⊤
⊢ Finite K V

Next tactic:
classical
    haveI := (b.linearIndependent.map' _ b.toDual_ker).finite_of_le_span_finite _ s ?_
    · exact Finite.of_basis b
    · rw [span_s]; apply le_top
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> intro h
  · obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
    nontriviality K
    obtain ⟨⟨s, span_s⟩⟩ := h
    classical
    

Proof state:
case mk.intro
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
ι : Type uV
b : Basis ι K V
✝ : Nontrivial K
s : Finset (Dual K V)
span_s : Submodule.span K ↑s = ⊤
⊢ Finite K V

Next tactic:
haveI := (b.linearIndependent.map' _ b.toDual_ker).finite_of_le_span_finite _ s ?_
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> intro h
  · obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
    nontriviality K
    obtain ⟨⟨s, span_s⟩⟩ := h
    classical
    haveI := (b.linearIndependent.map' _ b.toDual_ker).finite_of_le_span_finite _ s ?_
    · 

Proof state:
case mk.intro.refine_2
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
ι : Type uV
b : Basis ι K V
✝ : Nontrivial K
s : Finset (Dual K V)
span_s : Submodule.span K ↑s = ⊤
this : _root_.Finite ι
⊢ Finite K V

Next tactic:
exact Finite.of_basis b
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> intro h
  · obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
    nontriviality K
    obtain ⟨⟨s, span_s⟩⟩ := h
    classical
    haveI := (b.linearIndependent.map' _ b.toDual_ker).finite_of_le_span_finite _ s ?_
    · exact Finite.of_basis b
    · 

Proof state:
case mk.intro.refine_1
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
ι : Type uV
b : Basis ι K V
✝ : Nontrivial K
s : Finset (Dual K V)
span_s : Submodule.span K ↑s = ⊤
⊢ Set.range (⇑(toDual b) ∘ ⇑b) ≤ ↑(Submodule.span K ↑s)

Next tactic:
rw [span_s]
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> intro h
  · obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
    nontriviality K
    obtain ⟨⟨s, span_s⟩⟩ := h
    classical
    haveI := (b.linearIndependent.map' _ b.toDual_ker).finite_of_le_span_finite _ s ?_
    · exact Finite.of_basis b
    · rw [span_s]; 

Proof state:
case mk.intro.refine_1
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
ι : Type uV
b : Basis ι K V
✝ : Nontrivial K
s : Finset (Dual K V)
span_s : Submodule.span K ↑s = ⊤
⊢ Set.range (⇑(toDual b) ∘ ⇑b) ≤ ↑⊤

Next tactic:
apply le_top
theorem finite_dual_iff : Finite K (Dual K V) ↔ Finite K V := by
  constructor <;> intro h
  · obtain ⟨⟨ι, b⟩⟩ := Module.Free.exists_basis (R := K) (M := V)
    nontriviality K
    obtain ⟨⟨s, span_s⟩⟩ := h
    classical
    haveI := (b.linearIndependent.map' _ b.toDual_ker).finite_of_le_span_finite _ s ?_
    · exact Finite.of_basis b
    · rw [span_s]; apply le_top
  · 

Proof state:
case mpr
K : Type uK
V : Type uV
inst✝³ : CommRing K
inst✝² : AddCommGroup V
inst✝¹ : Module K V
inst✝ : Free K V
h : Finite K V
⊢ Finite K (Dual K V)

Next tactic:
infer_instance
@[simp] lemma apply_evalEquiv_symm_apply (f : Dual R M) (g : Dual R (Dual R M)) :
    f ((evalEquiv R M).symm g) = g f := by
  

Proof state:
K : Type uK
V : Type uV
inst✝⁹ : CommRing K
inst✝⁸ : AddCommGroup V
inst✝⁷ : Module K V
inst✝⁶ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : AddCommGroup N
inst✝² : Module R M
inst✝¹ : Module R N
inst✝ : IsReflexive R M
f : Dual R M
g : Dual R (Dual R M)
⊢ f ((LinearEquiv.symm (evalEquiv R M)) g) = g f

Next tactic:
set m := (evalEquiv R M).symm g
@[simp] lemma apply_evalEquiv_symm_apply (f : Dual R M) (g : Dual R (Dual R M)) :
    f ((evalEquiv R M).symm g) = g f := by
  set m := (evalEquiv R M).symm g
  

Proof state:
K : Type uK
V : Type uV
inst✝⁹ : CommRing K
inst✝⁸ : AddCommGroup V
inst✝⁷ : Module K V
inst✝⁶ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : AddCommGroup N
inst✝² : Module R M
inst✝¹ : Module R N
inst✝ : IsReflexive R M
f : Dual R M
g : Dual R (Dual R M)
m : M := (LinearEquiv.symm (evalEquiv R M)) g
⊢ f m = g f

Next tactic:
rw [← (evalEquiv R M).apply_symm_apply g, evalEquiv_apply, Dual.eval_apply]
@[simp] lemma symm_dualMap_evalEquiv :
    (evalEquiv R M).symm.dualMap = Dual.eval R (Dual R M) := by
  

Proof state:
K : Type uK
V : Type uV
inst✝⁹ : CommRing K
inst✝⁸ : AddCommGroup V
inst✝⁷ : Module K V
inst✝⁶ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : AddCommGroup N
inst✝² : Module R M
inst✝¹ : Module R N
inst✝ : IsReflexive R M
⊢ ↑(LinearEquiv.dualMap (LinearEquiv.symm (evalEquiv R M))) = Dual.eval R (Dual R M)

Next tactic:
ext
@[simp] lemma symm_dualMap_evalEquiv :
    (evalEquiv R M).symm.dualMap = Dual.eval R (Dual R M) := by
  ext; 

Proof state:
case h.h
K : Type uK
V : Type uV
inst✝⁹ : CommRing K
inst✝⁸ : AddCommGroup V
inst✝⁷ : Module K V
inst✝⁶ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : AddCommGroup N
inst✝² : Module R M
inst✝¹ : Module R N
inst✝ : IsReflexive R M
x✝¹ : Dual R M
x✝ : Dual R (Dual R M)
⊢ (↑(LinearEquiv.dualMap (LinearEquiv.symm (evalEquiv R M))) x✝¹) x✝ = ((Dual.eval R (Dual R M)) x✝¹) x✝

Next tactic:
simp
/-- The dual of a reflexive module is reflexive. -/
instance Dual.instIsReflecive : IsReflexive R (Dual R M) :=
⟨by 

Proof state:
K : Type uK
V : Type uV
inst✝⁹ : CommRing K
inst✝⁸ : AddCommGroup V
inst✝⁷ : Module K V
inst✝⁶ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : AddCommGroup N
inst✝² : Module R M
inst✝¹ : Module R N
inst✝ : IsReflexive R M
⊢ Bijective ⇑(eval R (Dual R M))

Next tactic:
simpa only [← symm_dualMap_evalEquiv] using (evalEquiv R M).dualMap.symm.bijective
instance _root_.Prod.instModuleIsReflexive [IsReflexive R N] :
    IsReflexive R (M × N) where
  bijective_dual_eval' := by
    

Proof state:
K : Type uK
V : Type uV
inst✝¹⁰ : CommRing K
inst✝⁹ : AddCommGroup V
inst✝⁸ : Module K V
inst✝⁷ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : AddCommGroup N
inst✝³ : Module R M
inst✝² : Module R N
inst✝¹ : IsReflexive R M
inst✝ : IsReflexive R N
⊢ Bijective ⇑(Dual.eval R (M × N))

Next tactic:
let e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
      (dualProdDualEquivDual R M N).dualMap.trans
        (dualProdDualEquivDual R (Dual R M) (Dual R N)).symm
instance _root_.Prod.instModuleIsReflexive [IsReflexive R N] :
    IsReflexive R (M × N) where
  bijective_dual_eval' := by
    let e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
      (dualProdDualEquivDual R M N).dualMap.trans
        (dualProdDualEquivDual R (Dual R M) (Dual R N)).symm
    

Proof state:
K : Type uK
V : Type uV
inst✝¹⁰ : CommRing K
inst✝⁹ : AddCommGroup V
inst✝⁸ : Module K V
inst✝⁷ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : AddCommGroup N
inst✝³ : Module R M
inst✝² : Module R N
inst✝¹ : IsReflexive R M
inst✝ : IsReflexive R N
e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
  LinearEquiv.dualMap (dualProdDualEquivDual R M N) ≪≫ₗ LinearEquiv.symm (dualProdDualEquivDual R (Dual R M) (Dual R N))
⊢ Bijective ⇑(Dual.eval R (M × N))

Next tactic:
have : Dual.eval R (M × N) = e.symm.comp ((Dual.eval R M).prodMap (Dual.eval R N)) := by
      ext m f <;> simp
instance _root_.Prod.instModuleIsReflexive [IsReflexive R N] :
    IsReflexive R (M × N) where
  bijective_dual_eval' := by
    let e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
      (dualProdDualEquivDual R M N).dualMap.trans
        (dualProdDualEquivDual R (Dual R M) (Dual R N)).symm
    have : Dual.eval R (M × N) = e.symm.comp ((Dual.eval R M).prodMap (Dual.eval R N)) := by
      

Proof state:
K : Type uK
V : Type uV
inst✝¹⁰ : CommRing K
inst✝⁹ : AddCommGroup V
inst✝⁸ : Module K V
inst✝⁷ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : AddCommGroup N
inst✝³ : Module R M
inst✝² : Module R N
inst✝¹ : IsReflexive R M
inst✝ : IsReflexive R N
e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
  LinearEquiv.dualMap (dualProdDualEquivDual R M N) ≪≫ₗ LinearEquiv.symm (dualProdDualEquivDual R (Dual R M) (Dual R N))
⊢ Dual.eval R (M × N) = ↑(LinearEquiv.symm e) ∘ₗ prodMap (Dual.eval R M) (Dual.eval R N)

Next tactic:
ext m f
instance _root_.Prod.instModuleIsReflexive [IsReflexive R N] :
    IsReflexive R (M × N) where
  bijective_dual_eval' := by
    let e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
      (dualProdDualEquivDual R M N).dualMap.trans
        (dualProdDualEquivDual R (Dual R M) (Dual R N)).symm
    have : Dual.eval R (M × N) = e.symm.comp ((Dual.eval R M).prodMap (Dual.eval R N)) := by
      ext m f <;> 

Proof state:
case hl.h.h
K : Type uK
V : Type uV
inst✝¹⁰ : CommRing K
inst✝⁹ : AddCommGroup V
inst✝⁸ : Module K V
inst✝⁷ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : AddCommGroup N
inst✝³ : Module R M
inst✝² : Module R N
inst✝¹ : IsReflexive R M
inst✝ : IsReflexive R N
e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
  LinearEquiv.dualMap (dualProdDualEquivDual R M N) ≪≫ₗ LinearEquiv.symm (dualProdDualEquivDual R (Dual R M) (Dual R N))
m : M
f : Dual R (M × N)
⊢ ((Dual.eval R (M × N) ∘ₗ inl R M N) m) f =
    (((↑(LinearEquiv.symm e) ∘ₗ prodMap (Dual.eval R M) (Dual.eval R N)) ∘ₗ inl R M N) m) f

Next tactic:
simp
instance _root_.Prod.instModuleIsReflexive [IsReflexive R N] :
    IsReflexive R (M × N) where
  bijective_dual_eval' := by
    let e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
      (dualProdDualEquivDual R M N).dualMap.trans
        (dualProdDualEquivDual R (Dual R M) (Dual R N)).symm
    have : Dual.eval R (M × N) = e.symm.comp ((Dual.eval R M).prodMap (Dual.eval R N)) := by
      ext m f <;> 

Proof state:
case hr.h.h
K : Type uK
V : Type uV
inst✝¹⁰ : CommRing K
inst✝⁹ : AddCommGroup V
inst✝⁸ : Module K V
inst✝⁷ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : AddCommGroup N
inst✝³ : Module R M
inst✝² : Module R N
inst✝¹ : IsReflexive R M
inst✝ : IsReflexive R N
e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
  LinearEquiv.dualMap (dualProdDualEquivDual R M N) ≪≫ₗ LinearEquiv.symm (dualProdDualEquivDual R (Dual R M) (Dual R N))
m : N
f : Dual R (M × N)
⊢ ((Dual.eval R (M × N) ∘ₗ inr R M N) m) f =
    (((↑(LinearEquiv.symm e) ∘ₗ prodMap (Dual.eval R M) (Dual.eval R N)) ∘ₗ inr R M N) m) f

Next tactic:
simp
instance _root_.Prod.instModuleIsReflexive [IsReflexive R N] :
    IsReflexive R (M × N) where
  bijective_dual_eval' := by
    let e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
      (dualProdDualEquivDual R M N).dualMap.trans
        (dualProdDualEquivDual R (Dual R M) (Dual R N)).symm
    have : Dual.eval R (M × N) = e.symm.comp ((Dual.eval R M).prodMap (Dual.eval R N)) := by
      ext m f <;> simp
    

Proof state:
K : Type uK
V : Type uV
inst✝¹⁰ : CommRing K
inst✝⁹ : AddCommGroup V
inst✝⁸ : Module K V
inst✝⁷ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : AddCommGroup N
inst✝³ : Module R M
inst✝² : Module R N
inst✝¹ : IsReflexive R M
inst✝ : IsReflexive R N
e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
  LinearEquiv.dualMap (dualProdDualEquivDual R M N) ≪≫ₗ LinearEquiv.symm (dualProdDualEquivDual R (Dual R M) (Dual R N))
this : Dual.eval R (M × N) = ↑(LinearEquiv.symm e) ∘ₗ prodMap (Dual.eval R M) (Dual.eval R N)
⊢ Bijective ⇑(Dual.eval R (M × N))

Next tactic:
simp only [this, LinearEquiv.trans_symm, LinearEquiv.symm_symm, LinearEquiv.dualMap_symm,
      coe_comp, LinearEquiv.coe_coe, EquivLike.comp_bijective]
instance _root_.Prod.instModuleIsReflexive [IsReflexive R N] :
    IsReflexive R (M × N) where
  bijective_dual_eval' := by
    let e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
      (dualProdDualEquivDual R M N).dualMap.trans
        (dualProdDualEquivDual R (Dual R M) (Dual R N)).symm
    have : Dual.eval R (M × N) = e.symm.comp ((Dual.eval R M).prodMap (Dual.eval R N)) := by
      ext m f <;> simp
    simp only [this, LinearEquiv.trans_symm, LinearEquiv.symm_symm, LinearEquiv.dualMap_symm,
      coe_comp, LinearEquiv.coe_coe, EquivLike.comp_bijective]
    

Proof state:
K : Type uK
V : Type uV
inst✝¹⁰ : CommRing K
inst✝⁹ : AddCommGroup V
inst✝⁸ : Module K V
inst✝⁷ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : AddCommGroup N
inst✝³ : Module R M
inst✝² : Module R N
inst✝¹ : IsReflexive R M
inst✝ : IsReflexive R N
e : Dual R (Dual R (M × N)) ≃ₗ[R] Dual R (Dual R M) × Dual R (Dual R N) :=
  LinearEquiv.dualMap (dualProdDualEquivDual R M N) ≪≫ₗ LinearEquiv.symm (dualProdDualEquivDual R (Dual R M) (Dual R N))
this : Dual.eval R (M × N) = ↑(LinearEquiv.symm e) ∘ₗ prodMap (Dual.eval R M) (Dual.eval R N)
⊢ Bijective ⇑(prodMap (Dual.eval R M) (Dual.eval R N))

Next tactic:
exact Bijective.Prod_map (bijective_dual_eval R M) (bijective_dual_eval R N)
variable {R M N} in
lemma equiv [IsReflexive R M] (e : M ≃ₗ[R] N) : IsReflexive R N where
  bijective_dual_eval' := by
    

Proof state:
K : Type uK
V : Type uV
inst✝¹⁰ : CommRing K
inst✝⁹ : AddCommGroup V
inst✝⁸ : Module K V
inst✝⁷ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : AddCommGroup N
inst✝³ : Module R M
inst✝² : Module R N
inst✝¹ inst✝ : IsReflexive R M
e : M ≃ₗ[R] N
⊢ Bijective ⇑(Dual.eval R N)

Next tactic:
let ed : Dual R (Dual R N) ≃ₗ[R] Dual R (Dual R M) := e.symm.dualMap.dualMap
variable {R M N} in
lemma equiv [IsReflexive R M] (e : M ≃ₗ[R] N) : IsReflexive R N where
  bijective_dual_eval' := by
    let ed : Dual R (Dual R N) ≃ₗ[R] Dual R (Dual R M) := e.symm.dualMap.dualMap
    

Proof state:
K : Type uK
V : Type uV
inst✝¹⁰ : CommRing K
inst✝⁹ : AddCommGroup V
inst✝⁸ : Module K V
inst✝⁷ : Free K V
R : Type u_1
M : Type u_2
N : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : AddCommGroup N
inst✝³ : Module R M
inst✝² : Module R N
inst✝¹ inst✝ : IsReflexive R M
e : M ≃ₗ[R] N
ed : Dual R (Dual R N) ≃ₗ[R] Dual R (Dual R M) := LinearEquiv.dualMap (LinearEquiv.dualMap (LinearEquiv.symm e))
⊢ Bijective ⇑(Dual.eval R N)

Next tactic:
have : Dual.eval R N = ed.symm.comp ((Dual.eval R M).comp e.symm.toLinearMap) := by
      ext m f
      exact FunLike.congr_arg f (e.apply_symm_apply m).symm