aboutsummaryrefslogtreecommitdiff
path: root/mathcomp
diff options
context:
space:
mode:
Diffstat (limited to 'mathcomp')
-rw-r--r--mathcomp/algebra/matrix.v321
-rw-r--r--mathcomp/algebra/mxalgebra.v61
-rw-r--r--mathcomp/algebra/mxpoly.v11
-rw-r--r--mathcomp/algebra/poly.v6
-rw-r--r--mathcomp/character/character.v2
-rw-r--r--mathcomp/field/algnum.v4
-rw-r--r--mathcomp/ssreflect/bigop.v63
-rw-r--r--mathcomp/ssreflect/finset.v16
-rw-r--r--mathcomp/ssreflect/fintype.v35
-rw-r--r--mathcomp/ssreflect/seq.v50
10 files changed, 485 insertions, 84 deletions
diff --git a/mathcomp/algebra/matrix.v b/mathcomp/algebra/matrix.v
index a2b874a..1730b0b 100644
--- a/mathcomp/algebra/matrix.v
+++ b/mathcomp/algebra/matrix.v
@@ -100,6 +100,7 @@ From mathcomp Require Import div prime binomial ssralg finalg zmodp countalg.
(* \adj A == the adjugate matrix of A (\adj A i j = cofactor j i A). *)
(* A \in unitmx == A is invertible (R must be a comUnitRingType). *)
(* invmx A == the inverse matrix of A if A \in unitmx A, otherwise A. *)
+(* A \is a mxOver S == the matrix A has its coefficients in S. *)
(* The following operations provide a correspondence between linear functions *)
(* and matrices: *)
(* lin1_mx f == the m x n matrix that emulates via right product *)
@@ -156,7 +157,7 @@ Reserved Notation "''cV[' R ]_ n" (at level 8, n at level 2). (* only parsing
Reserved Notation "''M[' R ]_ ( n )" (at level 8). (* only parsing *)
Reserved Notation "''M[' R ]_ ( m , n )" (at level 8). (* only parsing *)
-Reserved Notation "\matrix_ i E"
+Reserved Notation "\matrix_ i E"
(at level 36, E at level 36, i at level 2,
format "\matrix_ i E").
Reserved Notation "\matrix_ ( i < n ) E"
@@ -573,8 +574,7 @@ Proof. by apply/matrixP=> i j; rewrite mxE row_mxEr. Qed.
Lemma hsubmxK A : row_mx (lsubmx A) (rsubmx A) = A.
Proof.
-apply/matrixP=> i j; rewrite !mxE.
-by case: splitP => k Dk //=; rewrite !mxE //=; congr (A _ _); apply: val_inj.
+by apply/matrixP=> i j; rewrite !mxE; case: split_ordP => k ->; rewrite !mxE.
Qed.
Lemma col_mxEu A1 A2 i j : col_mx A1 A2 (lshift m2 i) j = A1 i j.
@@ -706,12 +706,10 @@ Proof. by apply/matrixP=> i j; rewrite !(col_mxEd, mxE). Qed.
Lemma col'Kl m n1 n2 j1 (A1 : 'M_(m, n1.+1)) (A2 : 'M_(m, n2)) :
col' (lshift n2 j1) (row_mx A1 A2) = row_mx (col' j1 A1) A2.
Proof.
-apply/matrixP=> i /= j; symmetry; rewrite 2!mxE.
-case: splitP => j' def_j'.
- rewrite mxE -(row_mxEl _ A2); congr (row_mx _ _ _); apply: ord_inj.
- by rewrite /= def_j'.
+apply/matrixP=> i /= j; symmetry; rewrite 2!mxE; case: split_ordP => j' ->.
+ by rewrite mxE -(row_mxEl _ A2); congr (row_mx _ _ _); apply: ord_inj.
rewrite -(row_mxEr A1); congr (row_mx _ _ _); apply: ord_inj => /=.
-by rewrite /bump def_j' -ltnS -addSn ltn_addr.
+by rewrite /bump -ltnS -addSn ltn_addr.
Qed.
Lemma row'Ku m1 m2 n i1 (A1 : 'M_(m1.+1, n)) (A2 : 'M_(m2, n)) :
@@ -1035,6 +1033,30 @@ End MapMatrix.
Arguments map_mx {aT rT} f {m n} A.
+Section MultipleMapMatrix.
+Local Notation "M ^ phi" := (map_mx phi M).
+
+Lemma map_mx_id (R : Type) m n (M : 'M[R]_(m,n)) : M ^ id = M.
+Proof. by apply/matrixP => i j; rewrite !mxE. Qed.
+
+Lemma map_mx_comp (R S T : Type) m n (M : 'M[R]_(m,n))
+ (f : R -> S) (g : S -> T) : M ^ (g \o f) = (M ^ f) ^ g.
+Proof. by apply/matrixP => i j; rewrite !mxE. Qed.
+
+Lemma eq_in_map_mx (R S : Type) m n (M : 'M[R]_(m,n)) (g f : R -> S) :
+ (forall i j, f (M i j) = g (M i j)) <-> M ^ f = M ^ g.
+Proof. by rewrite -matrixP; split => fg i j; have := fg i j; rewrite !mxE. Qed.
+
+Lemma eq_map_mx (R S : Type) m n (M : 'M[R]_(m,n)) (g f : R -> S) :
+ f =1 g -> M ^ f = M ^ g.
+Proof. by move=> eq_fg; apply/eq_in_map_mx. Qed.
+
+Lemma map_mx_id_in (R : Type) m n (M : 'M[R]_(m,n)) (f : R -> R) :
+ (forall i j, f (M i j) = M i j) -> M ^ f = M.
+Proof. by rewrite -[RHS]map_mx_id -eq_in_map_mx. Qed.
+
+End MultipleMapMatrix.
+
(*****************************************************************************)
(********************* Matrix Zmodule (additive) structure *******************)
(*****************************************************************************)
@@ -1191,6 +1213,30 @@ Lemma block_mx_eq0 m1 m2 n1 n2 (Aul : 'M_(m1, n1)) Aur Adl (Adr : 'M_(m2, n2)) :
[&& Aul == 0, Aur == 0, Adl == 0 & Adr == 0].
Proof. by rewrite col_mx_eq0 !row_mx_eq0 !andbA. Qed.
+Lemma matrix_eq0 m n (A : 'M_(m, n)) :
+ (A == 0) = [forall i, forall j, A i j == 0].
+Proof.
+apply/eqP/'forall_'forall_eqP => [-> i j|A_eq0]; first by rewrite !mxE.
+by apply/matrixP => i j; rewrite A_eq0 !mxE.
+Qed.
+
+Lemma matrix0Pn m n (A : 'M_(m, n)) : reflect (exists i j, A i j != 0) (A != 0).
+Proof.
+by rewrite matrix_eq0; apply/(iffP forallPn) => -[i /forallPn]; exists i.
+Qed.
+
+Lemma rV0Pn n (v : 'rV_n) : reflect (exists i, v 0 i != 0) (v != 0).
+Proof.
+apply: (iffP (matrix0Pn _)) => [[i [j]]|[j]]; last by exists 0, j.
+by rewrite ord1; exists j.
+Qed.
+
+Lemma cV0Pn n (v : 'cV_n) : reflect (exists i, v i 0 != 0) (v != 0).
+Proof.
+apply: (iffP (matrix0Pn _)) => [[i] [j]|[i]]; last by exists i, 0.
+by rewrite ord1; exists i.
+Qed.
+
Definition nz_row m n (A : 'M_(m, n)) :=
oapp (fun i => row i A) 0 [pick i | row i A != 0].
@@ -1275,7 +1321,7 @@ Proof. by apply/matrixP=> i j; rewrite !mxE mulrDr. Qed.
Lemma scalemxA x y A : x *m: (y *m: A) = (x * y) *m: A.
Proof. by apply/matrixP=> i j; rewrite !mxE mulrA. Qed.
-Definition matrix_lmodMixin :=
+Definition matrix_lmodMixin :=
LmodMixin scalemxA scale1mx scalemxDr scalemxDl.
Canonical matrix_lmodType :=
@@ -1288,10 +1334,10 @@ Lemma matrix_sum_delta A :
A = \sum_(i < m) \sum_(j < n) A i j *: delta_mx i j.
Proof.
apply/matrixP=> i j.
-rewrite summxE (bigD1 i) // summxE (bigD1 j) //= !mxE !eqxx mulr1.
-rewrite !big1 ?addr0 //= => [i' | j']; rewrite eq_sym => /negPf diff.
- by rewrite summxE big1 // => j' _; rewrite !mxE diff mulr0.
-by rewrite !mxE eqxx diff mulr0.
+rewrite summxE (bigD1_ord i) // summxE (bigD1_ord j) //= !mxE !eqxx mulr1.
+rewrite !big1 ?addr0 //= => [i' | j'] _.
+ by rewrite summxE big1// => j' _; rewrite !mxE eq_liftF mulr0.
+by rewrite !mxE eqxx eq_liftF mulr0.
Qed.
End RingModule.
@@ -1404,11 +1450,54 @@ Canonical diag_mx_linear n := Linear (@diag_mx_is_linear n).
Lemma diag_mx_sum_delta n (d : 'rV_n) :
diag_mx d = \sum_i d 0 i *: delta_mx i i.
Proof.
-apply/matrixP=> i j; rewrite summxE (bigD1 i) //= !mxE eqxx /=.
-rewrite eq_sym mulr_natr big1 ?addr0 // => i' ne_i'i.
-by rewrite !mxE eq_sym (negPf ne_i'i) mulr0.
+apply/matrixP=> i j; rewrite summxE (bigD1_ord i) //= !mxE eqxx /=.
+by rewrite eq_sym mulr_natr big1 ?addr0 // => i'; rewrite !mxE eq_liftF mulr0.
+Qed.
+
+Lemma row_diag_mx n (d : 'rV_n) i :
+ row i (diag_mx d) = d 0 i *: delta_mx 0 i.
+Proof. by apply/rowP => j; rewrite !mxE eqxx eq_sym mulr_natr. Qed.
+
+Definition is_diag_mx m n (A : 'M[R]_(m, n)) :=
+ [forall i : 'I__, forall j : 'I__, (i != j :> nat) ==> (A i j == 0)].
+
+Lemma is_diag_mxP m n (A : 'M[R]_(m, n)) :
+ reflect (forall i j : 'I__, i != j :> nat -> A i j = 0) (is_diag_mx A).
+Proof. by apply: (iffP 'forall_'forall_implyP) => /(_ _ _ _)/eqP. Qed.
+
+Lemma diag_mxP n (A : 'M[R]_n) :
+ reflect (exists d : 'rV_n, A = diag_mx d) (is_diag_mx A).
+Proof.
+apply: (iffP (is_diag_mxP _)) => [Adiag|[d ->] i j neq_ij]; last first.
+ by rewrite !mxE -val_eqE (negPf neq_ij).
+exists (\row_i A i i); apply/matrixP => i j; rewrite !mxE.
+by case: (altP (i =P j)) => [->|/Adiag->].
+Qed.
+
+Lemma diag_mx_is_diag n (r : 'rV[R]_n) : is_diag_mx (diag_mx r).
+Proof. by apply/diag_mxP; eexists. Qed.
+
+Lemma mx0_is_diag m n : is_diag_mx (0 : 'M[R]_(m, n)).
+Proof. by apply/is_diag_mxP => i j _; rewrite mxE. Qed.
+
+Definition is_trig_mx m n (A : 'M[R]_(m, n)) :=
+ [forall i : 'I__, forall j : 'I__, (i < j)%N ==> (A i j == 0)].
+
+Lemma is_trig_mxP m n (A : 'M[R]_(m, n)) :
+ reflect (forall i j : 'I__, (i < j)%N -> A i j = 0) (is_trig_mx A).
+Proof. by apply: (iffP 'forall_'forall_implyP) => /(_ _ _ _)/eqP. Qed.
+
+Lemma is_diag_mx_is_trig m n (A : 'M[R]_(m, n)) : is_diag_mx A -> is_trig_mx A.
+Proof.
+by move=> /is_diag_mxP A_eq0; apply/is_trig_mxP=> i j lt_ij; rewrite A_eq0// ltn_eqF.
Qed.
+Lemma diag_mx_is_trig n (r : 'rV[R]_n) : is_trig_mx (diag_mx r).
+Proof. exact/is_diag_mx_is_trig/diag_mx_is_diag. Qed.
+
+Lemma mx0_is_trig m n : is_trig_mx (0 : 'M[R]_(m, n)).
+Proof. by apply/is_trig_mxP => i j _; rewrite mxE. Qed.
+
(* Scalar matrix : a diagonal matrix with a constant on the diagonal *)
Section ScalarMx.
@@ -1465,6 +1554,18 @@ Proof. by apply/is_scalar_mxP; exists a. Qed.
Lemma mx0_is_scalar : is_scalar_mx 0.
Proof. by apply/is_scalar_mxP; exists 0; rewrite raddf0. Qed.
+Lemma scalar_mx_is_diag a : is_diag_mx (a%:M).
+Proof. by rewrite -diag_const_mx diag_mx_is_diag. Qed.
+
+Lemma is_scalar_mx_is_diag A : is_scalar_mx A -> is_diag_mx A.
+Proof. by move=> /is_scalar_mxP[a ->]; apply: scalar_mx_is_diag. Qed.
+
+Lemma scalar_mx_is_trig a : is_trig_mx (a%:M).
+Proof. by rewrite is_diag_mx_is_trig// scalar_mx_is_diag. Qed.
+
+Lemma is_scalar_mx_is_trig A : is_scalar_mx A -> is_trig_mx A.
+Proof. by move=> /is_scalar_mx_is_diag /is_diag_mx_is_trig. Qed.
+
End ScalarMx.
Notation "x %:M" := (scalar_mx _ x) : ring_scope.
@@ -1474,9 +1575,8 @@ Proof. by apply/rowP=> j; rewrite ord1 mxE. Qed.
Lemma scalar_mx_block n1 n2 a : a%:M = block_mx a%:M 0 0 a%:M :> 'M_(n1 + n2).
Proof.
-apply/matrixP=> i j; rewrite !mxE -val_eqE /=.
-by do 2![case: splitP => ? ->; rewrite !mxE];
- rewrite ?eqn_add2l // -?(eq_sym (n1 + _)%N) eqn_leq leqNgt lshift_subproof.
+apply/matrixP=> i j; rewrite !mxE.
+by do 2![case: split_ordP => ? ->; rewrite !mxE]; rewrite ?eq_shift.
Qed.
(* Matrix multiplication using bigops. *)
@@ -1562,8 +1662,8 @@ Qed.
Lemma rowE m n i (A : 'M_(m, n)) : row i A = delta_mx 0 i *m A.
Proof.
-apply/rowP=> j; rewrite !mxE (bigD1 i) //= mxE !eqxx mul1r.
-by rewrite big1 ?addr0 // => i' ne_i'i; rewrite mxE /= (negPf ne_i'i) mul0r.
+apply/rowP=> j; rewrite !mxE (bigD1_ord i) //= mxE !eqxx mul1r.
+by rewrite big1 ?addr0 // => i'; rewrite mxE /= lift_eqF mul0r.
Qed.
Lemma row_mul m n p (i : 'I_m) A (B : 'M_(n, p)) :
@@ -1579,9 +1679,9 @@ Qed.
Lemma mul_delta_mx_cond m n p (j1 j2 : 'I_n) (i1 : 'I_m) (k2 : 'I_p) :
delta_mx i1 j1 *m delta_mx j2 k2 = delta_mx i1 k2 *+ (j1 == j2).
Proof.
-apply/matrixP => i k; rewrite !mxE (bigD1 j1) //=.
+apply/matrixP => i k; rewrite !mxE (bigD1_ord j1) //=.
rewrite mulmxnE !mxE !eqxx andbT -natrM -mulrnA !mulnb !andbA andbAC.
-by rewrite big1 ?addr0 // => j; rewrite !mxE andbC -natrM; move/negPf->.
+by rewrite big1 ?addr0 // => j; rewrite !mxE andbC -natrM lift_eqF.
Qed.
Lemma mul_delta_mx m n p (j : 'I_n) (i : 'I_m) (k : 'I_p) :
@@ -1726,21 +1826,20 @@ Proof. by apply/matrixP=> i j; rewrite !mxE ltn_ord andbT. Qed.
Lemma pid_mx_row n r : pid_mx r = row_mx 1%:M 0 :> 'M_(r, r + n).
Proof.
apply/matrixP=> i j; rewrite !mxE ltn_ord andbT.
-case: splitP => j' ->; rewrite !mxE // .
-by rewrite eqn_leq andbC leqNgt lshift_subproof.
+by case: split_ordP => j' ->; rewrite !mxE// (val_eqE (lshift n i)) eq_shift.
Qed.
Lemma pid_mx_col m r : pid_mx r = col_mx 1%:M 0 :> 'M_(r + m, r).
Proof.
apply/matrixP=> i j; rewrite !mxE andbC.
-by case: splitP => i' ->; rewrite !mxE // eq_sym.
+by case: split_ordP => ? ->; rewrite !mxE//.
Qed.
Lemma pid_mx_block m n r : pid_mx r = block_mx 1%:M 0 0 0 :> 'M_(r + m, r + n).
Proof.
apply/matrixP=> i j; rewrite !mxE row_mx0 andbC.
-case: splitP => i' ->; rewrite !mxE //; case: splitP => j' ->; rewrite !mxE //=.
-by rewrite eqn_leq andbC leqNgt lshift_subproof.
+do ![case: split_ordP => ? ->; rewrite !mxE//].
+by rewrite (val_eqE (lshift n _)) eq_shift.
Qed.
Lemma tr_pid_mx m n r : (pid_mx r)^T = pid_mx r :> 'M_(n, m).
@@ -1748,7 +1847,7 @@ Proof. by apply/matrixP=> i j; rewrite !mxE; case: eqVneq => // ->. Qed.
Lemma pid_mx_minv m n r : pid_mx (minn m r) = pid_mx r :> 'M_(m, n).
Proof. by apply/matrixP=> i j; rewrite !mxE leq_min ltn_ord. Qed.
-
+
Lemma pid_mx_minh m n r : pid_mx (minn n r) = pid_mx r :> 'M_(m, n).
Proof. by apply: trmx_inj; rewrite !tr_pid_mx pid_mx_minv. Qed.
@@ -2055,6 +2154,13 @@ Prenex Implicits mulmx mxtrace determinant cofactor adjugate.
Arguments is_scalar_mxP {R n A}.
Arguments mul_delta_mx {R m n p}.
+Arguments is_diag_mx {R m n}.
+Arguments is_diag_mxP {R m n A}.
+Arguments is_trig_mx {R m n}.
+Arguments is_trig_mxP {R m n A}.
+
+Hint Resolve scalar_mx_is_diag scalar_mx_is_trig : core.
+Hint Resolve diag_mx_is_diag diag_mx_is_trig : core.
Notation "a %:M" := (scalar_mx a) : ring_scope.
Notation "A *m B" := (mulmx A B) : ring_scope.
@@ -2155,7 +2261,7 @@ Proof.
by move=> def_gf; apply/matrixP=> i j; rewrite !mxE -map_delta_mx -def_gf mxE.
Qed.
-Lemma map_lin_mx m1 n1 m2 n2 (g : 'M_(m1, n1) -> 'M_(m2, n2)) gf :
+Lemma map_lin_mx m1 n1 m2 n2 (g : 'M_(m1, n1) -> 'M_(m2, n2)) gf :
(forall A, (g A)^f = gf A^f) -> (lin_mx g)^f = lin_mx gf.
Proof.
move=> def_gf; apply: map_lin1_mx => A /=.
@@ -2421,7 +2527,7 @@ rewrite -tr_row' -tr_col' det_tr; congr (\det _).
by apply/matrixP=> ? ?; rewrite !mxE.
Qed.
-Lemma cofactorZ n a (A : 'M[R]_n) i j :
+Lemma cofactorZ n a (A : 'M[R]_n) i j :
cofactor (a *: A) i j = a ^+ n.-1 * cofactor A i j.
Proof. by rewrite {1}/cofactor !linearZ detZ mulrCA mulrA. Qed.
@@ -2754,8 +2860,7 @@ have [{detA0}A'0 | nzA'] := eqVneq (row 0 (\adj A)) 0; last first.
pose A' := col' 0 A; pose vA := col 0 A.
have defA: A = row_mx vA A'.
apply/matrixP=> i j; rewrite !mxE.
- case: splitP => j' def_j; rewrite mxE; congr (A i _); apply: val_inj => //=.
- by rewrite def_j [j']ord1.
+ by case: split_ordP => j' ->; rewrite !mxE ?ord1; congr (A i _); apply: val_inj.
have{IHn} w_ j : exists w : 'rV_n.+1, [/\ w != 0, w 0 j = 0 & w *m A' = 0].
have [|wj nzwj wjA'0] := IHn (row' j A').
by apply/eqP; move/rowP/(_ j)/eqP: A'0; rewrite !mxE mulf_eq0 signr_eq0.
@@ -2763,13 +2868,9 @@ have{IHn} w_ j : exists w : 'rV_n.+1, [/\ w != 0, w 0 j = 0 & w *m A' = 0].
rewrite !mxE unlift_none -wjA'0; split=> //.
apply: contraNneq nzwj => w0; apply/eqP/rowP=> k'.
by move/rowP/(_ (lift j k')): w0; rewrite !mxE liftK.
- apply/rowP=> k; rewrite !mxE (bigD1 j) //= mxE unlift_none mul0r add0r.
- rewrite (reindex_onto (lift j) (odflt k \o unlift j)) /= => [|k'].
- by apply: eq_big => k'; rewrite ?mxE liftK eq_sym neq_lift eqxx.
- by rewrite eq_sym; case/unlift_some=> ? ? ->.
-have [w0 [nz_w0 w00_0 w0A']] := w_ 0; pose a0 := (w0 *m vA) 0 0.
-have [j {nz_w0}/= nz_w0j | w00] := pickP [pred j | w0 0 j != 0]; last first.
- by case/eqP: nz_w0; apply/rowP=> j; rewrite mxE; move/eqP: (w00 j).
+ apply/rowP=> k; rewrite !mxE (bigD1_ord j) //= mxE unlift_none mul0r add0r.
+ by apply: eq_big => //= k'; rewrite !mxE/= liftK.
+have [w0 [/rV0Pn[j nz_w0j] w00_0 w0A']] := w_ 0; pose a0 := (w0 *m vA) 0 0.
have{w_} [wj [nz_wj wj0_0 wjA']] := w_ j; pose aj := (wj *m vA) 0 0.
have [aj0 | nz_aj] := eqVneq aj 0.
exists wj => //; rewrite defA (@mul_mx_row _ _ _ 1) [_ *m _]mx11_scalar -/aj.
@@ -2819,7 +2920,7 @@ Qed.
Lemma map_mx_inv n' (A : 'M_n'.+1) : A^-1^f = A^f^-1.
Proof. exact: map_invmx. Qed.
-
+
Lemma map_mx_eq0 m n (A : 'M_(m, n)) : (A^f == 0) = (A == 0).
Proof. by rewrite -(inj_eq map_mx_inj) raddf0. Qed.
@@ -2906,3 +3007,141 @@ by case: unliftP => [j'|] ->; [apply: Uu | rewrite /= mxE].
Qed.
End CormenLUP.
+
+Section mxOver.
+Section mxOverType.
+Context {m n : nat} {T : Type}.
+Implicit Types (S : {pred T}).
+
+Definition mxOver (S : {pred T}) :=
+ [qualify a M : 'M[T]_(m, n) | [forall i, [forall j, M i j \in S]]].
+
+Fact mxOver_key S : pred_key (mxOver S). Proof. by []. Qed.
+Canonical mxOver_keyed S := KeyedQualifier (mxOver_key S).
+
+Lemma mxOverP {S : {pred T}} {M : 'M[T]__} :
+ reflect (forall i j, M i j \in S) (M \is a mxOver S).
+Proof. exact/'forall_forallP. Qed.
+
+Lemma mxOverS (S1 S2 : {pred T}) :
+ {subset S1 <= S2} -> {subset mxOver S1 <= mxOver S2}.
+Proof. by move=> sS12 M /mxOverP S1M; apply/mxOverP=> i j; apply/sS12/S1M. Qed.
+
+Lemma mxOver_const c S : c \in S -> const_mx c \is a mxOver S.
+Proof. by move=> cS; apply/mxOverP => i j; rewrite !mxE. Qed.
+
+Lemma mxOver_constE c S : (m > 0)%N -> (n > 0)%N ->
+ (const_mx c \is a mxOver S) = (c \in S).
+Proof.
+move=> m_gt0 n_gt0; apply/idP/idP; last exact: mxOver_const.
+by move=> /mxOverP /(_ (Ordinal m_gt0) (Ordinal n_gt0)); rewrite mxE.
+Qed.
+
+End mxOverType.
+
+Lemma thinmxOver {n : nat} {T : Type} (M : 'M[T]_(n, 0)) S : M \is a mxOver S.
+Proof. by apply/mxOverP => ? []. Qed.
+
+Lemma flatmxOver {n : nat} {T : Type} (M : 'M[T]_(0, n)) S : M \is a mxOver S.
+Proof. by apply/mxOverP => - []. Qed.
+
+Section mxOverZmodule.
+Context {M : zmodType} {m n : nat}.
+Implicit Types (S : {pred M}).
+
+Lemma mxOver0 S : 0 \in S -> 0 \is a @mxOver m n _ S.
+Proof. exact: mxOver_const. Qed.
+
+Section mxOverAdd.
+Variables (S : {pred M}) (addS : addrPred S) (kS : keyed_pred addS).
+Fact mxOver_add_subproof : addr_closed (@mxOver m n _ kS).
+Proof.
+split=> [|p q Sp Sq]; first by rewrite mxOver0 // ?rpred0.
+by apply/mxOverP=> i j; rewrite mxE rpredD // !(mxOverP _).
+Qed.
+Canonical mxOver_addrPred := AddrPred mxOver_add_subproof.
+End mxOverAdd.
+
+Section mxOverOpp.
+Variables (S : {pred M}) (oppS : opprPred S) (kS : keyed_pred oppS).
+Fact mxOver_opp_subproof : oppr_closed (@mxOver m n _ kS).
+Proof. by move=> A /mxOverP SA; apply/mxOverP=> i j; rewrite mxE rpredN. Qed.
+Canonical mxOver_opprPred := OpprPred mxOver_opp_subproof.
+End mxOverOpp.
+
+Canonical mxOver_zmodPred (S : {pred M}) (zmodS : zmodPred S)
+ (kS : keyed_pred zmodS) := ZmodPred (@mxOver_opp_subproof _ _ kS).
+
+End mxOverZmodule.
+
+Section mxOverRing.
+Context {R : ringType} {m n : nat}.
+
+Lemma mxOver_scalar S c : 0 \in S -> c \in S -> c%:M \is a @mxOver n n R S.
+Proof. by move=> S0 cS; apply/mxOverP => i j; rewrite !mxE; case: eqP. Qed.
+
+Lemma mxOver_scalarE S c : (n > 0)%N ->
+ (c%:M \is a @mxOver n n R S) = ((n > 1) ==> (0 \in S)) && (c \in S).
+Proof.
+case: n => [|[|k]]//= _.
+ by apply/mxOverP/idP => [/(_ ord0 ord0)|cij i j]; rewrite ?mxE ?ord1.
+apply/mxOverP/andP => [cij|[S0 cij] i j]; last by rewrite !mxE; case: eqP.
+by split; [have := cij 0 1|have := cij 0 0]; rewrite !mxE.
+Qed.
+
+Section mxOverScale.
+Variables (S : {pred R}) (mulS : mulrPred S) (kS : keyed_pred mulS).
+Lemma mxOverZ : {in kS & mxOver kS, forall a : R, forall v : 'M[R]_(m, n),
+ a *: v \is a mxOver kS}.
+Proof.
+by move=> a v aS /mxOverP vS; apply/mxOverP => i j; rewrite !mxE rpredM.
+Qed.
+End mxOverScale.
+
+Lemma mxOver_diag (S : {pred R}) k (D : 'rV[R]_k) :
+ 0 \in S -> D \is a mxOver S -> diag_mx D \is a mxOver S.
+Proof.
+move=> S0 DS; apply/mxOverP => i j; rewrite !mxE.
+by case: eqP => //; rewrite (mxOverP DS).
+Qed.
+
+Lemma mxOver_diagE (S : {pred R}) k (D : 'rV[R]_k) : k > 0 ->
+ (diag_mx D \is a mxOver S) = ((k > 1) ==> (0 \in S)) && (D \is a mxOver S).
+Proof.
+case: k => [|[|k]]//= in D * => _.
+ by rewrite [diag_mx _]mx11_scalar [D in RHS]mx11_scalar !mxE.
+apply/idP/andP => [/mxOverP DS|[S0 DS]]; last exact: mxOver_diag.
+split; first by have := DS 0 1; rewrite !mxE.
+by apply/mxOverP => i j; have := DS j j; rewrite ord1 !mxE eqxx.
+Qed.
+
+Section mxOverMul.
+
+Variables (S : predPredType R) (ringS : semiringPred S) (kS : keyed_pred ringS).
+
+Lemma mxOverM p q r : {in mxOver kS & mxOver kS,
+ forall u : 'M[R]_(p, q), forall v : 'M[R]_(q, r), u *m v \is a mxOver kS}.
+Proof.
+move=> M N /mxOverP MS /mxOverP NS; apply/mxOverP => i j.
+by rewrite !mxE rpred_sum // => k _; rewrite rpredM.
+Qed.
+
+End mxOverMul.
+End mxOverRing.
+
+Section mxRingOver.
+Context {R : ringType} {n : nat}.
+
+Section semiring.
+Variables (S : {pred R}) (ringS : semiringPred S) (kS : keyed_pred ringS).
+Fact mxOver_mul_subproof : mulr_closed (@mxOver n.+1 n.+1 _ kS).
+Proof. by split; rewrite ?mxOver_scalar ?rpred0 ?rpred1//; apply: mxOverM. Qed.
+Canonical mxOver_mulrPred := MulrPred mxOver_mul_subproof.
+Canonical mxOver_semiringPred := SemiringPred mxOver_mul_subproof.
+End semiring.
+
+Canonical mxOver_subringPred (S : {pred R}) (ringS : subringPred S)
+ (kS : keyed_pred ringS):= SubringPred (mxOver_mul_subproof kS).
+
+End mxRingOver.
+End mxOver.
diff --git a/mathcomp/algebra/mxalgebra.v b/mathcomp/algebra/mxalgebra.v
index 9a0034d..c0c4577 100644
--- a/mathcomp/algebra/mxalgebra.v
+++ b/mathcomp/algebra/mxalgebra.v
@@ -490,6 +490,17 @@ rewrite -{4}[B]mulmx_ebase -!mulmxA mulKmx //.
by rewrite (mulmxA (pid_mx _)) pid_mx_id // !mulmxA -{}defA mulmxKV.
Qed.
+Lemma mulmxVp m n (A : 'M[F]_(m, n)) : row_free A -> A *m pinvmx A = 1%:M.
+Proof.
+move=> fA; rewrite -[X in X *m _]mulmx_ebase !mulmxA mulmxK ?row_ebase_unit//.
+rewrite -[X in X *m _]mulmxA mul_pid_mx !minnn (minn_idPr _) ?rank_leq_col//.
+by rewrite (eqP fA) pid_mx_1 mulmx1 mulmxV ?col_ebase_unit.
+Qed.
+
+Lemma mulmxKp p m n (B : 'M[F]_(m, n)) : row_free B ->
+ cancel ((@mulmx _ p _ _)^~ B) (mulmx^~ (pinvmx B)).
+Proof. by move=> ? A; rewrite -mulmxA mulmxVp ?mulmx1. Qed.
+
Lemma submxP m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) :
reflect (exists D, A = D *m B) (A <= B)%MS.
Proof.
@@ -715,6 +726,21 @@ Proof. by rewrite /ltmx sub1mx submx1. Qed.
Lemma lt1mx m n (A : 'M_(m, n)) : (1%:M < A)%MS = false.
Proof. by rewrite /ltmx submx1 andbF. Qed.
+Lemma pinvmxE n (A : 'M[F]_n) : A \in unitmx -> pinvmx A = invmx A.
+Proof.
+move=> A_unit; apply: (@row_free_inj _ _ _ A); rewrite ?row_free_unit//.
+by rewrite -[pinvmx _]mul1mx mulmxKpV ?sub1mx ?row_full_unit// mulVmx.
+Qed.
+
+Lemma mulVpmx m n (A : 'M[F]_(m, n)) : row_full A -> pinvmx A *m A = 1%:M.
+Proof. by move=> fA; rewrite -[pinvmx _]mul1mx mulmxKpV// sub1mx. Qed.
+
+Lemma pinvmx_free m n (A : 'M[F]_(m, n)) : row_full A -> row_free (pinvmx A).
+Proof. by move=> /mulVpmx pAA1; apply/row_freeP; exists A. Qed.
+
+Lemma pinvmx_full m n (A : 'M[F]_(m, n)) : row_free A -> row_full (pinvmx A).
+Proof. by move=> /mulmxVp ApA1; apply/row_fullP; exists A. Qed.
+
Lemma eqmxP m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) :
reflect (A :=: B)%MS (A == B)%MS.
Proof.
@@ -805,6 +831,9 @@ exists (col_ebase A *m pid_mx (\rank A)).
by rewrite mulmxA -(mulmxA _ _ (pid_mx _)) pid_mx_id // mulmx_ebase.
Qed.
+Lemma row_base0 (m n : nat) : row_base (0 : 'M[F]_(m, n)) = 0.
+Proof. by apply/eqmx0P; rewrite !eq_row_base !sub0mx. Qed.
+
Let qidmx_eq1 n (A : 'M_n) : qidmx A = (A == 1%:M).
Proof. by rewrite /qidmx eqxx pid_mx_1. Qed.
@@ -1174,11 +1203,22 @@ apply: (iffP submxP) => [[D ->]|]; first by rewrite -mulmxA mulmx_ker mulmx0.
by move/mulmxKV_ker; exists (B *m col_ebase A).
Qed.
+Lemma sub_kermx p m n (A : 'M_(m, n)) (B : 'M_(p, m)) :
+ (B <= kermx A)%MS = (B *m A == 0).
+Proof. exact/sub_kermxP/eqP. Qed.
+
+Lemma kermx0 m n : (kermx (0 : 'M_(m, n)) :=: 1%:M)%MS.
+Proof. by apply/eqmxP; rewrite submx1/= sub_kermx mulmx0. Qed.
+
+Lemma mulmx_free_eq0 m n p (A : 'M_(m, n)) (B : 'M_(n, p)) :
+ row_free B -> (A *m B == 0) = (A == 0).
+Proof. by rewrite -sub_kermx -kermx_eq0 => /eqP->; rewrite submx0. Qed.
+
Lemma mulmx0_rank_max m n p (A : 'M_(m, n)) (B : 'M_(n, p)) :
A *m B = 0 -> \rank A + \rank B <= n.
Proof.
move=> AB0; rewrite -{3}(subnK (rank_leq_row B)) leq_add2r.
-by rewrite -mxrank_ker mxrankS //; apply/sub_kermxP.
+by rewrite -mxrank_ker mxrankS // sub_kermx AB0.
Qed.
Lemma mxrank_Frobenius m n p q (A : 'M_(m, n)) B (C : 'M_(p, q)) :
@@ -1192,7 +1232,7 @@ set C1 := _ *m C; rewrite -{2}(subnKC (rank_leq_row C1)) leq_add2l -mxrank_ker.
rewrite -(mxrankMfree _ (row_base_free (A *m B))).
have: (row_base (A *m B) <= row_base B)%MS by rewrite !eq_row_base submxMl.
case/submxP=> D defD; rewrite defD mulmxA mxrankMfree ?mxrankS //.
-by apply/sub_kermxP; rewrite -mulmxA (mulmxA D) -defD -/C2 mulmx_ker.
+by rewrite sub_kermx -mulmxA (mulmxA D) -defD -/C2 mulmx_ker.
Qed.
Lemma mxrank_mul_min m n p (A : 'M_(m, n)) (B : 'M_(n, p)) :
@@ -1218,7 +1258,7 @@ apply/idP/andP=> [sAI | [/submxP[B' ->{A}] /submxP[C' eqBC']]].
rewrite -{1}[K]hsubmxK mul_row_col; move/(canRL (addrK _))->.
by rewrite add0r -mulNmx submxMl.
have: (row_mx B' (- C') <= kermx (col_mx B C))%MS.
- by apply/sub_kermxP; rewrite mul_row_col eqBC' mulNmx subrr.
+ by rewrite sub_kermx mul_row_col eqBC' mulNmx subrr.
case/submxP=> D; rewrite -[kermx _]hsubmxK mul_mx_row.
by case/eq_row_mx=> -> _; rewrite -mulmxA submxMl.
Qed.
@@ -1450,11 +1490,9 @@ apply/eqP; set K := kermx B; set C := (A :&: K)%MS.
rewrite -(eqmxMr B (eq_row_base A)); set K' := _ *m B.
rewrite -{2}(subnKC (rank_leq_row K')) -mxrank_ker eqn_add2l.
rewrite -(mxrankMfree _ (row_base_free A)) mxrank_leqif_sup.
- rewrite sub_capmx -(eq_row_base A) submxMl.
- by apply/sub_kermxP; rewrite -mulmxA mulmx_ker.
+ by rewrite sub_capmx -(eq_row_base A) submxMl sub_kermx -mulmxA mulmx_ker/=.
have /submxP[C' defC]: (C <= row_base A)%MS by rewrite eq_row_base capmxSl.
-rewrite defC submxMr //; apply/sub_kermxP.
-by rewrite mulmxA -defC; apply/sub_kermxP; rewrite capmxSr.
+by rewrite defC submxMr // sub_kermx mulmxA -defC -sub_kermx capmxSr.
Qed.
Lemma mxrank_injP m n p (A : 'M_(m, n)) (f : 'M_(n, p)) :
@@ -1936,10 +1974,7 @@ Definition eigenvalue : pred F := fun a => eigenspace a != 0.
Lemma eigenspaceP a m (W : 'M_(m, n)) :
reflect (W *m g = a *: W) (W <= eigenspace a)%MS.
-Proof.
-rewrite (sameP (sub_kermxP _ _) eqP).
-by rewrite mulmxBr subr_eq0 mul_mx_scalar; apply: eqP.
-Qed.
+Proof. by rewrite sub_kermx mulmxBr subr_eq0 mul_mx_scalar; apply/eqP. Qed.
Lemma eigenvalueP a :
reflect (exists2 v : 'rV_n, v *m g = a *: v & v != 0) (eigenvalue a).
@@ -2155,9 +2190,7 @@ rewrite -sum1_card (partition_big lsubmx nzC) => [|A]; last first.
rewrite -[A]hsubmxK v0 -[n.+1]/(1 + n)%N -col_mx0.
rewrite -[rsubmx _]vsubmxK -det_tr tr_row_mx !tr_col_mx !trmx0.
by rewrite det_lblock [0]mx11_scalar det_scalar1 mxE mul0r.
-rewrite -sum_nat_const; apply: eq_bigr; rewrite /= -[n.+1]/(1 + n)%N => v nzv.
-case: (pickP (fun i => v i 0 != 0)) => [k nza | v0]; last first.
- by case/eqP: nzv; apply/colP=> i; move/eqP: (v0 i); rewrite mxE.
+rewrite -sum_nat_const; apply: eq_bigr => /= v /cV0Pn[k nza].
have xrkK: involutive (@xrow F _ _ 0 k).
by move=> m A /=; rewrite /xrow -row_permM tperm2 row_perm1.
rewrite (reindex_inj (inv_inj (xrkK (1 + n)%N))) /= -[n.+1]/(1 + n)%N.
diff --git a/mathcomp/algebra/mxpoly.v b/mathcomp/algebra/mxpoly.v
index a8cf94b..f33e291 100644
--- a/mathcomp/algebra/mxpoly.v
+++ b/mathcomp/algebra/mxpoly.v
@@ -188,7 +188,7 @@ have: rj0T (Ss_ dj.+1) = 'X^dj *: rj0T (S_ j1) + 1 *: rj0T (Ss_ dj).
rewrite Sylvester_mxE insubdK; last exact: leq_ltn_trans (ltjS).
by have [->|] := eqP; rewrite (addr0, add0r).
rewrite -det_tr => /determinant_multilinear->;
- try by apply/matrixP=> i j; rewrite !mxE eq_sym (negPf (neq_lift _ _)).
+ try by apply/matrixP=> i j; rewrite !mxE lift_eqF.
have [dj0 | dj_gt0] := posnP dj; rewrite ?dj0 !mul1r.
rewrite !det_tr det_map_mx addrC (expand_det_col _ j0) big1 => [|i _].
rewrite add0r; congr (\det _)%:P.
@@ -598,6 +598,15 @@ Qed.
Lemma mxminpoly_min p : horner_mx A p = 0 -> p_A %| p.
Proof. by move=> pA0; rewrite /dvdp -horner_mxK pA0 mx_inv_horner0. Qed.
+Lemma mxminpoly_minP p : reflect (horner_mx A p = 0) (p_A %| p).
+Proof.
+apply: (iffP idP); last exact: mxminpoly_min.
+by move=> /Pdiv.Field.dvdpP[q ->]; rewrite rmorphM/= mx_root_minpoly mulr0.
+Qed.
+
+Lemma dvd_mxminpoly p : (p_A %| p) = (horner_mx A p == 0).
+Proof. exact/mxminpoly_minP/eqP. Qed.
+
Lemma horner_rVpoly_inj : injective (horner_mx A \o rVpoly : 'rV_d -> 'M_n).
Proof.
apply: can_inj (poly_rV \o mx_inv_horner) _ => u /=.
diff --git a/mathcomp/algebra/poly.v b/mathcomp/algebra/poly.v
index e83bc09..a33788d 100644
--- a/mathcomp/algebra/poly.v
+++ b/mathcomp/algebra/poly.v
@@ -1093,6 +1093,12 @@ Proof. by rewrite /comm_poly !hornerC !simp. Qed.
Lemma comm_polyX x : comm_poly 'X x.
Proof. by rewrite /comm_poly !hornerX. Qed.
+Lemma commr_horner a b p : GRing.comm a b -> comm_coef p a -> GRing.comm a p.[b].
+Proof.
+move=> cab cpa; rewrite horner_coef; apply: commr_sum => i _.
+by apply: commrM => //; apply: commrX.
+Qed.
+
Lemma hornerM_comm p q x : comm_poly q x -> (p * q).[x] = p.[x] * q.[x].
Proof.
move=> comm_qx.
diff --git a/mathcomp/character/character.v b/mathcomp/character/character.v
index 113ef8b..e7ea1e0 100644
--- a/mathcomp/character/character.v
+++ b/mathcomp/character/character.v
@@ -722,7 +722,7 @@ Lemma irr_free : free (irr G).
Proof.
apply/freeP=> s s0 i; apply: (mulIf (irr1_neq0 i)).
rewrite mul0r -(raddf0 (xcfun_r_additive 'e_i)) -{}s0 raddf_sum /=.
-rewrite (bigD1 i) //= -tnth_nth xcfunZl xcfun_id eqxx big1 ?addr0 // => j ne_ji.
+rewrite (bigD1 i)//= -tnth_nth xcfunZl xcfun_id eqxx big1 ?addr0 // => j ne_ji.
by rewrite -tnth_nth xcfunZl xcfun_id (negbTE ne_ji) mulr0.
Qed.
diff --git a/mathcomp/field/algnum.v b/mathcomp/field/algnum.v
index 997255b..821a21e 100644
--- a/mathcomp/field/algnum.v
+++ b/mathcomp/field/algnum.v
@@ -150,8 +150,8 @@ Lemma mem_Crat_span s : {subset s <= Crat_span s}.
Proof.
move=> _ /(nthP 0)[ix ltxs <-]; pose i0 := Ordinal ltxs.
apply/Crat_spanP; exists [ffun i => (i == i0)%:R].
-rewrite (bigD1 i0) //= ffunE eqxx // rmorph1 mul1r.
-by rewrite big1 ?addr0 // => i; rewrite ffunE rmorph_nat mulr_natl => /negbTE->.
+rewrite (bigD1_ord i0) //= ffunE eqxx // rmorph1 mul1r.
+by rewrite big1 ?addr0 // => i; rewrite ffunE rmorph_nat mulr_natl lift_eqF.
Qed.
Fact Crat_span_zmod_closed s : zmod_closed (Crat_span s).
diff --git a/mathcomp/ssreflect/bigop.v b/mathcomp/ssreflect/bigop.v
index c6b2dfc..405ee08 100644
--- a/mathcomp/ssreflect/bigop.v
+++ b/mathcomp/ssreflect/bigop.v
@@ -1464,18 +1464,29 @@ Lemma big_image_id (J : finType) (h : J -> R) (A : pred J) :
\big[*%M/1]_(i <- [seq h j | j in A]) i = \big[*%M/1]_(j in A) h j.
Proof. exact: big_image. Qed.
-Lemma reindex_onto (I J : finType) (h : J -> I) h' (P : pred I) F :
- (forall i, P i -> h (h' i) = i) ->
+Lemma reindex_omap (I J : finType) (h : J -> I) h' (P : pred I) F :
+ (forall i, P i -> omap h (h' i) = some i) ->
\big[*%M/1]_(i | P i) F i =
- \big[*%M/1]_(j | P (h j) && (h' (h j) == j)) F (h j).
+ \big[*%M/1]_(j | P (h j) && (h' (h j) == some j)) F (h j).
Proof.
move=> h'K; have [n lePn] := ubnP #|P|; elim: n => // n IHn in P h'K lePn *.
case: (pickP P) => [i Pi | P0]; last first.
by rewrite !big_pred0 // => j; rewrite P0.
-rewrite (bigD1 i Pi) (bigD1 (h' i)) h'K ?Pi ?eqxx //=; congr (_ * _).
-rewrite {}IHn => [|j /andP[]|]; [|by auto | by rewrite (cardD1x i) in lePn].
-apply: eq_bigl => j; rewrite andbC -andbA (andbCA (P _)); case: eqP => //= hK.
-by congr (_ && ~~ _); apply/eqP/eqP=> [<-|->] //; rewrite h'K.
+have := h'K i Pi; case h'i_eq : (h' i) => [/= j|//] [hj_eq].
+rewrite (bigD1 i Pi) (bigD1 j) hj_eq ?Pi ?h'i_eq ?eqxx //=; congr (_ * _).
+rewrite {}IHn => [|k /andP[]|]; [|by auto | by rewrite (cardD1x i) in lePn].
+apply: eq_bigl => k; rewrite andbC -andbA (andbCA (P _)); case: eqP => //= hK.
+congr (_ && ~~ _); apply/eqP/eqP => [|->//].
+by move=> /(congr1 h'); rewrite h'i_eq hK => -[].
+Qed.
+Arguments reindex_omap [I J] h h' [P F].
+
+Lemma reindex_onto (I J : finType) (h : J -> I) h' (P : pred I) F :
+ (forall i, P i -> h (h' i) = i) ->
+ \big[*%M/1]_(i | P i) F i =
+ \big[*%M/1]_(j | P (h j) && (h' (h j) == j)) F (h j).
+Proof.
+by move=> h'K; rewrite (reindex_omap h (some \o h'))//= => i Pi; rewrite h'K.
Qed.
Arguments reindex_onto [I J] h h' [P F].
@@ -1493,6 +1504,19 @@ Lemma reindex_inj (I : finType) (h : I -> I) (P : pred I) F :
Proof. by move=> injh; apply: reindex (onW_bij _ (injF_bij injh)). Qed.
Arguments reindex_inj [I h P F].
+Lemma bigD1_ord n j (P : pred 'I_n) F :
+ P j -> \big[*%M/1]_(i < n | P i) F i
+ = F j * \big[*%M/1]_(i < n.-1 | P (lift j i)) F (lift j i).
+Proof.
+move=> Pj; rewrite (bigD1 j Pj) (reindex_omap (lift j) (unlift j))/=.
+ (** Coq >= 8.10 *)
+ (* by under eq_bigl do rewrite liftK eq_sym eqxx neq_lift ?andbT. *)
+ (** Coq >= 8.7 *)
+ congr (_ * _); apply: eq_bigl => i.
+ by rewrite liftK eq_sym eqxx neq_lift ?andbT.
+by move=> i; case: unliftP => [k ->|->]; rewrite ?eqxx ?andbF.
+Qed.
+
Lemma big_enum_val_cond (I : finType) (A : pred I) (P : pred I) F :
\big[op/idx]_(x in A | P x) F x =
\big[op/idx]_(i < #|A| | P (enum_val i)) F (enum_val i).
@@ -1536,14 +1560,26 @@ do 2!rewrite (big_addn _ _ 0) big_mkord; rewrite (reindex_inj rev_ord_inj) /=.
by apply: eq_big => [i | i _]; rewrite /= -addSn subnDr addnC addnBA.
Qed.
+Lemma sig_big_dep (I : finType) (J : I -> finType)
+ (P : pred I) (Q : forall {i}, pred (J i)) (F : forall {i}, J i -> R) :
+ \big[op/idx]_(i | P i) \big[op/idx]_(j : J i | Q j) F j =
+ \big[op/idx]_(p : {i : I & J i} | P (tag p) && Q (tagged p)) F (tagged p).
+Proof.
+pose s := [seq Tagged J j | i <- index_enum I, j <- index_enum (J i)].
+rewrite [LHS]big_mkcond big_mkcondl [RHS]big_mkcond -[RHS](@perm_big _ s).
+ rewrite big_allpairs_dep/=; apply: eq_bigr => i _; rewrite -big_mkcond/=.
+ by case: P; rewrite // big1.
+rewrite uniq_perm ?index_enum_uniq//.
+ by rewrite allpairs_uniq_dep// => [|i|[i j] []]; rewrite ?index_enum_uniq.
+by move=> [i j]; rewrite ?mem_index_enum; apply/allpairsPdep; exists i, j.
+Qed.
+
Lemma pair_big_dep (I J : finType) (P : pred I) (Q : I -> pred J) F :
\big[*%M/1]_(i | P i) \big[*%M/1]_(j | Q i j) F i j =
\big[*%M/1]_(p | P p.1 && Q p.1 p.2) F p.1 p.2.
Proof.
-rewrite (partition_big fst P) => [|j]; last by case/andP.
-apply: eq_bigr => i /= Pi; rewrite (reindex_onto (pair i) snd).
- by apply: eq_bigl => j; rewrite !eqxx [P i]Pi !andbT.
-by case=> i' j /= /andP [_] /eqP ->.
+rewrite sig_big_dep; apply: (reindex (fun x => Tagged (fun=> J) x.2)).
+by exists (fun x => (projT1 x, projT2 x)) => -[].
Qed.
Lemma pair_big (I J : finType) (P : pred I) (Q : pred J) F :
@@ -1644,7 +1680,9 @@ Arguments bigID [R idx op I r].
Arguments bigU [R idx op I].
Arguments bigD1 [R idx op I] j [P F].
Arguments bigD1_seq [R idx op I r] j [F].
+Arguments bigD1_ord [R idx op n] j [P F].
Arguments partition_big [R idx op I J P] p Q [F].
+Arguments reindex_omap [R idx op I J] h h' [P F].
Arguments reindex_onto [R idx op I J] h h' [P F].
Arguments reindex [R idx op I J] h [P F].
Arguments reindex_inj [R idx op I h P F].
@@ -1652,6 +1690,7 @@ Arguments big_enum_val_cond [R idx op I A] P F.
Arguments big_enum_rank_cond [R idx op I A x] xA P F.
Arguments big_enum_val [R idx op I A] F.
Arguments big_enum_rank [R idx op I A x] xA F.
+Arguments sig_big_dep [R idx op I J].
Arguments pair_big_dep [R idx op I J].
Arguments pair_big [R idx op I J].
Arguments big_allpairs_dep {R idx op I1 I2 J h r1 r2 F}.
@@ -1736,7 +1775,7 @@ Proof.
have [j _ | J0] := pickP J; first by rewrite (big_distr_big_dep j).
have Q0 i: Q i =i pred0 by move=> /J0/esym/notF[].
transitivity (iter #|I| ( *%M 0) 1).
- by rewrite -big_const; apply/eq_bigr=> i; have /(big_pred0 _)-> := Q0 i.
+ by rewrite -big_const; apply/eq_bigr=> i; have /(big_pred0 _)-> := Q0 i.
have [i _ | I0] := pickP I.
rewrite (cardD1 i) //= mul0m big_pred0 // => f.
by apply/familyP=> /(_ i); rewrite Q0.
diff --git a/mathcomp/ssreflect/finset.v b/mathcomp/ssreflect/finset.v
index 9bd8c1f..4262ed7 100644
--- a/mathcomp/ssreflect/finset.v
+++ b/mathcomp/ssreflect/finset.v
@@ -1453,17 +1453,13 @@ Lemma big_imset h (A : {pred I}) G : {in A &, injective h} ->
\big[aop/idx]_(j in h @: A) G j = \big[aop/idx]_(i in A) G (h i).
Proof.
move=> injh; pose hA := mem (image h A).
-have [x0 Ax0 | A0] := pickP A; last first.
- by rewrite !big_pred0 // => x; apply/imsetP=> [[i]]; rewrite unfold_in A0.
rewrite (eq_bigl hA) => [|j]; last exact/imsetP/imageP.
-pose h' j := if insub j : {? j | hA j} is Some u then iinv (svalP u) else x0.
-rewrite (reindex_onto h h') => [|j hAj]; rewrite {}/h'; last first.
- by rewrite (insubT hA hAj) f_iinv.
-apply: eq_bigl => i; case: insubP => [u -> /= def_u | nhAhi].
- set i' := iinv _; have Ai' : i' \in A := mem_iinv (svalP u).
- by apply/eqP/idP=> [<- // | Ai]; apply: injh; rewrite ?f_iinv.
-symmetry; rewrite (negbTE nhAhi); apply/idP=> Ai.
-by case/imageP: nhAhi; exists i.
+pose h' := omap (fun u : {j | hA j} => iinv (svalP u)) \o insub.
+rewrite (reindex_omap h h') => [|j hAj]; rewrite {}/h'/= ?insubT/= ?f_iinv//.
+apply: eq_bigl => i; case: insubP => [u -> /= def_u | nhAhi]; last first.
+ by apply/andP/idP => [[]//| Ai]; case/imageP: nhAhi; exists i.
+set i' := iinv _; have Ai' : i' \in A := mem_iinv (svalP u).
+by apply/eqP/idP => [[<-] // | Ai]; congr Some; apply: injh; rewrite ?f_iinv.
Qed.
Lemma big_imset_cond h (A : {pred I}) (P : pred J) G : {in A &, injective h} ->
diff --git a/mathcomp/ssreflect/fintype.v b/mathcomp/ssreflect/fintype.v
index 7e440ab..3472a1d 100644
--- a/mathcomp/ssreflect/fintype.v
+++ b/mathcomp/ssreflect/fintype.v
@@ -2074,6 +2074,12 @@ Qed.
Lemma neq_lift n (h : 'I_n) i : h != lift h i.
Proof. exact: neq_bump. Qed.
+Lemma eq_liftF n (h : 'I_n) i : (h == lift h i) = false.
+Proof. exact/negbTE/neq_lift. Qed.
+
+Lemma lift_eqF n (h : 'I_n) i : (lift h i == h) = false.
+Proof. by rewrite eq_sym eq_liftF. Qed.
+
Lemma unlift_none n (h : 'I_n) : unlift h h = None.
Proof. by case: unliftP => // j Dh; case/eqP: (neq_lift h j). Qed.
@@ -2108,6 +2114,23 @@ Proof. by move=> ? ? /(f_equal val) /= /val_inj. Qed.
Lemma rshift_inj m n : injective (@rshift m n).
Proof. by move=> ? ? /(f_equal val) /addnI /val_inj. Qed.
+Lemma eq_lshift m n i j : (@lshift m n i == @lshift m n j) = (i == j).
+Proof. by rewrite (inj_eq (@lshift_inj _ _)). Qed.
+
+Lemma eq_rshift m n i j : (@rshift m n i == @rshift m n j) = (i == j).
+Proof. by rewrite (inj_eq (@rshift_inj _ _)). Qed.
+
+Lemma eq_lrshift m n i j : (@lshift m n i == @rshift m n j) = false.
+Proof.
+apply/eqP=> /(congr1 val)/= def_i; have := ltn_ord i.
+by rewrite def_i -ltn_subRL subnn.
+Qed.
+
+Lemma eq_rlshift m n i j : (@rshift m n i == @lshift m n j) = false.
+Proof. by rewrite eq_sym eq_lrshift. Qed.
+
+Definition eq_shift := (eq_lshift, eq_rshift, eq_lrshift, eq_rlshift).
+
Lemma split_subproof m n (i : 'I_(m + n)) : i >= m -> i - m < n.
Proof. by move/subSn <-; rewrite leq_subLR. Qed.
@@ -2131,6 +2154,13 @@ set lt_i_m := i < m; rewrite /split.
by case: _ _ _ _ {-}_ lt_i_m / ltnP; [left | right; rewrite subnKC].
Qed.
+Variant split_ord_spec m n (i : 'I_(m + n)) : 'I_m + 'I_n -> bool -> Type :=
+ | SplitOrdLo (j : 'I_m) of i = lshift _ j : split_ord_spec i (inl _ j) true
+ | SplitOrdHi (k : 'I_n) of i = rshift _ k : split_ord_spec i (inr _ k) false.
+
+Lemma split_ordP m n (i : 'I_(m + n)) : split_ord_spec i (split i) (i < m).
+Proof. by case: splitP; [left|right]; apply: val_inj. Qed.
+
Definition unsplit {m n} (jk : 'I_m + 'I_n) :=
match jk with inl j => lshift n j | inr k => rshift m k end.
@@ -2138,12 +2168,11 @@ Lemma ltn_unsplit m n (jk : 'I_m + 'I_n) : (unsplit jk < m) = jk.
Proof. by case: jk => [j|k]; rewrite /= ?ltn_ord // ltnNge leq_addr. Qed.
Lemma splitK {m n} : cancel (@split m n) unsplit.
-Proof. by move=> i; apply: val_inj; case: splitP. Qed.
+Proof. by move=> i; case: split_ordP. Qed.
Lemma unsplitK {m n} : cancel (@unsplit m n) split.
Proof.
-move=> jk; have:= ltn_unsplit jk.
-by do [case: splitP; case: jk => //= i j] => [|/addnI] => /ord_inj->.
+by move=> [j|k]; case: split_ordP => ? /eqP; rewrite eq_shift// => /eqP->.
Qed.
Section OrdinalPos.
diff --git a/mathcomp/ssreflect/seq.v b/mathcomp/ssreflect/seq.v
index dec68a3..059d04c 100644
--- a/mathcomp/ssreflect/seq.v
+++ b/mathcomp/ssreflect/seq.v
@@ -132,6 +132,8 @@ From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat.
(* i.e. self expanding definition for *)
(* [seq f x y | x <- s, y <- t] *)
(* := [:: f x_1 y_1; ...; f x_1 y_m; f x_2 y_1; ...; f x_n y_m] *)
+(* allrel r s := all id [seq r x y | x <- xs, y <- xs] *)
+(* == the proposition r x y holds for all possible x, y in xs *)
(* map f s == the sequence [:: f x_1, ..., f x_n]. *)
(* pmap pf s == the sequence [:: y_i1, ..., y_ik] where i1 < ... < ik, *)
(* pf x_i = Some y_i, and pf x_j = None iff j is not in *)
@@ -2474,6 +2476,12 @@ Proof.
by apply: (@eq_from_nth _ x0); rewrite size_mkseq // => i Hi; rewrite nth_mkseq.
Qed.
+Variant mkseq_spec s : seq T -> Type :=
+| MapIota n f : s = mkseq f n -> mkseq_spec s (mkseq f n).
+
+Lemma mkseqP s : mkseq_spec s s.
+Proof. by rewrite -[s]mkseq_nth; constructor. Qed.
+
End MakeSeq.
Section MakeEqSeq.
@@ -3138,6 +3146,48 @@ Arguments allpairsP {S T R f s t z}.
Arguments perm_nilP {T s}.
Arguments perm_consP {T x s t}.
+Section AllRel.
+
+Definition allrel {T : Type} (r : rel T) xs :=
+ all id [seq r x y | x <- xs, y <- xs].
+
+Lemma allrel0 (T : Type) (r : rel T) : allrel r [::].
+Proof. by []. Qed.
+
+Lemma allrel_map (T T' : Type) (f : T' -> T) (r : rel T) xs :
+ allrel r (map f xs) = allrel (relpre f r) xs.
+Proof. by rewrite /allrel allpairs_mapl allpairs_mapr. Qed.
+
+Lemma allrelP {T : eqType} {r : rel T} {xs : seq T} :
+ reflect {in xs &, forall x y, r x y} (allrel r xs).
+Proof. exact: all_allpairsP. Qed.
+
+Variable (T : nonPropType) (r : rel T).
+Implicit Types (xs : seq T) (x y z : T).
+Hypothesis (rxx : reflexive r) (rsym : symmetric r).
+
+Lemma allrel1 x : allrel r [:: x].
+Proof. by rewrite /allrel/= rxx. Qed.
+
+Lemma allrel2 x y : allrel r [:: x; y] = r x y.
+Proof. by rewrite /allrel/= !rxx [r y x]rsym !(andbT, andbb). Qed.
+
+Lemma allrel_cons x xs :
+ allrel r (x :: xs) = all (r x) xs && allrel r xs.
+Proof.
+case: (mkseqP x (_ :: _)) => -[//|n] f [-> ->].
+rewrite !allrel_map all_map; apply/allrelP/andP => /= [rf|].
+ split; first by apply/allP => i iP /=; rewrite rf// in_cons iP orbT.
+ by apply/allrelP => i j iP jP /=; rewrite rf// in_cons (iP, jP) orbT.
+move=> [/allP/= rf0 /allrelP/= rf] i j; rewrite !in_cons.
+by move=> /predU1P[->|iP] /predU1P[->|jP]//=; rewrite 2?(rf0, rsym)//= rf.
+Qed.
+
+End AllRel.
+
+Arguments allrel {T} r xs.
+Arguments allrelP {T r xs}.
+
Section Permutations.
Variable T : eqType.