l3lab/ntp-mathlib huggingface dataset:
theorem det_invOf [Invertible A] [Invertible A.det] : (⅟ A).det = ⅟ A.det := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁴ : Fintype n
inst✝³ : DecidableEq n
inst✝² : CommRing α
A B : Matrix n n α
inst✝¹ : Invertible A
inst✝ : Invertible (det A)
⊢ det ⅟A = ⅟(det A)

Next tactic:
letI := detInvertibleOfInvertible A
theorem det_invOf [Invertible A] [Invertible A.det] : (⅟ A).det = ⅟ A.det := by
  letI := detInvertibleOfInvertible A
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁴ : Fintype n
inst✝³ : DecidableEq n
inst✝² : CommRing α
A B : Matrix n n α
inst✝¹ : Invertible A
inst✝ : Invertible (det A)
this : Invertible (det A) := detInvertibleOfInvertible A
⊢ det ⅟A = ⅟(det A)

Next tactic:
convert (rfl : _ = ⅟ A.det)
theorem mul_eq_one_comm : A * B = 1 ↔ B * A = 1 :=
  suffices ∀ A B, A * B = 1 → B * A = 1 from ⟨this A B, this B A⟩
  fun A B h => by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A✝ B✝ A B : Matrix n n α
h : A * B = 1
⊢ B * A = 1

Next tactic:
letI : Invertible B.det := detInvertibleOfLeftInverse _ _ h
theorem mul_eq_one_comm : A * B = 1 ↔ B * A = 1 :=
  suffices ∀ A B, A * B = 1 → B * A = 1 from ⟨this A B, this B A⟩
  fun A B h => by
  letI : Invertible B.det := detInvertibleOfLeftInverse _ _ h
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A✝ B✝ A B : Matrix n n α
h : A * B = 1
this : Invertible (det B) := detInvertibleOfLeftInverse B A h
⊢ B * A = 1

Next tactic:
letI : Invertible B := invertibleOfDetInvertible B
theorem mul_eq_one_comm : A * B = 1 ↔ B * A = 1 :=
  suffices ∀ A B, A * B = 1 → B * A = 1 from ⟨this A B, this B A⟩
  fun A B h => by
  letI : Invertible B.det := detInvertibleOfLeftInverse _ _ h
  letI : Invertible B := invertibleOfDetInvertible B
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A✝ B✝ A B : Matrix n n α
h : A * B = 1
this✝ : Invertible (det B) := detInvertibleOfLeftInverse B A h
this : Invertible B := invertibleOfDetInvertible B
⊢ B * A = 1

Next tactic:
calc
    B * A = B * A * (B * ⅟ B) := by rw [mul_invOf_self, Matrix.mul_one]
    _ = B * (A * B * ⅟ B) := by simp only [Matrix.mul_assoc]
    _ = B * ⅟ B := by rw [h, Matrix.one_mul]
    _ = 1 := mul_invOf_self B
theorem mul_eq_one_comm : A * B = 1 ↔ B * A = 1 :=
  suffices ∀ A B, A * B = 1 → B * A = 1 from ⟨this A B, this B A⟩
  fun A B h => by
  letI : Invertible B.det := detInvertibleOfLeftInverse _ _ h
  letI : Invertible B := invertibleOfDetInvertible B
  calc
    B * A = B * A * (B * ⅟ B) := by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A✝ B✝ A B : Matrix n n α
h : A * B = 1
this✝ : Invertible (det B) := detInvertibleOfLeftInverse B A h
this : Invertible B := invertibleOfDetInvertible B
⊢ B * A = B * A * (B * ⅟B)

Next tactic:
rw [mul_invOf_self, Matrix.mul_one]
theorem mul_eq_one_comm : A * B = 1 ↔ B * A = 1 :=
  suffices ∀ A B, A * B = 1 → B * A = 1 from ⟨this A B, this B A⟩
  fun A B h => by
  letI : Invertible B.det := detInvertibleOfLeftInverse _ _ h
  letI : Invertible B := invertibleOfDetInvertible B
  calc
    B * A = B * A * (B * ⅟ B) := by rw [mul_invOf_self, Matrix.mul_one]
    _ = B * (A * B * ⅟ B) := by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A✝ B✝ A B : Matrix n n α
h : A * B = 1
this✝ : Invertible (det B) := detInvertibleOfLeftInverse B A h
this : Invertible B := invertibleOfDetInvertible B
⊢ B * A * (B * ⅟B) = B * (A * B * ⅟B)

Next tactic:
simp only [Matrix.mul_assoc]
theorem mul_eq_one_comm : A * B = 1 ↔ B * A = 1 :=
  suffices ∀ A B, A * B = 1 → B * A = 1 from ⟨this A B, this B A⟩
  fun A B h => by
  letI : Invertible B.det := detInvertibleOfLeftInverse _ _ h
  letI : Invertible B := invertibleOfDetInvertible B
  calc
    B * A = B * A * (B * ⅟ B) := by rw [mul_invOf_self, Matrix.mul_one]
    _ = B * (A * B * ⅟ B) := by simp only [Matrix.mul_assoc]
    _ = B * ⅟ B := by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A✝ B✝ A B : Matrix n n α
h : A * B = 1
this✝ : Invertible (det B) := detInvertibleOfLeftInverse B A h
this : Invertible B := invertibleOfDetInvertible B
⊢ B * (A * B * ⅟B) = B * ⅟B

Next tactic:
rw [h, Matrix.one_mul]
/-- When lowered to a prop, `Matrix.invertibleEquivDetInvertible` forms an `iff`. -/
theorem isUnit_iff_isUnit_det : IsUnit A ↔ IsUnit A.det := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
⊢ IsUnit A ↔ IsUnit (det A)

Next tactic:
simp only [← nonempty_invertible_iff_isUnit, (invertibleEquivDetInvertible A).nonempty_congr]
theorem isUnit_det_transpose (h : IsUnit A.det) : IsUnit Aᵀ.det := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h : IsUnit (det A)
⊢ IsUnit (det Aᵀ)

Next tactic:
rw [det_transpose]
theorem isUnit_det_transpose (h : IsUnit A.det) : IsUnit Aᵀ.det := by
  rw [det_transpose]
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h : IsUnit (det A)
⊢ IsUnit (det A)

Next tactic:
exact h
theorem nonsing_inv_apply_not_isUnit (h : ¬IsUnit A.det) : A⁻¹ = 0 := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h : ¬IsUnit (det A)
⊢ A⁻¹ = 0

Next tactic:
rw [inv_def, Ring.inverse_non_unit _ h, zero_smul]
theorem nonsing_inv_apply (h : IsUnit A.det) : A⁻¹ = (↑h.unit⁻¹ : α) • A.adjugate := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h : IsUnit (det A)
⊢ A⁻¹ = ↑(IsUnit.unit h)⁻¹ • adjugate A

Next tactic:
rw [inv_def, ← Ring.inverse_unit h.unit, IsUnit.unit_spec]
/-- The nonsingular inverse is the same as `invOf` when `A` is invertible. -/
@[simp]
theorem invOf_eq_nonsing_inv [Invertible A] : ⅟ A = A⁻¹ := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A B : Matrix n n α
inst✝ : Invertible A
⊢ ⅟A = A⁻¹

Next tactic:
letI := detInvertibleOfInvertible A
/-- The nonsingular inverse is the same as `invOf` when `A` is invertible. -/
@[simp]
theorem invOf_eq_nonsing_inv [Invertible A] : ⅟ A = A⁻¹ := by
  letI := detInvertibleOfInvertible A
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A B : Matrix n n α
inst✝ : Invertible A
this : Invertible (det A) := detInvertibleOfInvertible A
⊢ ⅟A = A⁻¹

Next tactic:
rw [inv_def, Ring.inverse_invertible, invOf_eq]
/-- Coercing the result of `Units.instInv` is the same as coercing first and applying the
nonsingular inverse. -/
@[simp, norm_cast]
theorem coe_units_inv (A : (Matrix n n α)ˣ) : ↑A⁻¹ = (A⁻¹ : Matrix n n α) := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A✝ B : Matrix n n α
A : (Matrix n n α)ˣ
⊢ ↑A⁻¹ = (↑A)⁻¹

Next tactic:
letI := A.invertible
/-- Coercing the result of `Units.instInv` is the same as coercing first and applying the
nonsingular inverse. -/
@[simp, norm_cast]
theorem coe_units_inv (A : (Matrix n n α)ˣ) : ↑A⁻¹ = (A⁻¹ : Matrix n n α) := by
  letI := A.invertible
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A✝ B : Matrix n n α
A : (Matrix n n α)ˣ
this : Invertible ↑A := Units.invertible A
⊢ ↑A⁻¹ = (↑A)⁻¹

Next tactic:
rw [← invOf_eq_nonsing_inv, invOf_units]
/-- The nonsingular inverse is the same as the general `Ring.inverse`. -/
theorem nonsing_inv_eq_ring_inverse : A⁻¹ = Ring.inverse A := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
⊢ A⁻¹ = Ring.inverse A

Next tactic:
by_cases h_det : IsUnit A.det
/-- The nonsingular inverse is the same as the general `Ring.inverse`. -/
theorem nonsing_inv_eq_ring_inverse : A⁻¹ = Ring.inverse A := by
  by_cases h_det : IsUnit A.det
  · 

Proof state:
case pos
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h_det : IsUnit (det A)
⊢ A⁻¹ = Ring.inverse A

Next tactic:
cases (A.isUnit_iff_isUnit_det.mpr h_det).nonempty_invertible
/-- The nonsingular inverse is the same as the general `Ring.inverse`. -/
theorem nonsing_inv_eq_ring_inverse : A⁻¹ = Ring.inverse A := by
  by_cases h_det : IsUnit A.det
  · cases (A.isUnit_iff_isUnit_det.mpr h_det).nonempty_invertible
    

Proof state:
case pos.intro
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h_det : IsUnit (det A)
val✝ : Invertible A
⊢ A⁻¹ = Ring.inverse A

Next tactic:
rw [← invOf_eq_nonsing_inv, Ring.inverse_invertible]
/-- The nonsingular inverse is the same as the general `Ring.inverse`. -/
theorem nonsing_inv_eq_ring_inverse : A⁻¹ = Ring.inverse A := by
  by_cases h_det : IsUnit A.det
  · cases (A.isUnit_iff_isUnit_det.mpr h_det).nonempty_invertible
    rw [← invOf_eq_nonsing_inv, Ring.inverse_invertible]
  · 

Proof state:
case neg
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h_det : ¬IsUnit (det A)
⊢ A⁻¹ = Ring.inverse A

Next tactic:
have h := mt A.isUnit_iff_isUnit_det.mp h_det
/-- The nonsingular inverse is the same as the general `Ring.inverse`. -/
theorem nonsing_inv_eq_ring_inverse : A⁻¹ = Ring.inverse A := by
  by_cases h_det : IsUnit A.det
  · cases (A.isUnit_iff_isUnit_det.mpr h_det).nonempty_invertible
    rw [← invOf_eq_nonsing_inv, Ring.inverse_invertible]
  · have h := mt A.isUnit_iff_isUnit_det.mp h_det
    

Proof state:
case neg
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h_det : ¬IsUnit (det A)
h : ¬IsUnit A
⊢ A⁻¹ = Ring.inverse A

Next tactic:
rw [Ring.inverse_non_unit _ h, nonsing_inv_apply_not_isUnit A h_det]
theorem transpose_nonsing_inv : A⁻¹ᵀ = Aᵀ⁻¹ := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
⊢ A⁻¹ᵀ = Aᵀ⁻¹

Next tactic:
rw [inv_def, inv_def, transpose_smul, det_transpose, adjugate_transpose]
theorem conjTranspose_nonsing_inv [StarRing α] : A⁻¹ᴴ = Aᴴ⁻¹ := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A B : Matrix n n α
inst✝ : StarRing α
⊢ A⁻¹ᴴ = Aᴴ⁻¹

Next tactic:
rw [inv_def, inv_def, conjTranspose_smul, det_conjTranspose, adjugate_conjTranspose,
    Ring.inverse_star]
/-- The `nonsing_inv` of `A` is a right inverse. -/
@[simp]
theorem mul_nonsing_inv (h : IsUnit A.det) : A * A⁻¹ = 1 := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h : IsUnit (det A)
⊢ A * A⁻¹ = 1

Next tactic:
cases (A.isUnit_iff_isUnit_det.mpr h).nonempty_invertible
/-- The `nonsing_inv` of `A` is a right inverse. -/
@[simp]
theorem mul_nonsing_inv (h : IsUnit A.det) : A * A⁻¹ = 1 := by
  cases (A.isUnit_iff_isUnit_det.mpr h).nonempty_invertible
  

Proof state:
case intro
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h : IsUnit (det A)
val✝ : Invertible A
⊢ A * A⁻¹ = 1

Next tactic:
rw [← invOf_eq_nonsing_inv, mul_invOf_self]
/-- The `nonsing_inv` of `A` is a left inverse. -/
@[simp]
theorem nonsing_inv_mul (h : IsUnit A.det) : A⁻¹ * A = 1 := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h : IsUnit (det A)
⊢ A⁻¹ * A = 1

Next tactic:
cases (A.isUnit_iff_isUnit_det.mpr h).nonempty_invertible
/-- The `nonsing_inv` of `A` is a left inverse. -/
@[simp]
theorem nonsing_inv_mul (h : IsUnit A.det) : A⁻¹ * A = 1 := by
  cases (A.isUnit_iff_isUnit_det.mpr h).nonempty_invertible
  

Proof state:
case intro
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B : Matrix n n α
h : IsUnit (det A)
val✝ : Invertible A
⊢ A⁻¹ * A = 1

Next tactic:
rw [← invOf_eq_nonsing_inv, invOf_mul_self]
instance [Invertible A] : Invertible A⁻¹ := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A B : Matrix n n α
inst✝ : Invertible A
⊢ Invertible A⁻¹

Next tactic:
rw [← invOf_eq_nonsing_inv]
instance [Invertible A] : Invertible A⁻¹ := by
  rw [← invOf_eq_nonsing_inv]
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A B : Matrix n n α
inst✝ : Invertible A
⊢ Invertible ⅟A

Next tactic:
infer_instance
@[simp]
theorem inv_inv_of_invertible [Invertible A] : A⁻¹⁻¹ = A := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A B : Matrix n n α
inst✝ : Invertible A
⊢ A⁻¹⁻¹ = A

Next tactic:
simp only [← invOf_eq_nonsing_inv, invOf_invOf]
@[simp]
theorem mul_nonsing_inv_cancel_right (B : Matrix m n α) (h : IsUnit A.det) : B * A * A⁻¹ = B := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B✝ : Matrix n n α
B : Matrix m n α
h : IsUnit (det A)
⊢ B * A * A⁻¹ = B

Next tactic:
simp [Matrix.mul_assoc, mul_nonsing_inv A h]
@[simp]
theorem mul_nonsing_inv_cancel_left (B : Matrix n m α) (h : IsUnit A.det) : A * (A⁻¹ * B) = B := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B✝ : Matrix n n α
B : Matrix n m α
h : IsUnit (det A)
⊢ A * (A⁻¹ * B) = B

Next tactic:
simp [← Matrix.mul_assoc, mul_nonsing_inv A h]
@[simp]
theorem nonsing_inv_mul_cancel_right (B : Matrix m n α) (h : IsUnit A.det) : B * A⁻¹ * A = B := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B✝ : Matrix n n α
B : Matrix m n α
h : IsUnit (det A)
⊢ B * A⁻¹ * A = B

Next tactic:
simp [Matrix.mul_assoc, nonsing_inv_mul A h]
@[simp]
theorem nonsing_inv_mul_cancel_left (B : Matrix n m α) (h : IsUnit A.det) : A⁻¹ * (A * B) = B := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝² : Fintype n
inst✝¹ : DecidableEq n
inst✝ : CommRing α
A B✝ : Matrix n n α
B : Matrix n m α
h : IsUnit (det A)
⊢ A⁻¹ * (A * B) = B

Next tactic:
simp [← Matrix.mul_assoc, nonsing_inv_mul A h]
theorem inv_mul_eq_iff_eq_mul_of_invertible (A B C : Matrix n n α) [Invertible A] :
    A⁻¹ * B = C ↔ B = A * C :=
  ⟨fun h => by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A✝ B✝ A B C : Matrix n n α
inst✝ : Invertible A
h : A⁻¹ * B = C
⊢ B = A * C

Next tactic:
rw [← h, mul_inv_cancel_left_of_invertible]
theorem inv_mul_eq_iff_eq_mul_of_invertible (A B C : Matrix n n α) [Invertible A] :
    A⁻¹ * B = C ↔ B = A * C :=
  ⟨fun h => by rw [← h, mul_inv_cancel_left_of_invertible],
   fun h => by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A✝ B✝ A B C : Matrix n n α
inst✝ : Invertible A
h : B = A * C
⊢ A⁻¹ * B = C

Next tactic:
rw [h, inv_mul_cancel_left_of_invertible]
theorem mul_inv_eq_iff_eq_mul_of_invertible (A B C : Matrix n n α) [Invertible A] :
    B * A⁻¹ = C ↔ B = C * A :=
  ⟨fun h => by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A✝ B✝ A B C : Matrix n n α
inst✝ : Invertible A
h : B * A⁻¹ = C
⊢ B = C * A

Next tactic:
rw [← h, inv_mul_cancel_right_of_invertible]
theorem mul_inv_eq_iff_eq_mul_of_invertible (A B C : Matrix n n α) [Invertible A] :
    B * A⁻¹ = C ↔ B = C * A :=
  ⟨fun h => by rw [← h, inv_mul_cancel_right_of_invertible],
   fun h => by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A✝ B✝ A B C : Matrix n n α
inst✝ : Invertible A
h : B = C * A
⊢ B * A⁻¹ = C

Next tactic:
rw [h, mul_inv_cancel_right_of_invertible]
lemma mul_right_injective_of_invertible [Invertible A] :
    Function.Injective (fun (x : Matrix n m α) => A * x) :=
  fun _ _ h => by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A B : Matrix n n α
inst✝ : Invertible A
x✝¹ x✝ : Matrix n m α
h : (fun x => A * x) x✝¹ = (fun x => A * x) x✝
⊢ x✝¹ = x✝

Next tactic:
simpa only [inv_mul_cancel_left_of_invertible] using congr_arg (A⁻¹ * ·) h
lemma mul_left_injective_of_invertible [Invertible A] :
    Function.Injective (fun (x : Matrix m n α) => x * A) :=
  fun a x hax => by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝³ : Fintype n
inst✝² : DecidableEq n
inst✝¹ : CommRing α
A B : Matrix n n α
inst✝ : Invertible A
a x : Matrix m n α
hax : (fun x => x * A) a = (fun x => x * A) x
⊢ a = x

Next tactic:
simpa only [mul_inv_cancel_right_of_invertible] using congr_arg (· * A⁻¹) hax
lemma mul_left_injective_of_inv (A : Matrix m n α) (B : Matrix n m α) (h : A * B = 1) :
    Function.Injective (fun x : Matrix l m α => x * A) :=
  fun _ _ g => by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B✝ : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
inst✝¹ : Fintype l
inst✝ : DecidableEq l
A : Matrix m n α
B : Matrix n m α
h : A * B = 1
x✝¹ x✝ : Matrix l m α
g : (fun x => x * A) x✝¹ = (fun x => x * A) x✝
⊢ x✝¹ = x✝

Next tactic:
simpa only [Matrix.mul_assoc, Matrix.mul_one, h] using congr_arg (· * B) g
lemma mul_right_injective_of_inv (A : Matrix m n α) (B : Matrix n m α) (h : A * B = 1) :
    Function.Injective (fun x : Matrix m l α => B * x) :=
  fun _ _ g => by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B✝ : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
inst✝¹ : Fintype l
inst✝ : DecidableEq l
A : Matrix m n α
B : Matrix n m α
h : A * B = 1
x✝¹ x✝ : Matrix m l α
g : (fun x => B * x) x✝¹ = (fun x => B * x) x✝
⊢ x✝¹ = x✝

Next tactic:
simpa only [← Matrix.mul_assoc, Matrix.one_mul, h] using congr_arg (A * ·) g
theorem vecMul_surjective_iff_exists_left_inverse [Semiring R] {A : Matrix m n R} :
    Function.Surjective A.vecMul ↔ ∃ B : Matrix n m R, B * A = 1 := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
K : Type u_2
R : Type u_3
inst✝¹ : Field K
inst✝ : Semiring R
A : Matrix m n R
⊢ (Function.Surjective fun v => vecMul v A) ↔ ∃ B, B * A = 1

Next tactic:
refine ⟨fun h ↦ ?_, fun ⟨B, hBA⟩ y ↦ ⟨B.vecMul y, by simp [hBA]⟩⟩
theorem vecMul_surjective_iff_exists_left_inverse [Semiring R] {A : Matrix m n R} :
    Function.Surjective A.vecMul ↔ ∃ B : Matrix n m R, B * A = 1 := by
  refine ⟨fun h ↦ ?_, fun ⟨B, hBA⟩ y ↦ ⟨B.vecMul y, by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B✝ : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
K : Type u_2
R : Type u_3
inst✝¹ : Field K
inst✝ : Semiring R
A : Matrix m n R
x✝ : ∃ B, B * A = 1
y : n → R
B : Matrix n m R
hBA : B * A = 1
⊢ (fun v => vecMul v A) (vecMul y B) = y

Next tactic:
simp [hBA]
theorem vecMul_surjective_iff_exists_left_inverse [Semiring R] {A : Matrix m n R} :
    Function.Surjective A.vecMul ↔ ∃ B : Matrix n m R, B * A = 1 := by
  refine ⟨fun h ↦ ?_, fun ⟨B, hBA⟩ y ↦ ⟨B.vecMul y, by simp [hBA]⟩⟩
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
K : Type u_2
R : Type u_3
inst✝¹ : Field K
inst✝ : Semiring R
A : Matrix m n R
h : Function.Surjective fun v => vecMul v A
⊢ ∃ B, B * A = 1

Next tactic:
choose rows hrows using (h <| Pi.single · 1)
theorem vecMul_surjective_iff_exists_left_inverse [Semiring R] {A : Matrix m n R} :
    Function.Surjective A.vecMul ↔ ∃ B : Matrix n m R, B * A = 1 := by
  refine ⟨fun h ↦ ?_, fun ⟨B, hBA⟩ y ↦ ⟨B.vecMul y, by simp [hBA]⟩⟩
  choose rows hrows using (h <| Pi.single · 1)
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
K : Type u_2
R : Type u_3
inst✝¹ : Field K
inst✝ : Semiring R
A : Matrix m n R
h : Function.Surjective fun v => vecMul v A
rows : n → m → R
hrows : ∀ (x : n), (fun v => vecMul v A) (rows x) = Pi.single x 1
⊢ ∃ B, B * A = 1

Next tactic:
refine ⟨Matrix.of rows, Matrix.ext fun i j => ?_⟩
theorem vecMul_surjective_iff_exists_left_inverse [Semiring R] {A : Matrix m n R} :
    Function.Surjective A.vecMul ↔ ∃ B : Matrix n m R, B * A = 1 := by
  refine ⟨fun h ↦ ?_, fun ⟨B, hBA⟩ y ↦ ⟨B.vecMul y, by simp [hBA]⟩⟩
  choose rows hrows using (h <| Pi.single · 1)
  refine ⟨Matrix.of rows, Matrix.ext fun i j => ?_⟩
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
K : Type u_2
R : Type u_3
inst✝¹ : Field K
inst✝ : Semiring R
A : Matrix m n R
h : Function.Surjective fun v => vecMul v A
rows : n → m → R
hrows : ∀ (x : n), (fun v => vecMul v A) (rows x) = Pi.single x 1
i j : n
⊢ (of rows * A) i j = OfNat.ofNat 1 i j

Next tactic:
rw [mul_apply_eq_vecMul, one_eq_pi_single, ← hrows]
theorem vecMul_surjective_iff_exists_left_inverse [Semiring R] {A : Matrix m n R} :
    Function.Surjective A.vecMul ↔ ∃ B : Matrix n m R, B * A = 1 := by
  refine ⟨fun h ↦ ?_, fun ⟨B, hBA⟩ y ↦ ⟨B.vecMul y, by simp [hBA]⟩⟩
  choose rows hrows using (h <| Pi.single · 1)
  refine ⟨Matrix.of rows, Matrix.ext fun i j => ?_⟩
  rw [mul_apply_eq_vecMul, one_eq_pi_single, ← hrows]
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
K : Type u_2
R : Type u_3
inst✝¹ : Field K
inst✝ : Semiring R
A : Matrix m n R
h : Function.Surjective fun v => vecMul v A
rows : n → m → R
hrows : ∀ (x : n), (fun v => vecMul v A) (rows x) = Pi.single x 1
i j : n
⊢ vecMul (of rows i) A j = (fun v => vecMul v A) (rows i) j

Next tactic:
rfl
theorem mulVec_surjective_iff_exists_right_inverse [Semiring R] {A : Matrix m n R} :
    Function.Surjective A.mulVec ↔ ∃ B : Matrix n m R, A * B = 1 := by
  

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
K : Type u_2
R : Type u_3
inst✝¹ : Field K
inst✝ : Semiring R
A : Matrix m n R
⊢ Function.Surjective (mulVec A) ↔ ∃ B, A * B = 1

Next tactic:
refine ⟨fun h ↦ ?_, fun ⟨B, hBA⟩ y ↦ ⟨B.mulVec y, by simp [hBA]⟩⟩
theorem mulVec_surjective_iff_exists_right_inverse [Semiring R] {A : Matrix m n R} :
    Function.Surjective A.mulVec ↔ ∃ B : Matrix n m R, A * B = 1 := by
  refine ⟨fun h ↦ ?_, fun ⟨B, hBA⟩ y ↦ ⟨B.mulVec y, by 

Proof state:
l : Type u_1
m : Type u
n : Type u'
α : Type v
inst✝⁶ : Fintype n
inst✝⁵ : DecidableEq n
inst✝⁴ : CommRing α
A✝ B✝ : Matrix n n α
inst✝³ : Fintype m
inst✝² : DecidableEq m
K : Type u_2
R : Type u_3
inst✝¹ : Field K
inst✝ : Semiring R
A : Matrix m n R
x✝ : ∃ B, A * B = 1
y : m → R
B : Matrix n m R
hBA : A * B = 1
⊢ mulVec A (mulVec B y) = y

Next tactic:
simp [hBA]