l3lab/ntp-mathlib huggingface dataset:
theorem inv_add (_ : ((a₁ : ℕ) : R) = b₁) (_ : ((a₂ : ℕ) : R) = b₂) :
    ((a₁ + a₂ : ℕ) : R) = b₁ + b₂ := by 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a₁ : ℕ
b₁ : R
a₂ : ℕ
b₂ : R
x✝¹ : ↑a₁ = b₁
x✝ : ↑a₂ = b₂
⊢ ↑(a₁ + a₂) = b₁ + b₂

Next tactic:
subst_vars
theorem inv_add (_ : ((a₁ : ℕ) : R) = b₁) (_ : ((a₂ : ℕ) : R) = b₂) :
    ((a₁ + a₂ : ℕ) : R) = b₁ + b₂ := by subst_vars; 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a₁ a₂ : ℕ
⊢ ↑(a₁ + a₂) = ↑a₁ + ↑a₂

Next tactic:
simp
theorem div_pf {R} [DivisionRing R] {a b c d : R}
    (_ : b⁻¹ = c) (_ : a * c = d) : a / b = d := by 

Proof state:
u : Lean.Level
R✝ : Type ?u.398894
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : DivisionRing R
a b c d : R
x✝¹ : b⁻¹ = c
x✝ : a * c = d
⊢ a / b = d

Next tactic:
subst_vars
theorem div_pf {R} [DivisionRing R] {a b c d : R}
    (_ : b⁻¹ = c) (_ : a * c = d) : a / b = d := by subst_vars; 

Proof state:
u : Lean.Level
R✝ : Type ?u.398894
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : DivisionRing R
a b : R
⊢ a / b = a * b⁻¹

Next tactic:
simp [div_eq_mul_inv]
theorem add_congr (_ : a = a') (_ : b = b')
    (_ : a' + b' = c) : (a + b : R) = c := by 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a a' b b' c : R
x✝² : a = a'
x✝¹ : b = b'
x✝ : a' + b' = c
⊢ a + b = c

Next tactic:
subst_vars
theorem add_congr (_ : a = a') (_ : b = b')
    (_ : a' + b' = c) : (a + b : R) = c := by subst_vars; 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a' b' : R
⊢ a' + b' = a' + b'

Next tactic:
rfl
theorem mul_congr (_ : a = a') (_ : b = b')
    (_ : a' * b' = c) : (a * b : R) = c := by 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a a' b b' c : R
x✝² : a = a'
x✝¹ : b = b'
x✝ : a' * b' = c
⊢ a * b = c

Next tactic:
subst_vars
theorem mul_congr (_ : a = a') (_ : b = b')
    (_ : a' * b' = c) : (a * b : R) = c := by subst_vars; 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a' b' : R
⊢ a' * b' = a' * b'

Next tactic:
rfl
theorem nsmul_congr (_ : (a : ℕ) = a') (_ : b = b')
    (_ : a' • b' = c) : (a • (b : R)) = c := by 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a a' : ℕ
b b' c : R
x✝² : a = a'
x✝¹ : b = b'
x✝ : a' • b' = c
⊢ a • b = c

Next tactic:
subst_vars
theorem nsmul_congr (_ : (a : ℕ) = a') (_ : b = b')
    (_ : a' • b' = c) : (a • (b : R)) = c := by subst_vars; 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a' : ℕ
b' : R
⊢ a' • b' = a' • b'

Next tactic:
rfl
theorem pow_congr (_ : a = a') (_ : b = b')
    (_ : a' ^ b' = c) : (a ^ b : R) = c := by 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a a' : R
b b' : ℕ
c : R
x✝² : a = a'
x✝¹ : b = b'
x✝ : a' ^ b' = c
⊢ a ^ b = c

Next tactic:
subst_vars
theorem pow_congr (_ : a = a') (_ : b = b')
    (_ : a' ^ b' = c) : (a ^ b : R) = c := by subst_vars; 

Proof state:
u : Lean.Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a' : R
b' : ℕ
⊢ a' ^ b' = a' ^ b'

Next tactic:
rfl
theorem neg_congr {R} [Ring R] {a a' b : R} (_ : a = a')
    (_ : -a' = b) : (-a : R) = b := by 

Proof state:
u : Lean.Level
R✝ : Type ?u.404817
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : Ring R
a a' b : R
x✝¹ : a = a'
x✝ : -a' = b
⊢ -a = b

Next tactic:
subst_vars
theorem neg_congr {R} [Ring R] {a a' b : R} (_ : a = a')
    (_ : -a' = b) : (-a : R) = b := by subst_vars; 

Proof state:
u : Lean.Level
R✝ : Type ?u.404817
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : Ring R
a' : R
⊢ -a' = -a'

Next tactic:
rfl
theorem sub_congr {R} [Ring R] {a a' b b' c : R} (_ : a = a') (_ : b = b')
    (_ : a' - b' = c) : (a - b : R) = c := by 

Proof state:
u : Lean.Level
R✝ : Type ?u.404935
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : Ring R
a a' b b' c : R
x✝² : a = a'
x✝¹ : b = b'
x✝ : a' - b' = c
⊢ a - b = c

Next tactic:
subst_vars
theorem sub_congr {R} [Ring R] {a a' b b' c : R} (_ : a = a') (_ : b = b')
    (_ : a' - b' = c) : (a - b : R) = c := by subst_vars; 

Proof state:
u : Lean.Level
R✝ : Type ?u.404935
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : Ring R
a' b' : R
⊢ a' - b' = a' - b'

Next tactic:
rfl
theorem inv_congr {R} [DivisionRing R] {a a' b : R} (_ : a = a')
    (_ : a'⁻¹ = b) : (a⁻¹ : R) = b := by 

Proof state:
u : Lean.Level
R✝ : Type ?u.405141
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : DivisionRing R
a a' b : R
x✝¹ : a = a'
x✝ : a'⁻¹ = b
⊢ a⁻¹ = b

Next tactic:
subst_vars
theorem inv_congr {R} [DivisionRing R] {a a' b : R} (_ : a = a')
    (_ : a'⁻¹ = b) : (a⁻¹ : R) = b := by subst_vars; 

Proof state:
u : Lean.Level
R✝ : Type ?u.405141
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : DivisionRing R
a' : R
⊢ a'⁻¹ = a'⁻¹

Next tactic:
rfl
theorem div_congr {R} [DivisionRing R] {a a' b b' c : R} (_ : a = a') (_ : b = b')
    (_ : a' / b' = c) : (a / b : R) = c := by 

Proof state:
u : Lean.Level
R✝ : Type ?u.405320
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : DivisionRing R
a a' b b' c : R
x✝² : a = a'
x✝¹ : b = b'
x✝ : a' / b' = c
⊢ a / b = c

Next tactic:
subst_vars
theorem div_congr {R} [DivisionRing R] {a a' b b' c : R} (_ : a = a') (_ : b = b')
    (_ : a' / b' = c) : (a / b : R) = c := by subst_vars; 

Proof state:
u : Lean.Level
R✝ : Type ?u.405320
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝¹ : CommSemiring R✝
R : Type u_1
inst✝ : DivisionRing R
a' b' : R
⊢ a' / b' = a' / b'

Next tactic:
rfl
theorem of_lift {α β} [inst : CSLift α β] {a b : α} {a' b' : β}
    [h1 : CSLiftVal a a'] [h2 : CSLiftVal b b'] (h : a' = b') : a = b :=
  inst.2 <| by 

Proof state:
u : Lean.Level
R : Type ?u.494333
α✝ : Q(Type u)
sα : Q(CommSemiring $α✝)
inst✝ : CommSemiring R
α β : Type u_1
inst : CSLift α β
a b : α
a' b' : β
h1 : CSLiftVal a a'
h2 : CSLiftVal b b'
h : a' = b'
⊢ CSLift.lift a = CSLift.lift b

Next tactic:
rwa [← h1.1, ← h2.1]
theorem of_eq (_ : (a : R) = c) (_ : b = c) : a = b := by 

Proof state:
u : Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
a c b : R
x✝¹ : a = c
x✝ : b = c
⊢ a = b

Next tactic:
subst_vars
theorem of_eq (_ : (a : R) = c) (_ : b = c) : a = b := by subst_vars; 

Proof state:
u : Level
R : Type u_1
α : Q(Type u)
sα : Q(CommSemiring «$α»)
inst✝ : CommSemiring R
b : R
⊢ b = b

Next tactic:
rfl
theorem embedding_sigmaMk_comp [Nonempty X] :
    Embedding (fun g : Σ i, C(X, Y i) ↦ (sigmaMk g.1).comp g.2) where
  toInducing := inducing_sigma.2
    ⟨fun i ↦ (sigmaMk i).inducing_comp embedding_sigmaMk.toInducing, fun i ↦
      let ⟨x⟩ := ‹Nonempty X›
      ⟨_, (isOpen_sigma_fst_preimage {i}).preimage (continuous_eval_const x), fun _ ↦ Iff.rfl⟩⟩
  inj := by
    · 

Proof state:
X : Type u_1
ι : Type u_2
Y : ι → Type u_3
inst✝² : TopologicalSpace X
inst✝¹ : (i : ι) → TopologicalSpace (Y i)
inst✝ : Nonempty X
⊢ Function.Injective fun g => comp (sigmaMk g.fst) g.snd

Next tactic:
rintro ⟨i, g⟩ ⟨i', g'⟩ h
theorem embedding_sigmaMk_comp [Nonempty X] :
    Embedding (fun g : Σ i, C(X, Y i) ↦ (sigmaMk g.1).comp g.2) where
  toInducing := inducing_sigma.2
    ⟨fun i ↦ (sigmaMk i).inducing_comp embedding_sigmaMk.toInducing, fun i ↦
      let ⟨x⟩ := ‹Nonempty X›
      ⟨_, (isOpen_sigma_fst_preimage {i}).preimage (continuous_eval_const x), fun _ ↦ Iff.rfl⟩⟩
  inj := by
    · rintro ⟨i, g⟩ ⟨i', g'⟩ h
      

Proof state:
case mk.mk
X : Type u_1
ι : Type u_2
Y : ι → Type u_3
inst✝² : TopologicalSpace X
inst✝¹ : (i : ι) → TopologicalSpace (Y i)
inst✝ : Nonempty X
i : ι
g : C(X, Y i)
i' : ι
g' : C(X, Y i')
h :
  (fun g => comp (sigmaMk g.fst) g.snd) { fst := i, snd := g } =
    (fun g => comp (sigmaMk g.fst) g.snd) { fst := i', snd := g' }
⊢ { fst := i, snd := g } = { fst := i', snd := g' }

Next tactic:
obtain ⟨rfl, hg⟩ : i = i' ∧ HEq (⇑g) (⇑g') :=
        Function.eq_of_sigmaMk_comp <| congr_arg FunLike.coe h
theorem embedding_sigmaMk_comp [Nonempty X] :
    Embedding (fun g : Σ i, C(X, Y i) ↦ (sigmaMk g.1).comp g.2) where
  toInducing := inducing_sigma.2
    ⟨fun i ↦ (sigmaMk i).inducing_comp embedding_sigmaMk.toInducing, fun i ↦
      let ⟨x⟩ := ‹Nonempty X›
      ⟨_, (isOpen_sigma_fst_preimage {i}).preimage (continuous_eval_const x), fun _ ↦ Iff.rfl⟩⟩
  inj := by
    · rintro ⟨i, g⟩ ⟨i', g'⟩ h
      obtain ⟨rfl, hg⟩ : i = i' ∧ HEq (⇑g) (⇑g') :=
        Function.eq_of_sigmaMk_comp <| congr_arg FunLike.coe h
      

Proof state:
case mk.mk.intro
X : Type u_1
ι : Type u_2
Y : ι → Type u_3
inst✝² : TopologicalSpace X
inst✝¹ : (i : ι) → TopologicalSpace (Y i)
inst✝ : Nonempty X
i : ι
g g' : C(X, Y i)
h :
  (fun g => comp (sigmaMk g.fst) g.snd) { fst := i, snd := g } =
    (fun g => comp (sigmaMk g.fst) g.snd) { fst := i, snd := g' }
hg : HEq ⇑g ⇑g'
⊢ { fst := i, snd := g } = { fst := i, snd := g' }

Next tactic:
simpa using hg
/-- Given `hA : IsUnit A.det` and `b : Basis R b`, `A.toLinearEquiv b hA` is
the `LinearEquiv` arising from `toLin b b A`.

See `Matrix.toLinearEquiv'` for this result on `n → R`.
-/
@[simps apply]
noncomputable def toLinearEquiv [DecidableEq n] (A : Matrix n n R) (hA : IsUnit A.det) :
    M ≃ₗ[R] M := by
  

Proof state:
n : Type u_1
inst✝⁴ : Fintype n
R : Type u_2
M : Type u_3
inst✝³ : CommRing R
inst✝² : AddCommGroup M
inst✝¹ : Module R M
b : Basis n R M
inst✝ : DecidableEq n
A : Matrix n n R
hA : IsUnit (det A)
⊢ M ≃ₗ[R] M

Next tactic:
refine'
  { toLin b b A with
    toFun := toLin b b A
    invFun := toLin b b A⁻¹
    left_inv := fun x => _
    right_inv := fun x => _ }
/-- Given `hA : IsUnit A.det` and `b : Basis R b`, `A.toLinearEquiv b hA` is
the `LinearEquiv` arising from `toLin b b A`.

See `Matrix.toLinearEquiv'` for this result on `n → R`.
-/
@[simps apply]
noncomputable def toLinearEquiv [DecidableEq n] (A : Matrix n n R) (hA : IsUnit A.det) :
    M ≃ₗ[R] M := by
  refine'
  { toLin b b A with
    toFun := toLin b b A
    invFun := toLin b b A⁻¹
    left_inv := fun x => _
    right_inv := fun x => _ } <;>
    

Proof state:
case refine'_1
n : Type u_1
inst✝⁴ : Fintype n
R : Type u_2
M : Type u_3
inst✝³ : CommRing R
inst✝² : AddCommGroup M
inst✝¹ : Module R M
b : Basis n R M
inst✝ : DecidableEq n
A : Matrix n n R
hA : IsUnit (det A)
src✝ : M →ₗ[R] M := (toLin b b) A
x : M
⊢ ((toLin b b) A⁻¹)
      (AddHom.toFun
        {
            toAddHom :=
              { toFun := ⇑((toLin b b) A),
                map_add' :=
                  (_ :
                    ∀ (x y : M),
                      AddHom.toFun src✝.toAddHom (x + y) =
                        AddHom.toFun src✝.toAddHom x + AddHom.toFun src✝.toAddHom y) },
            map_smul' :=
              (_ :
                ∀ (r : R) (x : M),
                  AddHom.toFun src✝.toAddHom (r • x) = (RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
        x) =
    x

Next tactic:
simp only
/-- Given `hA : IsUnit A.det` and `b : Basis R b`, `A.toLinearEquiv b hA` is
the `LinearEquiv` arising from `toLin b b A`.

See `Matrix.toLinearEquiv'` for this result on `n → R`.
-/
@[simps apply]
noncomputable def toLinearEquiv [DecidableEq n] (A : Matrix n n R) (hA : IsUnit A.det) :
    M ≃ₗ[R] M := by
  refine'
  { toLin b b A with
    toFun := toLin b b A
    invFun := toLin b b A⁻¹
    left_inv := fun x => _
    right_inv := fun x => _ } <;>
    

Proof state:
case refine'_2
n : Type u_1
inst✝⁴ : Fintype n
R : Type u_2
M : Type u_3
inst✝³ : CommRing R
inst✝² : AddCommGroup M
inst✝¹ : Module R M
b : Basis n R M
inst✝ : DecidableEq n
A : Matrix n n R
hA : IsUnit (det A)
src✝ : M →ₗ[R] M := (toLin b b) A
x : M
⊢ AddHom.toFun
      {
          toAddHom :=
            { toFun := ⇑((toLin b b) A),
              map_add' :=
                (_ :
                  ∀ (x y : M),
                    AddHom.toFun src✝.toAddHom (x + y) = AddHom.toFun src✝.toAddHom x + AddHom.toFun src✝.toAddHom y) },
          map_smul' :=
            (_ :
              ∀ (r : R) (x : M),
                AddHom.toFun src✝.toAddHom (r • x) = (RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
      (((toLin b b) A⁻¹) x) =
    x

Next tactic:
simp only
/-- Given `hA : IsUnit A.det` and `b : Basis R b`, `A.toLinearEquiv b hA` is
the `LinearEquiv` arising from `toLin b b A`.

See `Matrix.toLinearEquiv'` for this result on `n → R`.
-/
@[simps apply]
noncomputable def toLinearEquiv [DecidableEq n] (A : Matrix n n R) (hA : IsUnit A.det) :
    M ≃ₗ[R] M := by
  refine'
  { toLin b b A with
    toFun := toLin b b A
    invFun := toLin b b A⁻¹
    left_inv := fun x => _
    right_inv := fun x => _ } <;>
    simp only <;>
    

Proof state:
case refine'_1
n : Type u_1
inst✝⁴ : Fintype n
R : Type u_2
M : Type u_3
inst✝³ : CommRing R
inst✝² : AddCommGroup M
inst✝¹ : Module R M
b : Basis n R M
inst✝ : DecidableEq n
A : Matrix n n R
hA : IsUnit (det A)
src✝ : M →ₗ[R] M := (toLin b b) A
x : M
⊢ ((toLin b b) A⁻¹) (((toLin b b) A) x) = x

Next tactic:
rw [← LinearMap.comp_apply]
/-- Given `hA : IsUnit A.det` and `b : Basis R b`, `A.toLinearEquiv b hA` is
the `LinearEquiv` arising from `toLin b b A`.

See `Matrix.toLinearEquiv'` for this result on `n → R`.
-/
@[simps apply]
noncomputable def toLinearEquiv [DecidableEq n] (A : Matrix n n R) (hA : IsUnit A.det) :
    M ≃ₗ[R] M := by
  refine'
  { toLin b b A with
    toFun := toLin b b A
    invFun := toLin b b A⁻¹
    left_inv := fun x => _
    right_inv := fun x => _ } <;>
    simp only <;>
    

Proof state:
case refine'_2
n : Type u_1
inst✝⁴ : Fintype n
R : Type u_2
M : Type u_3
inst✝³ : CommRing R
inst✝² : AddCommGroup M
inst✝¹ : Module R M
b : Basis n R M
inst✝ : DecidableEq n
A : Matrix n n R
hA : IsUnit (det A)
src✝ : M →ₗ[R] M := (toLin b b) A
x : M
⊢ ((toLin b b) A) (((toLin b b) A⁻¹) x) = x

Next tactic:
rw [← LinearMap.comp_apply]
/-- Given `hA : IsUnit A.det` and `b : Basis R b`, `A.toLinearEquiv b hA` is
the `LinearEquiv` arising from `toLin b b A`.

See `Matrix.toLinearEquiv'` for this result on `n → R`.
-/
@[simps apply]
noncomputable def toLinearEquiv [DecidableEq n] (A : Matrix n n R) (hA : IsUnit A.det) :
    M ≃ₗ[R] M := by
  refine'
  { toLin b b A with
    toFun := toLin b b A
    invFun := toLin b b A⁻¹
    left_inv := fun x => _
    right_inv := fun x => _ } <;>
    simp only <;>
    rw [← LinearMap.comp_apply] <;>
    

Proof state:
case refine'_1
n : Type u_1
inst✝⁴ : Fintype n
R : Type u_2
M : Type u_3
inst✝³ : CommRing R
inst✝² : AddCommGroup M
inst✝¹ : Module R M
b : Basis n R M
inst✝ : DecidableEq n
A : Matrix n n R
hA : IsUnit (det A)
src✝ : M →ₗ[R] M := (toLin b b) A
x : M
⊢ ((toLin b b) A⁻¹ ∘ₗ (toLin b b) A) x = x

Next tactic:
simp only [← Matrix.toLin_mul b b b, Matrix.nonsing_inv_mul _ hA, Matrix.mul_nonsing_inv _ hA,
      toLin_one, LinearMap.id_apply]
/-- Given `hA : IsUnit A.det` and `b : Basis R b`, `A.toLinearEquiv b hA` is
the `LinearEquiv` arising from `toLin b b A`.

See `Matrix.toLinearEquiv'` for this result on `n → R`.
-/
@[simps apply]
noncomputable def toLinearEquiv [DecidableEq n] (A : Matrix n n R) (hA : IsUnit A.det) :
    M ≃ₗ[R] M := by
  refine'
  { toLin b b A with
    toFun := toLin b b A
    invFun := toLin b b A⁻¹
    left_inv := fun x => _
    right_inv := fun x => _ } <;>
    simp only <;>
    rw [← LinearMap.comp_apply] <;>
    

Proof state:
case refine'_2
n : Type u_1
inst✝⁴ : Fintype n
R : Type u_2
M : Type u_3
inst✝³ : CommRing R
inst✝² : AddCommGroup M
inst✝¹ : Module R M
b : Basis n R M
inst✝ : DecidableEq n
A : Matrix n n R
hA : IsUnit (det A)
src✝ : M →ₗ[R] M := (toLin b b) A
x : M
⊢ ((toLin b b) A ∘ₗ (toLin b b) A⁻¹) x = x

Next tactic:
simp only [← Matrix.toLin_mul b b b, Matrix.nonsing_inv_mul _ hA, Matrix.mul_nonsing_inv _ hA,
      toLin_one, LinearMap.id_apply]
/-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`),
not just fields, but it's easier to prove it for the field of fractions first. -/
theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} :
    (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by
  

Proof state:
n : Type u_1
inst✝⁵ : Fintype n
R : Type u_2
M✝ : Type u_3
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M✝
inst✝² : Module R M✝
K : Type u_4
inst✝¹ : DecidableEq n
inst✝ : Field K
M : Matrix n n K
⊢ (∃ v, v ≠ 0 ∧ mulVec M v = 0) ↔ det M = 0

Next tactic:
constructor
/-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`),
not just fields, but it's easier to prove it for the field of fractions first. -/
theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} :
    (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by
  constructor
  · 

Proof state:
case mp
n : Type u_1
inst✝⁵ : Fintype n
R : Type u_2
M✝ : Type u_3
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M✝
inst✝² : Module R M✝
K : Type u_4
inst✝¹ : DecidableEq n
inst✝ : Field K
M : Matrix n n K
⊢ (∃ v, v ≠ 0 ∧ mulVec M v = 0) → det M = 0

Next tactic:
rintro ⟨v, hv, mul_eq⟩
/-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`),
not just fields, but it's easier to prove it for the field of fractions first. -/
theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} :
    (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by
  constructor
  · rintro ⟨v, hv, mul_eq⟩
    

Proof state:
case mp.intro.intro
n : Type u_1
inst✝⁵ : Fintype n
R : Type u_2
M✝ : Type u_3
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M✝
inst✝² : Module R M✝
K : Type u_4
inst✝¹ : DecidableEq n
inst✝ : Field K
M : Matrix n n K
v : n → K
hv : v ≠ 0
mul_eq : mulVec M v = 0
⊢ det M = 0

Next tactic:
contrapose! hv
/-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`),
not just fields, but it's easier to prove it for the field of fractions first. -/
theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} :
    (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by
  constructor
  · rintro ⟨v, hv, mul_eq⟩
    contrapose! hv
    

Proof state:
case mp.intro.intro
n : Type u_1
inst✝⁵ : Fintype n
R : Type u_2
M✝ : Type u_3
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M✝
inst✝² : Module R M✝
K : Type u_4
inst✝¹ : DecidableEq n
inst✝ : Field K
M : Matrix n n K
v : n → K
mul_eq : mulVec M v = 0
hv : det M ≠ 0
⊢ v = 0

Next tactic:
exact eq_zero_of_mulVec_eq_zero hv mul_eq
/-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`),
not just fields, but it's easier to prove it for the field of fractions first. -/
theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} :
    (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by
  constructor
  · rintro ⟨v, hv, mul_eq⟩
    contrapose! hv
    exact eq_zero_of_mulVec_eq_zero hv mul_eq
  · 

Proof state:
case mpr
n : Type u_1
inst✝⁵ : Fintype n
R : Type u_2
M✝ : Type u_3
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M✝
inst✝² : Module R M✝
K : Type u_4
inst✝¹ : DecidableEq n
inst✝ : Field K
M : Matrix n n K
⊢ det M = 0 → ∃ v, v ≠ 0 ∧ mulVec M v = 0

Next tactic:
contrapose!
/-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`),
not just fields, but it's easier to prove it for the field of fractions first. -/
theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} :
    (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by
  constructor
  · rintro ⟨v, hv, mul_eq⟩
    contrapose! hv
    exact eq_zero_of_mulVec_eq_zero hv mul_eq
  · contrapose!
    

Proof state:
case mpr
n : Type u_1
inst✝⁵ : Fintype n
R : Type u_2
M✝ : Type u_3
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M✝
inst✝² : Module R M✝
K : Type u_4
inst✝¹ : DecidableEq n
inst✝ : Field K
M : Matrix n n K
⊢ (∀ (v : n → K), v ≠ 0 → mulVec M v ≠ 0) → det M ≠ 0

Next tactic:
intro h
/-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`),
not just fields, but it's easier to prove it for the field of fractions first. -/
theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} :
    (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by
  constructor
  · rintro ⟨v, hv, mul_eq⟩
    contrapose! hv
    exact eq_zero_of_mulVec_eq_zero hv mul_eq
  · contrapose!
    intro h
    

Proof state:
case mpr
n : Type u_1
inst✝⁵ : Fintype n
R : Type u_2
M✝ : Type u_3
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M✝
inst✝² : Module R M✝
K : Type u_4
inst✝¹ : DecidableEq n
inst✝ : Field K
M : Matrix n n K
h : ∀ (v : n → K), v ≠ 0 → mulVec M v ≠ 0
⊢ det M ≠ 0

Next tactic:
have : Function.Injective (Matrix.toLin' M) := by
      simpa only [← LinearMap.ker_eq_bot, ker_toLin'_eq_bot_iff, not_imp_not] using h
/-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`),
not just fields, but it's easier to prove it for the field of fractions first. -/
theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} :
    (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by
  constructor
  · rintro ⟨v, hv, mul_eq⟩
    contrapose! hv
    exact eq_zero_of_mulVec_eq_zero hv mul_eq
  · contrapose!
    intro h
    have : Function.Injective (Matrix.toLin' M) := by
      

Proof state:
n : Type u_1
inst✝⁵ : Fintype n
R : Type u_2
M✝ : Type u_3
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M✝
inst✝² : Module R M✝
K : Type u_4
inst✝¹ : DecidableEq n
inst✝ : Field K
M : Matrix n n K
h : ∀ (v : n → K), v ≠ 0 → mulVec M v ≠ 0
⊢ Function.Injective ⇑(toLin' M)

Next tactic:
simpa only [← LinearMap.ker_eq_bot, ker_toLin'_eq_bot_iff, not_imp_not] using h
/-- This holds for all integral domains (see `Matrix.exists_mulVec_eq_zero_iff`),
not just fields, but it's easier to prove it for the field of fractions first. -/
theorem exists_mulVec_eq_zero_iff_aux {K : Type*} [DecidableEq n] [Field K] {M : Matrix n n K} :
    (∃ v ≠ 0, M.mulVec v = 0) ↔ M.det = 0 := by
  constructor
  · rintro ⟨v, hv, mul_eq⟩
    contrapose! hv
    exact eq_zero_of_mulVec_eq_zero hv mul_eq
  · contrapose!
    intro h
    have : Function.Injective (Matrix.toLin' M) := by
      simpa only [← LinearMap.ker_eq_bot, ker_toLin'_eq_bot_iff, not_imp_not] using h
    

Proof state:
case mpr
n : Type u_1
inst✝⁵ : Fintype n
R : Type u_2
M✝ : Type u_3
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M✝
inst✝² : Module R M✝
K : Type u_4
inst✝¹ : DecidableEq n
inst✝ : Field K
M : Matrix n n K
h : ∀ (v : n → K), v ≠ 0 → mulVec M v ≠ 0
this : Function.Injective ⇑(toLin' M)
⊢ det M ≠ 0

Next tactic:
have :
      M *
          LinearMap.toMatrix'
            ((LinearEquiv.ofInjectiveEndo (Matrix.toLin' M) this).symm : (n → K) →ₗ[K] n → K) =
        1 := by
      refine' Matrix.toLin'.injective (LinearMap.ext fun v => _)
      rw [Matrix.toLin'_mul, Matrix.toLin'_one, Matrix.toLin'_toMatrix', LinearMap.comp_apply]
      exact (LinearEquiv.ofInjectiveEndo (Matrix.toLin' M) this).apply_symm_apply v