Module triangular_rs

Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype.
Require Import finfun finset ssralg perm zmodp seqmatrixCR.
Require Import rs_definitions aux_lemmas advf_type advf_ord_triangular triangular.
Require Import Recdef matrix rs_admissible boolF2 cssralg rs_dvf.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

Open Local Scope ring_scope.



Section Triangular_ulsubseqmx.


Lemma compij_M_ulsubseqmx M k: forall i j, i < k -> j < k ->
  compij i j M = compij i j (take k M).
Proof.
move=> i j ik jk.
by rewrite /compij nth_take.
Qed.

Lemma compij_M_ulsubseqmx2 M k: forall i j, i < k -> j < k ->
  k <= size M ->compij i j M = compij i j (map (take k) M).
Proof.
move=> i j ik jk HH.
rewrite /compij (nth_map [::]) /=.
  case H2: k =>[|k11].
    by move:jk; rewrite H2.
 rewrite nth_take; first by done.
by rewrite -H2.
move:HH; rewrite leq_eqVlt; move/orP=>[H1|H1].
  by rewrite -(eqP H1).
by rewrite (ltn_trans ik H1).
Qed.



Lemma compij_M_ulsubseqmx1 M k: forall i j, i < k -> j < k ->
  k <= size M -> compij i j M = compij i j (ulsubseqmx k k M).
Proof.
move=> i j ik jk HH.
rewrite /ulsubseqmx map_take.
rewrite (compij_M_ulsubseqmx M ik jk).
have H1: (k <= size (take k M)); first by rewrite size_take; case:(k < size M).
by rewrite (compij_M_ulsubseqmx2 ik jk H1) map_take.
Qed.



Lemma size_dvf_reorderM dvfo M:
size dvfo <= size (reorderM_dvf dvfo M).
Proof.
rewrite /reorderM_dvf /reorderM /take_columns_s size_map.
rewrite /take_rows_s size_map /fill size_cat -sizedvf_getfirst.
case H: (size (filter [pred i | i \notin getfirstElemseq dvfo] (iota 0 (size M)))); first
  by rewrite addn0.
by rewrite -{1}(addn0(size dvfo)) leq_add2l.
Qed.



Lemma diagonalis1_ulsubseqmx dvf M ords:
  let n:= size dvf in
  Vecfieldadm M dvf ords ->
  (forall k, k < n ->
   compij k k (ulsubseqmx n n (reorderM_dvf dvf M)) = true).
Proof.
rewrite /reorderM_dvf.
rewrite /=.
move=> H1 k H2.
move: (diagonalis1_gen H1 H2).
rewrite (@compij_M_ulsubseqmx1 (reorderM (fill (getfirstElemseq dvf) (size M))
     (fill (getsndElemseq dvf) (size (head [::] M))) M) (size dvf) k k H2 H2); first by done.
apply:(size_dvf_reorderM).
Qed.


Lemma diagonalis1_ulsubseqmx_dvford (dvf:vectorfield) m1 n1 (M:matZ2):
is_matrix m1 n1 M ->
let dvf := dvford M in
let n:= size dvf in
  (forall k, 0 <= k < (size dvf) ->
   compij k k (ulsubseqmx n n (reorderM_dvf dvf M)) = true).
Proof.
move=> H /=.
by apply: (diagonalis1_ulsubseqmx (dvfordisVecfieldadm H)).
Qed.




Lemma onDiagonal0_ulsubseqmx (M:matZ2)(dvfo:vectorfield) ords:
  let n := size dvfo in
  Vecfieldadm M dvfo ords ->
  (forall (r s:nat), (r< n) && (s < n) && (r < s) ->
    compij r s (ulsubseqmx n n (reorderM_dvf dvfo M)) = false).
Proof.
rewrite /reorderM_dvf /=.
move=> H1 r s H2.
move: (onDiagonal0_gen (size dvfo) H1 H2).
move:H2; move/andP=>[H21 H22]; move:(andP H21)=>[H3 H4].
rewrite (@compij_M_ulsubseqmx1 (reorderM (fill (getfirstElemseq dvfo) (size M))
     (fill (getsndElemseq dvfo) (size (head [::] M))) M) (size dvfo) r s H3 H4); first by done.
apply:(size_dvf_reorderM).
Qed.


Lemma onDiagonal0_ulsubseqmx_dvford (n:nat)(M:matZ2)(dvfo:vectorfield):
  is_matrix n n M ->
let dvfo := dvford M in
  let n := size dvfo in
  (forall (r s:nat), (r< n) && (s < n) && (r < s) ->
    compij r s (ulsubseqmx n n (reorderM_dvf dvfo M)) = false).
Proof.
move=> H /=.
apply: (onDiagonal0_ulsubseqmx (dvfordisVecfieldadm H)).
Qed.



End Triangular_ulsubseqmx.



Section triangular_seq_ulsubseq.

Definition lower_triangular_seq n (M:matZ2) :=
  (forall k, k < (n+1) -> (compij k k M) = true) /\
  (forall r s, (r < (n+1)) && (0 <= s < (n+1)) && (r < s) -> (compij r s M) = false).


Lemma lower_triangular_seq_ulsubseqmx_rs M dvf ords:
  let n:= ((size dvf)%N)%N in
  0 < n ->
  Vecfieldadm M dvf ords ->
  lower_triangular_seq (size dvf - 1) (ulsubseqmx n n (reorderM_dvf dvf M)).
Proof.
rewrite /reorderM_dvf.
case H: dvf =>[|v1 v2]; first by done.
rewrite /= => h H1.
rewrite /lower_triangular_seq.
have H3: ((size v2 + 1)%N = size (v1::v2)); first by rewrite addn1 /=.
rewrite !subn1 /=; split.
  move=> k H4.
  rewrite addn1 in H4.
  by rewrite (diagonalis1_ulsubseqmx H1 H4).
move=> r s H2.
rewrite H3 in H2.
by move: (onDiagonal0_ulsubseqmx H1 H2); rewrite /=.
Qed.


End triangular_seq_ulsubseq.



Section triangular_ulsubseq.

Lemma eq_nat_of_ord_eq_ord n (i j:'I_n) : (nat_of_ord i)==(nat_of_ord j) -> i==j.
Proof.
by move=>H; apply/eqP; apply : val_inj; move : (eqP H) => H1.
Qed.


Lemma lower_triangular_seqE : forall n (M:'M_(n+1)),
   lower_triangular_seq n (seqmx_of_mx bool_cunitRingType M) <-> (lower_triangular M).
Proof.
split.
  move => [H1 H2].
  rewrite /lower_triangular => i j ij.
  move : ij; rewrite leq_eqVlt; move/orP => [H3|H4].
    rewrite (eq_nat_of_ord_eq_ord H3) /=.
    rewrite (eqP (eq_nat_of_ord_eq_ord H3)).
    have : (seqmx_of_mx bool_cunitRingType M) j j = true.
      by rewrite -(H1 j); last by apply : (ltn_ord j).
    rewrite seqmxE.
    move : (or_Z2ring (M j j)) => [Ha | Ha].
      by rewrite (eqP Ha).
    by rewrite (eqP Ha).
  have -> : (i == j) = false by apply/eqP/eqP; rewrite neq_ltn; apply/orP; left.
    rewrite //=.
  have H5 : (0 <= i < n+1) && (0 <= j < n+1) && (i < j); first by rewrite H4 (ltn_ord j) (ltn_ord i).
  have : (seqmx_of_mx bool_cunitRingType M) i j = false by rewrite -(H2 i j H5).
  rewrite seqmxE.
    move : (or_Z2ring (M i j)) => [Ha | Ha].
      by rewrite (eqP Ha).
    by rewrite (eqP Ha).
move => H; split.
  move => k0; rewrite /= /compij => H1.
  have -> : nth false (nth [::] (seqmx_of_mx bool_cunitRingType M) k0) k0 =
            (seqmx_of_mx bool_cunitRingType M) k0 k0 by done.
  rewrite (seqmxE bool_cunitRingType M (Ordinal H1) (Ordinal H1)).
    rewrite (H (Ordinal H1) (Ordinal H1)).
    by have -> : (Ordinal H1 == Ordinal H1); first by apply/eqP.
  by rewrite leq_eqVlt; apply/orP; left; apply/eqP.
move => r s; move/andP => [H1 H2]; move : H1; rewrite /=; move/andP => [H3 H4].
have -> : compij r s (seqmx_of_mx bool_cunitRingType M) =
          (seqmx_of_mx bool_cunitRingType M) r s by done.
rewrite (seqmxE bool_cunitRingType M (Ordinal H3) (Ordinal H4)).
rewrite (H (Ordinal H3) (Ordinal H4)); last first.
  by rewrite leq_eqVlt; apply/orP; right.
have -> : (Ordinal H3 == Ordinal H4) = false; last by done.
by apply/eqP/eqP; rewrite neq_ltn; apply/orP; left.
Qed.


Section identity_lemmas.



Variables m n : nat.

Local Open Scope ring_scope.


Definition boolseqtoF2 (s : seq bool) :=
map (fun i => if (i == false) then 0:'F_2 else 1:'F_2) s.


Definition mx_of_seqmx (M:seqmatrix bool_cunitRingType) :=
  \matrix_(i < m, j < n) nth (0:'F_2) (boolseqtoF2 (rowseqmx M i)) j.



Lemma trans_mx_of_seqmx (M : seqmatrix bool_cunitRingType) :
  [/\ m = size M & forall i, i < m -> size (rowseqmx M i) = n] -> forall (i : 'I_m) (j:'I_n),
  M i j = trans (mx_of_seqmx M i j).
Proof.
move => [H1 H2] i j.
rewrite /trans /= /bool_trans mxE (nth_map false) /rowseqmx.
have <- : (M i j) = (nth false (nth [::] M i) j) by done.
move : (or_bool (M i j)) => [Ha | Ha].
    by rewrite Ha (eqP Ha).
  by rewrite (eqP Ha).
by rewrite (H2 i (ltn_ord i)).
Qed.


Lemma seqmx_of_mx_mx_of_seqmx: forall (M : seqmatrix bool_cunitRingType),
  [/\ m = size M & forall i, i < m -> size (rowseqmx M i) = n] ->
   (@seqmx_of_mx _ bool_cunitRingType m n (mx_of_seqmx M)) = M.
Proof.
move => M H.
move: (@seqmxP _ bool_cunitRingType m n M (mx_of_seqmx M)).
case => H1 _.
move : (trans_mx_of_seqmx H) => H2.
move : H => [Ha Hb].
by rewrite -H1; split.
Qed.


End identity_lemmas.




Lemma lower_triangular_ulsubseqmx_rs M dvf ords:
  let n:= ((size dvf)%N - 1%N)%N in
  dvf!=[::] ->
  Vecfieldadm M dvf ords ->
  lower_triangular (mx_of_seqmx (n+1) (n+1) (ulsubseqmx (n+1) (n+1) (reorderM_dvf dvf M))).
Proof.
rewrite /reorderM_dvf /=; move=> H1 H2.
have H11: (0 < size dvf); first by move: H1; by case hh: dvf.
rewrite -(lower_triangular_seqE) /=.
have HH: (((size dvf)%N - 1 + 1)%N = size dvf).
  by move:H11; case H4:(size dvf)=>[|n1]; last by rewrite subn1 /= addn1.
have H21 : size dvf =
   size
     (ulsubseqmx (size dvf) (size dvf)
        (reorderM (fill (getfirstElemseq dvf) (size M))
           (fill (getsndElemseq dvf) (size (head [::] M))) M)).
  rewrite /ulsubseqmx size_map size_take.
  move: (size_dvf_reorderM dvf M).
  by rewrite leq_eqVlt; move/orP=>[H4|->];first by rewrite -(eqP H4) ltnn.
have H22: forall i : nat,
   i < size dvf ->
   size
     (rowseqmx
        (ulsubseqmx (size dvf) (size dvf)
           (reorderM (fill (getfirstElemseq dvf) (size M))
              (fill (getsndElemseq dvf) (size (head [::] M))) M)) i) =
   size dvf.
move=> i H.
rewrite /reorderM /ulsubseqmx !map_take.
rewrite /rowseqmx (nth_take [::] H).
move: (size_dvf_reorderM dvf M) =>H4.
move: (size_takel H4) => H5.
rewrite (nth_map [::]); last first.
  move: H4; rewrite /reorderM.
  rewrite leq_eqVlt; move/orP=>[H6|H6].
    by rewrite -(eqP H6).
  by rewrite (ltn_trans H H6).
  rewrite /take_columns_s.
rewrite (nth_map [::]).
  rewrite /take_rows_s size_take; last first.
  case H6:(size dvf < size (take_row_s (fill (getsndElemseq dvf) (size (head [::] M)))
  (nth [::] (map (nth [::] M) (fill (getfirstElemseq dvf) (size M))) i))); first by done.
  move:H6; rewrite /take_row_s size_map /fill.
  case H6:(filter [pred i0 | i0 \notin getsndElemseq dvf]
      (iota 0 (size (head [::] M)))) =>[|t s]; first by rewrite cats0 sizedvf_getsnd.
  rewrite size_cat /= -sizedvf_getsnd.
  by have ->: ((size dvf < size dvf + (size s).+1)); first by rewrite -{1}(addn0 (size dvf)) ltn_add2l.
rewrite /take_rows_s size_map /fill size_cat -sizedvf_getfirst.
case H6:(size (filter [pred i0 | i0 \notin getfirstElemseq dvf] (iota 0 (size M))))=>[|n1]; first by rewrite addn0.
have H7:(size dvf < size dvf + n1.+1); first by rewrite -{1}(addn0 (size dvf)) ltn_add2l.
by rewrite (ltn_trans H H7).
rewrite (@seqmx_of_mx_mx_of_seqmx (size dvf - 1 + 1) (size dvf - 1 + 1) (ulsubseqmx (size dvf - 1 + 1) (size dvf - 1 + 1)
           (reorderM (fill (getfirstElemseq dvf) (size M))
              (fill (getsndElemseq dvf) (size (head [::] M))) M))).
  rewrite HH; apply: (lower_triangular_seq_ulsubseqmx_rs H11 H2).
rewrite HH; split.
   by rewrite {1}H21.
  by done.
Qed.

Lemma lower_triangular_det_1 M dvf ords:
  let n:= ((size dvf)%N - 1%N)%N in
  let A:= (mx_of_seqmx (n+1) (n+1) (ulsubseqmx (n+1) (n+1) (reorderM_dvf dvf M))) in
  dvf!= [::] ->
  Vecfieldadm M dvf ords -> \det A = 1.
Proof.
rewrite /reorderM_dvf /= => H1 H2.
move: (lower_triangular_ulsubseqmx_rs H1 H2)=> H3.
by apply: (lower_triangular_det_1 H3).
Qed.


End triangular_ulsubseq.