l3lab/ntp-mathlib huggingface dataset:
theorem rank_eq_finrank_range_toLin [DecidableEq n] {M₁ M₂ : Type*} [AddCommGroup M₁]
    [AddCommGroup M₂] [Module R M₁] [Module R M₂] (A : Matrix m n R) (v₁ : Basis m R M₁)
    (v₂ : Basis n R M₂) : A.rank = finrank R (LinearMap.range (toLin v₂ v₁ A)) := by
  let e₁ := (Pi.basisFun R m).equiv v₁ (Equiv.refl _)
  let e₂ := (Pi.basisFun R n).equiv v₂ (Equiv.refl _)
  have range_e₂ : LinearMap.range e₂ = ⊤ := by
    rw [LinearMap.range_eq_top]
    exact e₂.surjective
  refine' LinearEquiv.finrank_eq (e₁.ofSubmodules _ _ _)
  rw [← LinearMap.range_comp, ← LinearMap.range_comp_of_range_eq_top (toLin v₂ v₁ A) range_e₂]
  congr 1
  apply LinearMap.pi_ext'
  rintro i
  apply LinearMap.ext_ring
  have aux₁ := toLin_self (Pi.basisFun R n) (Pi.basisFun R m) A i
  have aux₂ := Basis.equiv_apply (Pi.basisFun R n) i v₂
  rw [toLin_eq_toLin', toLin'_apply'] at aux₁
  

Proof state:
case e_f.h.h
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁷ : Fintype n
inst✝⁶ : Fintype o
inst✝⁵ : CommRing R
inst✝⁴ : DecidableEq n
M₁ : Type u_6
M₂ : Type u_7
inst✝³ : AddCommGroup M₁
inst✝² : AddCommGroup M₂
inst✝¹ : Module R M₁
inst✝ : Module R M₂
A : Matrix m n R
v₁ : Basis m R M₁
v₂ : Basis n R M₂
e₁ : (m → R) ≃ₗ[R] M₁ := Basis.equiv (Pi.basisFun R m) v₁ (Equiv.refl m)
e₂ : (n → R) ≃ₗ[R] M₂ := Basis.equiv (Pi.basisFun R n) v₂ (Equiv.refl n)
range_e₂ : LinearMap.range e₂ = ⊤
i : n
aux₁ : (mulVecLin A) ((Pi.basisFun R n) i) = Finset.sum Finset.univ fun j => A j i • (Pi.basisFun R m) j
aux₂ : ∀ (e : n ≃ n), (Basis.equiv (Pi.basisFun R n) v₂ e) ((Pi.basisFun R n) i) = v₂ (e i)
⊢ ((↑e₁ ∘ₗ mulVecLin A) ∘ₗ LinearMap.single i) 1 = (((toLin v₂ v₁) A ∘ₗ ↑e₂) ∘ₗ LinearMap.single i) 1

Next tactic:
rw [Pi.basisFun_apply, LinearMap.coe_stdBasis] at aux₁ aux₂
theorem rank_eq_finrank_range_toLin [DecidableEq n] {M₁ M₂ : Type*} [AddCommGroup M₁]
    [AddCommGroup M₂] [Module R M₁] [Module R M₂] (A : Matrix m n R) (v₁ : Basis m R M₁)
    (v₂ : Basis n R M₂) : A.rank = finrank R (LinearMap.range (toLin v₂ v₁ A)) := by
  let e₁ := (Pi.basisFun R m).equiv v₁ (Equiv.refl _)
  let e₂ := (Pi.basisFun R n).equiv v₂ (Equiv.refl _)
  have range_e₂ : LinearMap.range e₂ = ⊤ := by
    rw [LinearMap.range_eq_top]
    exact e₂.surjective
  refine' LinearEquiv.finrank_eq (e₁.ofSubmodules _ _ _)
  rw [← LinearMap.range_comp, ← LinearMap.range_comp_of_range_eq_top (toLin v₂ v₁ A) range_e₂]
  congr 1
  apply LinearMap.pi_ext'
  rintro i
  apply LinearMap.ext_ring
  have aux₁ := toLin_self (Pi.basisFun R n) (Pi.basisFun R m) A i
  have aux₂ := Basis.equiv_apply (Pi.basisFun R n) i v₂
  rw [toLin_eq_toLin', toLin'_apply'] at aux₁
  rw [Pi.basisFun_apply, LinearMap.coe_stdBasis] at aux₁ aux₂
  

Proof state:
case e_f.h.h
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁷ : Fintype n
inst✝⁶ : Fintype o
inst✝⁵ : CommRing R
inst✝⁴ : DecidableEq n
M₁ : Type u_6
M₂ : Type u_7
inst✝³ : AddCommGroup M₁
inst✝² : AddCommGroup M₂
inst✝¹ : Module R M₁
inst✝ : Module R M₂
A : Matrix m n R
v₁ : Basis m R M₁
v₂ : Basis n R M₂
e₁ : (m → R) ≃ₗ[R] M₁ := Basis.equiv (Pi.basisFun R m) v₁ (Equiv.refl m)
e₂ : (n → R) ≃ₗ[R] M₂ := Basis.equiv (Pi.basisFun R n) v₂ (Equiv.refl n)
range_e₂ : LinearMap.range e₂ = ⊤
i : n
aux₁ : (mulVecLin A) (Pi.single i 1) = Finset.sum Finset.univ fun j => A j i • (Pi.basisFun R m) j
aux₂ : ∀ (e : n ≃ n), (Basis.equiv (Pi.basisFun R n) v₂ e) (Pi.single i 1) = v₂ (e i)
⊢ ((↑e₁ ∘ₗ mulVecLin A) ∘ₗ LinearMap.single i) 1 = (((toLin v₂ v₁) A ∘ₗ ↑e₂) ∘ₗ LinearMap.single i) 1

Next tactic:
simp only [LinearMap.comp_apply, LinearEquiv.coe_coe, Equiv.refl_apply, aux₁, aux₂,
    LinearMap.coe_single, toLin_self, map_sum, LinearEquiv.map_smul, Basis.equiv_apply]
theorem rank_le_card_height [StrongRankCondition R] (A : Matrix m n R) :
    A.rank ≤ Fintype.card m := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : CommRing R
inst✝ : StrongRankCondition R
A : Matrix m n R
⊢ rank A ≤ Fintype.card m

Next tactic:
haveI : Module.Finite R (m → R) := Module.Finite.pi
theorem rank_le_card_height [StrongRankCondition R] (A : Matrix m n R) :
    A.rank ≤ Fintype.card m := by
  haveI : Module.Finite R (m → R) := Module.Finite.pi
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : CommRing R
inst✝ : StrongRankCondition R
A : Matrix m n R
this : Module.Finite R (m → R)
⊢ rank A ≤ Fintype.card m

Next tactic:
haveI : Module.Free R (m → R) := Module.Free.pi _ _
theorem rank_le_card_height [StrongRankCondition R] (A : Matrix m n R) :
    A.rank ≤ Fintype.card m := by
  haveI : Module.Finite R (m → R) := Module.Finite.pi
  haveI : Module.Free R (m → R) := Module.Free.pi _ _
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : CommRing R
inst✝ : StrongRankCondition R
A : Matrix m n R
this✝ : Module.Finite R (m → R)
this : Module.Free R (m → R)
⊢ rank A ≤ Fintype.card m

Next tactic:
exact (Submodule.finrank_le _).trans (finrank_pi R).le
/-- The rank of a matrix is the rank of the space spanned by its columns. -/
theorem rank_eq_finrank_span_cols (A : Matrix m n R) :
    A.rank = finrank R (Submodule.span R (Set.range Aᵀ)) := by 

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝² : Fintype n
inst✝¹ : Fintype o
inst✝ : CommRing R
A : Matrix m n R
⊢ rank A = finrank R ↥(Submodule.span R (Set.range Aᵀ))

Next tactic:
rw [rank, Matrix.range_mulVecLin]
/-- The rank of a diagnonal matrix is the count of non-zero elements on its main diagonal -/
theorem rank_diagonal [DecidableEq m] [DecidableEq R] (w : m → R) :
    (diagonal w).rank = Fintype.card {i // (w i) ≠ 0} := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁴ : Fintype n
inst✝³ : Fintype o
inst✝² : Field R
inst✝¹ : DecidableEq m
inst✝ : DecidableEq R
w : m → R
⊢ rank (diagonal w) = Fintype.card { i // w i ≠ 0 }

Next tactic:
rw [Matrix.rank, ← Matrix.toLin'_apply', FiniteDimensional.finrank, ← LinearMap.rank,
    LinearMap.rank_diagonal, Cardinal.toNat_cast]
theorem ker_mulVecLin_conjTranspose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᴴ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁵ : Fintype n
inst✝⁴ : Fintype o
inst✝³ : Fintype m
inst✝² : Field R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
A : Matrix m n R
⊢ LinearMap.ker (mulVecLin (Aᴴ * A)) = LinearMap.ker (mulVecLin A)

Next tactic:
ext x
theorem ker_mulVecLin_conjTranspose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᴴ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  ext x
  

Proof state:
case h
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁵ : Fintype n
inst✝⁴ : Fintype o
inst✝³ : Fintype m
inst✝² : Field R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
A : Matrix m n R
x : n → R
⊢ x ∈ LinearMap.ker (mulVecLin (Aᴴ * A)) ↔ x ∈ LinearMap.ker (mulVecLin A)

Next tactic:
simp only [LinearMap.mem_ker, mulVecLin_apply, conjTranspose_mul_self_mulVec_eq_zero]
theorem rank_conjTranspose_mul_self (A : Matrix m n R) : (Aᴴ * A).rank = A.rank := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁵ : Fintype n
inst✝⁴ : Fintype o
inst✝³ : Fintype m
inst✝² : Field R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
A : Matrix m n R
⊢ rank (Aᴴ * A) = rank A

Next tactic:
dsimp only [rank]
theorem rank_conjTranspose_mul_self (A : Matrix m n R) : (Aᴴ * A).rank = A.rank := by
  dsimp only [rank]
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁵ : Fintype n
inst✝⁴ : Fintype o
inst✝³ : Fintype m
inst✝² : Field R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
A : Matrix m n R
⊢ finrank R ↥(LinearMap.range (mulVecLin (Aᴴ * A))) = finrank R ↥(LinearMap.range (mulVecLin A))

Next tactic:
refine' add_left_injective (finrank R (LinearMap.ker (mulVecLin A))) _
theorem rank_conjTranspose_mul_self (A : Matrix m n R) : (Aᴴ * A).rank = A.rank := by
  dsimp only [rank]
  refine' add_left_injective (finrank R (LinearMap.ker (mulVecLin A))) _
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁵ : Fintype n
inst✝⁴ : Fintype o
inst✝³ : Fintype m
inst✝² : Field R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
A : Matrix m n R
⊢ (fun x => x + finrank R ↥(LinearMap.ker (mulVecLin A))) (finrank R ↥(LinearMap.range (mulVecLin (Aᴴ * A)))) =
    (fun x => x + finrank R ↥(LinearMap.ker (mulVecLin A))) (finrank R ↥(LinearMap.range (mulVecLin A)))

Next tactic:
dsimp only
theorem rank_conjTranspose_mul_self (A : Matrix m n R) : (Aᴴ * A).rank = A.rank := by
  dsimp only [rank]
  refine' add_left_injective (finrank R (LinearMap.ker (mulVecLin A))) _
  dsimp only
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁵ : Fintype n
inst✝⁴ : Fintype o
inst✝³ : Fintype m
inst✝² : Field R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
A : Matrix m n R
⊢ finrank R ↥(LinearMap.range (mulVecLin (Aᴴ * A))) + finrank R ↥(LinearMap.ker (mulVecLin A)) =
    finrank R ↥(LinearMap.range (mulVecLin A)) + finrank R ↥(LinearMap.ker (mulVecLin A))

Next tactic:
trans finrank R { x // x ∈ LinearMap.range (mulVecLin (Aᴴ * A)) } +
    finrank R { x // x ∈ LinearMap.ker (mulVecLin (Aᴴ * A)) }
theorem rank_conjTranspose_mul_self (A : Matrix m n R) : (Aᴴ * A).rank = A.rank := by
  dsimp only [rank]
  refine' add_left_injective (finrank R (LinearMap.ker (mulVecLin A))) _
  dsimp only
  trans finrank R { x // x ∈ LinearMap.range (mulVecLin (Aᴴ * A)) } +
    finrank R { x // x ∈ LinearMap.ker (mulVecLin (Aᴴ * A)) }
  · 

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁵ : Fintype n
inst✝⁴ : Fintype o
inst✝³ : Fintype m
inst✝² : Field R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
A : Matrix m n R
⊢ finrank R ↥(LinearMap.range (mulVecLin (Aᴴ * A))) + finrank R ↥(LinearMap.ker (mulVecLin A)) =
    finrank R ↥(LinearMap.range (mulVecLin (Aᴴ * A))) + finrank R ↥(LinearMap.ker (mulVecLin (Aᴴ * A)))

Next tactic:
rw [ker_mulVecLin_conjTranspose_mul_self]
theorem rank_conjTranspose_mul_self (A : Matrix m n R) : (Aᴴ * A).rank = A.rank := by
  dsimp only [rank]
  refine' add_left_injective (finrank R (LinearMap.ker (mulVecLin A))) _
  dsimp only
  trans finrank R { x // x ∈ LinearMap.range (mulVecLin (Aᴴ * A)) } +
    finrank R { x // x ∈ LinearMap.ker (mulVecLin (Aᴴ * A)) }
  · rw [ker_mulVecLin_conjTranspose_mul_self]
  · 

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁵ : Fintype n
inst✝⁴ : Fintype o
inst✝³ : Fintype m
inst✝² : Field R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
A : Matrix m n R
⊢ finrank R ↥(LinearMap.range (mulVecLin (Aᴴ * A))) + finrank R ↥(LinearMap.ker (mulVecLin (Aᴴ * A))) =
    finrank R ↥(LinearMap.range (mulVecLin A)) + finrank R ↥(LinearMap.ker (mulVecLin A))

Next tactic:
simp only [LinearMap.finrank_range_add_finrank_ker]
@[simp]
theorem rank_self_mul_conjTranspose (A : Matrix m n R) : (A * Aᴴ).rank = A.rank := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝⁵ : Fintype n
inst✝⁴ : Fintype o
inst✝³ : Fintype m
inst✝² : Field R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
A : Matrix m n R
⊢ rank (A * Aᴴ) = rank A

Next tactic:
simpa only [rank_conjTranspose, conjTranspose_conjTranspose] using
    rank_conjTranspose_mul_self Aᴴ
theorem ker_mulVecLin_transpose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᵀ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
⊢ LinearMap.ker (mulVecLin (Aᵀ * A)) = LinearMap.ker (mulVecLin A)

Next tactic:
ext x
theorem ker_mulVecLin_transpose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᵀ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  ext x
  

Proof state:
case h
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
x : n → R
⊢ x ∈ LinearMap.ker (mulVecLin (Aᵀ * A)) ↔ x ∈ LinearMap.ker (mulVecLin A)

Next tactic:
simp only [LinearMap.mem_ker, mulVecLin_apply, ← mulVec_mulVec]
theorem ker_mulVecLin_transpose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᵀ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  ext x
  simp only [LinearMap.mem_ker, mulVecLin_apply, ← mulVec_mulVec]
  

Proof state:
case h
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
x : n → R
⊢ mulVec Aᵀ (mulVec A x) = 0 ↔ mulVec A x = 0

Next tactic:
constructor
theorem ker_mulVecLin_transpose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᵀ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  ext x
  simp only [LinearMap.mem_ker, mulVecLin_apply, ← mulVec_mulVec]
  constructor
  · 

Proof state:
case h.mp
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
x : n → R
⊢ mulVec Aᵀ (mulVec A x) = 0 → mulVec A x = 0

Next tactic:
intro h
theorem ker_mulVecLin_transpose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᵀ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  ext x
  simp only [LinearMap.mem_ker, mulVecLin_apply, ← mulVec_mulVec]
  constructor
  · intro h
    

Proof state:
case h.mp
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
x : n → R
h : mulVec Aᵀ (mulVec A x) = 0
⊢ mulVec A x = 0

Next tactic:
replace h := congr_arg (dotProduct x) h
theorem ker_mulVecLin_transpose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᵀ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  ext x
  simp only [LinearMap.mem_ker, mulVecLin_apply, ← mulVec_mulVec]
  constructor
  · intro h
    replace h := congr_arg (dotProduct x) h
    

Proof state:
case h.mp
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
x : n → R
h : x ⬝ᵥ mulVec Aᵀ (mulVec A x) = x ⬝ᵥ 0
⊢ mulVec A x = 0

Next tactic:
rwa [dotProduct_mulVec, dotProduct_zero, vecMul_transpose, dotProduct_self_eq_zero] at h
theorem ker_mulVecLin_transpose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᵀ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  ext x
  simp only [LinearMap.mem_ker, mulVecLin_apply, ← mulVec_mulVec]
  constructor
  · intro h
    replace h := congr_arg (dotProduct x) h
    rwa [dotProduct_mulVec, dotProduct_zero, vecMul_transpose, dotProduct_self_eq_zero] at h
  · 

Proof state:
case h.mpr
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
x : n → R
⊢ mulVec A x = 0 → mulVec Aᵀ (mulVec A x) = 0

Next tactic:
intro h
theorem ker_mulVecLin_transpose_mul_self (A : Matrix m n R) :
    LinearMap.ker (Aᵀ * A).mulVecLin = LinearMap.ker (mulVecLin A) := by
  ext x
  simp only [LinearMap.mem_ker, mulVecLin_apply, ← mulVec_mulVec]
  constructor
  · intro h
    replace h := congr_arg (dotProduct x) h
    rwa [dotProduct_mulVec, dotProduct_zero, vecMul_transpose, dotProduct_self_eq_zero] at h
  · intro h
    

Proof state:
case h.mpr
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
x : n → R
h : mulVec A x = 0
⊢ mulVec Aᵀ (mulVec A x) = 0

Next tactic:
rw [h, mulVec_zero]
theorem rank_transpose_mul_self (A : Matrix m n R) : (Aᵀ * A).rank = A.rank := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
⊢ rank (Aᵀ * A) = rank A

Next tactic:
dsimp only [rank]
theorem rank_transpose_mul_self (A : Matrix m n R) : (Aᵀ * A).rank = A.rank := by
  dsimp only [rank]
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
⊢ finrank R ↥(LinearMap.range (mulVecLin (Aᵀ * A))) = finrank R ↥(LinearMap.range (mulVecLin A))

Next tactic:
refine' add_left_injective (finrank R <| LinearMap.ker A.mulVecLin) _
theorem rank_transpose_mul_self (A : Matrix m n R) : (Aᵀ * A).rank = A.rank := by
  dsimp only [rank]
  refine' add_left_injective (finrank R <| LinearMap.ker A.mulVecLin) _
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
⊢ (fun x => x + finrank R ↥(LinearMap.ker (mulVecLin A))) (finrank R ↥(LinearMap.range (mulVecLin (Aᵀ * A)))) =
    (fun x => x + finrank R ↥(LinearMap.ker (mulVecLin A))) (finrank R ↥(LinearMap.range (mulVecLin A)))

Next tactic:
dsimp only
theorem rank_transpose_mul_self (A : Matrix m n R) : (Aᵀ * A).rank = A.rank := by
  dsimp only [rank]
  refine' add_left_injective (finrank R <| LinearMap.ker A.mulVecLin) _
  dsimp only
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
⊢ finrank R ↥(LinearMap.range (mulVecLin (Aᵀ * A))) + finrank R ↥(LinearMap.ker (mulVecLin A)) =
    finrank R ↥(LinearMap.range (mulVecLin A)) + finrank R ↥(LinearMap.ker (mulVecLin A))

Next tactic:
trans finrank R { x // x ∈ LinearMap.range (mulVecLin (Aᵀ * A)) } +
    finrank R { x // x ∈ LinearMap.ker (mulVecLin (Aᵀ * A)) }
theorem rank_transpose_mul_self (A : Matrix m n R) : (Aᵀ * A).rank = A.rank := by
  dsimp only [rank]
  refine' add_left_injective (finrank R <| LinearMap.ker A.mulVecLin) _
  dsimp only
  trans finrank R { x // x ∈ LinearMap.range (mulVecLin (Aᵀ * A)) } +
    finrank R { x // x ∈ LinearMap.ker (mulVecLin (Aᵀ * A)) }
  · 

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
⊢ finrank R ↥(LinearMap.range (mulVecLin (Aᵀ * A))) + finrank R ↥(LinearMap.ker (mulVecLin A)) =
    finrank R ↥(LinearMap.range (mulVecLin (Aᵀ * A))) + finrank R ↥(LinearMap.ker (mulVecLin (Aᵀ * A)))

Next tactic:
rw [ker_mulVecLin_transpose_mul_self]
theorem rank_transpose_mul_self (A : Matrix m n R) : (Aᵀ * A).rank = A.rank := by
  dsimp only [rank]
  refine' add_left_injective (finrank R <| LinearMap.ker A.mulVecLin) _
  dsimp only
  trans finrank R { x // x ∈ LinearMap.range (mulVecLin (Aᵀ * A)) } +
    finrank R { x // x ∈ LinearMap.ker (mulVecLin (Aᵀ * A)) }
  · rw [ker_mulVecLin_transpose_mul_self]
  · 

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
⊢ finrank R ↥(LinearMap.range (mulVecLin (Aᵀ * A))) + finrank R ↥(LinearMap.ker (mulVecLin (Aᵀ * A))) =
    finrank R ↥(LinearMap.range (mulVecLin A)) + finrank R ↥(LinearMap.ker (mulVecLin A))

Next tactic:
simp only [LinearMap.finrank_range_add_finrank_ker]
@[simp]
theorem rank_self_mul_transpose (A : Matrix m n R) : (A * Aᵀ).rank = A.rank := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : Fintype m
inst✝ : LinearOrderedField R
A : Matrix m n R
⊢ rank (A * Aᵀ) = rank A

Next tactic:
simpa only [rank_transpose, transpose_transpose] using rank_transpose_mul_self Aᵀ
/-- The rank of a matrix is the rank of the space spanned by its rows.

TODO: prove this in a generality that works for `ℂ` too, not just `ℚ` and `ℝ`. -/
theorem rank_eq_finrank_span_row [LinearOrderedField R] [Finite m] (A : Matrix m n R) :
    A.rank = finrank R (Submodule.span R (Set.range A)) := by
  

Proof state:
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : LinearOrderedField R
inst✝ : Finite m
A : Matrix m n R
⊢ rank A = finrank R ↥(Submodule.span R (Set.range A))

Next tactic:
cases nonempty_fintype m
/-- The rank of a matrix is the rank of the space spanned by its rows.

TODO: prove this in a generality that works for `ℂ` too, not just `ℚ` and `ℝ`. -/
theorem rank_eq_finrank_span_row [LinearOrderedField R] [Finite m] (A : Matrix m n R) :
    A.rank = finrank R (Submodule.span R (Set.range A)) := by
  cases nonempty_fintype m
  

Proof state:
case intro
l : Type u_1
m : Type u_2
n : Type u_3
o : Type u_4
R : Type u_5
m_fin : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype o
inst✝¹ : LinearOrderedField R
inst✝ : Finite m
A : Matrix m n R
val✝ : Fintype m
⊢ rank A = finrank R ↥(Submodule.span R (Set.range A))

Next tactic:
rw [← rank_transpose, rank_eq_finrank_span_cols, transpose_transpose]
/-- Shows that `IntFractPair.stream` has the sequence property, that is once we return `none` at
position `n`, we also return `none` at `n + 1`.
-/
theorem stream_isSeq (v : K) : (IntFractPair.stream v).IsSeq := by
  

Proof state:
K : Type u_1
inst✝¹ : LinearOrderedField K
inst✝ : FloorRing K
v : K
⊢ Stream'.IsSeq (IntFractPair.stream v)

Next tactic:
intro _ hyp
/-- Shows that `IntFractPair.stream` has the sequence property, that is once we return `none` at
position `n`, we also return `none` at `n + 1`.
-/
theorem stream_isSeq (v : K) : (IntFractPair.stream v).IsSeq := by
  intro _ hyp
  

Proof state:
K : Type u_1
inst✝¹ : LinearOrderedField K
inst✝ : FloorRing K
v : K
n✝ : ℕ
hyp : IntFractPair.stream v n✝ = none
⊢ IntFractPair.stream v (n✝ + 1) = none

Next tactic:
simp [IntFractPair.stream, hyp]
lemma toColex_inj {s t : Finset α} : toColex s = toColex t ↔ s = t := by 

Proof state:
α : Type u_1
β : Type u_2
s t : Finset α
⊢ { ofColex := s } = { ofColex := t } ↔ s = t

Next tactic:
simp
@[simp]
lemma ofColex_inj {s t : Colex α} : ofColex s = ofColex t ↔ s = t := by 

Proof state:
α : Type u_1
β : Type u_2
s t : Colex α
⊢ s.ofColex = t.ofColex ↔ s = t

Next tactic:
cases s
@[simp]
lemma ofColex_inj {s t : Colex α} : ofColex s = ofColex t ↔ s = t := by cases s; 

Proof state:
case toColex
α : Type u_1
β : Type u_2
t : Colex α
ofColex✝ : Finset α
⊢ { ofColex := ofColex✝ }.ofColex = t.ofColex ↔ { ofColex := ofColex✝ } = t

Next tactic:
cases t
@[simp]
lemma ofColex_inj {s t : Colex α} : ofColex s = ofColex t ↔ s = t := by cases s; cases t; 

Proof state:
case toColex.toColex
α : Type u_1
β : Type u_2
ofColex✝¹ ofColex✝ : Finset α
⊢ { ofColex := ofColex✝¹ }.ofColex = { ofColex := ofColex✝ }.ofColex ↔
    { ofColex := ofColex✝¹ } = { ofColex := ofColex✝ }

Next tactic:
simp
lemma toColex_ne_toColex {s t : Finset α} : toColex s ≠ toColex t ↔ s ≠ t := by 

Proof state:
α : Type u_1
β : Type u_2
s t : Finset α
⊢ { ofColex := s } ≠ { ofColex := t } ↔ s ≠ t

Next tactic:
simp
lemma ofColex_ne_ofColex {s t : Colex α} : ofColex s ≠ ofColex t ↔ s ≠ t := by 

Proof state:
α : Type u_1
β : Type u_2
s t : Colex α
⊢ s.ofColex ≠ t.ofColex ↔ s ≠ t

Next tactic:
simp