Notation "''M_' ( n )" := 'M_n (only parsing) : type_scope.Notation "\tr A" := (mxtrace A) : ring_scope.Canonical matrix_eqType (R : eqType) m n:=
  Eval hnf in EqType 'M[R]_(m, n) (matrix_eqMixin R m n).Canonical matrix_choiceType (R : choiceType) m n :=
  Eval hnf in ChoiceType 'M[R]_(m, n) (matrix_choiceMixin R m n).Canonical matrix_countType (R : countType) m n :=
  Eval hnf in CountType 'M[R]_(m, n) (matrix_countMixin R m n).Canonical matrix_finType (R : finType) m n :=
  Eval hnf in FinType 'M[R]_(m, n) (matrix_finMixin R m n).(* Constant matrix *)
Fact const_mx_key : unit.Definition const_mx m n a : 'M[R]_(m, n) := \matrix[const_mx_key]_(i, j) a.Definition conform_mx m' n' B A :=
  match m =P m', n =P n' with
  | ReflectT eq_m, ReflectT eq_n => castmx (eq_m, eq_n) A
  | _, _ => B
  end.(* Transpose a matrix *)
Fact trmx_key : unit.Definition trmx A := \matrix[trmx_key]_(i, j) A j i.(* Permute a matrix vertically (rows) or horizontally (columns) *)
Fact row_perm_key : unit.Fact col_perm_key : unit.(* Exchange two rows/columns of a matrix *)
Definition xrow i1 i2 := row_perm (tperm i1 i2).Definition xcol j1 j2 := col_perm (tperm j1 j2).(* Row/Column sub matrices of a matrix *)
Definition row i0 A := \row_j A i0 j.Definition col j0 A := \col_i A i j0.(* Removing a row/column from a matrix *)
Definition row' i0 A := \matrix_(i, j) A (lift i0 i) j.Definition col' j0 A := \matrix_(i, j) A i (lift j0 j).

(* Specifications: *)
Lemma castmx_const m' n' (eq_mn : (m = m') * (n = n')) a : castmx eq_mn (const_mx a) = const_mx a.
Lemma trmx_const a : trmx (const_mx a) = const_mx a.
Lemma row_perm_const s a : row_perm s (const_mx a) = const_mx a.
Lemma col_perm_const s a : col_perm s (const_mx a) = const_mx a.
Lemma xrow_const i1 i2 a : xrow i1 i2 (const_mx a) = const_mx a.
Lemma xcol_const j1 j2 a : xcol j1 j2 (const_mx a) = const_mx a.
Lemma rowP (u v : 'rV[R]_n) : u 0 =1 v 0 <-> u = v.
Lemma rowK u_ i0 : row i0 (\matrix_i u_ i) = u_ i0.
Lemma row_matrixP A B : (forall i, row i A = row i B) <-> A = B.
Lemma colP (u v : 'cV[R]_m) : u^~ 0 =1 v^~ 0 <-> u = v.
Lemma row_const i0 a : row i0 (const_mx a) = const_mx a.
Lemma col_const j0 a : col j0 (const_mx a) = const_mx a.
Lemma row'_const i0 a : row' i0 (const_mx a) = const_mx a.
Lemma col'_const j0 a : col' j0 (const_mx a) = const_mx a.
Lemma col_perm1 A : col_perm 1 A = A.
Lemma row_perm1 A : row_perm 1 A = A.
Lemma col_permM s t A : col_perm (s * t) A = col_perm s (col_perm t A).
Lemma row_permM s t A : row_perm (s * t) A = row_perm s (row_perm t A).
Lemma col_row_permC s t A : col_perm s (row_perm t A) = row_perm t (col_perm s A).
Lemma castmx_id m n erefl_mn (A : 'M_(m, n)) : castmx erefl_mn A = A.
Lemma castmx_comp m1 n1 m2 n2 m3 n3 (eq_m1 : m1 = m2) (eq_n1 : n1 = n2) (eq_m2 : m2 = m3) (eq_n2 : n2 = n3) A : castmx (eq_m2, eq_n2) (castmx (eq_m1, eq_n1) A) = castmx (etrans eq_m1 eq_m2, etrans eq_n1 eq_n2) A.
Lemma castmxK m1 n1 m2 n2 (eq_m : m1 = m2) (eq_n : n1 = n2) : cancel (castmx (eq_m, eq_n)) (castmx (esym eq_m, esym eq_n)).
Lemma castmxKV m1 n1 m2 n2 (eq_m : m1 = m2) (eq_n : n1 = n2) : cancel (castmx (esym eq_m, esym eq_n)) (castmx (eq_m, eq_n)).
Lemma castmx_sym m1 n1 m2 n2 (eq_m : m1 = m2) (eq_n : n1 = n2) A1 A2 : A1 = castmx (eq_m, eq_n) A2 -> A2 = castmx (esym eq_m, esym eq_n) A1.
Lemma conform_mx_id m n (B A : 'M_(m, n)) : conform_mx B A = A.
Lemma conform_castmx m1 n1 m2 n2 m3 n3 (e_mn : (m2 = m3) * (n2 = n3)) (B : 'M_(m1, n1)) A : conform_mx B (castmx e_mn A) = conform_mx B A.
Lemma trmxK m n : cancel (@trmx m n) (@trmx n m).
Lemma trmx_inj m n : injective (@trmx m n).
Lemma tr_row_perm m n s (A : 'M_(m, n)) : (row_perm s A)^T = col_perm s A^T.
Lemma tr_col_perm m n s (A : 'M_(m, n)) : (col_perm s A)^T = row_perm s A^T.
Lemma tr_xrow m n i1 i2 (A : 'M_(m, n)) : (xrow i1 i2 A)^T = xcol i1 i2 A^T.
Lemma tr_xcol m n j1 j2 (A : 'M_(m, n)) : (xcol j1 j2 A)^T = xrow j1 j2 A^T.
Lemma row_id n i (V : 'rV_n) : row i V = V.
Lemma col_id n j (V : 'cV_n) : col j V = V.
Lemma row_eq m1 m2 n i1 i2 (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : row i1 A1 = row i2 A2 -> A1 i1 =1 A2 i2.
Lemma col_eq m n1 n2 j1 j2 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : col j1 A1 = col j2 A2 -> A1^~ j1 =1 A2^~ j2.
Lemma tr_row m n i0 (A : 'M_(m, n)) : (row i0 A)^T = col i0 A^T.
Lemma tr_row' m n i0 (A : 'M_(m, n)) : (row' i0 A)^T = col' i0 A^T.
Lemma tr_col m n j0 (A : 'M_(m, n)) : (col j0 A)^T = row j0 A^T.
Lemma tr_col' m n j0 (A : 'M_(m, n)) : (col' j0 A)^T = row' j0 A^T.